@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
JavaScript
;
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
});