@nmnmcc/ability 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,160 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { fromRawRules, isAbility } from "./Ability.js";
3
+ import * as Effect from "effect/Effect";
4
+ import * as Equal from "effect/Equal";
5
+ import * as Formatter from "effect/Formatter";
6
+ import { dual } from "effect/Function";
7
+ import * as Hash from "effect/Hash";
8
+ import * as Inspectable from "effect/Inspectable";
9
+ import * as Pipeable from "effect/Pipeable";
10
+ import * as Predicate from "effect/Predicate";
11
+ //#region src/AbilityRef.ts
12
+ /**
13
+ * Mutable ability references for applications that need to swap immutable
14
+ * abilities at runtime.
15
+ *
16
+ * Mental model:
17
+ * - `AbilityRef` is the explicit mutable boundary for this package.
18
+ * - The current ability can be replaced while subscribers observe update events.
19
+ * - All policy evaluation still happens against immutable `Ability` values.
20
+ *
21
+ * Common tasks:
22
+ * - Create a reference with {@link make}.
23
+ * - Read the current ability with {@link get}.
24
+ * - Replace the current ability with {@link set} or {@link update}.
25
+ * - Subscribe to update events with {@link on}.
26
+ *
27
+ * Gotchas:
28
+ * - Event handlers run in registration order.
29
+ * - `update` accepts raw rules and reuses the current ability options.
30
+ * - `AbilityRef` equality is referential because the current value is mutable.
31
+ *
32
+ * @since 0.1.0
33
+ * @module
34
+ */
35
+ var AbilityRef_exports = /* @__PURE__ */ __exportAll({
36
+ TypeId: () => TypeId,
37
+ get: () => get,
38
+ isAbilityRef: () => isAbilityRef,
39
+ make: () => make,
40
+ on: () => on,
41
+ set: () => set,
42
+ update: () => update
43
+ });
44
+ /**
45
+ * @since 0.1.0
46
+ * @category Type Ids
47
+ */
48
+ const TypeId = Symbol.for("@nmnmcc/ability/AbilityRef");
49
+ const RefIdentityTypeId = Symbol.for("@nmnmcc/ability/AbilityRef/identity");
50
+ let refIdentity = 0;
51
+ const inspectableToString = function() {
52
+ return Formatter.format(this.toJSON(), {
53
+ ignoreToString: true,
54
+ space: 2
55
+ });
56
+ };
57
+ const inspectableNode = function() {
58
+ return this.toJSON();
59
+ };
60
+ const AbilityRefProto = {
61
+ ...Pipeable.Prototype,
62
+ [TypeId]: TypeId,
63
+ [Equal.symbol](that) {
64
+ return isAbilityRef(that) && this[RefIdentityTypeId] === that[RefIdentityTypeId];
65
+ },
66
+ [Hash.symbol]() {
67
+ return Hash.number(this[RefIdentityTypeId]);
68
+ },
69
+ toString: inspectableToString,
70
+ toJSON() {
71
+ return {
72
+ _id: "AbilityRef",
73
+ current: this.current
74
+ };
75
+ },
76
+ [Inspectable.NodeInspectSymbol]: inspectableNode
77
+ };
78
+ /**
79
+ * @since 0.1.0
80
+ * @category Constructors
81
+ */
82
+ const make = (ability) => {
83
+ const ref = Object.create(AbilityRefProto);
84
+ ref.current = ability;
85
+ ref[RefIdentityTypeId] = refIdentity;
86
+ refIdentity = refIdentity + 1;
87
+ ref.handlers = {
88
+ update: [],
89
+ updated: []
90
+ };
91
+ return ref;
92
+ };
93
+ /**
94
+ * @since 0.1.0
95
+ * @category Guards
96
+ */
97
+ const isAbilityRef = (value) => Predicate.hasProperty(value, TypeId);
98
+ /**
99
+ * @since 0.1.0
100
+ * @category Accessors
101
+ */
102
+ const get = (self) => self.current;
103
+ const toEffect = (evaluate) => Effect.flatMap(Effect.sync(evaluate), (result) => Effect.isEffect(result) ? result : Effect.void);
104
+ const emit = Effect.fnUntraced(function* (self, name, event) {
105
+ const handlers = Array.from(self.handlers[name]);
106
+ for (const handler of handlers) yield* toEffect(() => handler(event));
107
+ });
108
+ /**
109
+ * @since 0.1.0
110
+ * @category Combinators
111
+ */
112
+ const setEffect = Effect.fnUntraced(function* (self, ability) {
113
+ const previous = self.current;
114
+ const next = ability;
115
+ const mutable = self;
116
+ yield* emit(self, "update", {
117
+ previous,
118
+ next
119
+ });
120
+ mutable.current = next;
121
+ yield* emit(self, "updated", {
122
+ previous,
123
+ current: next
124
+ });
125
+ });
126
+ /**
127
+ * @since 0.1.0
128
+ * @category Combinators
129
+ */
130
+ const set = dual(2, setEffect);
131
+ /**
132
+ * @since 0.1.0
133
+ * @category Combinators
134
+ */
135
+ const update = dual(2, Effect.fnUntraced(function* (self, next) {
136
+ if (Symbol.iterator in Object(next) && !isAbility(next)) return yield* setEffect(self, yield* fromRawRules(next, self.current.options));
137
+ return yield* setEffect(self, next);
138
+ }));
139
+ /**
140
+ * @since 0.1.0
141
+ * @category Combinators
142
+ */
143
+ const onEffect = (self, name, handler) => Effect.sync(() => {
144
+ const handlers = self.handlers[name];
145
+ handlers.push(handler);
146
+ let active = true;
147
+ return () => {
148
+ if (!active) return;
149
+ active = false;
150
+ const index = handlers.indexOf(handler);
151
+ if (index >= 0) handlers.splice(index, 1);
152
+ };
153
+ });
154
+ /**
155
+ * @since 0.1.0
156
+ * @category Combinators
157
+ */
158
+ const on = dual(3, onEffect);
159
+ //#endregion
160
+ export { AbilityRef_exports, TypeId, get, isAbilityRef, make, on, set, update };
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll };
@@ -0,0 +1,4 @@
1
+ import { Ability_d_exports } from "./Ability.js";
2
+ import { AbilityExtra_d_exports } from "./AbilityExtra.js";
3
+ import { AbilityRef_d_exports } from "./AbilityRef.js";
4
+ export { Ability_d_exports as Ability, AbilityExtra_d_exports as AbilityExtra, AbilityRef_d_exports as AbilityRef };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { Ability_exports } from "./Ability.js";
2
+ import { AbilityExtra_exports } from "./AbilityExtra.js";
3
+ import { AbilityRef_exports } from "./AbilityRef.js";
4
+ export { Ability_exports as Ability, AbilityExtra_exports as AbilityExtra, AbilityRef_exports as AbilityRef };
@@ -0,0 +1,114 @@
1
+ import * as _$effect_Types0 from "effect/Types";
2
+ import * as _$effect_Cause0 from "effect/Cause";
3
+
4
+ //#region src/internal/ability.d.ts
5
+ /**
6
+ * @internal
7
+ */
8
+ declare const TypeId: unique symbol;
9
+ /**
10
+ * @internal
11
+ */
12
+ declare const SubjectTypeId: unique symbol;
13
+ /**
14
+ * @internal
15
+ */
16
+ declare const RuleTypeId: unique symbol;
17
+ declare const AuthorizationError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
18
+ readonly _tag: "AuthorizationError";
19
+ } & Readonly<A>;
20
+ /**
21
+ * @since 0.1.0
22
+ * @category Errors
23
+ */
24
+ declare class AuthorizationError extends AuthorizationError_base<{
25
+ readonly action: string;
26
+ readonly subject: string;
27
+ readonly field?: string;
28
+ readonly reason?: string;
29
+ }> {}
30
+ declare const ConditionError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
31
+ readonly _tag: "ConditionError";
32
+ } & Readonly<A>;
33
+ /**
34
+ * @since 0.1.0
35
+ * @category Errors
36
+ */
37
+ declare class ConditionError extends ConditionError_base<{
38
+ readonly action: string;
39
+ readonly subject: string;
40
+ readonly field?: string;
41
+ readonly cause: unknown;
42
+ }> {}
43
+ declare const PredicateEvaluationError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
44
+ readonly _tag: "PredicateEvaluationError";
45
+ } & Readonly<A>;
46
+ /**
47
+ * @since 0.1.0
48
+ * @category Errors
49
+ */
50
+ declare class PredicateEvaluationError extends PredicateEvaluationError_base<{
51
+ readonly action: string;
52
+ readonly subject: string;
53
+ readonly field?: string;
54
+ readonly cause: unknown;
55
+ }> {}
56
+ declare const SerializationError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
57
+ readonly _tag: "SerializationError";
58
+ } & Readonly<A>;
59
+ /**
60
+ * @since 0.1.0
61
+ * @category Errors
62
+ */
63
+ declare class SerializationError extends SerializationError_base<{
64
+ readonly reason: string;
65
+ readonly ruleIndex?: number;
66
+ }> {}
67
+ declare const RawRuleError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
68
+ readonly _tag: "RawRuleError";
69
+ } & Readonly<A>;
70
+ /**
71
+ * @since 0.1.0
72
+ * @category Errors
73
+ */
74
+ declare class RawRuleError extends RawRuleError_base<{
75
+ readonly reason: string;
76
+ readonly ruleIndex?: number;
77
+ readonly cause?: unknown;
78
+ }> {}
79
+ declare const SubjectDetectionError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
80
+ readonly _tag: "SubjectDetectionError";
81
+ } & Readonly<A>;
82
+ /**
83
+ * @since 0.1.0
84
+ * @category Errors
85
+ */
86
+ declare class SubjectDetectionError extends SubjectDetectionError_base<{
87
+ readonly reason: string;
88
+ readonly cause?: unknown;
89
+ }> {}
90
+ declare const AliasError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
91
+ readonly _tag: "AliasError";
92
+ } & Readonly<A>;
93
+ /**
94
+ * @since 0.1.0
95
+ * @category Errors
96
+ */
97
+ declare class AliasError extends AliasError_base<{
98
+ readonly reason: string;
99
+ readonly action?: string;
100
+ }> {}
101
+ declare const QueryGenerationError_base: new <A extends Record<string, any> = {}>(args: _$effect_Types0.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => _$effect_Cause0.YieldableError & {
102
+ readonly _tag: "QueryGenerationError";
103
+ } & Readonly<A>;
104
+ /**
105
+ * @since 0.1.0
106
+ * @category Errors
107
+ */
108
+ declare class QueryGenerationError extends QueryGenerationError_base<{
109
+ readonly reason: string;
110
+ readonly ruleIndex?: number;
111
+ readonly cause?: unknown;
112
+ }> {}
113
+ //#endregion
114
+ export { AliasError, AuthorizationError, ConditionError, PredicateEvaluationError, QueryGenerationError, RawRuleError, RuleTypeId, SerializationError, SubjectDetectionError, SubjectTypeId, TypeId };