UNPKG

@falcondev-oss/caps

Version:

Simple, fully type-safe library to handle permissions/access control by defining capabilities with generators.

180 lines (176 loc) 5.25 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { MissingCapabilityError: () => MissingCapabilityError, arg: () => arg, createActor: () => createActor, mode: () => mode }); module.exports = __toCommonJS(index_exports); // src/capabilties.ts var R = __toESM(require("remeda"), 1); function collectGenerator(generator) { const items = []; let next = generator.next(); do { items.push(next.value); next = generator.next(); } while (!next.done); items.push(next.value); return items.filter(Boolean).flat(); } function createActor() { return { build(builder) { return (actor, opts) => { return builder(createCapability(actor, opts)); }; } }; } var filterInputSymbol = Symbol("filterInput"); function createCapability(actor, opts) { function getDefine() { return (resolver, args) => createQuery({ actor, resolver, opts }); } return { subject: () => ({ define: getDefine() }), define: getDefine() }; } var MissingCapabilityError = class extends Error { constructor(capability) { super(`Missing capability: '${capability}'`); this.name = "MissingCapabilityError"; } }; function createQuery({ actor, resolver, opts }) { function list({ subject, args = {} }) { const generator = resolver({ actor, subject, args }); return collectGenerator(generator); } function getCan(subject) { return (capability, ...args) => { const getCapabilities = () => list({ subject, args: args[0] ?? {} }); return { throw: () => { const actorCaps = list({ subject, args: args[0] }); if (actorCaps.includes(capability)) return; throw opts?.createError?.({ capability }) ?? new MissingCapabilityError(capability); }, check: () => getCapabilities().includes(capability) }; }; } const query = { subject: (subject) => ({ can: getCan(subject), list(args) { return list({ subject, args }); } }), subjects: (subjects, ...args) => { const mapper = args[0]; const mappedSubjects = mapper ? subjects.map(mapper) : subjects; return { canSome: (capability, ...args2) => { return { check: () => mappedSubjects.some((subject) => getCan(subject)(capability, ...args2).check()), throw: () => mappedSubjects.some((subject) => getCan(subject)(capability, ...args2).throw()) }; }, canEvery: (capability, ...args2) => { return { check: () => mappedSubjects.every((subject) => getCan(subject)(capability, ...args2).check()), throw: () => { if (mappedSubjects.every((subject) => getCan(subject)(capability, ...args2).check())) return; throw opts?.createError?.({ capability }) ?? new MissingCapabilityError(capability); } }; }, filter: (capabilities, args2) => { return subjects.map((s) => ({ ...mapper ? mapper(s) : s, [filterInputSymbol]: s })).filter( (subject) => R.intersection( list({ subject, args: args2 }), capabilities ).length === capabilities.length ).map((s) => s[filterInputSymbol]); } }; }, can: getCan(void 0), list(args) { return list({ subject: void 0, args }); } }; return query; } // src/index.ts function arg() { return {}; } function mode(key, obj) { return { __mode: key, ...obj }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { MissingCapabilityError, arg, createActor, mode });