@l3dev/abac 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -39,7 +39,7 @@ const OrganisationABAC = ABAC.createResource("organisation")
39
39
  .withObject<Organisation>()
40
40
  .setActions([
41
41
  ABAC.createAction("create").withoutObject(),
42
- ABAC.createAction("view.public"),
42
+ ABAC.createAction("view.public").addTag("public"),
43
43
  ABAC.createAction("join")
44
44
  .setTitle("Allow Joining")
45
45
  .setDescription("Allow users to join the organisation")
@@ -63,6 +63,26 @@ export const abac = ABAC.create([OrganisationABAC])
63
63
  .allow("organisation:delete", (ctx) => ctx.subject.id === ctx.object.owner.id)
64
64
  );
65
65
 
66
+ // Getting tagged actions
67
+
68
+ abac.getTaggedActions("public");
69
+ /* [
70
+ {
71
+ path: "organisation:view.public",
72
+ action: ...,
73
+ own: false
74
+ }
75
+ ] */
76
+
77
+ abac.getTaggedActions("configurable");
78
+ /* [
79
+ {
80
+ path: "organisation:join",
81
+ action: ...,
82
+ own: false
83
+ }
84
+ ] */
85
+
66
86
  // Checking permissions
67
87
 
68
88
  const adminUser: User = {
@@ -90,9 +110,9 @@ const myOrganisation: Organisation = {
90
110
  owner: myUser
91
111
  };
92
112
 
93
- abac.can(myUser, "organisation:delete").granted({ object: myOrganisation }); // true
113
+ abac.can(myUser, "organisation:delete").granted(myOrganisation); // true
94
114
 
95
- abac.can(otherUser, "organisation:delete").granted({ object: myOrganisation }); // false
115
+ abac.can(otherUser, "organisation:delete").granted(myOrganisation); // false
96
116
 
97
- abac.can(adminUser, "organisation:delete").granted({ object: myOrganisation }); // true
117
+ abac.can(adminUser, "organisation:delete").granted(myOrganisation); // true
98
118
  ```
package/build/abac.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Action, type RuleCtx, type InferActionSubject } from "./action.js";
1
+ import { Action, type RuleCtx, type InferActionSubject, type ActionTag } from "./action.js";
2
2
  import { ActionGroup } from "./actionGroup.js";
3
3
  import type { ResourceMap } from "./internal/collections.js";
4
4
  import type { UnsetMarker } from "./internal/core.js";
@@ -8,27 +8,27 @@ import { Permission, type PermissionOptions } from "./permission.js";
8
8
  import { Policy } from "./policy.js";
9
9
  import { PolicyFilters } from "./policyFilters.js";
10
10
  import { Resource } from "./resource.js";
11
- export type ConfigurableAction = {
11
+ export type TaggedAction = {
12
12
  path: string;
13
13
  action: Action<any, any>;
14
14
  own: boolean;
15
15
  };
16
- type ConfigurableActionGroup = {
16
+ type TaggedActionGroup = {
17
17
  meta: IMeta;
18
- children: ConfigurableActionTreeNode[];
18
+ children: TaggedActionTreeNode[];
19
19
  };
20
- export type ConfigurableActionTreeNode = ConfigurableAction | ConfigurableActionGroup;
20
+ export type TaggedActionTreeNode = TaggedAction | TaggedActionGroup;
21
21
  export declare class ABAC<TResources extends ResourceMap> {
22
22
  private _resourceMap;
23
23
  private _policies;
24
24
  constructor(resourceMap: TResources);
25
25
  $resources: TResources;
26
26
  $actions: ActionPaths<TResources>;
27
- $configurableActions: FilterActionPaths<TResources, any, true>;
27
+ $taggedActions: <TTag extends ActionTag>() => FilterActionPaths<TResources, any, TTag>;
28
28
  $filterActions: <TCtx>() => FilterActionPaths<TResources, TCtx>;
29
- getConfigurableActions(): ConfigurableAction[];
30
- getConfigurableActionsTree(): ConfigurableActionTreeNode[];
31
- can<TActionPath extends ActionPaths<TResources>>(subject: InferActionSubject<ActionFromPath<TResources, TActionPath>>, path: TActionPath, options?: PermissionOptions<TActionPath, ActionFromPath<TResources, TActionPath>>): Omit<Permission<TActionPath, ActionFromPath<TResources, TActionPath>>, "granted" | "filter"> & (import("./internal/core.js").IsOnlyEmptyObject<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">> extends true ? {
29
+ getTaggedActions(tag: ActionTag): TaggedAction[];
30
+ getTaggedActionsTree(tag: ActionTag): TaggedActionTreeNode[];
31
+ can<TActionPath extends ActionPaths<TResources>>(subject: InferActionSubject<ActionFromPath<TResources, TActionPath>>, path: TActionPath, options?: PermissionOptions<TActionPath, ActionFromPath<TResources, TActionPath>>): Omit<Permission<TActionPath, ActionFromPath<TResources, TActionPath>>, "filter" | "granted"> & (import("./internal/core.js").IsOnlyEmptyObject<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">> extends true ? {
32
32
  granted(): boolean;
33
33
  test(): {
34
34
  granted: boolean;
@@ -36,18 +36,30 @@ export declare class ABAC<TResources extends ResourceMap> {
36
36
  policy: Policy<any> | null;
37
37
  rule: import("./policy.js").Rule | null;
38
38
  };
39
+ } : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T ? T extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T extends {
40
+ object: infer TObject;
41
+ } ? import("./internal/core.js").KeysEqual<{
42
+ object: any;
43
+ }, T> extends true ? {
44
+ granted(object: TObject): boolean;
45
+ test(object: TObject): {
46
+ granted: boolean;
47
+ specitivity: import("./policy.js").Specitivity;
48
+ policy: Policy<any> | null;
49
+ rule: import("./policy.js").Rule | null;
50
+ };
39
51
  } : {
40
- granted(ctx: import("./internal/core.js").Expand<Partial<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T ? T extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never> & Pick<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_1 ? T_1 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_1 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never, ((Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_5 ? T_5 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_5 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never) extends infer T_2 ? { [K in keyof T_2]: (Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_3 ? T_3 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_3 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never)[K] extends Exclude<(Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_4 ? T_4 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_4 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never)[K], undefined> ? K : never; } : never)[keyof (Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_6 ? T_6 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_6 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never)]>>): boolean;
41
- test(ctx: import("./internal/core.js").Expand<Partial<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T ? T extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never> & Pick<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_1 ? T_1 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_1 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never, ((Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_5 ? T_5 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_5 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never) extends infer T_2 ? { [K in keyof T_2]: (Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_3 ? T_3 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_3 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never)[K] extends Exclude<(Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_4 ? T_4 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_4 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never)[K], undefined> ? K : never; } : never)[keyof (Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> extends infer T_6 ? T_6 extends Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> ? T_6 extends import("./internal/core.js").EmptyObject ? Omit<Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject">, "object"> : Omit<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "subject"> : never : never)]>>): {
52
+ granted(object: TObject, additionalContext: import("./internal/core.js").Expand<Partial<Omit<T, "object">> & Pick<Omit<T, "object">, (Omit<T, "object"> extends infer T_1 ? { [K in keyof T_1]: Omit<T, "object">[K] extends Exclude<Omit<T, "object">[K], undefined> ? K : never; } : never)[Exclude<keyof T, "object">]>>): boolean;
53
+ test(object: TObject, additionalContext: import("./internal/core.js").Expand<Partial<Omit<T, "object">> & Pick<Omit<T, "object">, (Omit<T, "object"> extends infer T_1 ? { [K in keyof T_1]: Omit<T, "object">[K] extends Exclude<Omit<T, "object">[K], undefined> ? K : never; } : never)[Exclude<keyof T, "object">]>>): {
42
54
  granted: boolean;
43
55
  specitivity: import("./policy.js").Specitivity;
44
56
  policy: Policy<any> | null;
45
57
  rule: import("./policy.js").Rule | null;
46
58
  };
47
- }) & (import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>> extends import("./internal/core.js").EmptyObject ? {} : import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>> extends {} ? {
59
+ } : never : never : never) & (import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>> extends import("./internal/core.js").EmptyObject ? {} : import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>> extends {} ? {
48
60
  filter(objects: Exclude<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>["object"], void | undefined>[]): Exclude<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>["object"], void | undefined>[];
49
61
  } : {
50
- filter(objects: Exclude<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>["object"], void | undefined>[], ctx: import("./internal/core.js").Expand<Partial<import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>> & Pick<import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>, (import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>> extends infer T ? { [K in keyof T]: import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>[K] extends Exclude<import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>[K], undefined> ? K : never; } : never)[Exclude<keyof import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "object" | "subject">]>>): Exclude<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>["object"], void | undefined>[];
62
+ filter(objects: Exclude<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>["object"], void | undefined>[], additionalContext: import("./internal/core.js").Expand<Partial<import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>> & Pick<import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>, (import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>> extends infer T_1 ? { [K in keyof T_1]: import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>[K] extends Exclude<import("./action.js").InferActionAdditionalContext<ActionFromPath<TResources, TActionPath>>[K], undefined> ? K : never; } : never)[Exclude<keyof import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, "object" | "subject">]>>): Exclude<import("./action.js").InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>["object"], void | undefined>[];
51
63
  });
52
64
  addPolicy(build: (policy: Policy<TResources>) => Policy<TResources>): this;
53
65
  static create<TResource extends Resource<any, any>>(resources: TResource[]): ABAC<import("./internal/core.js").UnionToIntersection<TResource extends Resource<infer TName extends string, any> ? { [name in TName]: TResource; } : never, ResourceMap>>;
@@ -65,7 +77,7 @@ export declare class ABAC<TResources extends ResourceMap> {
65
77
  object: UnsetMarker;
66
78
  }>(name: TName): Action<TName, {
67
79
  ctx: TCtx;
68
- configurable: false;
80
+ tags: UnsetMarker;
69
81
  }>;
70
82
  static createActionGroup<TName extends string, TCtx extends RuleCtx = {
71
83
  subject: UnsetMarker;
package/build/abac.js CHANGED
@@ -11,22 +11,22 @@ export class ABAC {
11
11
  constructor(resourceMap) {
12
12
  this._resourceMap = resourceMap;
13
13
  }
14
- getConfigurableActions() {
14
+ getTaggedActions(tag) {
15
15
  const actions = [];
16
16
  const visitor = new ActionVisitor(this._resourceMap);
17
17
  visitor.traverse(({ action, resource, path }) => {
18
- if (!action.configurable) {
18
+ if (!action.tags.has(tag)) {
19
19
  return;
20
20
  }
21
21
  actions.push({
22
22
  path,
23
23
  action,
24
- own: resource.ownable && resource.ownConfigurable && !action.noObject
24
+ own: resource.ownable && !action.noObject
25
25
  });
26
26
  });
27
27
  return actions;
28
28
  }
29
- getConfigurableActionsTree() {
29
+ getTaggedActionsTree(tag) {
30
30
  const nodeMap = new Map();
31
31
  const root = {
32
32
  children: []
@@ -34,7 +34,7 @@ export class ABAC {
34
34
  nodeMap.set("", root);
35
35
  const visitor = new ActionVisitor(this._resourceMap);
36
36
  visitor.traverse(({ action, resource, path, stack }) => {
37
- if (!action.configurable) {
37
+ if (!action.tags.has(tag)) {
38
38
  return;
39
39
  }
40
40
  let parent = root;
@@ -56,7 +56,7 @@ export class ABAC {
56
56
  parent.children.push({
57
57
  path,
58
58
  action,
59
- own: resource.ownable && resource.ownConfigurable && !action.noObject
59
+ own: resource.ownable && !action.noObject
60
60
  });
61
61
  });
62
62
  return root.children;
package/build/abac.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"abac.js","sourceRoot":"","sources":["../src/abac.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAyC,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKnD,OAAO,EAAE,UAAU,EAA0B,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAezC,MAAM,OAAO,IAAI;IACR,YAAY,CAAa;IACzB,SAAS,GAAyB,EAAE,CAAC;IAE7C,YAAY,WAAuB;QAClC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;IACjC,CAAC;IAOM,sBAAsB;QAC5B,MAAM,OAAO,GAAyB,EAAE,CAAC;QAEzC,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrD,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;YAC/C,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;gBAC1B,OAAO;YACR,CAAC;YAED,OAAO,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,MAAM;gBACN,GAAG,EAAE,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,QAAQ;aACrE,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC;IAChB,CAAC;IAEM,0BAA0B;QAChC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;QAC3D,MAAM,IAAI,GAAG;YACZ,QAAQ,EAAE,EAAE;SAC0B,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAEtB,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrD,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;YACtD,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;gBAC1B,OAAO;YACR,CAAC;YAED,IAAI,MAAM,GAAG,IAAI,CAAC;YAClB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBAClB,IAAI,SAAS,GAAG,EAAE,CAAC;gBACnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBAC1B,SAAS,GAAG,GAAG,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACxC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC7B,MAAM,IAAI,GAAG;4BACZ,IAAI,EAAE,IAAI;4BACV,QAAQ,EAAE,EAAE;yBACZ,CAAC;wBACF,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC3B,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;oBAC9B,CAAC;oBAED,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC;gBAClC,CAAC;YACF,CAAC;YAED,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACpB,IAAI;gBACJ,MAAM;gBACN,GAAG,EAAE,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,QAAQ;aACrE,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,GAAG,CACT,OAAoE,EACpE,IAAiB,EACjB,OAAiF;QAEjF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAE9E,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAErD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,UAAyB,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,cAAc,UAAU,8BAA8B,CAAC,CAAC;QACzE,CAAC;QAED,OAAO,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5F,CAAC;IAEM,SAAS,CAAC,KAAyD;QACzE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,MAAM,CAAC,MAAM,CAAuC,SAAsB;QAChF,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CACnC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACnB,GAAG,GAAG;YACN,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ;SACzB,CAAC,EACF,EAAmC,CACnC,CAAC;QAEF,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9B,CAAC;IAEM,MAAM,CAAC,cAAc,CAAuB,IAAW;QAC7D,OAAO,IAAI,QAAQ,CAWjB,IAAI,CAAC,CAAC;IACT,CAAC;IAEM,MAAM,CAAC,YAAY,CAGxB,IAAW;QACZ,OAAO,IAAI,MAAM,CAA4C,IAAI,CAAC,CAAC;IACpE,CAAC;IAEM,MAAM,CAAC,iBAAiB,CAG7B,IAAW;QACZ,OAAO,IAAI,WAAW,CAMpB,IAAI,CAAC,CAAC;IACT,CAAC;IAEM,MAAM,CAAC,YAAY;QACzB,OAAO,IAAI,MAAM,EAAc,CAAC;IACjC,CAAC;IAEM,MAAM,CAAC,MAAM,GAAG,aAAa,CAAC","sourcesContent":["import { Action, type RuleCtx, type InferActionSubject } from \"./action.js\";\nimport { ActionGroup } from \"./actionGroup.js\";\nimport { ActionVisitor } from \"./actionVisitor.js\";\nimport type { ResourceMap, UnionToResourceMap } from \"./internal/collections.js\";\nimport type { UnsetMarker } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\nimport type { ActionFromPath, ActionPaths, FilterActionPaths } from \"./internal/paths.js\";\nimport { Permission, type PermissionOptions } from \"./permission.js\";\nimport { Policy } from \"./policy.js\";\nimport { PolicyFilters } from \"./policyFilters.js\";\nimport { Resource } from \"./resource.js\";\n\nexport type ConfigurableAction = {\n\tpath: string;\n\taction: Action<any, any>;\n\town: boolean;\n};\n\ntype ConfigurableActionGroup = {\n\tmeta: IMeta;\n\tchildren: ConfigurableActionTreeNode[];\n};\n\nexport type ConfigurableActionTreeNode = ConfigurableAction | ConfigurableActionGroup;\n\nexport class ABAC<TResources extends ResourceMap> {\n\tprivate _resourceMap: TResources;\n\tprivate _policies: Policy<TResources>[] = [];\n\n\tconstructor(resourceMap: TResources) {\n\t\tthis._resourceMap = resourceMap;\n\t}\n\n\tdeclare public $resources: TResources;\n\tdeclare public $actions: ActionPaths<TResources>;\n\tdeclare public $configurableActions: FilterActionPaths<TResources, any, true>;\n\tdeclare public $filterActions: <TCtx>() => FilterActionPaths<TResources, TCtx>;\n\n\tpublic getConfigurableActions() {\n\t\tconst actions: ConfigurableAction[] = [];\n\n\t\tconst visitor = new ActionVisitor(this._resourceMap);\n\t\tvisitor.traverse(({ action, resource, path }) => {\n\t\t\tif (!action.configurable) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tactions.push({\n\t\t\t\tpath,\n\t\t\t\taction,\n\t\t\t\town: resource.ownable && resource.ownConfigurable && !action.noObject\n\t\t\t});\n\t\t});\n\n\t\treturn actions;\n\t}\n\n\tpublic getConfigurableActionsTree() {\n\t\tconst nodeMap = new Map<string, ConfigurableActionGroup>();\n\t\tconst root = {\n\t\t\tchildren: []\n\t\t} as unknown as ConfigurableActionGroup;\n\t\tnodeMap.set(\"\", root);\n\n\t\tconst visitor = new ActionVisitor(this._resourceMap);\n\t\tvisitor.traverse(({ action, resource, path, stack }) => {\n\t\t\tif (!action.configurable) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet parent = root;\n\t\t\tif (stack.length) {\n\t\t\t\tlet stackPath = \"\";\n\t\t\t\tfor (const item of stack) {\n\t\t\t\t\tstackPath = `${stackPath}.${item.name}`;\n\t\t\t\t\tif (!nodeMap.has(stackPath)) {\n\t\t\t\t\t\tconst node = {\n\t\t\t\t\t\t\tmeta: item,\n\t\t\t\t\t\t\tchildren: []\n\t\t\t\t\t\t};\n\t\t\t\t\t\tparent.children.push(node);\n\t\t\t\t\t\tnodeMap.set(stackPath, node);\n\t\t\t\t\t}\n\n\t\t\t\t\tparent = nodeMap.get(stackPath)!;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tparent.children.push({\n\t\t\t\tpath,\n\t\t\t\taction,\n\t\t\t\town: resource.ownable && resource.ownConfigurable && !action.noObject\n\t\t\t});\n\t\t});\n\n\t\treturn root.children;\n\t}\n\n\tpublic can<TActionPath extends ActionPaths<TResources>>(\n\t\tsubject: InferActionSubject<ActionFromPath<TResources, TActionPath>>,\n\t\tpath: TActionPath,\n\t\toptions?: PermissionOptions<TActionPath, ActionFromPath<TResources, TActionPath>>\n\t) {\n\t\tconst policies = this._policies.filter((policy) => policy.match({ subject }));\n\n\t\tconst visitor = new ActionVisitor(this._resourceMap);\n\n\t\tconst actionPath = path.endsWith(\".own\") ? path.slice(0, -4) : path;\n\t\tconst result = visitor.findByPath(actionPath as TActionPath);\n\t\tif (!result) {\n\t\t\tthrow new Error(`No action '${actionPath}' found in ABAC resource map`);\n\t\t}\n\n\t\treturn Permission.create(subject, path, result.resource, result.action, policies, options);\n\t}\n\n\tpublic addPolicy(build: (policy: Policy<TResources>) => Policy<TResources>) {\n\t\tconst policy = build(ABAC.createPolicy());\n\t\tthis._policies.push(policy);\n\t\treturn this;\n\t}\n\n\tpublic static create<TResource extends Resource<any, any>>(resources: TResource[]) {\n\t\tconst resourceMap = resources.reduce(\n\t\t\t(map, resource) => ({\n\t\t\t\t...map,\n\t\t\t\t[resource.name]: resource\n\t\t\t}),\n\t\t\t{} as UnionToResourceMap<TResource>\n\t\t);\n\n\t\treturn new ABAC(resourceMap);\n\t}\n\n\tpublic static createResource<TName extends string>(name: TName) {\n\t\treturn new Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: {\n\t\t\t\t\tsubject: UnsetMarker;\n\t\t\t\t\tobject: UnsetMarker;\n\t\t\t\t};\n\t\t\t\tactions: UnsetMarker;\n\t\t\t\tsubResources: UnsetMarker;\n\t\t\t\townable: false;\n\t\t\t}\n\t\t>(name);\n\t}\n\n\tpublic static createAction<\n\t\tTName extends string,\n\t\tTCtx extends RuleCtx = { subject: UnsetMarker; object: UnsetMarker }\n\t>(name: TName) {\n\t\treturn new Action<TName, { ctx: TCtx; configurable: false }>(name);\n\t}\n\n\tpublic static createActionGroup<\n\t\tTName extends string,\n\t\tTCtx extends RuleCtx = { subject: UnsetMarker; object: UnsetMarker }\n\t>(name: TName) {\n\t\treturn new ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TCtx;\n\t\t\t\tactions: UnsetMarker;\n\t\t\t}\n\t\t>(name);\n\t}\n\n\tpublic static createPolicy<TResources extends ResourceMap>() {\n\t\treturn new Policy<TResources>();\n\t}\n\n\tpublic static Filter = PolicyFilters;\n}\n"]}
1
+ {"version":3,"file":"abac.js","sourceRoot":"","sources":["../src/abac.ts"],"names":[],"mappings":"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","sourcesContent":["import { Action, type RuleCtx, type InferActionSubject, type ActionTag } from \"./action.js\";\nimport { ActionGroup } from \"./actionGroup.js\";\nimport { ActionVisitor } from \"./actionVisitor.js\";\nimport type { ResourceMap, UnionToResourceMap } from \"./internal/collections.js\";\nimport type { UnsetMarker } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\nimport type { ActionFromPath, ActionPaths, FilterActionPaths } from \"./internal/paths.js\";\nimport { Permission, type PermissionOptions } from \"./permission.js\";\nimport { Policy } from \"./policy.js\";\nimport { PolicyFilters } from \"./policyFilters.js\";\nimport { Resource } from \"./resource.js\";\n\nexport type TaggedAction = {\n\tpath: string;\n\taction: Action<any, any>;\n\town: boolean;\n};\n\ntype TaggedActionGroup = {\n\tmeta: IMeta;\n\tchildren: TaggedActionTreeNode[];\n};\n\nexport type TaggedActionTreeNode = TaggedAction | TaggedActionGroup;\n\nexport class ABAC<TResources extends ResourceMap> {\n\tprivate _resourceMap: TResources;\n\tprivate _policies: Policy<TResources>[] = [];\n\n\tconstructor(resourceMap: TResources) {\n\t\tthis._resourceMap = resourceMap;\n\t}\n\n\tdeclare public $resources: TResources;\n\tdeclare public $actions: ActionPaths<TResources>;\n\tdeclare public $taggedActions: <TTag extends ActionTag>() => FilterActionPaths<\n\t\tTResources,\n\t\tany,\n\t\tTTag\n\t>;\n\tdeclare public $filterActions: <TCtx>() => FilterActionPaths<TResources, TCtx>;\n\n\tpublic getTaggedActions(tag: ActionTag) {\n\t\tconst actions: TaggedAction[] = [];\n\n\t\tconst visitor = new ActionVisitor(this._resourceMap);\n\t\tvisitor.traverse(({ action, resource, path }) => {\n\t\t\tif (!action.tags.has(tag)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tactions.push({\n\t\t\t\tpath,\n\t\t\t\taction,\n\t\t\t\town: resource.ownable && !action.noObject\n\t\t\t});\n\t\t});\n\n\t\treturn actions;\n\t}\n\n\tpublic getTaggedActionsTree(tag: ActionTag) {\n\t\tconst nodeMap = new Map<string, TaggedActionGroup>();\n\t\tconst root = {\n\t\t\tchildren: []\n\t\t} as unknown as TaggedActionGroup;\n\t\tnodeMap.set(\"\", root);\n\n\t\tconst visitor = new ActionVisitor(this._resourceMap);\n\t\tvisitor.traverse(({ action, resource, path, stack }) => {\n\t\t\tif (!action.tags.has(tag)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet parent = root;\n\t\t\tif (stack.length) {\n\t\t\t\tlet stackPath = \"\";\n\t\t\t\tfor (const item of stack) {\n\t\t\t\t\tstackPath = `${stackPath}.${item.name}`;\n\t\t\t\t\tif (!nodeMap.has(stackPath)) {\n\t\t\t\t\t\tconst node = {\n\t\t\t\t\t\t\tmeta: item,\n\t\t\t\t\t\t\tchildren: []\n\t\t\t\t\t\t};\n\t\t\t\t\t\tparent.children.push(node);\n\t\t\t\t\t\tnodeMap.set(stackPath, node);\n\t\t\t\t\t}\n\n\t\t\t\t\tparent = nodeMap.get(stackPath)!;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tparent.children.push({\n\t\t\t\tpath,\n\t\t\t\taction,\n\t\t\t\town: resource.ownable && !action.noObject\n\t\t\t});\n\t\t});\n\n\t\treturn root.children;\n\t}\n\n\tpublic can<TActionPath extends ActionPaths<TResources>>(\n\t\tsubject: InferActionSubject<ActionFromPath<TResources, TActionPath>>,\n\t\tpath: TActionPath,\n\t\toptions?: PermissionOptions<TActionPath, ActionFromPath<TResources, TActionPath>>\n\t) {\n\t\tconst policies = this._policies.filter((policy) => policy.match({ subject }));\n\n\t\tconst visitor = new ActionVisitor(this._resourceMap);\n\n\t\tconst actionPath = path.endsWith(\".own\") ? path.slice(0, -4) : path;\n\t\tconst result = visitor.findByPath(actionPath as TActionPath);\n\t\tif (!result) {\n\t\t\tthrow new Error(`No action '${actionPath}' found in ABAC resource map`);\n\t\t}\n\n\t\treturn Permission.create(subject, path, result.resource, result.action, policies, options);\n\t}\n\n\tpublic addPolicy(build: (policy: Policy<TResources>) => Policy<TResources>) {\n\t\tconst policy = build(ABAC.createPolicy());\n\t\tthis._policies.push(policy);\n\t\treturn this;\n\t}\n\n\tpublic static create<TResource extends Resource<any, any>>(resources: TResource[]) {\n\t\tconst resourceMap = resources.reduce(\n\t\t\t(map, resource) => ({\n\t\t\t\t...map,\n\t\t\t\t[resource.name]: resource\n\t\t\t}),\n\t\t\t{} as UnionToResourceMap<TResource>\n\t\t);\n\n\t\treturn new ABAC(resourceMap);\n\t}\n\n\tpublic static createResource<TName extends string>(name: TName) {\n\t\treturn new Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: {\n\t\t\t\t\tsubject: UnsetMarker;\n\t\t\t\t\tobject: UnsetMarker;\n\t\t\t\t};\n\t\t\t\tactions: UnsetMarker;\n\t\t\t\tsubResources: UnsetMarker;\n\t\t\t\townable: false;\n\t\t\t}\n\t\t>(name);\n\t}\n\n\tpublic static createAction<\n\t\tTName extends string,\n\t\tTCtx extends RuleCtx = { subject: UnsetMarker; object: UnsetMarker }\n\t>(name: TName) {\n\t\treturn new Action<TName, { ctx: TCtx; tags: UnsetMarker }>(name);\n\t}\n\n\tpublic static createActionGroup<\n\t\tTName extends string,\n\t\tTCtx extends RuleCtx = { subject: UnsetMarker; object: UnsetMarker }\n\t>(name: TName) {\n\t\treturn new ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TCtx;\n\t\t\t\tactions: UnsetMarker;\n\t\t\t}\n\t\t>(name);\n\t}\n\n\tpublic static createPolicy<TResources extends ResourceMap>() {\n\t\treturn new Policy<TResources>();\n\t}\n\n\tpublic static Filter = PolicyFilters;\n}\n"]}
package/build/action.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MakeOptional } from "./internal/core.js";
1
+ import type { Expand, MakeOptional, UnsetMarker } from "./internal/core.js";
2
2
  import type { IMeta } from "./internal/meta.js";
3
3
  export type RuleCtx = {
4
4
  subject: any;
@@ -6,17 +6,18 @@ export type RuleCtx = {
6
6
  };
7
7
  export type ActionContext = {
8
8
  ctx: RuleCtx;
9
- configurable: boolean;
9
+ tags: any;
10
10
  };
11
11
  export type InferActionRuleCtx<TAction> = TAction extends Action<any, infer TContext> ? TContext["ctx"] : never;
12
12
  export type InferActionSubject<TAction> = Pick<InferActionRuleCtx<TAction>, "subject">["subject"];
13
13
  export type InferActionObject<TAction> = Exclude<Pick<InferActionRuleCtx<TAction>, "object">["object"], void | undefined>;
14
14
  export type InferActionAdditionalContext<TAction> = Omit<InferActionRuleCtx<TAction>, "subject" | "object">;
15
+ export type ActionTag = "configurable" | (string & {});
15
16
  export declare class Action<TName extends string, TContext extends ActionContext> implements IMeta {
16
17
  private _name;
17
18
  private _title;
18
19
  private _description;
19
- private _configurable;
20
+ private _tags;
20
21
  private _noObject;
21
22
  constructor(name: TName);
22
23
  get name(): TName;
@@ -24,24 +25,28 @@ export declare class Action<TName extends string, TContext extends ActionContext
24
25
  setTitle(title: string): this;
25
26
  get description(): string | null;
26
27
  setDescription(description: string): this;
27
- get configurable(): boolean;
28
+ get tags(): Set<TContext["tags"]>;
29
+ addTag<TTag extends ActionTag>(tag: TTag): Action<TName, {
30
+ ctx: TContext["ctx"];
31
+ tags: TContext["tags"] extends UnsetMarker ? TTag : TContext["tags"] | TTag;
32
+ }>;
28
33
  setConfigurable<TConfigurable extends boolean>(configurable: TConfigurable): Action<TName, {
29
34
  ctx: TContext["ctx"];
30
- configurable: TConfigurable;
35
+ tags: TContext["tags"] extends UnsetMarker ? TConfigurable extends true ? "configurable" : UnsetMarker : TConfigurable extends true ? TContext["tags"] | "configurable" : Exclude<TContext["tags"], "configurable">;
31
36
  }>;
32
37
  withSubject<TOverrideSubject>(): Action<TName, {
33
38
  ctx: {
34
39
  subject: TOverrideSubject;
35
40
  object: TContext["ctx"]["object"];
36
41
  };
37
- configurable: TContext["configurable"];
42
+ tags: TContext["tags"];
38
43
  }>;
39
44
  withObject<TOverrideObject>(): Action<TName, {
40
45
  ctx: {
41
46
  subject: TContext["ctx"]["subject"];
42
47
  object: TOverrideObject;
43
48
  };
44
- configurable: TContext["configurable"];
49
+ tags: TContext["tags"];
45
50
  }>;
46
51
  get noObject(): boolean;
47
52
  withoutObject(): Action<TName, {
@@ -49,14 +54,17 @@ export declare class Action<TName extends string, TContext extends ActionContext
49
54
  subject: TContext["ctx"]["subject"];
50
55
  object: void;
51
56
  };
52
- configurable: TContext["configurable"];
57
+ tags: TContext["tags"];
53
58
  }>;
54
59
  optionalObject(): Action<TName, {
55
60
  ctx: {
56
61
  subject: TContext["ctx"]["subject"];
57
62
  object: MakeOptional<TContext["ctx"]["object"]>;
58
63
  };
59
- configurable: TContext["configurable"];
64
+ tags: TContext["tags"];
65
+ }>;
66
+ withAdditionalContext<TAdditionalContext extends object>(): Action<TName, {
67
+ ctx: Expand<TContext["ctx"] & TAdditionalContext>;
68
+ tags: TContext["tags"];
60
69
  }>;
61
- withAdditionalContext<TAdditionalContext extends object>(): Action<TName, TContext & TAdditionalContext>;
62
70
  }
package/build/action.js CHANGED
@@ -2,7 +2,7 @@ export class Action {
2
2
  _name;
3
3
  _title = null;
4
4
  _description = null;
5
- _configurable = false;
5
+ _tags = new Set();
6
6
  _noObject = false;
7
7
  constructor(name) {
8
8
  this._name = name;
@@ -24,11 +24,20 @@ export class Action {
24
24
  this._description = description;
25
25
  return this;
26
26
  }
27
- get configurable() {
28
- return this._configurable;
27
+ get tags() {
28
+ return this._tags;
29
+ }
30
+ addTag(tag) {
31
+ this._tags.add(tag);
32
+ return this;
29
33
  }
30
34
  setConfigurable(configurable) {
31
- this._configurable = configurable;
35
+ if (configurable) {
36
+ this._tags.add("configurable");
37
+ }
38
+ else {
39
+ this._tags.delete("configurable");
40
+ }
32
41
  return this;
33
42
  }
34
43
  withSubject() {
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AA4BA,MAAM,OAAO,MAAM;IACV,KAAK,CAAQ;IACb,MAAM,GAAkB,IAAI,CAAC;IAC7B,YAAY,GAAkB,IAAI,CAAC;IACnC,aAAa,GAAY,KAAK,CAAC;IAC/B,SAAS,GAAY,KAAK,CAAC;IAEnC,YAAY,IAAW;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,IAAW,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,WAAW;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAEM,cAAc,CAAC,WAAmB;QACxC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,YAAY;QACtB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAEM,eAAe,CAAgC,YAA2B;QAChF,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAClC,OAAO,IAMN,CAAC;IACH,CAAC;IAEM,WAAW;QACjB,OAAO,IASN,CAAC;IACH,CAAC;IAEM,UAAU;QAChB,OAAO,IASN,CAAC;IACH,CAAC;IAED,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAEM,aAAa;QACnB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,UAAU,EAAQ,CAAC;IAChC,CAAC;IAEM,cAAc;QACpB,OAAO,IAAI,CAAC,UAAU,EAA2C,CAAC;IACnE,CAAC;IAEM,qBAAqB;QAC3B,OAAO,IAA+D,CAAC;IACxE,CAAC;CACD","sourcesContent":["import type { MakeOptional } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\n\nexport type RuleCtx = {\n\tsubject: any;\n\tobject: any;\n};\n\nexport type ActionContext = {\n\tctx: RuleCtx;\n\tconfigurable: boolean;\n};\n\nexport type InferActionRuleCtx<TAction> =\n\tTAction extends Action<any, infer TContext> ? TContext[\"ctx\"] : never;\n\nexport type InferActionSubject<TAction> = Pick<InferActionRuleCtx<TAction>, \"subject\">[\"subject\"];\n\nexport type InferActionObject<TAction> = Exclude<\n\tPick<InferActionRuleCtx<TAction>, \"object\">[\"object\"],\n\tvoid | undefined\n>;\n\nexport type InferActionAdditionalContext<TAction> = Omit<\n\tInferActionRuleCtx<TAction>,\n\t\"subject\" | \"object\"\n>;\n\nexport class Action<TName extends string, TContext extends ActionContext> implements IMeta {\n\tprivate _name: TName;\n\tprivate _title: string | null = null;\n\tprivate _description: string | null = null;\n\tprivate _configurable: boolean = false;\n\tprivate _noObject: boolean = false;\n\n\tconstructor(name: TName) {\n\t\tthis._name = name;\n\t}\n\n\tpublic get name(): TName {\n\t\treturn this._name;\n\t}\n\n\tpublic get title(): string | null {\n\t\treturn this._title;\n\t}\n\n\tpublic setTitle(title: string) {\n\t\tthis._title = title;\n\t\treturn this;\n\t}\n\n\tpublic get description(): string | null {\n\t\treturn this._description;\n\t}\n\n\tpublic setDescription(description: string) {\n\t\tthis._description = description;\n\t\treturn this;\n\t}\n\n\tpublic get configurable(): boolean {\n\t\treturn this._configurable;\n\t}\n\n\tpublic setConfigurable<TConfigurable extends boolean>(configurable: TConfigurable) {\n\t\tthis._configurable = configurable;\n\t\treturn this as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tconfigurable: TConfigurable;\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withSubject<TOverrideSubject>() {\n\t\treturn this as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: {\n\t\t\t\t\tsubject: TOverrideSubject;\n\t\t\t\t\tobject: TContext[\"ctx\"][\"object\"];\n\t\t\t\t};\n\t\t\t\tconfigurable: TContext[\"configurable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withObject<TOverrideObject>() {\n\t\treturn this as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: {\n\t\t\t\t\tsubject: TContext[\"ctx\"][\"subject\"];\n\t\t\t\t\tobject: TOverrideObject;\n\t\t\t\t};\n\t\t\t\tconfigurable: TContext[\"configurable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic get noObject() {\n\t\treturn this._noObject;\n\t}\n\n\tpublic withoutObject() {\n\t\tthis._noObject = true;\n\t\treturn this.withObject<void>();\n\t}\n\n\tpublic optionalObject() {\n\t\treturn this.withObject<MakeOptional<TContext[\"ctx\"][\"object\"]>>();\n\t}\n\n\tpublic withAdditionalContext<TAdditionalContext extends object>() {\n\t\treturn this as unknown as Action<TName, TContext & TAdditionalContext>;\n\t}\n}\n"]}
1
+ {"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AA8BA,MAAM,OAAO,MAAM;IACV,KAAK,CAAQ;IACb,MAAM,GAAkB,IAAI,CAAC;IAC7B,YAAY,GAAkB,IAAI,CAAC;IACnC,KAAK,GAA0B,IAAI,GAAG,EAAE,CAAC;IACzC,SAAS,GAAY,KAAK,CAAC;IAEnC,YAAY,IAAW;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,IAAW,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,WAAW;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAEM,cAAc,CAAC,WAAmB;QACxC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAEM,MAAM,CAAyB,GAAS;QAC9C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpB,OAAO,IAMN,CAAC;IACH,CAAC;IAEM,eAAe,CAAgC,YAA2B;QAChF,IAAI,YAAY,EAAE,CAAC;YAClB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,IAYN,CAAC;IACH,CAAC;IAEM,WAAW;QACjB,OAAO,IASN,CAAC;IACH,CAAC;IAEM,UAAU;QAChB,OAAO,IASN,CAAC;IACH,CAAC;IAED,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAEM,aAAa;QACnB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC,UAAU,EAAQ,CAAC;IAChC,CAAC;IAEM,cAAc;QACpB,OAAO,IAAI,CAAC,UAAU,EAA2C,CAAC;IACnE,CAAC;IAEM,qBAAqB;QAC3B,OAAO,IAMN,CAAC;IACH,CAAC;CACD","sourcesContent":["import type { Expand, MakeOptional, UnsetMarker } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\n\nexport type RuleCtx = {\n\tsubject: any;\n\tobject: any;\n};\n\nexport type ActionContext = {\n\tctx: RuleCtx;\n\ttags: any;\n};\n\nexport type InferActionRuleCtx<TAction> =\n\tTAction extends Action<any, infer TContext> ? TContext[\"ctx\"] : never;\n\nexport type InferActionSubject<TAction> = Pick<InferActionRuleCtx<TAction>, \"subject\">[\"subject\"];\n\nexport type InferActionObject<TAction> = Exclude<\n\tPick<InferActionRuleCtx<TAction>, \"object\">[\"object\"],\n\tvoid | undefined\n>;\n\nexport type InferActionAdditionalContext<TAction> = Omit<\n\tInferActionRuleCtx<TAction>,\n\t\"subject\" | \"object\"\n>;\n\nexport type ActionTag = \"configurable\" | (string & {});\n\nexport class Action<TName extends string, TContext extends ActionContext> implements IMeta {\n\tprivate _name: TName;\n\tprivate _title: string | null = null;\n\tprivate _description: string | null = null;\n\tprivate _tags: Set<TContext[\"tags\"]> = new Set();\n\tprivate _noObject: boolean = false;\n\n\tconstructor(name: TName) {\n\t\tthis._name = name;\n\t}\n\n\tpublic get name(): TName {\n\t\treturn this._name;\n\t}\n\n\tpublic get title(): string | null {\n\t\treturn this._title;\n\t}\n\n\tpublic setTitle(title: string) {\n\t\tthis._title = title;\n\t\treturn this;\n\t}\n\n\tpublic get description(): string | null {\n\t\treturn this._description;\n\t}\n\n\tpublic setDescription(description: string) {\n\t\tthis._description = description;\n\t\treturn this;\n\t}\n\n\tpublic get tags(): Set<TContext[\"tags\"]> {\n\t\treturn this._tags;\n\t}\n\n\tpublic addTag<TTag extends ActionTag>(tag: TTag) {\n\t\tthis._tags.add(tag);\n\t\treturn this as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\ttags: TContext[\"tags\"] extends UnsetMarker ? TTag : TContext[\"tags\"] | TTag;\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic setConfigurable<TConfigurable extends boolean>(configurable: TConfigurable) {\n\t\tif (configurable) {\n\t\t\tthis._tags.add(\"configurable\");\n\t\t} else {\n\t\t\tthis._tags.delete(\"configurable\");\n\t\t}\n\t\treturn this as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\ttags: TContext[\"tags\"] extends UnsetMarker\n\t\t\t\t\t? TConfigurable extends true\n\t\t\t\t\t\t? \"configurable\"\n\t\t\t\t\t\t: UnsetMarker\n\t\t\t\t\t: TConfigurable extends true\n\t\t\t\t\t\t? TContext[\"tags\"] | \"configurable\"\n\t\t\t\t\t\t: Exclude<TContext[\"tags\"], \"configurable\">;\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withSubject<TOverrideSubject>() {\n\t\treturn this as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: {\n\t\t\t\t\tsubject: TOverrideSubject;\n\t\t\t\t\tobject: TContext[\"ctx\"][\"object\"];\n\t\t\t\t};\n\t\t\t\ttags: TContext[\"tags\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withObject<TOverrideObject>() {\n\t\treturn this as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: {\n\t\t\t\t\tsubject: TContext[\"ctx\"][\"subject\"];\n\t\t\t\t\tobject: TOverrideObject;\n\t\t\t\t};\n\t\t\t\ttags: TContext[\"tags\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic get noObject() {\n\t\treturn this._noObject;\n\t}\n\n\tpublic withoutObject() {\n\t\tthis._noObject = true;\n\t\treturn this.withObject<void>();\n\t}\n\n\tpublic optionalObject() {\n\t\treturn this.withObject<MakeOptional<TContext[\"ctx\"][\"object\"]>>();\n\t}\n\n\tpublic withAdditionalContext<TAdditionalContext extends object>() {\n\t\treturn this as unknown as Action<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<TContext[\"ctx\"] & TAdditionalContext>;\n\t\t\t\ttags: TContext[\"tags\"];\n\t\t\t}\n\t\t>;\n\t}\n}\n"]}
@@ -34,7 +34,7 @@ export declare class ActionGroup<TName extends string, TContext extends ActionGr
34
34
  actions: TContext["actions"];
35
35
  }>;
36
36
  withAdditionalContext<TAdditionalContext extends object>(): ActionGroup<TName, {
37
- ctx: TContext["ctx"] & TAdditionalContext;
37
+ ctx: Expand<TContext["ctx"] & TAdditionalContext>;
38
38
  actions: TContext["actions"];
39
39
  }>;
40
40
  get actions(): TContext["actions"];
@@ -1 +1 @@
1
- {"version":3,"file":"actionGroup.js","sourceRoot":"","sources":["../src/actionGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,MAAM,aAAa,CAAC;AAexD,MAAM,OAAO,WAAW;IAKf,KAAK,CAAQ;IACb,MAAM,GAAkB,IAAI,CAAC;IAC7B,YAAY,GAAkB,IAAI,CAAC;IACnC,QAAQ,GAAwB,EAAyB,CAAC;IAElE,YAAY,IAAW;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,IAAW,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,WAAW;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAEM,cAAc,CAAC,WAAmB;QACxC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,WAAW;QACjB,OAAO,IAUN,CAAC;IACH,CAAC;IAEM,UAAU;QAChB,OAAO,IAUN,CAAC;IACH,CAAC;IAEM,qBAAqB;QAC3B,OAAO,IAMN,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,UAAU,CAChB,OAAmB;QAEnB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAC7B,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACjB,GAAG,GAAG;YACN,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM;SACrB,CAAC,EACF,EAAE,CACF,CAAC;QACF,OAAO,IAMN,CAAC;IACH,CAAC;CACD","sourcesContent":["import { type Action, type RuleCtx } from \"./action.js\";\nimport type { ActionMap, ToActionMap } from \"./internal/collections.js\";\nimport type { Expand, UnsetMarker } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\n\nexport type ActionGroupContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap | UnsetMarker;\n};\n\nexport type AnyActionGroupContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap;\n};\n\nexport class ActionGroup<\n\tTName extends string,\n\tTContext extends ActionGroupContext = AnyActionGroupContext\n> implements IMeta\n{\n\tprivate _name: TName;\n\tprivate _title: string | null = null;\n\tprivate _description: string | null = null;\n\tprivate _actions: TContext[\"actions\"] = {} as TContext[\"actions\"];\n\n\tconstructor(name: TName) {\n\t\tthis._name = name;\n\t}\n\n\tpublic get name(): TName {\n\t\treturn this._name;\n\t}\n\n\tpublic get title(): string | null {\n\t\treturn this._title;\n\t}\n\n\tpublic setTitle(title: string) {\n\t\tthis._title = title;\n\t\treturn this;\n\t}\n\n\tpublic get description(): string | null {\n\t\treturn this._description;\n\t}\n\n\tpublic setDescription(description: string) {\n\t\tthis._description = description;\n\t\treturn this;\n\t}\n\n\tpublic withSubject<TSubject>() {\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"subject\"> & {\n\t\t\t\t\t\tsubject: TSubject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withObject<TObject>() {\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"object\"> & {\n\t\t\t\t\t\tobject: TObject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withAdditionalContext<TAdditionalContext extends object>() {\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"] & TAdditionalContext;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tget actions(): TContext[\"actions\"] {\n\t\treturn this._actions;\n\t}\n\n\tpublic setActions<TActions extends Action<any, any> | ActionGroup<any, any>>(\n\t\tactions: TActions[]\n\t) {\n\t\tthis._actions = actions.reduce(\n\t\t\t(acc, action) => ({\n\t\t\t\t...acc,\n\t\t\t\t[action.name]: action\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: Expand<ToActionMap<TActions>>;\n\t\t\t}\n\t\t>;\n\t}\n}\n"]}
1
+ {"version":3,"file":"actionGroup.js","sourceRoot":"","sources":["../src/actionGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,MAAM,aAAa,CAAC;AAexD,MAAM,OAAO,WAAW;IAKf,KAAK,CAAQ;IACb,MAAM,GAAkB,IAAI,CAAC;IAC7B,YAAY,GAAkB,IAAI,CAAC;IACnC,QAAQ,GAAwB,EAAyB,CAAC;IAElE,YAAY,IAAW;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,IAAW,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,WAAW;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAEM,cAAc,CAAC,WAAmB;QACxC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,WAAW;QACjB,OAAO,IAUN,CAAC;IACH,CAAC;IAEM,UAAU;QAChB,OAAO,IAUN,CAAC;IACH,CAAC;IAEM,qBAAqB;QAC3B,OAAO,IAMN,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,UAAU,CAChB,OAAmB;QAEnB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAC7B,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACjB,GAAG,GAAG;YACN,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM;SACrB,CAAC,EACF,EAAE,CACF,CAAC;QACF,OAAO,IAMN,CAAC;IACH,CAAC;CACD","sourcesContent":["import { type Action, type RuleCtx } from \"./action.js\";\nimport type { ActionMap, ToActionMap } from \"./internal/collections.js\";\nimport type { Expand, UnsetMarker } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\n\nexport type ActionGroupContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap | UnsetMarker;\n};\n\nexport type AnyActionGroupContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap;\n};\n\nexport class ActionGroup<\n\tTName extends string,\n\tTContext extends ActionGroupContext = AnyActionGroupContext\n> implements IMeta\n{\n\tprivate _name: TName;\n\tprivate _title: string | null = null;\n\tprivate _description: string | null = null;\n\tprivate _actions: TContext[\"actions\"] = {} as TContext[\"actions\"];\n\n\tconstructor(name: TName) {\n\t\tthis._name = name;\n\t}\n\n\tpublic get name(): TName {\n\t\treturn this._name;\n\t}\n\n\tpublic get title(): string | null {\n\t\treturn this._title;\n\t}\n\n\tpublic setTitle(title: string) {\n\t\tthis._title = title;\n\t\treturn this;\n\t}\n\n\tpublic get description(): string | null {\n\t\treturn this._description;\n\t}\n\n\tpublic setDescription(description: string) {\n\t\tthis._description = description;\n\t\treturn this;\n\t}\n\n\tpublic withSubject<TSubject>() {\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"subject\"> & {\n\t\t\t\t\t\tsubject: TSubject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withObject<TObject>() {\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"object\"> & {\n\t\t\t\t\t\tobject: TObject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withAdditionalContext<TAdditionalContext extends object>() {\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<TContext[\"ctx\"] & TAdditionalContext>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tget actions(): TContext[\"actions\"] {\n\t\treturn this._actions;\n\t}\n\n\tpublic setActions<TActions extends Action<any, any> | ActionGroup<any, any>>(\n\t\tactions: TActions[]\n\t) {\n\t\tthis._actions = actions.reduce(\n\t\t\t(acc, action) => ({\n\t\t\t\t...acc,\n\t\t\t\t[action.name]: action\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\t\treturn this as unknown as ActionGroup<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: Expand<ToActionMap<TActions>>;\n\t\t\t}\n\t\t>;\n\t}\n}\n"]}
@@ -17,3 +17,6 @@ export type EmptyObject = {
17
17
  object: void;
18
18
  };
19
19
  export type IsOnlyEmptyObject<T> = KeysEqual<EmptyObject, T> extends true ? (T extends EmptyObject ? true : false) : false;
20
+ export type HasOnlyObject<T> = KeysEqual<{
21
+ object: any;
22
+ }, T>;
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/internal/core.ts"],"names":[],"mappings":"","sourcesContent":["export type UnsetMarker = \"unset\" & {\n\t__brand: \"unsetMarker\";\n};\n\nexport type OptionalMarker = \"optional\" & {\n\t__brand: \"optionalMarker\";\n};\n\nexport type MakeOptional<T> = T extends UnsetMarker ? OptionalMarker : T | undefined;\n\nexport type Expand<T> = T extends Record<any, any> ? { [K in keyof T]: T[K] } : never;\n\nexport type KeysEqual<A, B> =\n\tA extends Record<keyof B, any> ? (B extends Record<keyof A, any> ? true : false) : false;\n\nexport type UnionToIntersection<U, T> = (U extends any ? (k: U) => void : never) extends (\n\tk: infer I extends T\n) => void\n\t? I\n\t: never;\n\nexport type OptionalUndefinedFields<T> = Expand<\n\tPartial<T> &\n\t\tPick<\n\t\t\tT,\n\t\t\t{\n\t\t\t\t[K in keyof T]: T[K] extends Exclude<T[K], undefined> ? K : never;\n\t\t\t}[keyof T]\n\t\t>\n>;\n\nexport type EmptyObject = { object: void };\n\nexport type IsOnlyEmptyObject<T> =\n\tKeysEqual<EmptyObject, T> extends true ? (T extends EmptyObject ? true : false) : false;\n"]}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/internal/core.ts"],"names":[],"mappings":"","sourcesContent":["export type UnsetMarker = \"unset\" & {\n\t__brand: \"unsetMarker\";\n};\n\nexport type OptionalMarker = \"optional\" & {\n\t__brand: \"optionalMarker\";\n};\n\nexport type MakeOptional<T> = T extends UnsetMarker ? OptionalMarker : T | undefined;\n\nexport type Expand<T> = T extends Record<any, any> ? { [K in keyof T]: T[K] } : never;\n\nexport type KeysEqual<A, B> =\n\tA extends Record<keyof B, any> ? (B extends Record<keyof A, any> ? true : false) : false;\n\nexport type UnionToIntersection<U, T> = (U extends any ? (k: U) => void : never) extends (\n\tk: infer I extends T\n) => void\n\t? I\n\t: never;\n\nexport type OptionalUndefinedFields<T> = Expand<\n\tPartial<T> &\n\t\tPick<\n\t\t\tT,\n\t\t\t{\n\t\t\t\t[K in keyof T]: T[K] extends Exclude<T[K], undefined> ? K : never;\n\t\t\t}[keyof T]\n\t\t>\n>;\n\nexport type EmptyObject = { object: void };\n\nexport type IsOnlyEmptyObject<T> =\n\tKeysEqual<EmptyObject, T> extends true ? (T extends EmptyObject ? true : false) : false;\n\nexport type HasOnlyObject<T> = KeysEqual<{ object: any }, T>;\n"]}
@@ -24,10 +24,10 @@ export type WildcardActionPaths<TResources extends ResourceMap> = {
24
24
  type MergeRuleCtx<A extends RuleCtx, B extends RuleCtx> = {
25
25
  subject: A["subject"] extends UnsetMarker ? B["subject"] : A["subject"];
26
26
  object: A["object"] extends UnsetMarker ? B["object"] : A["object"] extends OptionalMarker ? MakeOptional<B["object"]> : A["object"];
27
- };
27
+ } & Omit<A, "subject" | "object"> & Omit<B, "subject" | "object">;
28
28
  type ResolveAction<TParentCtx extends RuleCtx, TAction extends Action<any, any>> = TAction extends Action<infer TName, infer TActionContext> ? Action<TName, Expand<{
29
29
  ctx: Expand<MergeRuleCtx<TActionContext["ctx"], TParentCtx>>;
30
- configurable: TActionContext["configurable"];
30
+ tags: TActionContext["tags"];
31
31
  }>> : never;
32
32
  type IndexActionGroupWithPath<TPath extends string, TActionGroup extends ActionGroup<any, any>, TParentCtx extends RuleCtx> = TPath extends keyof TActionGroup["actions"] ? ResolveAction<TParentCtx, TActionGroup["actions"][TPath]> : TPath extends `${infer ActionGroupName}.${infer Rest}` ? TActionGroup["actions"][ActionGroupName] extends ActionGroup<any, infer TActionGroupContext> ? IndexActionGroupWithPath<Rest, TActionGroup["actions"][ActionGroupName], MergeRuleCtx<TActionGroupContext["ctx"], TParentCtx>> : never : TPath extends `${infer ActionGroupName}:${infer ActionName}` ? TActionGroup["actions"][ActionGroupName] extends ActionGroup<any, any> ? ResolveAction<TParentCtx, TActionGroup["actions"][ActionGroupName]["actions"][ActionName]> : never : never;
33
33
  type IndexResourceWithPath<TPath extends string, TResource extends Resource<any, any>, TParentCtx extends RuleCtx> = TPath extends keyof TResource["actions"] ? TResource["actions"][TPath] extends Action<any, any> ? ResolveAction<TParentCtx, TResource["actions"][TPath]> : never : TPath extends `${infer ResourceOrGroupName}.${infer Rest}` ? ResourceOrGroupName extends keyof TResource["actions"] ? TResource["actions"][ResourceOrGroupName] extends ActionGroup<any, infer TActionGroupContext> ? IndexActionGroupWithPath<Rest, TResource["actions"][ResourceOrGroupName], MergeRuleCtx<TActionGroupContext["ctx"], TParentCtx>> : never : TResource["subResources"][ResourceOrGroupName] extends Resource<any, infer TResourceContext> ? IndexResourceWithPath<Rest, TResource["subResources"][ResourceOrGroupName], MergeRuleCtx<TResourceContext["ctx"], TParentCtx>> : never : TPath extends `${infer ResourceOrGroupName}:${infer ActionName}` ? TResource["actions"][ResourceOrGroupName] extends ActionGroup<any, infer TActionGroupContext> ? ResolveAction<MergeRuleCtx<TActionGroupContext["ctx"], TParentCtx>, TResource["actions"][ResourceOrGroupName]["actions"][ActionName]> : TResource["subResources"][ResourceOrGroupName] extends Resource<any, infer TResourceContext> ? ResolveAction<MergeRuleCtx<TResourceContext["ctx"], TParentCtx>, TResource["subResources"][ResourceOrGroupName]["actions"][ActionName]> : never : never;
@@ -38,8 +38,8 @@ type ActionPathsWithAction<TResources extends ResourceMap, TPaths extends string
38
38
  action: ActionFromPath<TResources, path>;
39
39
  };
40
40
  }[TPaths];
41
- export type FilterActionPaths<TResources extends ResourceMap, TCtxPattern, TConfigurable extends boolean = boolean, TPathsAndActions = ActionPathsWithAction<TResources, ActionPaths<TResources>>> = TPathsAndActions extends {
41
+ export type FilterActionPaths<TResources extends ResourceMap, TCtxPattern, TTag extends string = any, TPathsAndActions = ActionPathsWithAction<TResources, ActionPaths<TResources>>> = TPathsAndActions extends {
42
42
  path: string;
43
43
  action: Action<any, infer TActionContext>;
44
- } ? TActionContext["ctx"] extends TCtxPattern ? TActionContext["configurable"] extends TConfigurable ? TPathsAndActions["path"] : never : never : never;
44
+ } ? TActionContext["ctx"] extends TCtxPattern ? TTag extends TActionContext["tags"] ? TPathsAndActions["path"] : never : never : never;
45
45
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/internal/paths.ts"],"names":[],"mappings":"","sourcesContent":["import type { Action, RuleCtx } from \"../action.js\";\nimport type { ActionGroup } from \"../actionGroup.js\";\nimport type { Resource } from \"../resource.js\";\nimport type { ResourceMap } from \"./collections.js\";\nimport type { EmptyObject, Expand, MakeOptional, OptionalMarker, UnsetMarker } from \"./core.js\";\n\ntype ActionNames<TActionMap, TExcludeEmptyObjects extends boolean = false> = {\n\t[actionName in keyof TActionMap]: TActionMap[actionName] extends Action<\n\t\tinfer TActionName,\n\t\tinfer TActionContext\n\t>\n\t\t? TActionContext[\"ctx\"] extends EmptyObject\n\t\t\t? TExcludeEmptyObjects extends true\n\t\t\t\t? never\n\t\t\t\t: `:${TActionName}`\n\t\t\t: `:${TActionName}`\n\t\t: TActionMap[actionName] extends ActionGroup<infer TGroupName, infer TGroupContext>\n\t\t\t? `.${TGroupName}${ActionNames<TGroupContext[\"actions\"], TExcludeEmptyObjects>}`\n\t\t\t: never;\n}[keyof TActionMap];\n\nexport type OwnableActionPaths<TResources extends ResourceMap> = {\n\t[resourceName in Extract<keyof TResources, string>]:\n\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t? never\n\t\t\t\t: `${resourceName}.${OwnableActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t| (TResources[resourceName] extends Resource<any, infer TResourceContext>\n\t\t\t\t? TResourceContext[\"ownable\"] extends true\n\t\t\t\t\t? TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}${ActionNames<TResources[resourceName][\"actions\"], true>}`\n\t\t\t\t\t: never\n\t\t\t\t: never);\n}[Extract<keyof TResources, string>];\n\nexport type ActionPaths<TResources extends ResourceMap> =\n\t| {\n\t\t\t[resourceName in Extract<keyof TResources, string>]:\n\t\t\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}.${ActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t\t\t| (TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}${ActionNames<TResources[resourceName][\"actions\"]>}`);\n\t }[Extract<keyof TResources, string>]\n\t| `${OwnableActionPaths<TResources>}.own`;\n\ntype ActionNamesWithWildcards<TActionMap> = {\n\t[actionName in keyof TActionMap]: TActionMap[actionName] extends ActionGroup<\n\t\tinfer TGroupName,\n\t\tinfer TGroupContext\n\t>\n\t\t? `.${TGroupName}${ActionNamesWithWildcards<TGroupContext[\"actions\"]>}` | `.${TGroupName}:*`\n\t\t: never;\n}[keyof TActionMap];\n\nexport type OwnableWildcardActionPaths<TResources extends ResourceMap> = {\n\t[resourceName in Extract<keyof TResources, string>]: TResources[resourceName] extends Resource<\n\t\tany,\n\t\tinfer TResourceContext\n\t>\n\t\t? TResourceContext[\"ownable\"] extends true\n\t\t\t?\n\t\t\t\t\t| `${resourceName}:*`\n\t\t\t\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: `${resourceName}.${OwnableWildcardActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t\t\t\t| (TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: `${resourceName}${ActionNamesWithWildcards<TResources[resourceName][\"actions\"]>}`)\n\t\t\t: never\n\t\t: never;\n}[Extract<keyof TResources, string>];\n\nexport type WildcardActionPaths<TResources extends ResourceMap> =\n\t| {\n\t\t\t[resourceName in Extract<keyof TResources, string>]:\n\t\t\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}.${WildcardActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t\t\t| (TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}${ActionNamesWithWildcards<TResources[resourceName][\"actions\"]>}`)\n\t\t\t\t| `${resourceName}:*`\n\t\t\t\t| `${resourceName}.*`;\n\t }[Extract<keyof TResources, string>]\n\t| `${OwnableWildcardActionPaths<TResources>}.own`;\n\ntype MergeRuleCtx<A extends RuleCtx, B extends RuleCtx> = {\n\tsubject: A[\"subject\"] extends UnsetMarker ? B[\"subject\"] : A[\"subject\"];\n\tobject: A[\"object\"] extends UnsetMarker\n\t\t? B[\"object\"]\n\t\t: A[\"object\"] extends OptionalMarker\n\t\t\t? MakeOptional<B[\"object\"]>\n\t\t\t: A[\"object\"];\n};\n\ntype ResolveAction<TParentCtx extends RuleCtx, TAction extends Action<any, any>> =\n\tTAction extends Action<infer TName, infer TActionContext>\n\t\t? Action<\n\t\t\t\tTName,\n\t\t\t\tExpand<{\n\t\t\t\t\tctx: Expand<MergeRuleCtx<TActionContext[\"ctx\"], TParentCtx>>;\n\t\t\t\t\tconfigurable: TActionContext[\"configurable\"];\n\t\t\t\t}>\n\t\t\t>\n\t\t: never;\n\ntype IndexActionGroupWithPath<\n\tTPath extends string,\n\tTActionGroup extends ActionGroup<any, any>,\n\tTParentCtx extends RuleCtx\n> = TPath extends keyof TActionGroup[\"actions\"] // Check fast path first\n\t? ResolveAction<TParentCtx, TActionGroup[\"actions\"][TPath]>\n\t: TPath extends `${infer ActionGroupName}.${infer Rest}`\n\t\t? TActionGroup[\"actions\"][ActionGroupName] extends ActionGroup<any, infer TActionGroupContext>\n\t\t\t? IndexActionGroupWithPath<\n\t\t\t\t\tRest,\n\t\t\t\t\tTActionGroup[\"actions\"][ActionGroupName],\n\t\t\t\t\tMergeRuleCtx<TActionGroupContext[\"ctx\"], TParentCtx>\n\t\t\t\t>\n\t\t\t: never\n\t\t: TPath extends `${infer ActionGroupName}:${infer ActionName}`\n\t\t\t? TActionGroup[\"actions\"][ActionGroupName] extends ActionGroup<any, any>\n\t\t\t\t? ResolveAction<TParentCtx, TActionGroup[\"actions\"][ActionGroupName][\"actions\"][ActionName]>\n\t\t\t\t: never\n\t\t\t: never;\n\ntype IndexResourceWithPath<\n\tTPath extends string,\n\tTResource extends Resource<any, any>,\n\tTParentCtx extends RuleCtx\n> = TPath extends keyof TResource[\"actions\"] // Check fast path first\n\t? TResource[\"actions\"][TPath] extends Action<any, any>\n\t\t? ResolveAction<TParentCtx, TResource[\"actions\"][TPath]>\n\t\t: never\n\t: TPath extends `${infer ResourceOrGroupName}.${infer Rest}`\n\t\t? ResourceOrGroupName extends keyof TResource[\"actions\"]\n\t\t\t? TResource[\"actions\"][ResourceOrGroupName] extends ActionGroup<\n\t\t\t\t\tany,\n\t\t\t\t\tinfer TActionGroupContext\n\t\t\t\t>\n\t\t\t\t? IndexActionGroupWithPath<\n\t\t\t\t\t\tRest,\n\t\t\t\t\t\tTResource[\"actions\"][ResourceOrGroupName],\n\t\t\t\t\t\tMergeRuleCtx<TActionGroupContext[\"ctx\"], TParentCtx>\n\t\t\t\t\t>\n\t\t\t\t: never\n\t\t\t: TResource[\"subResources\"][ResourceOrGroupName] extends Resource<any, infer TResourceContext>\n\t\t\t\t? IndexResourceWithPath<\n\t\t\t\t\t\tRest,\n\t\t\t\t\t\tTResource[\"subResources\"][ResourceOrGroupName],\n\t\t\t\t\t\tMergeRuleCtx<TResourceContext[\"ctx\"], TParentCtx>\n\t\t\t\t\t>\n\t\t\t\t: never\n\t\t: TPath extends `${infer ResourceOrGroupName}:${infer ActionName}`\n\t\t\t? TResource[\"actions\"][ResourceOrGroupName] extends ActionGroup<\n\t\t\t\t\tany,\n\t\t\t\t\tinfer TActionGroupContext\n\t\t\t\t>\n\t\t\t\t? ResolveAction<\n\t\t\t\t\t\tMergeRuleCtx<TActionGroupContext[\"ctx\"], TParentCtx>,\n\t\t\t\t\t\tTResource[\"actions\"][ResourceOrGroupName][\"actions\"][ActionName]\n\t\t\t\t\t>\n\t\t\t\t: TResource[\"subResources\"][ResourceOrGroupName] extends Resource<\n\t\t\t\t\t\t\tany,\n\t\t\t\t\t\t\tinfer TResourceContext\n\t\t\t\t\t >\n\t\t\t\t\t? ResolveAction<\n\t\t\t\t\t\t\tMergeRuleCtx<TResourceContext[\"ctx\"], TParentCtx>,\n\t\t\t\t\t\t\tTResource[\"subResources\"][ResourceOrGroupName][\"actions\"][ActionName]\n\t\t\t\t\t\t>\n\t\t\t\t\t: never\n\t\t\t: never;\n\nexport type ActionFromPath<\n\tTResources extends ResourceMap,\n\tTPath extends string\n> = TPath extends `${infer TActualPath}.own`\n\t? ActionFromPath<TResources, TActualPath>\n\t: TPath extends `${infer ResourceName extends Extract<keyof TResources, string>}.${infer Rest}`\n\t\t? TResources[ResourceName] extends Resource<any, infer TResourceContext>\n\t\t\t? IndexResourceWithPath<Rest, TResources[ResourceName], TResourceContext[\"ctx\"]>\n\t\t\t: never\n\t\t: TPath extends `${infer ResourceName extends Extract<keyof TResources, string>}:${infer ActionName}`\n\t\t\t? TResources[ResourceName] extends Resource<any, infer TResourceContext>\n\t\t\t\t? ResolveAction<TResourceContext[\"ctx\"], TResources[ResourceName][\"actions\"][ActionName]>\n\t\t\t\t: never\n\t\t\t: never;\n\ntype ActionPathsWithAction<TResources extends ResourceMap, TPaths extends string> = {\n\t[path in TPaths]: {\n\t\tpath: path;\n\t\taction: ActionFromPath<TResources, path>;\n\t};\n}[TPaths];\n\nexport type FilterActionPaths<\n\tTResources extends ResourceMap,\n\tTCtxPattern,\n\tTConfigurable extends boolean = boolean,\n\tTPathsAndActions = ActionPathsWithAction<TResources, ActionPaths<TResources>>\n> = TPathsAndActions extends { path: string; action: Action<any, infer TActionContext> }\n\t? TActionContext[\"ctx\"] extends TCtxPattern\n\t\t? TActionContext[\"configurable\"] extends TConfigurable\n\t\t\t? TPathsAndActions[\"path\"]\n\t\t\t: never\n\t\t: never\n\t: never;\n"]}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/internal/paths.ts"],"names":[],"mappings":"","sourcesContent":["import type { Action, RuleCtx } from \"../action.js\";\nimport type { ActionGroup } from \"../actionGroup.js\";\nimport type { Resource } from \"../resource.js\";\nimport type { ResourceMap } from \"./collections.js\";\nimport type { EmptyObject, Expand, MakeOptional, OptionalMarker, UnsetMarker } from \"./core.js\";\n\ntype ActionNames<TActionMap, TExcludeEmptyObjects extends boolean = false> = {\n\t[actionName in keyof TActionMap]: TActionMap[actionName] extends Action<\n\t\tinfer TActionName,\n\t\tinfer TActionContext\n\t>\n\t\t? TActionContext[\"ctx\"] extends EmptyObject\n\t\t\t? TExcludeEmptyObjects extends true\n\t\t\t\t? never\n\t\t\t\t: `:${TActionName}`\n\t\t\t: `:${TActionName}`\n\t\t: TActionMap[actionName] extends ActionGroup<infer TGroupName, infer TGroupContext>\n\t\t\t? `.${TGroupName}${ActionNames<TGroupContext[\"actions\"], TExcludeEmptyObjects>}`\n\t\t\t: never;\n}[keyof TActionMap];\n\nexport type OwnableActionPaths<TResources extends ResourceMap> = {\n\t[resourceName in Extract<keyof TResources, string>]:\n\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t? never\n\t\t\t\t: `${resourceName}.${OwnableActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t| (TResources[resourceName] extends Resource<any, infer TResourceContext>\n\t\t\t\t? TResourceContext[\"ownable\"] extends true\n\t\t\t\t\t? TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}${ActionNames<TResources[resourceName][\"actions\"], true>}`\n\t\t\t\t\t: never\n\t\t\t\t: never);\n}[Extract<keyof TResources, string>];\n\nexport type ActionPaths<TResources extends ResourceMap> =\n\t| {\n\t\t\t[resourceName in Extract<keyof TResources, string>]:\n\t\t\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}.${ActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t\t\t| (TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}${ActionNames<TResources[resourceName][\"actions\"]>}`);\n\t }[Extract<keyof TResources, string>]\n\t| `${OwnableActionPaths<TResources>}.own`;\n\ntype ActionNamesWithWildcards<TActionMap> = {\n\t[actionName in keyof TActionMap]: TActionMap[actionName] extends ActionGroup<\n\t\tinfer TGroupName,\n\t\tinfer TGroupContext\n\t>\n\t\t? `.${TGroupName}${ActionNamesWithWildcards<TGroupContext[\"actions\"]>}` | `.${TGroupName}:*`\n\t\t: never;\n}[keyof TActionMap];\n\nexport type OwnableWildcardActionPaths<TResources extends ResourceMap> = {\n\t[resourceName in Extract<keyof TResources, string>]: TResources[resourceName] extends Resource<\n\t\tany,\n\t\tinfer TResourceContext\n\t>\n\t\t? TResourceContext[\"ownable\"] extends true\n\t\t\t?\n\t\t\t\t\t| `${resourceName}:*`\n\t\t\t\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: `${resourceName}.${OwnableWildcardActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t\t\t\t| (TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t\t? never\n\t\t\t\t\t\t\t: `${resourceName}${ActionNamesWithWildcards<TResources[resourceName][\"actions\"]>}`)\n\t\t\t: never\n\t\t: never;\n}[Extract<keyof TResources, string>];\n\nexport type WildcardActionPaths<TResources extends ResourceMap> =\n\t| {\n\t\t\t[resourceName in Extract<keyof TResources, string>]:\n\t\t\t\t| (TResources[resourceName][\"subResources\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}.${WildcardActionPaths<TResources[resourceName][\"subResources\"]>}`)\n\t\t\t\t| (TResources[resourceName][\"actions\"] extends UnsetMarker\n\t\t\t\t\t\t? never\n\t\t\t\t\t\t: `${resourceName}${ActionNamesWithWildcards<TResources[resourceName][\"actions\"]>}`)\n\t\t\t\t| `${resourceName}:*`\n\t\t\t\t| `${resourceName}.*`;\n\t }[Extract<keyof TResources, string>]\n\t| `${OwnableWildcardActionPaths<TResources>}.own`;\n\ntype MergeRuleCtx<A extends RuleCtx, B extends RuleCtx> = {\n\tsubject: A[\"subject\"] extends UnsetMarker ? B[\"subject\"] : A[\"subject\"];\n\tobject: A[\"object\"] extends UnsetMarker\n\t\t? B[\"object\"]\n\t\t: A[\"object\"] extends OptionalMarker\n\t\t\t? MakeOptional<B[\"object\"]>\n\t\t\t: A[\"object\"];\n} & Omit<A, \"subject\" | \"object\"> &\n\tOmit<B, \"subject\" | \"object\">;\n\ntype ResolveAction<TParentCtx extends RuleCtx, TAction extends Action<any, any>> =\n\tTAction extends Action<infer TName, infer TActionContext>\n\t\t? Action<\n\t\t\t\tTName,\n\t\t\t\tExpand<{\n\t\t\t\t\tctx: Expand<MergeRuleCtx<TActionContext[\"ctx\"], TParentCtx>>;\n\t\t\t\t\ttags: TActionContext[\"tags\"];\n\t\t\t\t}>\n\t\t\t>\n\t\t: never;\n\ntype IndexActionGroupWithPath<\n\tTPath extends string,\n\tTActionGroup extends ActionGroup<any, any>,\n\tTParentCtx extends RuleCtx\n> = TPath extends keyof TActionGroup[\"actions\"] // Check fast path first\n\t? ResolveAction<TParentCtx, TActionGroup[\"actions\"][TPath]>\n\t: TPath extends `${infer ActionGroupName}.${infer Rest}`\n\t\t? TActionGroup[\"actions\"][ActionGroupName] extends ActionGroup<any, infer TActionGroupContext>\n\t\t\t? IndexActionGroupWithPath<\n\t\t\t\t\tRest,\n\t\t\t\t\tTActionGroup[\"actions\"][ActionGroupName],\n\t\t\t\t\tMergeRuleCtx<TActionGroupContext[\"ctx\"], TParentCtx>\n\t\t\t\t>\n\t\t\t: never\n\t\t: TPath extends `${infer ActionGroupName}:${infer ActionName}`\n\t\t\t? TActionGroup[\"actions\"][ActionGroupName] extends ActionGroup<any, any>\n\t\t\t\t? ResolveAction<TParentCtx, TActionGroup[\"actions\"][ActionGroupName][\"actions\"][ActionName]>\n\t\t\t\t: never\n\t\t\t: never;\n\ntype IndexResourceWithPath<\n\tTPath extends string,\n\tTResource extends Resource<any, any>,\n\tTParentCtx extends RuleCtx\n> = TPath extends keyof TResource[\"actions\"] // Check fast path first\n\t? TResource[\"actions\"][TPath] extends Action<any, any>\n\t\t? ResolveAction<TParentCtx, TResource[\"actions\"][TPath]>\n\t\t: never\n\t: TPath extends `${infer ResourceOrGroupName}.${infer Rest}`\n\t\t? ResourceOrGroupName extends keyof TResource[\"actions\"]\n\t\t\t? TResource[\"actions\"][ResourceOrGroupName] extends ActionGroup<\n\t\t\t\t\tany,\n\t\t\t\t\tinfer TActionGroupContext\n\t\t\t\t>\n\t\t\t\t? IndexActionGroupWithPath<\n\t\t\t\t\t\tRest,\n\t\t\t\t\t\tTResource[\"actions\"][ResourceOrGroupName],\n\t\t\t\t\t\tMergeRuleCtx<TActionGroupContext[\"ctx\"], TParentCtx>\n\t\t\t\t\t>\n\t\t\t\t: never\n\t\t\t: TResource[\"subResources\"][ResourceOrGroupName] extends Resource<any, infer TResourceContext>\n\t\t\t\t? IndexResourceWithPath<\n\t\t\t\t\t\tRest,\n\t\t\t\t\t\tTResource[\"subResources\"][ResourceOrGroupName],\n\t\t\t\t\t\tMergeRuleCtx<TResourceContext[\"ctx\"], TParentCtx>\n\t\t\t\t\t>\n\t\t\t\t: never\n\t\t: TPath extends `${infer ResourceOrGroupName}:${infer ActionName}`\n\t\t\t? TResource[\"actions\"][ResourceOrGroupName] extends ActionGroup<\n\t\t\t\t\tany,\n\t\t\t\t\tinfer TActionGroupContext\n\t\t\t\t>\n\t\t\t\t? ResolveAction<\n\t\t\t\t\t\tMergeRuleCtx<TActionGroupContext[\"ctx\"], TParentCtx>,\n\t\t\t\t\t\tTResource[\"actions\"][ResourceOrGroupName][\"actions\"][ActionName]\n\t\t\t\t\t>\n\t\t\t\t: TResource[\"subResources\"][ResourceOrGroupName] extends Resource<\n\t\t\t\t\t\t\tany,\n\t\t\t\t\t\t\tinfer TResourceContext\n\t\t\t\t\t >\n\t\t\t\t\t? ResolveAction<\n\t\t\t\t\t\t\tMergeRuleCtx<TResourceContext[\"ctx\"], TParentCtx>,\n\t\t\t\t\t\t\tTResource[\"subResources\"][ResourceOrGroupName][\"actions\"][ActionName]\n\t\t\t\t\t\t>\n\t\t\t\t\t: never\n\t\t\t: never;\n\nexport type ActionFromPath<\n\tTResources extends ResourceMap,\n\tTPath extends string\n> = TPath extends `${infer TActualPath}.own`\n\t? ActionFromPath<TResources, TActualPath>\n\t: TPath extends `${infer ResourceName extends Extract<keyof TResources, string>}.${infer Rest}`\n\t\t? TResources[ResourceName] extends Resource<any, infer TResourceContext>\n\t\t\t? IndexResourceWithPath<Rest, TResources[ResourceName], TResourceContext[\"ctx\"]>\n\t\t\t: never\n\t\t: TPath extends `${infer ResourceName extends Extract<keyof TResources, string>}:${infer ActionName}`\n\t\t\t? TResources[ResourceName] extends Resource<any, infer TResourceContext>\n\t\t\t\t? ResolveAction<TResourceContext[\"ctx\"], TResources[ResourceName][\"actions\"][ActionName]>\n\t\t\t\t: never\n\t\t\t: never;\n\ntype ActionPathsWithAction<TResources extends ResourceMap, TPaths extends string> = {\n\t[path in TPaths]: {\n\t\tpath: path;\n\t\taction: ActionFromPath<TResources, path>;\n\t};\n}[TPaths];\n\nexport type FilterActionPaths<\n\tTResources extends ResourceMap,\n\tTCtxPattern,\n\tTTag extends string = any,\n\tTPathsAndActions = ActionPathsWithAction<TResources, ActionPaths<TResources>>\n> = TPathsAndActions extends { path: string; action: Action<any, infer TActionContext> }\n\t? TActionContext[\"ctx\"] extends TCtxPattern\n\t\t? TTag extends TActionContext[\"tags\"]\n\t\t\t? TPathsAndActions[\"path\"]\n\t\t\t: never\n\t\t: never\n\t: never;\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { Action, InferActionAdditionalContext, InferActionObject, InferActionRuleCtx, InferActionSubject, RuleCtx } from "./action.js";
2
2
  import type { ResourceMap } from "./internal/collections.js";
3
- import type { EmptyObject, Expand, IsOnlyEmptyObject, OptionalUndefinedFields } from "./internal/core.js";
3
+ import type { EmptyObject, Expand, HasOnlyObject, IsOnlyEmptyObject, OptionalUndefinedFields } from "./internal/core.js";
4
4
  import type { ActionFromPath } from "./internal/paths.js";
5
5
  import { Specitivity, type Policy, type Rule } from "./policy.js";
6
6
  import type { Resource } from "./resource.js";
@@ -13,14 +13,19 @@ type PermissionTestResult = {
13
13
  type Granted<TAction extends Action<any, any>, TCtx extends Omit<InferActionRuleCtx<TAction>, "subject"> = Omit<InferActionRuleCtx<TAction>, "subject">> = IsOnlyEmptyObject<TCtx> extends true ? {
14
14
  granted(): boolean;
15
15
  test(): PermissionTestResult;
16
+ } : TCtx extends {
17
+ object: infer TObject;
18
+ } ? HasOnlyObject<TCtx> extends true ? {
19
+ granted(object: TObject): boolean;
20
+ test(object: TObject): PermissionTestResult;
16
21
  } : {
17
- granted(ctx: OptionalUndefinedFields<TCtx extends EmptyObject ? Omit<TCtx, "object"> : TCtx>): boolean;
18
- test(ctx: OptionalUndefinedFields<TCtx extends EmptyObject ? Omit<TCtx, "object"> : TCtx>): PermissionTestResult;
19
- };
22
+ granted(object: TObject, additionalContext: OptionalUndefinedFields<Omit<TCtx, "object">>): boolean;
23
+ test(object: TObject, additionalContext: OptionalUndefinedFields<Omit<TCtx, "object">>): PermissionTestResult;
24
+ } : never;
20
25
  type Filter<TAction extends Action<any, any>, TObjects extends InferActionObject<TAction>[] = InferActionObject<TAction>[]> = InferActionRuleCtx<TAction> extends EmptyObject ? {} : InferActionAdditionalContext<TAction> extends {} ? {
21
26
  filter(objects: TObjects): TObjects;
22
27
  } : {
23
- filter(objects: TObjects, ctx: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>): TObjects;
28
+ filter(objects: TObjects, additionalContext: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>): TObjects;
24
29
  };
25
30
  type ResolvedPermission<TActionPath extends string, TAction extends Action<any, any>> = Omit<Permission<TActionPath, TAction>, "granted" | "filter"> & Granted<TAction> & Filter<TAction>;
26
31
  export type PermissionCtx<TAction extends Action<any, any>, TCtx extends RuleCtx = InferActionRuleCtx<TAction>> = TCtx extends EmptyObject ? Expand<Omit<TCtx, "object">> : Expand<TCtx>;
@@ -42,9 +47,9 @@ export declare class Permission<TActionPath extends string, TAction extends Acti
42
47
  get resource(): Resource<any, any>;
43
48
  get action(): TAction;
44
49
  get policies(): Policy<any>[];
45
- test(ctx?: OptionalUndefinedFields<Omit<InferActionRuleCtx<TAction>, "subject">>): PermissionTestResult;
46
- granted(ctx?: OptionalUndefinedFields<Omit<InferActionRuleCtx<TAction>, "subject">>): boolean;
47
- filter(objects: InferActionObject<TAction>[], ctx?: InferActionAdditionalContext<TAction>): Exclude<InferActionRuleCtx<TAction>["object"], void | undefined>[];
50
+ test(object?: InferActionObject<TAction>, additionalContext?: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>): PermissionTestResult;
51
+ granted(object?: InferActionObject<TAction>, additionalContext?: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>): boolean;
52
+ filter(objects: InferActionObject<TAction>[], additionalContext?: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>): Exclude<InferActionRuleCtx<TAction>["object"], void | undefined>[];
48
53
  private isGranted;
49
54
  private checkOwnership;
50
55
  private static matchPathPattern;
@@ -28,26 +28,31 @@ export class Permission {
28
28
  get policies() {
29
29
  return this._policies;
30
30
  }
31
- test(ctx) {
32
- const fullCtx = {
33
- ...(ctx ?? {}),
34
- subject: this._subject
31
+ test(object, additionalContext) {
32
+ const ctx = {
33
+ object,
34
+ subject: this._subject,
35
+ ...additionalContext
35
36
  };
36
37
  let granted = false;
37
38
  let specitivity = -1;
38
39
  let grantPolicy = null;
39
40
  let grantRule = null;
40
- const ownsObject = this.checkOwnership(fullCtx);
41
- const isGranted = !this._action.configurable ||
42
- this.isGranted(this._path, fullCtx.object) ||
43
- (ownsObject && this.isGranted(this._path + ".own", fullCtx.object));
41
+ let isGranted = !this._action.tags.has("configurable");
42
+ if (!this._path.endsWith(".own")) {
43
+ isGranted ||= this.isGranted(this._path, ctx.object);
44
+ }
45
+ const ownsObject = this.checkOwnership(ctx);
46
+ if (ownsObject) {
47
+ isGranted ||= this.isGranted(this._path + (this._path.endsWith(".own") ? "" : ".own"), ctx.object);
48
+ }
44
49
  for (const policy of this._policies) {
45
50
  for (const rule of policy.rules) {
46
51
  const match = Permission.matchPathPattern(this._path, rule.action);
47
52
  if (!match.matches || specitivity > match.specitivity) {
48
53
  continue;
49
54
  }
50
- const result = rule.predicate(fullCtx, this._action);
55
+ const result = rule.predicate(ctx, this._action);
51
56
  granted = result === "ifgranted" ? isGranted : result;
52
57
  specitivity = rule.specitivity ?? match.specitivity;
53
58
  grantPolicy = policy;
@@ -67,18 +72,15 @@ export class Permission {
67
72
  rule: grantRule
68
73
  };
69
74
  }
70
- granted(ctx) {
71
- const { granted } = this.test(ctx);
75
+ granted(object, additionalContext) {
76
+ const { granted } = this.test(object, additionalContext);
72
77
  return granted;
73
78
  }
74
- filter(objects, ctx) {
79
+ filter(objects, additionalContext) {
75
80
  return objects
76
81
  .map((object) => ({
77
82
  object,
78
- granted: this.granted({
79
- object,
80
- ...(ctx ?? {})
81
- })
83
+ granted: this.granted(object, additionalContext)
82
84
  }))
83
85
  .filter(({ granted }) => granted)
84
86
  .map(({ object }) => object);
@@ -1 +1 @@
1
- {"version":3,"file":"permission.js","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport type {\n\tAction,\n\tInferActionAdditionalContext,\n\tInferActionObject,\n\tInferActionRuleCtx,\n\tInferActionSubject,\n\tRuleCtx\n} from \"./action.js\";\nimport type { ResourceMap } from \"./internal/collections.js\";\nimport type {\n\tEmptyObject,\n\tExpand,\n\tIsOnlyEmptyObject,\n\tOptionalUndefinedFields\n} from \"./internal/core.js\";\nimport type { ActionFromPath } from \"./internal/paths.js\";\nimport { Specitivity, type Policy, type Rule } from \"./policy.js\";\nimport type { Resource } from \"./resource.js\";\n\ntype PermissionTestResult = {\n\tgranted: boolean;\n\tspecitivity: Specitivity;\n\tpolicy: Policy<any> | null;\n\trule: Rule | null;\n};\n\ntype Granted<\n\tTAction extends Action<any, any>,\n\tTCtx extends Omit<InferActionRuleCtx<TAction>, \"subject\"> = Omit<\n\t\tInferActionRuleCtx<TAction>,\n\t\t\"subject\"\n\t>\n> =\n\tIsOnlyEmptyObject<TCtx> extends true\n\t\t? {\n\t\t\t\tgranted(): boolean;\n\t\t\t\ttest(): PermissionTestResult;\n\t\t\t}\n\t\t: {\n\t\t\t\tgranted(\n\t\t\t\t\tctx: OptionalUndefinedFields<TCtx extends EmptyObject ? Omit<TCtx, \"object\"> : TCtx>\n\t\t\t\t): boolean;\n\t\t\t\ttest(\n\t\t\t\t\tctx: OptionalUndefinedFields<TCtx extends EmptyObject ? Omit<TCtx, \"object\"> : TCtx>\n\t\t\t\t): PermissionTestResult;\n\t\t\t};\n\ntype Filter<\n\tTAction extends Action<any, any>,\n\tTObjects extends InferActionObject<TAction>[] = InferActionObject<TAction>[]\n> =\n\tInferActionRuleCtx<TAction> extends EmptyObject\n\t\t? {}\n\t\t: InferActionAdditionalContext<TAction> extends {}\n\t\t\t? {\n\t\t\t\t\tfilter(objects: TObjects): TObjects;\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tfilter(\n\t\t\t\t\t\tobjects: TObjects,\n\t\t\t\t\t\tctx: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>\n\t\t\t\t\t): TObjects;\n\t\t\t\t};\n\ntype ResolvedPermission<TActionPath extends string, TAction extends Action<any, any>> = Omit<\n\tPermission<TActionPath, TAction>,\n\t\"granted\" | \"filter\"\n> &\n\tGranted<TAction> &\n\tFilter<TAction>;\n\nexport type PermissionCtx<\n\tTAction extends Action<any, any>,\n\tTCtx extends RuleCtx = InferActionRuleCtx<TAction>\n> = TCtx extends EmptyObject ? Expand<Omit<TCtx, \"object\">> : Expand<TCtx>;\n\nexport type GrantedPermissionsResolver<\n\tTActionPath extends string,\n\tTAction extends Action<any, any>\n> = (\n\tobject: InferActionObject<TAction>,\n\tpermission: ResolvedPermission<TActionPath, TAction>\n) => string[] | Set<string>;\n\nexport type PermissionOptions<TActionPath extends string, TAction extends Action<any, any>> = {\n\tgrantedPermissions?:\n\t\t| \"all\"\n\t\t| string[]\n\t\t| Set<string>\n\t\t| GrantedPermissionsResolver<TActionPath, TAction>;\n\tcheckOwnership?: (ctx: InferActionRuleCtx<TAction>) => boolean;\n};\n\nconst VoidObjectCacheKey = Symbol(\"void-object\");\n\nexport class Permission<TActionPath extends string, TAction extends Action<any, any>> {\n\tprivate _subject: InferActionSubject<TAction>;\n\tprivate _path: TActionPath;\n\tprivate _resource: Resource<any, any>;\n\tprivate _action: TAction;\n\tprivate _policies: Policy<any>[];\n\tprivate _options: PermissionOptions<TActionPath, TAction>;\n\n\tprivate _grantedPermissionsCache: Map<any, Set<string>> = new Map();\n\n\tconstructor(\n\t\tsubject: InferActionSubject<TAction>,\n\t\tpath: TActionPath,\n\t\tresource: Resource<any, any>,\n\t\taction: TAction,\n\t\tpolicies: Policy<any>[],\n\t\toptions?: PermissionOptions<TActionPath, TAction>\n\t) {\n\t\tthis._subject = subject;\n\t\tthis._path = path;\n\t\tthis._resource = resource;\n\t\tthis._action = action;\n\t\tthis._policies = policies;\n\n\t\tthis._options = options ?? {};\n\t}\n\n\tpublic get path() {\n\t\treturn this._path;\n\t}\n\n\tpublic get resource() {\n\t\treturn this._resource;\n\t}\n\n\tpublic get action() {\n\t\treturn this._action;\n\t}\n\n\tpublic get policies() {\n\t\treturn this._policies;\n\t}\n\n\tpublic test(\n\t\tctx?: OptionalUndefinedFields<Omit<InferActionRuleCtx<TAction>, \"subject\">>\n\t): PermissionTestResult {\n\t\tconst fullCtx = {\n\t\t\t...(ctx ?? {}),\n\t\t\tsubject: this._subject\n\t\t} as unknown as InferActionRuleCtx<TAction>;\n\n\t\tlet granted = false;\n\t\tlet specitivity = -1;\n\t\tlet grantPolicy: Policy<any> | null = null;\n\t\tlet grantRule: Rule | null = null;\n\n\t\tconst ownsObject = this.checkOwnership(fullCtx);\n\t\tconst isGranted =\n\t\t\t!this._action.configurable ||\n\t\t\tthis.isGranted(this._path, fullCtx.object) ||\n\t\t\t(ownsObject && this.isGranted(this._path + \".own\", fullCtx.object));\n\n\t\tfor (const policy of this._policies) {\n\t\t\tfor (const rule of policy.rules) {\n\t\t\t\tconst match = Permission.matchPathPattern(this._path, rule.action);\n\t\t\t\tif (!match.matches || specitivity > match.specitivity) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = rule.predicate(fullCtx, this._action);\n\t\t\t\tgranted = result === \"ifgranted\" ? isGranted : result;\n\t\t\t\tspecitivity = rule.specitivity ?? match.specitivity;\n\t\t\t\tgrantPolicy = policy;\n\t\t\t\tgrantRule = rule;\n\n\t\t\t\tif (specitivity === Specitivity.Exact) {\n\t\t\t\t\t// This rule is an exact match, so we can stop and return early\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (specitivity === Specitivity.Exact) break;\n\t\t}\n\n\t\treturn {\n\t\t\tgranted,\n\t\t\tspecitivity,\n\t\t\tpolicy: grantPolicy,\n\t\t\trule: grantRule\n\t\t};\n\t}\n\n\tpublic granted(ctx?: OptionalUndefinedFields<Omit<InferActionRuleCtx<TAction>, \"subject\">>) {\n\t\tconst { granted } = this.test(ctx);\n\t\treturn granted;\n\t}\n\n\tpublic filter(\n\t\tobjects: InferActionObject<TAction>[],\n\t\tctx?: InferActionAdditionalContext<TAction>\n\t) {\n\t\treturn objects\n\t\t\t.map((object) => ({\n\t\t\t\tobject,\n\t\t\t\tgranted: this.granted({\n\t\t\t\t\tobject,\n\t\t\t\t\t...(ctx ?? {})\n\t\t\t\t} as any)\n\t\t\t}))\n\t\t\t.filter(({ granted }) => granted)\n\t\t\t.map(({ object }) => object);\n\t}\n\n\tprivate isGranted(path: string, object: InferActionObject<TAction>) {\n\t\tif (this._options.grantedPermissions === \"all\") {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst cacheKey: any = object ? object : VoidObjectCacheKey;\n\t\tlet grantedPermissions: Set<string>;\n\t\tif (this._grantedPermissionsCache.has(cacheKey)) {\n\t\t\tgrantedPermissions = this._grantedPermissionsCache.get(cacheKey)!;\n\t\t} else {\n\t\t\tif (typeof this._options.grantedPermissions === \"function\") {\n\t\t\t\tgrantedPermissions = new Set(\n\t\t\t\t\tthis._options.grantedPermissions(\n\t\t\t\t\t\tobject,\n\t\t\t\t\t\tthis as unknown as ResolvedPermission<TActionPath, TAction>\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tgrantedPermissions = new Set(this._options.grantedPermissions ?? []);\n\t\t\t}\n\n\t\t\tthis._grantedPermissionsCache.set(cacheKey, grantedPermissions);\n\t\t}\n\n\t\treturn grantedPermissions.has(path);\n\t}\n\n\tprivate checkOwnership(ctx: InferActionRuleCtx<TAction>) {\n\t\tif (!this._resource.ownable) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (typeof this._options.checkOwnership === \"function\") {\n\t\t\treturn this._options.checkOwnership(ctx);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate static matchPathPattern(path: string, pattern: string) {\n\t\tif (pattern === \"*\") {\n\t\t\t// Any action\n\t\t\treturn {\n\t\t\t\tmatches: true,\n\t\t\t\tspecitivity: Specitivity.Any\n\t\t\t};\n\t\t}\n\n\t\tif (pattern.endsWith(\".*\")) {\n\t\t\t// Any action, sub-resource or action group on this resource\n\t\t\treturn {\n\t\t\t\tmatches: path.startsWith(pattern.slice(0, -2)),\n\t\t\t\tspecitivity: Specitivity.ActionsAndNested\n\t\t\t};\n\t\t}\n\n\t\tif (pattern.endsWith(\":*\")) {\n\t\t\t// Any action on this resource (excluding action groups)\n\t\t\treturn {\n\t\t\t\tmatches: path.startsWith(pattern.slice(0, -1)),\n\t\t\t\tspecitivity: Specitivity.ActionsOnly\n\t\t\t};\n\t\t}\n\n\t\tif (pattern.endsWith(\":*.own\")) {\n\t\t\treturn {\n\t\t\t\tmatches: path.startsWith(pattern.slice(0, -6)) && path.endsWith(\".own\"),\n\t\t\t\tspecitivity: Specitivity.OwnedActionsOnly\n\t\t\t};\n\t\t}\n\n\t\t// Specific action\n\t\treturn {\n\t\t\tmatches: path === pattern,\n\t\t\tspecitivity: Specitivity.Exact\n\t\t};\n\t}\n\n\tpublic static create<\n\t\tTResources extends ResourceMap,\n\t\tTActionPath extends string,\n\t\tTAction extends Action<any, any> = ActionFromPath<TResources, TActionPath>\n\t>(\n\t\tsubject: InferActionSubject<TAction>,\n\t\tpath: TActionPath,\n\t\tresource: Resource<any, any>,\n\t\taction: TAction,\n\t\tpolicies: Policy<TResources>[],\n\t\toptions?: PermissionOptions<TActionPath, TAction>\n\t) {\n\t\treturn new Permission(\n\t\t\tsubject,\n\t\t\tpath,\n\t\t\tresource,\n\t\t\taction,\n\t\t\tpolicies,\n\t\t\toptions\n\t\t) as unknown as ResolvedPermission<TActionPath, TAction>;\n\t}\n}\n"]}
1
+ {"version":3,"file":"permission.js","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport type {\n\tAction,\n\tInferActionAdditionalContext,\n\tInferActionObject,\n\tInferActionRuleCtx,\n\tInferActionSubject,\n\tRuleCtx\n} from \"./action.js\";\nimport type { ResourceMap } from \"./internal/collections.js\";\nimport type {\n\tEmptyObject,\n\tExpand,\n\tHasOnlyObject,\n\tIsOnlyEmptyObject,\n\tOptionalUndefinedFields\n} from \"./internal/core.js\";\nimport type { ActionFromPath } from \"./internal/paths.js\";\nimport { Specitivity, type Policy, type Rule } from \"./policy.js\";\nimport type { Resource } from \"./resource.js\";\n\ntype PermissionTestResult = {\n\tgranted: boolean;\n\tspecitivity: Specitivity;\n\tpolicy: Policy<any> | null;\n\trule: Rule | null;\n};\n\ntype Granted<\n\tTAction extends Action<any, any>,\n\tTCtx extends Omit<InferActionRuleCtx<TAction>, \"subject\"> = Omit<\n\t\tInferActionRuleCtx<TAction>,\n\t\t\"subject\"\n\t>\n> =\n\tIsOnlyEmptyObject<TCtx> extends true\n\t\t? {\n\t\t\t\tgranted(): boolean;\n\t\t\t\ttest(): PermissionTestResult;\n\t\t\t}\n\t\t: TCtx extends { object: infer TObject }\n\t\t\t? HasOnlyObject<TCtx> extends true\n\t\t\t\t? {\n\t\t\t\t\t\tgranted(object: TObject): boolean;\n\t\t\t\t\t\ttest(object: TObject): PermissionTestResult;\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tgranted(\n\t\t\t\t\t\t\tobject: TObject,\n\t\t\t\t\t\t\tadditionalContext: OptionalUndefinedFields<Omit<TCtx, \"object\">>\n\t\t\t\t\t\t): boolean;\n\t\t\t\t\t\ttest(\n\t\t\t\t\t\t\tobject: TObject,\n\t\t\t\t\t\t\tadditionalContext: OptionalUndefinedFields<Omit<TCtx, \"object\">>\n\t\t\t\t\t\t): PermissionTestResult;\n\t\t\t\t\t}\n\t\t\t: never;\n\ntype Filter<\n\tTAction extends Action<any, any>,\n\tTObjects extends InferActionObject<TAction>[] = InferActionObject<TAction>[]\n> =\n\tInferActionRuleCtx<TAction> extends EmptyObject\n\t\t? {}\n\t\t: InferActionAdditionalContext<TAction> extends {}\n\t\t\t? {\n\t\t\t\t\tfilter(objects: TObjects): TObjects;\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tfilter(\n\t\t\t\t\t\tobjects: TObjects,\n\t\t\t\t\t\tadditionalContext: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>\n\t\t\t\t\t): TObjects;\n\t\t\t\t};\n\ntype ResolvedPermission<TActionPath extends string, TAction extends Action<any, any>> = Omit<\n\tPermission<TActionPath, TAction>,\n\t\"granted\" | \"filter\"\n> &\n\tGranted<TAction> &\n\tFilter<TAction>;\n\nexport type PermissionCtx<\n\tTAction extends Action<any, any>,\n\tTCtx extends RuleCtx = InferActionRuleCtx<TAction>\n> = TCtx extends EmptyObject ? Expand<Omit<TCtx, \"object\">> : Expand<TCtx>;\n\nexport type GrantedPermissionsResolver<\n\tTActionPath extends string,\n\tTAction extends Action<any, any>\n> = (\n\tobject: InferActionObject<TAction>,\n\tpermission: ResolvedPermission<TActionPath, TAction>\n) => string[] | Set<string>;\n\nexport type PermissionOptions<TActionPath extends string, TAction extends Action<any, any>> = {\n\tgrantedPermissions?:\n\t\t| \"all\"\n\t\t| string[]\n\t\t| Set<string>\n\t\t| GrantedPermissionsResolver<TActionPath, TAction>;\n\tcheckOwnership?: (ctx: InferActionRuleCtx<TAction>) => boolean;\n};\n\nconst VoidObjectCacheKey = Symbol(\"void-object\");\n\nexport class Permission<TActionPath extends string, TAction extends Action<any, any>> {\n\tprivate _subject: InferActionSubject<TAction>;\n\tprivate _path: TActionPath;\n\tprivate _resource: Resource<any, any>;\n\tprivate _action: TAction;\n\tprivate _policies: Policy<any>[];\n\tprivate _options: PermissionOptions<TActionPath, TAction>;\n\n\tprivate _grantedPermissionsCache: Map<any, Set<string>> = new Map();\n\n\tconstructor(\n\t\tsubject: InferActionSubject<TAction>,\n\t\tpath: TActionPath,\n\t\tresource: Resource<any, any>,\n\t\taction: TAction,\n\t\tpolicies: Policy<any>[],\n\t\toptions?: PermissionOptions<TActionPath, TAction>\n\t) {\n\t\tthis._subject = subject;\n\t\tthis._path = path;\n\t\tthis._resource = resource;\n\t\tthis._action = action;\n\t\tthis._policies = policies;\n\n\t\tthis._options = options ?? {};\n\t}\n\n\tpublic get path() {\n\t\treturn this._path;\n\t}\n\n\tpublic get resource() {\n\t\treturn this._resource;\n\t}\n\n\tpublic get action() {\n\t\treturn this._action;\n\t}\n\n\tpublic get policies() {\n\t\treturn this._policies;\n\t}\n\n\tpublic test(\n\t\tobject?: InferActionObject<TAction>,\n\t\tadditionalContext?: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>\n\t): PermissionTestResult {\n\t\tconst ctx = {\n\t\t\tobject,\n\t\t\tsubject: this._subject,\n\t\t\t...additionalContext\n\t\t} as unknown as InferActionRuleCtx<TAction>;\n\n\t\tlet granted = false;\n\t\tlet specitivity = -1;\n\t\tlet grantPolicy: Policy<any> | null = null;\n\t\tlet grantRule: Rule | null = null;\n\n\t\tlet isGranted = !this._action.tags.has(\"configurable\");\n\t\tif (!this._path.endsWith(\".own\")) {\n\t\t\tisGranted ||= this.isGranted(this._path, ctx.object);\n\t\t}\n\n\t\tconst ownsObject = this.checkOwnership(ctx);\n\t\tif (ownsObject) {\n\t\t\tisGranted ||= this.isGranted(\n\t\t\t\tthis._path + (this._path.endsWith(\".own\") ? \"\" : \".own\"),\n\t\t\t\tctx.object\n\t\t\t);\n\t\t}\n\n\t\tfor (const policy of this._policies) {\n\t\t\tfor (const rule of policy.rules) {\n\t\t\t\tconst match = Permission.matchPathPattern(this._path, rule.action);\n\t\t\t\tif (!match.matches || specitivity > match.specitivity) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = rule.predicate(ctx, this._action);\n\t\t\t\tgranted = result === \"ifgranted\" ? isGranted : result;\n\t\t\t\tspecitivity = rule.specitivity ?? match.specitivity;\n\t\t\t\tgrantPolicy = policy;\n\t\t\t\tgrantRule = rule;\n\n\t\t\t\tif (specitivity === Specitivity.Exact) {\n\t\t\t\t\t// This rule is an exact match, so we can stop and return early\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (specitivity === Specitivity.Exact) break;\n\t\t}\n\n\t\treturn {\n\t\t\tgranted,\n\t\t\tspecitivity,\n\t\t\tpolicy: grantPolicy,\n\t\t\trule: grantRule\n\t\t};\n\t}\n\n\tpublic granted(\n\t\tobject?: InferActionObject<TAction>,\n\t\tadditionalContext?: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>\n\t) {\n\t\tconst { granted } = this.test(object, additionalContext);\n\t\treturn granted;\n\t}\n\n\tpublic filter(\n\t\tobjects: InferActionObject<TAction>[],\n\t\tadditionalContext?: OptionalUndefinedFields<InferActionAdditionalContext<TAction>>\n\t) {\n\t\treturn objects\n\t\t\t.map((object) => ({\n\t\t\t\tobject,\n\t\t\t\tgranted: this.granted(object, additionalContext)\n\t\t\t}))\n\t\t\t.filter(({ granted }) => granted)\n\t\t\t.map(({ object }) => object);\n\t}\n\n\tprivate isGranted(path: string, object: InferActionObject<TAction>) {\n\t\tif (this._options.grantedPermissions === \"all\") {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst cacheKey: any = object ? object : VoidObjectCacheKey;\n\t\tlet grantedPermissions: Set<string>;\n\t\tif (this._grantedPermissionsCache.has(cacheKey)) {\n\t\t\tgrantedPermissions = this._grantedPermissionsCache.get(cacheKey)!;\n\t\t} else {\n\t\t\tif (typeof this._options.grantedPermissions === \"function\") {\n\t\t\t\tgrantedPermissions = new Set(\n\t\t\t\t\tthis._options.grantedPermissions(\n\t\t\t\t\t\tobject,\n\t\t\t\t\t\tthis as unknown as ResolvedPermission<TActionPath, TAction>\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tgrantedPermissions = new Set(this._options.grantedPermissions ?? []);\n\t\t\t}\n\n\t\t\tthis._grantedPermissionsCache.set(cacheKey, grantedPermissions);\n\t\t}\n\n\t\treturn grantedPermissions.has(path);\n\t}\n\n\tprivate checkOwnership(ctx: InferActionRuleCtx<TAction>) {\n\t\tif (!this._resource.ownable) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (typeof this._options.checkOwnership === \"function\") {\n\t\t\treturn this._options.checkOwnership(ctx);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate static matchPathPattern(path: string, pattern: string) {\n\t\tif (pattern === \"*\") {\n\t\t\t// Any action\n\t\t\treturn {\n\t\t\t\tmatches: true,\n\t\t\t\tspecitivity: Specitivity.Any\n\t\t\t};\n\t\t}\n\n\t\tif (pattern.endsWith(\".*\")) {\n\t\t\t// Any action, sub-resource or action group on this resource\n\t\t\treturn {\n\t\t\t\tmatches: path.startsWith(pattern.slice(0, -2)),\n\t\t\t\tspecitivity: Specitivity.ActionsAndNested\n\t\t\t};\n\t\t}\n\n\t\tif (pattern.endsWith(\":*\")) {\n\t\t\t// Any action on this resource (excluding action groups)\n\t\t\treturn {\n\t\t\t\tmatches: path.startsWith(pattern.slice(0, -1)),\n\t\t\t\tspecitivity: Specitivity.ActionsOnly\n\t\t\t};\n\t\t}\n\n\t\tif (pattern.endsWith(\":*.own\")) {\n\t\t\treturn {\n\t\t\t\tmatches: path.startsWith(pattern.slice(0, -6)) && path.endsWith(\".own\"),\n\t\t\t\tspecitivity: Specitivity.OwnedActionsOnly\n\t\t\t};\n\t\t}\n\n\t\t// Specific action\n\t\treturn {\n\t\t\tmatches: path === pattern,\n\t\t\tspecitivity: Specitivity.Exact\n\t\t};\n\t}\n\n\tpublic static create<\n\t\tTResources extends ResourceMap,\n\t\tTActionPath extends string,\n\t\tTAction extends Action<any, any> = ActionFromPath<TResources, TActionPath>\n\t>(\n\t\tsubject: InferActionSubject<TAction>,\n\t\tpath: TActionPath,\n\t\tresource: Resource<any, any>,\n\t\taction: TAction,\n\t\tpolicies: Policy<TResources>[],\n\t\toptions?: PermissionOptions<TActionPath, TAction>\n\t) {\n\t\treturn new Permission(\n\t\t\tsubject,\n\t\t\tpath,\n\t\t\tresource,\n\t\t\taction,\n\t\t\tpolicies,\n\t\t\toptions\n\t\t) as unknown as ResolvedPermission<TActionPath, TAction>;\n\t}\n}\n"]}
package/build/policy.d.ts CHANGED
@@ -5,7 +5,7 @@ export type MatchCtx = {
5
5
  subject: any;
6
6
  };
7
7
  export type PolicyMatchPredicate = (ctx: MatchCtx) => boolean;
8
- type InferRulePredicateReturn<TAction> = TAction extends Action<any, infer TContext extends ActionContext> ? TContext["configurable"] extends true ? "ifgranted" | boolean : boolean : boolean;
8
+ type InferRulePredicateReturn<TAction> = TAction extends Action<any, infer TContext extends ActionContext> ? "configurable" extends TContext["tags"] ? "ifgranted" | boolean : boolean : boolean;
9
9
  type SimplifyPredicate<T> = T extends (ctx: infer TCtx) => infer TReturn ? (ctx: TCtx) => TReturn : T;
10
10
  export type RulePredicate<TResources extends ResourceMap, TActionPath extends string> = (ctx: InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>, action: ActionFromPath<TResources, TActionPath>) => InferRulePredicateReturn<ActionFromPath<TResources, TActionPath>>;
11
11
  type AnyRulePredicate = (ctx: RuleCtx, action: Action<any, any>) => boolean | "ifgranted";
@@ -38,12 +38,24 @@ export declare class Policy<TResources extends ResourceMap> {
38
38
  denyAll({ force }?: {
39
39
  force?: boolean;
40
40
  }): this;
41
- allow<TActionPath extends WildcardActionPaths<TResources>>(action: TActionPath, predicate?: AnyRulePredicate): this;
42
- allow<TActionPath extends ActionPaths<TResources>>(action: TActionPath, predicate: SimplifyPredicate<RulePredicate<TResources, TActionPath>>): this;
43
- allowOwn<TActionPath extends OwnableActionPaths<TResources>>(action: TActionPath, checkOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>, predicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>): this;
44
- deny<TActionPath extends WildcardActionPaths<TResources>>(action: TActionPath): this;
45
- deny<TActionPath extends ActionPaths<TResources>>(action: TActionPath): this;
46
- denyOwn<TActionPath extends OwnableActionPaths<TResources>>(action: TActionPath, checkOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>, otherPredicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>): this;
41
+ allow<TActionPath extends WildcardActionPaths<TResources>>(action: TActionPath, predicate?: AnyRulePredicate, options?: {
42
+ specitivity?: Specitivity;
43
+ }): this;
44
+ allow<TActionPath extends ActionPaths<TResources>>(action: TActionPath, predicate: SimplifyPredicate<RulePredicate<TResources, TActionPath>>, options?: {
45
+ specitivity?: Specitivity;
46
+ }): this;
47
+ allowOwn<TActionPath extends OwnableActionPaths<TResources>>(action: TActionPath, checkOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>, predicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>, { specitivity }?: {
48
+ specitivity?: Specitivity;
49
+ }): this;
50
+ deny<TActionPath extends WildcardActionPaths<TResources>>(action: TActionPath, options?: {
51
+ specitivity?: Specitivity;
52
+ }): this;
53
+ deny<TActionPath extends ActionPaths<TResources>>(action: TActionPath, options?: {
54
+ specitivity?: Specitivity;
55
+ }): this;
56
+ denyOwn<TActionPath extends OwnableActionPaths<TResources>>(action: TActionPath, checkOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>, otherPredicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>, { specitivity }?: {
57
+ specitivity?: Specitivity;
58
+ }): this;
47
59
  private pushRule;
48
60
  }
49
61
  export {};
package/build/policy.js CHANGED
@@ -37,32 +37,32 @@ export class Policy {
37
37
  this.pushRule("*", ABAC.Filter.deny(), force ? Specitivity.Exact : undefined);
38
38
  return this;
39
39
  }
40
- allow(action, predicate) {
41
- this.pushRule(action, predicate ?? ABAC.Filter.allow());
40
+ allow(action, predicate, { specitivity } = {}) {
41
+ this.pushRule(action, predicate ?? ABAC.Filter.allow(), specitivity);
42
42
  return this;
43
43
  }
44
- allowOwn(action, checkOwnership, predicate) {
45
- this.pushRule(`${action}.own`, ABAC.Filter.allow());
44
+ allowOwn(action, checkOwnership, predicate, { specitivity } = {}) {
45
+ this.pushRule(`${action}.own`, ABAC.Filter.allow(), specitivity);
46
46
  this.pushRule(action, (ctx, action) => {
47
47
  if (!checkOwnership(ctx)) {
48
48
  return false;
49
49
  }
50
50
  return (predicate ?? ABAC.Filter.allow())(ctx, action);
51
- });
51
+ }, specitivity);
52
52
  return this;
53
53
  }
54
- deny(action) {
55
- this.pushRule(action, ABAC.Filter.deny());
54
+ deny(action, { specitivity } = {}) {
55
+ this.pushRule(action, ABAC.Filter.deny(), specitivity);
56
56
  return this;
57
57
  }
58
- denyOwn(action, checkOwnership, otherPredicate) {
59
- this.pushRule(`${action}.own`, ABAC.Filter.deny());
58
+ denyOwn(action, checkOwnership, otherPredicate, { specitivity } = {}) {
59
+ this.pushRule(`${action}.own`, ABAC.Filter.deny(), specitivity);
60
60
  this.pushRule(action, (ctx, action) => {
61
61
  if (checkOwnership(ctx)) {
62
62
  return false;
63
63
  }
64
64
  return (otherPredicate ?? ABAC.Filter.allow())(ctx, action);
65
- });
65
+ }, specitivity);
66
66
  return this;
67
67
  }
68
68
  pushRule(action, predicate, specitivity) {
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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","sourcesContent":["import { ABAC } from \"./abac.js\";\nimport type { Action, RuleCtx, InferActionRuleCtx, ActionContext } from \"./action.js\";\nimport type { ResourceMap } from \"./internal/collections.js\";\nimport type {\n\tActionFromPath,\n\tActionPaths,\n\tOwnableActionPaths,\n\tWildcardActionPaths\n} from \"./internal/paths.js\";\n\nexport type MatchCtx = {\n\tsubject: any;\n};\n\nexport type PolicyMatchPredicate = (ctx: MatchCtx) => boolean;\n\ntype InferRulePredicateReturn<TAction> =\n\tTAction extends Action<any, infer TContext extends ActionContext>\n\t\t? TContext[\"configurable\"] extends true\n\t\t\t? \"ifgranted\" | boolean\n\t\t\t: boolean\n\t\t: boolean;\n\ntype SimplifyPredicate<T> = T extends (ctx: infer TCtx) => infer TReturn\n\t? (ctx: TCtx) => TReturn\n\t: T;\n\nexport type RulePredicate<TResources extends ResourceMap, TActionPath extends string> = (\n\tctx: InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>,\n\taction: ActionFromPath<TResources, TActionPath>\n) => InferRulePredicateReturn<ActionFromPath<TResources, TActionPath>>;\n\ntype AnyRulePredicate = (ctx: RuleCtx, action: Action<any, any>) => boolean | \"ifgranted\";\n\nexport type OwnershipPredicate<TResources extends ResourceMap, TActionPath extends string> = (\n\tctx: InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>\n) => boolean;\n\nexport enum Specitivity {\n\tAny = -1,\n\tActionsAndNested,\n\tActionsOnly,\n\tOwnedActionsOnly,\n\tExact\n}\n\nexport type Rule = {\n\taction: string;\n\tpredicate: AnyRulePredicate;\n\tspecitivity?: Specitivity;\n};\n\nexport class Policy<TResources extends ResourceMap> {\n\tprivate _name: string | null = null;\n\tprivate _match: PolicyMatchPredicate = ABAC.Filter.allow();\n\tprivate _rules: Rule[] = [];\n\n\tconstructor() {}\n\n\tpublic get name() {\n\t\treturn this._name;\n\t}\n\n\tpublic setName(name: string) {\n\t\tthis._name = name;\n\t\treturn this;\n\t}\n\n\tpublic get match() {\n\t\treturn this._match;\n\t}\n\n\tpublic setMatch(predicate: PolicyMatchPredicate) {\n\t\tthis._match = predicate;\n\t\treturn this;\n\t}\n\n\tpublic get rules() {\n\t\treturn this._rules;\n\t}\n\n\tpublic allowAll({ force = false }: { force?: boolean } = {}) {\n\t\tthis.pushRule(\"*\", ABAC.Filter.allow(), force ? Specitivity.Exact : undefined);\n\t\treturn this;\n\t}\n\n\tpublic denyAll({ force = false }: { force?: boolean } = {}) {\n\t\tthis.pushRule(\"*\", ABAC.Filter.deny(), force ? Specitivity.Exact : undefined);\n\t\treturn this;\n\t}\n\n\tpublic allow<TActionPath extends WildcardActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tpredicate?: AnyRulePredicate\n\t): this;\n\tpublic allow<TActionPath extends ActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tpredicate: SimplifyPredicate<RulePredicate<TResources, TActionPath>>\n\t): this;\n\tpublic allow(action: string, predicate?: any) {\n\t\tthis.pushRule(action, predicate ?? ABAC.Filter.allow());\n\t\treturn this;\n\t}\n\n\tpublic allowOwn<TActionPath extends OwnableActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tcheckOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>,\n\t\tpredicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>\n\t) {\n\t\tthis.pushRule(`${action}.own`, ABAC.Filter.allow());\n\t\tthis.pushRule(action, (ctx: any, action: any) => {\n\t\t\tif (!checkOwnership(ctx)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn (predicate ?? ABAC.Filter.allow())(ctx, action);\n\t\t});\n\t\treturn this;\n\t}\n\n\tpublic deny<TActionPath extends WildcardActionPaths<TResources>>(action: TActionPath): this;\n\tpublic deny<TActionPath extends ActionPaths<TResources>>(action: TActionPath): this;\n\tpublic deny(action: string) {\n\t\tthis.pushRule(action, ABAC.Filter.deny());\n\t\treturn this;\n\t}\n\n\tpublic denyOwn<TActionPath extends OwnableActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tcheckOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>,\n\t\totherPredicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>\n\t) {\n\t\tthis.pushRule(`${action}.own`, ABAC.Filter.deny());\n\t\tthis.pushRule(action, (ctx: any, action: any) => {\n\t\t\tif (checkOwnership(ctx)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn (otherPredicate ?? ABAC.Filter.allow())(ctx, action);\n\t\t});\n\t\treturn this;\n\t}\n\n\tprivate pushRule(action: string, predicate: AnyRulePredicate, specitivity?: Specitivity) {\n\t\tthis._rules.push({ action, predicate, specitivity });\n\t}\n}\n"]}
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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","sourcesContent":["import { ABAC } from \"./abac.js\";\nimport type { Action, RuleCtx, InferActionRuleCtx, ActionContext } from \"./action.js\";\nimport type { ResourceMap } from \"./internal/collections.js\";\nimport type {\n\tActionFromPath,\n\tActionPaths,\n\tOwnableActionPaths,\n\tWildcardActionPaths\n} from \"./internal/paths.js\";\n\nexport type MatchCtx = {\n\tsubject: any;\n};\n\nexport type PolicyMatchPredicate = (ctx: MatchCtx) => boolean;\n\ntype InferRulePredicateReturn<TAction> =\n\tTAction extends Action<any, infer TContext extends ActionContext>\n\t\t? \"configurable\" extends TContext[\"tags\"]\n\t\t\t? \"ifgranted\" | boolean\n\t\t\t: boolean\n\t\t: boolean;\n\ntype SimplifyPredicate<T> = T extends (ctx: infer TCtx) => infer TReturn\n\t? (ctx: TCtx) => TReturn\n\t: T;\n\nexport type RulePredicate<TResources extends ResourceMap, TActionPath extends string> = (\n\tctx: InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>,\n\taction: ActionFromPath<TResources, TActionPath>\n) => InferRulePredicateReturn<ActionFromPath<TResources, TActionPath>>;\n\ntype AnyRulePredicate = (ctx: RuleCtx, action: Action<any, any>) => boolean | \"ifgranted\";\n\nexport type OwnershipPredicate<TResources extends ResourceMap, TActionPath extends string> = (\n\tctx: InferActionRuleCtx<ActionFromPath<TResources, TActionPath>>\n) => boolean;\n\nexport enum Specitivity {\n\tAny = -1,\n\tActionsAndNested,\n\tActionsOnly,\n\tOwnedActionsOnly,\n\tExact\n}\n\nexport type Rule = {\n\taction: string;\n\tpredicate: AnyRulePredicate;\n\tspecitivity?: Specitivity;\n};\n\nexport class Policy<TResources extends ResourceMap> {\n\tprivate _name: string | null = null;\n\tprivate _match: PolicyMatchPredicate = ABAC.Filter.allow();\n\tprivate _rules: Rule[] = [];\n\n\tconstructor() {}\n\n\tpublic get name() {\n\t\treturn this._name;\n\t}\n\n\tpublic setName(name: string) {\n\t\tthis._name = name;\n\t\treturn this;\n\t}\n\n\tpublic get match() {\n\t\treturn this._match;\n\t}\n\n\tpublic setMatch(predicate: PolicyMatchPredicate) {\n\t\tthis._match = predicate;\n\t\treturn this;\n\t}\n\n\tpublic get rules() {\n\t\treturn this._rules;\n\t}\n\n\tpublic allowAll({ force = false }: { force?: boolean } = {}) {\n\t\tthis.pushRule(\"*\", ABAC.Filter.allow(), force ? Specitivity.Exact : undefined);\n\t\treturn this;\n\t}\n\n\tpublic denyAll({ force = false }: { force?: boolean } = {}) {\n\t\tthis.pushRule(\"*\", ABAC.Filter.deny(), force ? Specitivity.Exact : undefined);\n\t\treturn this;\n\t}\n\n\tpublic allow<TActionPath extends WildcardActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tpredicate?: AnyRulePredicate,\n\t\toptions?: { specitivity?: Specitivity }\n\t): this;\n\tpublic allow<TActionPath extends ActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tpredicate: SimplifyPredicate<RulePredicate<TResources, TActionPath>>,\n\t\toptions?: { specitivity?: Specitivity }\n\t): this;\n\tpublic allow(\n\t\taction: string,\n\t\tpredicate?: any,\n\t\t{ specitivity }: { specitivity?: Specitivity } = {}\n\t) {\n\t\tthis.pushRule(action, predicate ?? ABAC.Filter.allow(), specitivity);\n\t\treturn this;\n\t}\n\n\tpublic allowOwn<TActionPath extends OwnableActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tcheckOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>,\n\t\tpredicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>,\n\t\t{ specitivity }: { specitivity?: Specitivity } = {}\n\t) {\n\t\tthis.pushRule(`${action}.own`, ABAC.Filter.allow(), specitivity);\n\t\tthis.pushRule(\n\t\t\taction,\n\t\t\t(ctx: any, action: any) => {\n\t\t\t\tif (!checkOwnership(ctx)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn (predicate ?? ABAC.Filter.allow())(ctx, action);\n\t\t\t},\n\t\t\tspecitivity\n\t\t);\n\t\treturn this;\n\t}\n\n\tpublic deny<TActionPath extends WildcardActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\toptions?: { specitivity?: Specitivity }\n\t): this;\n\tpublic deny<TActionPath extends ActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\toptions?: { specitivity?: Specitivity }\n\t): this;\n\tpublic deny(action: string, { specitivity }: { specitivity?: Specitivity } = {}) {\n\t\tthis.pushRule(action, ABAC.Filter.deny(), specitivity);\n\t\treturn this;\n\t}\n\n\tpublic denyOwn<TActionPath extends OwnableActionPaths<TResources>>(\n\t\taction: TActionPath,\n\t\tcheckOwnership: SimplifyPredicate<OwnershipPredicate<TResources, TActionPath>>,\n\t\totherPredicate?: SimplifyPredicate<RulePredicate<TResources, TActionPath>>,\n\t\t{ specitivity }: { specitivity?: Specitivity } = {}\n\t) {\n\t\tthis.pushRule(`${action}.own`, ABAC.Filter.deny(), specitivity);\n\t\tthis.pushRule(\n\t\t\taction,\n\t\t\t(ctx: any, action: any) => {\n\t\t\t\tif (checkOwnership(ctx)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn (otherPredicate ?? ABAC.Filter.allow())(ctx, action);\n\t\t\t},\n\t\t\tspecitivity\n\t\t);\n\t\treturn this;\n\t}\n\n\tprivate pushRule(action: string, predicate: AnyRulePredicate, specitivity?: Specitivity) {\n\t\tthis._rules.push({ action, predicate, specitivity });\n\t}\n}\n"]}
@@ -20,7 +20,6 @@ export declare class Resource<TName extends string, TContext extends ResourceCon
20
20
  private _title;
21
21
  private _description;
22
22
  private _ownable;
23
- private _ownConfigurable;
24
23
  private _actions;
25
24
  private _subResources;
26
25
  constructor(name: TName);
@@ -30,8 +29,7 @@ export declare class Resource<TName extends string, TContext extends ResourceCon
30
29
  get description(): string | null;
31
30
  setDescription(description: string): this;
32
31
  get ownable(): boolean;
33
- get ownConfigurable(): boolean;
34
- setOwnable<TOwnable extends boolean>(ownable: TOwnable, configurable?: boolean): Resource<TName, {
32
+ setOwnable<TOwnable extends boolean>(ownable: TOwnable): Resource<TName, {
35
33
  ctx: TContext["ctx"];
36
34
  actions: TContext["actions"];
37
35
  subResources: TContext["subResources"];
@@ -54,7 +52,7 @@ export declare class Resource<TName extends string, TContext extends ResourceCon
54
52
  ownable: TContext["ownable"];
55
53
  }>;
56
54
  withAdditionalContext<TAdditionalContext extends object>(): Resource<TName, {
57
- ctx: TContext["ctx"] & TAdditionalContext;
55
+ ctx: Expand<TContext["ctx"] & TAdditionalContext>;
58
56
  actions: TContext["actions"];
59
57
  subResources: TContext["subResources"];
60
58
  ownable: TContext["ownable"];
package/build/resource.js CHANGED
@@ -4,7 +4,6 @@ export class Resource {
4
4
  _title = null;
5
5
  _description = null;
6
6
  _ownable = false;
7
- _ownConfigurable = false;
8
7
  _actions = {};
9
8
  _subResources = {};
10
9
  constructor(name) {
@@ -30,12 +29,8 @@ export class Resource {
30
29
  get ownable() {
31
30
  return this._ownable;
32
31
  }
33
- get ownConfigurable() {
34
- return this._ownConfigurable;
35
- }
36
- setOwnable(ownable, configurable = true) {
32
+ setOwnable(ownable) {
37
33
  this._ownable = ownable;
38
- this._ownConfigurable = configurable;
39
34
  return this;
40
35
  }
41
36
  withSubject() {
@@ -1 +1 @@
1
- {"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,MAAM,aAAa,CAAC;AAyBxD,MAAM,OAAO,QAAQ;IAGZ,KAAK,CAAQ;IACb,MAAM,GAAkB,IAAI,CAAC;IAC7B,YAAY,GAAkB,IAAI,CAAC;IACnC,QAAQ,GAAwB,KAAK,CAAC;IACtC,gBAAgB,GAAY,KAAK,CAAC;IAClC,QAAQ,GAAwB,EAAyB,CAAC;IAC1D,aAAa,GAA6B,EAA8B,CAAC;IAEjF,YAAY,IAAW;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,IAAW,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,WAAW;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAEM,cAAc,CAAC,WAAmB;QACxC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,OAAO;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED,IAAW,eAAe;QACzB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC9B,CAAC;IAEM,UAAU,CAA2B,OAAiB,EAAE,YAAY,GAAG,IAAI;QACjF,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC;QACrC,OAAO,IAQN,CAAC;IACH,CAAC;IAEM,WAAW;QACjB,OAAO,IAYN,CAAC;IACH,CAAC;IAEM,UAAU;QAChB,OAAO,IAYN,CAAC;IACH,CAAC;IAEM,qBAAqB;QAC3B,OAAO,IAQN,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,UAAU,CAChB,OAAmB;QAEnB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAC7B,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACjB,GAAG,GAAG;YACN,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM;SACrB,CAAC,EACF,EAAE,CACF,CAAC;QACF,OAAO,IAQN,CAAC;IACH,CAAC;IAED,IAAI,YAAY;QACf,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAEM,eAAe,CAAwC,SAAuB;QACpF,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC,MAAM,CACpC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACnB,GAAG,GAAG;YACN,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ;SACzB,CAAC,EACF,EAAE,CACF,CAAC;QACF,OAAO,IAQN,CAAC;IACH,CAAC;CACD","sourcesContent":["import { type Action, type RuleCtx } from \"./action.js\";\nimport type { ActionGroup } from \"./actionGroup.js\";\nimport type {\n\tActionMap,\n\tResourceMap,\n\tToActionMap,\n\tUnionToResourceMap\n} from \"./internal/collections.js\";\nimport type { Expand, UnsetMarker } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\n\nexport type ResourceContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap | UnsetMarker;\n\tsubResources: ResourceMap | UnsetMarker;\n\townable: boolean;\n};\n\nexport type AnyResourceContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap;\n\tsubResources: ResourceMap;\n\townable: boolean;\n};\n\nexport class Resource<TName extends string, TContext extends ResourceContext = AnyResourceContext>\n\timplements IMeta\n{\n\tprivate _name: TName;\n\tprivate _title: string | null = null;\n\tprivate _description: string | null = null;\n\tprivate _ownable: TContext[\"ownable\"] = false;\n\tprivate _ownConfigurable: boolean = false;\n\tprivate _actions: TContext[\"actions\"] = {} as TContext[\"actions\"];\n\tprivate _subResources: TContext[\"subResources\"] = {} as TContext[\"subResources\"];\n\n\tconstructor(name: TName) {\n\t\tthis._name = name;\n\t}\n\n\tpublic get name(): TName {\n\t\treturn this._name;\n\t}\n\n\tpublic get title(): string | null {\n\t\treturn this._title;\n\t}\n\n\tpublic setTitle(title: string) {\n\t\tthis._title = title;\n\t\treturn this;\n\t}\n\n\tpublic get description(): string | null {\n\t\treturn this._description;\n\t}\n\n\tpublic setDescription(description: string) {\n\t\tthis._description = description;\n\t\treturn this;\n\t}\n\n\tpublic get ownable(): boolean {\n\t\treturn this._ownable;\n\t}\n\n\tpublic get ownConfigurable(): boolean {\n\t\treturn this._ownConfigurable;\n\t}\n\n\tpublic setOwnable<TOwnable extends boolean>(ownable: TOwnable, configurable = true) {\n\t\tthis._ownable = ownable;\n\t\tthis._ownConfigurable = configurable;\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TOwnable;\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withSubject<TSubject>() {\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"subject\"> & {\n\t\t\t\t\t\tsubject: TSubject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withObject<TObject>() {\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"object\"> & {\n\t\t\t\t\t\tobject: TObject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withAdditionalContext<TAdditionalContext extends object>() {\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"] & TAdditionalContext;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tget actions(): TContext[\"actions\"] {\n\t\treturn this._actions;\n\t}\n\n\tpublic setActions<TActions extends Action<any, any> | ActionGroup<any, any>>(\n\t\tactions: TActions[]\n\t) {\n\t\tthis._actions = actions.reduce(\n\t\t\t(acc, action) => ({\n\t\t\t\t...acc,\n\t\t\t\t[action.name]: action\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: Expand<ToActionMap<TActions>>;\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tget subResources(): TContext[\"subResources\"] {\n\t\treturn this._subResources;\n\t}\n\n\tpublic setSubResources<TResources extends Resource<any, any>>(resources: TResources[]) {\n\t\tthis._subResources = resources.reduce(\n\t\t\t(acc, resource) => ({\n\t\t\t\t...acc,\n\t\t\t\t[resource.name]: resource\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: Expand<UnionToResourceMap<TResources>>;\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n}\n"]}
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,MAAM,aAAa,CAAC;AAyBxD,MAAM,OAAO,QAAQ;IAGZ,KAAK,CAAQ;IACb,MAAM,GAAkB,IAAI,CAAC;IAC7B,YAAY,GAAkB,IAAI,CAAC;IACnC,QAAQ,GAAwB,KAAK,CAAC;IACtC,QAAQ,GAAwB,EAAyB,CAAC;IAC1D,aAAa,GAA6B,EAA8B,CAAC;IAEjF,YAAY,IAAW;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,IAAW,IAAI;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,IAAW,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAEM,QAAQ,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,WAAW;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAEM,cAAc,CAAC,WAAmB;QACxC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAW,OAAO;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,UAAU,CAA2B,OAAiB;QAC5D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,OAAO,IAQN,CAAC;IACH,CAAC;IAEM,WAAW;QACjB,OAAO,IAYN,CAAC;IACH,CAAC;IAEM,UAAU;QAChB,OAAO,IAYN,CAAC;IACH,CAAC;IAEM,qBAAqB;QAC3B,OAAO,IAQN,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAEM,UAAU,CAChB,OAAmB;QAEnB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAC7B,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACjB,GAAG,GAAG;YACN,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM;SACrB,CAAC,EACF,EAAE,CACF,CAAC;QACF,OAAO,IAQN,CAAC;IACH,CAAC;IAED,IAAI,YAAY;QACf,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAEM,eAAe,CAAwC,SAAuB;QACpF,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC,MAAM,CACpC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACnB,GAAG,GAAG;YACN,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ;SACzB,CAAC,EACF,EAAE,CACF,CAAC;QACF,OAAO,IAQN,CAAC;IACH,CAAC;CACD","sourcesContent":["import { type Action, type RuleCtx } from \"./action.js\";\nimport type { ActionGroup } from \"./actionGroup.js\";\nimport type {\n\tActionMap,\n\tResourceMap,\n\tToActionMap,\n\tUnionToResourceMap\n} from \"./internal/collections.js\";\nimport type { Expand, UnsetMarker } from \"./internal/core.js\";\nimport type { IMeta } from \"./internal/meta.js\";\n\nexport type ResourceContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap | UnsetMarker;\n\tsubResources: ResourceMap | UnsetMarker;\n\townable: boolean;\n};\n\nexport type AnyResourceContext = {\n\tctx: RuleCtx;\n\tactions: ActionMap;\n\tsubResources: ResourceMap;\n\townable: boolean;\n};\n\nexport class Resource<TName extends string, TContext extends ResourceContext = AnyResourceContext>\n\timplements IMeta\n{\n\tprivate _name: TName;\n\tprivate _title: string | null = null;\n\tprivate _description: string | null = null;\n\tprivate _ownable: TContext[\"ownable\"] = false;\n\tprivate _actions: TContext[\"actions\"] = {} as TContext[\"actions\"];\n\tprivate _subResources: TContext[\"subResources\"] = {} as TContext[\"subResources\"];\n\n\tconstructor(name: TName) {\n\t\tthis._name = name;\n\t}\n\n\tpublic get name(): TName {\n\t\treturn this._name;\n\t}\n\n\tpublic get title(): string | null {\n\t\treturn this._title;\n\t}\n\n\tpublic setTitle(title: string) {\n\t\tthis._title = title;\n\t\treturn this;\n\t}\n\n\tpublic get description(): string | null {\n\t\treturn this._description;\n\t}\n\n\tpublic setDescription(description: string) {\n\t\tthis._description = description;\n\t\treturn this;\n\t}\n\n\tpublic get ownable(): boolean {\n\t\treturn this._ownable;\n\t}\n\n\tpublic setOwnable<TOwnable extends boolean>(ownable: TOwnable) {\n\t\tthis._ownable = ownable;\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TOwnable;\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withSubject<TSubject>() {\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"subject\"> & {\n\t\t\t\t\t\tsubject: TSubject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withObject<TObject>() {\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<\n\t\t\t\t\tOmit<TContext[\"ctx\"], \"object\"> & {\n\t\t\t\t\t\tobject: TObject;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tpublic withAdditionalContext<TAdditionalContext extends object>() {\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: Expand<TContext[\"ctx\"] & TAdditionalContext>;\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tget actions(): TContext[\"actions\"] {\n\t\treturn this._actions;\n\t}\n\n\tpublic setActions<TActions extends Action<any, any> | ActionGroup<any, any>>(\n\t\tactions: TActions[]\n\t) {\n\t\tthis._actions = actions.reduce(\n\t\t\t(acc, action) => ({\n\t\t\t\t...acc,\n\t\t\t\t[action.name]: action\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: Expand<ToActionMap<TActions>>;\n\t\t\t\tsubResources: TContext[\"subResources\"];\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n\n\tget subResources(): TContext[\"subResources\"] {\n\t\treturn this._subResources;\n\t}\n\n\tpublic setSubResources<TResources extends Resource<any, any>>(resources: TResources[]) {\n\t\tthis._subResources = resources.reduce(\n\t\t\t(acc, resource) => ({\n\t\t\t\t...acc,\n\t\t\t\t[resource.name]: resource\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\t\treturn this as unknown as Resource<\n\t\t\tTName,\n\t\t\t{\n\t\t\t\tctx: TContext[\"ctx\"];\n\t\t\t\tactions: TContext[\"actions\"];\n\t\t\t\tsubResources: Expand<UnionToResourceMap<TResources>>;\n\t\t\t\townable: TContext[\"ownable\"];\n\t\t\t}\n\t\t>;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@l3dev/abac",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Type-safe attribute-based access control library",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",