@zap-studio/permit 0.3.3 → 1.0.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.
@@ -4,15 +4,30 @@ import { StandardSchemaV1 } from "@zap-studio/validation";
4
4
  * Represents the possible outcomes of a policy decision.
5
5
  * - "allow": The action is permitted.
6
6
  * - "deny": The action is not permitted.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const decision: Decision = "allow";
11
+ * ```
7
12
  */
8
13
  type Decision = "allow" | "deny";
9
14
  /**
10
15
  * Represents the context in which a policy decision is made.
11
16
  * Can include user information, environment, or any relevant data.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * type AppContext = Context<{ user: { id: string; role: string } }>;
21
+ * ```
12
22
  */
13
23
  type Context<TContext = unknown> = TContext;
14
24
  /**
15
25
  * Represents a role within the system.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * type AppRole = Role<"guest" | "user" | "admin">;
30
+ * ```
16
31
  */
17
32
  type Role<TRole extends string = string> = TRole;
18
33
  /**
@@ -64,12 +79,23 @@ type Resources<TResourceKey extends string = string> = Record<TResourceKey, Stan
64
79
  type Actions<TResources extends Resources> = { [K in keyof TResources]: readonly string[]; };
65
80
  /**
66
81
  * Infers the output type from a Standard Schema.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * type Post = InferResource<typeof resources, "post">;
86
+ * ```
67
87
  */
68
88
  type InferResource<TResources extends Resources, TResourceKey extends keyof TResources> = StandardSchemaV1.InferOutput<TResources[TResourceKey]>;
69
89
  /**
70
90
  * Infers the action union type for a specific resource.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * type PostAction = InferAction<typeof resources, typeof actions, "post">;
95
+ * // "read" | "write" | "delete"
96
+ * ```
71
97
  */
72
- type InferAction<TActions extends Record<string, readonly string[]>, K extends keyof TActions> = TActions[K][number];
98
+ type InferAction<TResources extends Resources, TActions extends Actions<TResources>, K extends keyof TActions> = TActions[K][number];
73
99
  /**
74
100
  * Infers the permission-string union for all resource/action combinations.
75
101
  *
@@ -79,24 +105,76 @@ type InferAction<TActions extends Record<string, readonly string[]>, K extends k
79
105
  * // "post:read" | "post:write" | "comment:read"
80
106
  * ```
81
107
  */
82
- type InferPermission<TResources extends Resources, TActions extends Actions<TResources>> = { [K in keyof TResources & keyof TActions]: `${K & string}:${InferAction<TActions, K> & string}`; }[keyof TResources & keyof TActions];
108
+ type InferPermission<TResources extends Resources, TActions extends Actions<TResources>> = { [K in keyof TResources & keyof TActions]: `${K & string}:${InferAction<TResources, TActions, K> & string}`; }[keyof TResources & keyof TActions];
83
109
  /**
84
110
  * A function that determines whether a given action on a resource is allowed in a specific context.
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * const readPolicy: PolicyFn<AppContext, "read", Post> = (context, action, post) =>
115
+ * post.visibility === "public" ? "allow" : "deny";
116
+ * ```
85
117
  */
86
118
  type PolicyFn<TContext extends Context, TAction extends string = string, TResource = unknown> = (context: TContext, action: TAction, resource: TResource) => Decision;
87
119
  /**
88
120
  * A function that evaluates a condition for a given action and resource in a specific context.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * const isOwner: ConditionFn<AppContext, "write", Post> = (context, action, post) =>
125
+ * context.user.id === post.authorId;
126
+ * ```
89
127
  */
90
128
  type ConditionFn<TContext extends Context, TAction extends string = string, TResource = unknown> = (context: TContext, action: TAction, resource: TResource) => boolean;
129
+ /**
130
+ * Call signatures for {@link hasRole}, preserving the with/without hierarchy overloads.
131
+ */
132
+ interface HasRoleFn {
133
+ <TContext extends {
134
+ role: Role | Role[];
135
+ }, TAction extends string = string, TResource = unknown>(role: Role): ConditionFn<TContext, TAction, TResource>;
136
+ <TContext extends {
137
+ role: TRole | TRole[];
138
+ }, TAction extends string = string, TResource = unknown, TRole extends Role = Role>(role: TRole, hierarchy: RoleHierarchy<TRole>): ConditionFn<TContext, TAction, TResource>;
139
+ }
91
140
  /**
92
141
  * Maps actions to their corresponding policy functions for a specific resource.
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * import type { ActionPolicyMap } from "@zap-studio/permit/types";
146
+ *
147
+ * type PostActions = "read" | "write" | "delete";
148
+ *
149
+ * const postPolicies: ActionPolicyMap<AppContext, PostActions, Post> = {
150
+ * read: (context, action, post) => "allow",
151
+ * write: (context, action, post) =>
152
+ * post.authorId === context.userId ? "allow" : "deny",
153
+ * };
154
+ * ```
93
155
  */
94
156
  type ActionPolicyMap<TContext extends Context, TAction extends string = string, TResource = unknown> = { [A in TAction]?: PolicyFn<TContext, A, TResource>; };
95
157
  /**
96
158
  * Defines the rules for each resource and action combination.
97
159
  * Each resource key maps to an object where each action key maps to a policy function.
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * import type { Rules } from "@zap-studio/permit/types";
164
+ *
165
+ * const rules: Rules<AppContext, typeof resources, typeof actions> = {
166
+ * post: {
167
+ * read: (context, action, post) => "allow",
168
+ * write: (context, action, post) =>
169
+ * post.authorId === context.userId ? "allow" : "deny",
170
+ * },
171
+ * comment: {
172
+ * read: (context, action, comment) => "allow",
173
+ * },
174
+ * };
175
+ * ```
98
176
  */
99
- type Rules<TContext extends Context, TResources extends Resources = Resources, TActions extends Actions<TResources> = Actions<TResources>> = { [K in keyof TResources & keyof TActions]: ActionPolicyMap<TContext, InferAction<TActions, K>, InferResource<TResources, K>>; };
177
+ type Rules<TContext extends Context, TResources extends Resources = Resources, TActions extends Actions<TResources> = Actions<TResources>> = { [K in keyof TResources & keyof TActions]: ActionPolicyMap<TContext, InferAction<TResources, TActions, K>, InferResource<TResources, K>>; };
100
178
  /**
101
179
  * Configuration object for creating a permit policy.
102
180
  *
@@ -135,8 +213,8 @@ interface Policy<TContext extends Context, TResources extends Resources = Resour
135
213
  /**
136
214
  * Determines if the specified action is permitted on the resource in the given context.
137
215
  */
138
- can: <K extends keyof TResources & keyof TActions>(context: TContext, permission: `${K & string}:${InferAction<TActions, K> & string}`, resource: InferResource<TResources, K>) => Promise<boolean>;
216
+ can: <K extends keyof TResources & keyof TActions>(context: TContext, permission: `${K & string}:${InferAction<TResources, TActions, K> & string}`, resource: InferResource<TResources, K>) => Promise<boolean>;
139
217
  }
140
218
  //#endregion
141
- export { ActionPolicyMap, Actions, ConditionFn, Context, Decision, InferAction, InferPermission, InferResource, PermitConfig, Policy, PolicyFn, Resources, Role, RoleHierarchy, Rules };
142
- //# sourceMappingURL=types.d.mts.map
219
+ export { ActionPolicyMap, Actions, ConditionFn, Context, Decision, HasRoleFn, InferAction, InferPermission, InferResource, PermitConfig, Policy, PolicyFn, Resources, Role, RoleHierarchy, Rules };
220
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;;KAkBY;;;;;;;;;;KAWA,QAAQ,sBAAsB;;;;;;;;;KAU9B,KAAK,iCAAiC;;;;;;;;;;;;;;;;KAiBtC,cAAc,cAAc,OAAO,QAAQ,OAAO,OAAO;;;;;;;;;;;;;;;;KAiBzD,UAAU,wCAAwC,OAC5D,cACA;;;;;;;;;;;;;;;KAiBU,QAAQ,mBAAmB,gBACpC,WAAW;;;;;;;;;KAWF,cACV,mBAAmB,WACnB,2BAA2B,cACzB,iBAAiB,YAAY,WAAW;;;;;;;;;;KAWhC,YACV,mBAAmB,WACnB,iBAAiB,QAAQ,aACzB,gBAAgB,YACd,SAAS;;;;;;;;;;KAWD,gBACV,mBAAmB,WACnB,iBAAiB,QAAQ,kBAGvB,WAAW,mBAAmB,cAC1B,cAAc,YAAY,YAAY,UAAU,uBAChD,mBAAmB;;;;;;;;;;KAWf,SACV,iBAAiB,SACjB,iCACA,wBACG,SAAS,UAAU,QAAQ,SAAS,UAAU,cAAc;;;;;;;;;;KAWrD,YACV,iBAAiB,SACjB,iCACA,wBACG,SAAS,UAAU,QAAQ,SAAS,UAAU;;;;UAKlC;GAEb;IAAmB,MAAM,OAAO;KAChC,iCACA,qBAEA,MAAM,OACL,YAAY,UAAU,SAAS;GAEhC;IAAmB,MAAM,QAAQ;KACjC,iCACA,qBACA,cAAc,OAAO,MAErB,MAAM,OACN,WAAW,cAAc,SACxB,YAAY,UAAU,SAAS;;;;;;;;;;;;;;;;;;KAmBxB,gBACV,iBAAiB,SACjB,iCACA,0BAEC,KAAK,WAAW,SAAS,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;KAuB7B,MACV,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ,kBAE9C,WAAW,mBAAmB,WAAW,gBACxC,UACA,YAAY,YAAY,UAAU,IAClC,cAAc,YAAY;;;;;;;;;;;;;;;UAkBb,aACf,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ;EAE/C,SAAS;EACT,WAAW;EACX,OAAO,MAAM,UAAU,YAAY;;;;;;;;;;;;;;;;;UAkBpB,OACf,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ;;;;EAK/C,MAAM,gBAAgB,mBAAmB,UACvC,SAAS,UACT,eAAe,cAAc,YAAY,YAAY,UAAU,eAC/D,UAAU,cAAc,YAAY,OACjC"}
package/dist/types.js ADDED
File without changes
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@zap-studio/permit",
3
- "version": "0.3.3",
3
+ "version": "1.0.0",
4
4
  "private": false,
5
- "description": "A type-safe, declarative authorization library for TypeScript with Standard Schema support",
5
+ "description": "A type-safe, declarative, tree-shakeable authorization library for TypeScript with Standard Schema support",
6
6
  "keywords": [
7
7
  "abac",
8
8
  "access-control",
@@ -31,30 +31,28 @@
31
31
  ],
32
32
  "type": "module",
33
33
  "sideEffects": false,
34
- "types": "./dist/index.d.mts",
34
+ "types": "./dist/index.d.ts",
35
35
  "exports": {
36
- ".": "./dist/index.mjs",
37
- "./errors": "./dist/errors.mjs",
38
- "./helpers": "./dist/helpers.mjs",
39
- "./types": "./dist/types.mjs",
36
+ ".": "./dist/index.js",
37
+ "./conditions": "./dist/conditions.js",
38
+ "./errors": "./dist/errors.js",
39
+ "./policy": "./dist/policy.js",
40
+ "./types": "./dist/types.js",
40
41
  "./package.json": "./package.json"
41
42
  },
42
43
  "publishConfig": {
43
44
  "access": "public"
44
45
  },
45
46
  "dependencies": {
46
- "@zap-studio/validation": "0.3.5"
47
+ "@zap-studio/validation": "1.0.0"
47
48
  },
48
49
  "devDependencies": {
49
- "tsdown": "^0.22.4",
50
+ "tsdown": "^0.22.14",
50
51
  "typescript": "^7.0.2",
51
52
  "vitest": "^4.1.10",
52
53
  "@zap-studio/typescript": "0.0.0"
53
54
  },
54
55
  "engines": {
55
56
  "node": ">=18.0.0"
56
- },
57
- "scripts": {
58
- "build": "tsdown --config ./tsdown.config.ts"
59
57
  }
60
58
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.d.mts","names":[],"sources":["../src/errors.ts"],"mappings":";;;;;;;;;;cAUa,oBAAoB;;;;;;EAM/B,YAAY"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Error primitives for policy evaluation and configuration failures.\n *\n * @module @zap-studio/permit/errors\n */\n\n/**\n * Represents an error that occurs during policy evaluation or enforcement.\n * Use this error to indicate issues related to policy logic, configuration, or execution.\n */\nexport class PolicyError extends Error {\n /**\n * Creates a policy error with a human-readable message.\n *\n * @param message - Error message describing the policy failure.\n */\n constructor(message: string) {\n super(message);\n this.name = \"PolicyError\";\n }\n}\n"],"mappings":";;;;;;;;;;AAUA,IAAa,cAAb,cAAiC,MAAM;;;;;;CAMrC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF"}
@@ -1,32 +0,0 @@
1
- //#region src/helpers.d.ts
2
- /**
3
- * Helper utilities for permit consumers.
4
- *
5
- * @module @zap-studio/permit/helpers
6
- */
7
- /**
8
- * Ensures that a value of type `never` is actually never encountered at runtime.
9
- * This is useful for exhaustive checks on discriminated unions.
10
- *
11
- * @example
12
- * ```ts
13
- * type Action = 'read' | 'write'
14
- *
15
- * function performAction(action: Action) {
16
- * switch (action) {
17
- * case 'read':
18
- * console.log('Reading...')
19
- * break
20
- * case 'write':
21
- * console.log('Writing...')
22
- * break
23
- * default:
24
- * assertNever(action) // TypeScript will error if a new Action is added but not handled
25
- * }
26
- * }
27
- * ```
28
- */
29
- declare const assertNever: (value: never) => never;
30
- //#endregion
31
- export { assertNever };
32
- //# sourceMappingURL=helpers.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"helpers.d.mts","names":[],"sources":["../src/helpers.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4Ba,cAAe"}
package/dist/helpers.mjs DELETED
@@ -1,35 +0,0 @@
1
- //#region src/helpers.ts
2
- /**
3
- * Helper utilities for permit consumers.
4
- *
5
- * @module @zap-studio/permit/helpers
6
- */
7
- /**
8
- * Ensures that a value of type `never` is actually never encountered at runtime.
9
- * This is useful for exhaustive checks on discriminated unions.
10
- *
11
- * @example
12
- * ```ts
13
- * type Action = 'read' | 'write'
14
- *
15
- * function performAction(action: Action) {
16
- * switch (action) {
17
- * case 'read':
18
- * console.log('Reading...')
19
- * break
20
- * case 'write':
21
- * console.log('Writing...')
22
- * break
23
- * default:
24
- * assertNever(action) // TypeScript will error if a new Action is added but not handled
25
- * }
26
- * }
27
- * ```
28
- */
29
- const assertNever = (value) => {
30
- throw new Error(`Unexpected value: ${String(value)}`);
31
- };
32
- //#endregion
33
- export { assertNever };
34
-
35
- //# sourceMappingURL=helpers.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"helpers.mjs","names":[],"sources":["../src/helpers.ts"],"sourcesContent":["/**\n * Helper utilities for permit consumers.\n *\n * @module @zap-studio/permit/helpers\n */\n\n/**\n * Ensures that a value of type `never` is actually never encountered at runtime.\n * This is useful for exhaustive checks on discriminated unions.\n *\n * @example\n * ```ts\n * type Action = 'read' | 'write'\n *\n * function performAction(action: Action) {\n * switch (action) {\n * case 'read':\n * console.log('Reading...')\n * break\n * case 'write':\n * console.log('Writing...')\n * break\n * default:\n * assertNever(action) // TypeScript will error if a new Action is added but not handled\n * }\n * }\n * ```\n */\nexport const assertNever = (value: never): never => {\n throw new Error(`Unexpected value: ${String(value)}`);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAa,eAAe,UAAwB;CAClD,MAAM,IAAI,MAAM,qBAAqB,OAAO,KAAK,GAAG;AACtD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;cAwCa,QAET,iBAAiB,SACjB,iCACA,0BACG,SAAS,UAAU,SAAS;;;;;;;;;;;;;;;;;cAoBtB,OAET,iBAAiB,SACjB,iCACA,0BACG,SAAS,UAAU,SAAS;;;;;;;;;;;;;;;;;cAoBtB,OAET,iBAAiB,SACjB,iCACA,qBAEA,WAAW,YAAY,UAAU,SAAS,eACzC,SAAS,UAAU,SAAS;;;;;;;;;;;;;;;;;;cAqBpB,MAET,iBAAiB,SACjB,iCACA,wBAEG,YAAY,YAAY,UAAU,SAAS,iBAC7C,YAAY,UAAU,SAAS;;;;;;;;;;;;;;;;;;cAqBvB,KAET,iBAAiB,SACjB,iCACA,wBAEG,YAAY,YAAY,UAAU,SAAS,iBAC7C,YAAY,UAAU,SAAS;;;;;;;;;;;;;;;cAkBvB,MAET,iBAAiB,SACjB,iCACA,qBAEA,WAAW,YAAY,UAAU,SAAS,eACzC,YAAY,UAAU,SAAS;;;;;;;;;;;;;cAgBvB,MACV,iBAAiB,SAAS,gBAAgB,UACzC,KAAK,GACL,OAAO,SAAS,OACf,YAAY;;;;;;;;;;;;;;;;;;cAqBJ,wBAAyB,cAAc,OAAO,MACzD,OAAO,SACP,WAAW,cAAc,WACxB,IAAI;;;;UAwBG;GAEN;IAAmB,MAAM,OAAO;KAChC,iCACA,qBAEA,MAAM,OACL,YAAY,UAAU,SAAS;GAEhC;IAAmB,MAAM,QAAQ;KACjC,iCACA,qBACA,cAAc,OAAO,MAErB,MAAM,OACN,WAAW,cAAc,SACxB,YAAY,UAAU,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8BvB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAsGT,eACX,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ,aAE/C,QAAQ,aAAa,UAAU,YAAY,cAC1C,OAAO,UAAU,YAAY;;;;;;;;;;;;;;cA2InB,gBACX,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ,gBAE5C,UAAU,OAAO,UAAU,YAAY,gBACzC,OAAO,UAAU,YAAY;;;;;;;;;;;;;;cAgBnB,mBACX,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ,gBAE5C,UAAU,OAAO,UAAU,YAAY,gBACzC,OAAO,UAAU,YAAY"}
package/dist/index.mjs DELETED
@@ -1,328 +0,0 @@
1
- import { PolicyError } from "./errors.mjs";
2
- import { createStandardValidator } from "@zap-studio/validation";
3
- //#region src/index.ts
4
- /**
5
- * Returns a policy function that always allows the action.
6
- *
7
- * @example
8
- * ```ts
9
- * const policy = createPolicy({
10
- * resources,
11
- * actions,
12
- * rules: {
13
- * post: {
14
- * read: allow(), // Always allow reading posts
15
- * },
16
- * },
17
- * });
18
- * ```
19
- */
20
- const allow = () => () => "allow";
21
- /**
22
- * Returns a policy function that always denies the action.
23
- *
24
- * @example
25
- * ```ts
26
- * const policy = createPolicy({
27
- * resources,
28
- * actions,
29
- * rules: {
30
- * post: {
31
- * delete: deny(), // Never allow deleting posts
32
- * },
33
- * },
34
- * });
35
- * ```
36
- */
37
- const deny = () => () => "deny";
38
- /**
39
- * Returns a policy function that allows or denies based on a condition.
40
- *
41
- * @example
42
- * ```ts
43
- * const policy = createPolicy({
44
- * resources,
45
- * actions,
46
- * rules: {
47
- * post: {
48
- * write: when((ctx, action, resource) => ctx.user.id === resource.authorId),
49
- * },
50
- * },
51
- * });
52
- * ```
53
- */
54
- const when = (condition) => (context, action, resource) => condition(context, action, resource) ? "allow" : "deny";
55
- /**
56
- * Returns a condition function that returns `true` if all conditions are met.
57
- *
58
- * @example
59
- * ```ts
60
- * const isOwnerAndPublished = and(
61
- * (ctx, action, resource) => ctx.user.id === resource.authorId,
62
- * (ctx, action, resource) => resource.status === "published"
63
- * );
64
- *
65
- * rules: {
66
- * post: {
67
- * delete: when(isOwnerAndPublished),
68
- * },
69
- * }
70
- * ```
71
- */
72
- const and = (...conditions) => (context, action, resource) => conditions.every((condition) => condition(context, action, resource));
73
- /**
74
- * Returns a condition function that returns `true` if any condition is met.
75
- *
76
- * @example
77
- * ```ts
78
- * const isOwnerOrAdmin = or(
79
- * (ctx, action, resource) => ctx.user.id === resource.authorId,
80
- * (ctx, action, resource) => ctx.user.role === "admin"
81
- * );
82
- *
83
- * rules: {
84
- * post: {
85
- * write: when(isOwnerOrAdmin),
86
- * },
87
- * }
88
- * ```
89
- */
90
- const or = (...conditions) => (context, action, resource) => conditions.some((condition) => condition(context, action, resource));
91
- /**
92
- * Returns a condition function that negates another condition.
93
- *
94
- * @example
95
- * ```ts
96
- * const isNotOwner = not((ctx, action, resource) => ctx.user.id === resource.authorId);
97
- *
98
- * rules: {
99
- * post: {
100
- * like: when(isNotOwner), // Can only like posts you don't own
101
- * },
102
- * }
103
- * ```
104
- */
105
- const not = (condition) => (context, action, resource) => !condition(context, action, resource);
106
- /**
107
- * Returns a condition function that checks if a context property equals a value.
108
- *
109
- * @example
110
- * ```ts
111
- * rules: {
112
- * post: {
113
- * write: when(has("role", "admin")), // Only admins can write
114
- * },
115
- * }
116
- * ```
117
- */
118
- const has = (key, value) => (context) => context[key] === value;
119
- /**
120
- * Collects all roles including inherited ones from a role hierarchy.
121
- *
122
- * @example
123
- * ```ts
124
- * type Role = "guest" | "user" | "admin";
125
- *
126
- * const hierarchy: RoleHierarchy<Role> = {
127
- * guest: [],
128
- * user: ["guest"],
129
- * admin: ["user"],
130
- * };
131
- *
132
- * collectInheritedRoles(["admin"], hierarchy);
133
- * // Returns: Set { "admin", "user", "guest" }
134
- * ```
135
- */
136
- const collectInheritedRoles = (roles, hierarchy) => {
137
- const inherited = /* @__PURE__ */ new Set();
138
- const add = (role) => {
139
- if (inherited.has(role)) return;
140
- inherited.add(role);
141
- const parents = hierarchy[role] ?? [];
142
- for (const parent of parents) add(parent);
143
- };
144
- for (const role of roles) add(role);
145
- return inherited;
146
- };
147
- /**
148
- * Returns a condition function that checks if the user has a specific role.
149
- * Supports role hierarchy for inherited permissions.
150
- *
151
- * @example
152
- * ```ts
153
- * // Without hierarchy
154
- * rules: {
155
- * post: {
156
- * delete: when(hasRole("admin")),
157
- * },
158
- * }
159
- *
160
- * // With hierarchy
161
- * const hierarchy = {
162
- * guest: [],
163
- * user: ["guest"],
164
- * admin: ["user"],
165
- * };
166
- *
167
- * rules: {
168
- * post: {
169
- * read: when(hasRole("guest", hierarchy)), // Admins and users can also read
170
- * },
171
- * }
172
- * ```
173
- */
174
- const hasRole = (role, hierarchy) => (context) => {
175
- const userRoles = Array.isArray(context.role) ? context.role : [context.role];
176
- if (hierarchy === void 0) return userRoles.includes(role);
177
- return collectInheritedRoles(userRoles, hierarchy).has(role);
178
- };
179
- /**
180
- * Splits a typed `resource:action` permission string into its parts.
181
- * Returns `null` when the string is malformed (missing/empty part or extra segments).
182
- */
183
- const parsePermission = (permission) => {
184
- const [resourceTypeValue, actionValue, ...rest] = permission.split(":");
185
- if (resourceTypeValue === void 0 || resourceTypeValue.length === 0 || actionValue === void 0 || actionValue.length === 0 || rest.length > 0) return null;
186
- return {
187
- action: actionValue,
188
- resourceType: resourceTypeValue
189
- };
190
- };
191
- /**
192
- * Creates a type-safe policy from resource schemas, actions, and rules.
193
- *
194
- * @example
195
- * ```ts
196
- * import { z } from "zod";
197
- * import { createPolicy, allow, deny, when } from "@zap-studio/permit";
198
- * import type { Resources, Actions } from "@zap-studio/permit/types";
199
- *
200
- * // Define resource schemas
201
- * const resources = {
202
- * post: z.object({
203
- * id: z.string(),
204
- * authorId: z.string(),
205
- * visibility: z.enum(["public", "private"]),
206
- * }),
207
- * comment: z.object({
208
- * id: z.string(),
209
- * postId: z.string(),
210
- * authorId: z.string(),
211
- * }),
212
- * } satisfies Resources;
213
- *
214
- * // Define actions per resource
215
- * const actions = {
216
- * post: ["read", "write", "delete"],
217
- * comment: ["read", "write"],
218
- * } as const satisfies Actions<typeof resources>;
219
- *
220
- * // Define context type
221
- * type AppContext = { user: { id: string; role: string } };
222
- *
223
- * // Create the policy
224
- * const policy = createPolicy<AppContext>({
225
- * resources,
226
- * actions,
227
- * rules: {
228
- * post: {
229
- * read: when((ctx, action, resource) => resource.visibility === "public"),
230
- * write: when((ctx, action, resource) => ctx.user.id === resource.authorId),
231
- * delete: deny(),
232
- * },
233
- * comment: {
234
- * read: allow(),
235
- * write: when((ctx, action, resource) => ctx.user.id === resource.authorId),
236
- * },
237
- * },
238
- * });
239
- *
240
- * // Check permissions
241
- * const post = { id: "1", authorId: "user-1", visibility: "public" as const };
242
- * await policy.can(ctx, "post:read", post); // true
243
- * await policy.can(ctx, "post:write", post); // depends on ctx.user.id
244
- * ```
245
- */
246
- const createPolicy = (config) => {
247
- const { rules, resources, actions } = config;
248
- const validators = /* @__PURE__ */ new Map();
249
- const getValidatedResource = async (resourceType, resource) => {
250
- const validator = validators.get(resourceType);
251
- if (validator === void 0) return null;
252
- try {
253
- const result = await validator(resource);
254
- if (result.issues) return null;
255
- return result.value;
256
- } catch (error) {
257
- console.warn(`Resource validation failed for ${String(resourceType)}: ${String(error)}`);
258
- return null;
259
- }
260
- };
261
- const hasAllowedAction = (resourceType, action) => actions[resourceType]?.includes(action) ?? false;
262
- const evaluatePolicy = (context, resourceType, action, resource) => {
263
- const policyFn = rules[resourceType]?.[action];
264
- if (policyFn === void 0) return false;
265
- try {
266
- return policyFn(context, action, resource) === "allow";
267
- } catch (error) {
268
- console.warn(`Policy evaluation error for ${String(resourceType)}.${action}: ${String(error)}`);
269
- return false;
270
- }
271
- };
272
- for (const key of Object.keys(resources)) {
273
- const schema = resources[key];
274
- if (schema === void 0) throw new PolicyError(`Missing schema for resource: ${String(key)}`);
275
- const validator = createStandardValidator(schema);
276
- validators.set(key, async (input) => await validator(input));
277
- }
278
- return { async can(context, permission, resource) {
279
- const parsedPermission = parsePermission(permission);
280
- if (parsedPermission === null) return false;
281
- const { action, resourceType } = parsedPermission;
282
- if (!hasAllowedAction(resourceType, action)) return false;
283
- const validatedResource = await getValidatedResource(resourceType, resource);
284
- if (validatedResource === null) return false;
285
- return evaluatePolicy(context, resourceType, action, validatedResource);
286
- } };
287
- };
288
- const mergePoliciesWithStrategy = (policies, strategy) => ({ async can(context, permission, resource) {
289
- if (policies.length === 0) return false;
290
- for (const policy of policies) {
291
- const allowed = await policy.can(context, permission, resource);
292
- if (strategy === "allow-overrides" && allowed) return true;
293
- if (strategy === "deny-overrides" && !allowed) return false;
294
- }
295
- return strategy === "deny-overrides";
296
- } });
297
- /**
298
- * Merges multiple policies into one using "deny-overrides" strategy.
299
- * If any policy denies, the merged policy denies. All must allow for the result to allow.
300
- *
301
- * @example
302
- * ```ts
303
- * const basePolicy = createPolicy({ ... });
304
- * const adminPolicy = createPolicy({ ... });
305
- *
306
- * const merged = mergePolicies(basePolicy, adminPolicy);
307
- * // Both policies must allow for the action to be permitted
308
- * ```
309
- */
310
- const mergePolicies = (...policies) => mergePoliciesWithStrategy(policies, "deny-overrides");
311
- /**
312
- * Merges multiple policies into one using "allow-overrides" strategy.
313
- * If any policy allows, the merged policy allows. All must deny for the result to deny.
314
- *
315
- * @example
316
- * ```ts
317
- * const guestPolicy = createPolicy({ ... });
318
- * const memberPolicy = createPolicy({ ... });
319
- *
320
- * const merged = mergePoliciesAny(guestPolicy, memberPolicy);
321
- * // If either policy allows, the action is permitted
322
- * ```
323
- */
324
- const mergePoliciesAny = (...policies) => mergePoliciesWithStrategy(policies, "allow-overrides");
325
- //#endregion
326
- export { allow, and, collectInheritedRoles, createPolicy, deny, has, hasRole, mergePolicies, mergePoliciesAny, not, or, when };
327
-
328
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Policy composition and evaluation utilities.\n *\n * @module @zap-studio/permit\n */\n\nimport type { StandardSchemaV1 } from \"@zap-studio/validation\";\nimport { createStandardValidator } from \"@zap-studio/validation\";\n\nimport { PolicyError } from \"./errors.js\";\nimport type {\n Actions,\n ConditionFn,\n Context,\n InferAction,\n InferResource,\n PermitConfig,\n Policy,\n PolicyFn,\n Resources,\n Role,\n RoleHierarchy,\n} from \"./types.js\";\n\n/**\n * Returns a policy function that always allows the action.\n *\n * @example\n * ```ts\n * const policy = createPolicy({\n * resources,\n * actions,\n * rules: {\n * post: {\n * read: allow(), // Always allow reading posts\n * },\n * },\n * });\n * ```\n */\nexport const allow =\n <\n TContext extends Context,\n TAction extends string = string,\n TResource = unknown,\n >(): PolicyFn<TContext, TAction, TResource> =>\n () =>\n \"allow\";\n\n/**\n * Returns a policy function that always denies the action.\n *\n * @example\n * ```ts\n * const policy = createPolicy({\n * resources,\n * actions,\n * rules: {\n * post: {\n * delete: deny(), // Never allow deleting posts\n * },\n * },\n * });\n * ```\n */\nexport const deny =\n <\n TContext extends Context,\n TAction extends string = string,\n TResource = unknown,\n >(): PolicyFn<TContext, TAction, TResource> =>\n () =>\n \"deny\";\n\n/**\n * Returns a policy function that allows or denies based on a condition.\n *\n * @example\n * ```ts\n * const policy = createPolicy({\n * resources,\n * actions,\n * rules: {\n * post: {\n * write: when((ctx, action, resource) => ctx.user.id === resource.authorId),\n * },\n * },\n * });\n * ```\n */\nexport const when =\n <\n TContext extends Context,\n TAction extends string = string,\n TResource = unknown,\n >(\n condition: ConditionFn<TContext, TAction, TResource>\n ): PolicyFn<TContext, TAction, TResource> =>\n (context, action, resource) =>\n condition(context, action, resource) ? \"allow\" : \"deny\";\n\n/**\n * Returns a condition function that returns `true` if all conditions are met.\n *\n * @example\n * ```ts\n * const isOwnerAndPublished = and(\n * (ctx, action, resource) => ctx.user.id === resource.authorId,\n * (ctx, action, resource) => resource.status === \"published\"\n * );\n *\n * rules: {\n * post: {\n * delete: when(isOwnerAndPublished),\n * },\n * }\n * ```\n */\nexport const and =\n <\n TContext extends Context,\n TAction extends string = string,\n TResource = unknown,\n >(\n ...conditions: ConditionFn<TContext, TAction, TResource>[]\n ): ConditionFn<TContext, TAction, TResource> =>\n (context, action, resource) =>\n conditions.every((condition) => condition(context, action, resource));\n\n/**\n * Returns a condition function that returns `true` if any condition is met.\n *\n * @example\n * ```ts\n * const isOwnerOrAdmin = or(\n * (ctx, action, resource) => ctx.user.id === resource.authorId,\n * (ctx, action, resource) => ctx.user.role === \"admin\"\n * );\n *\n * rules: {\n * post: {\n * write: when(isOwnerOrAdmin),\n * },\n * }\n * ```\n */\nexport const or =\n <\n TContext extends Context,\n TAction extends string = string,\n TResource = unknown,\n >(\n ...conditions: ConditionFn<TContext, TAction, TResource>[]\n ): ConditionFn<TContext, TAction, TResource> =>\n (context, action, resource) =>\n conditions.some((condition) => condition(context, action, resource));\n\n/**\n * Returns a condition function that negates another condition.\n *\n * @example\n * ```ts\n * const isNotOwner = not((ctx, action, resource) => ctx.user.id === resource.authorId);\n *\n * rules: {\n * post: {\n * like: when(isNotOwner), // Can only like posts you don't own\n * },\n * }\n * ```\n */\nexport const not =\n <\n TContext extends Context,\n TAction extends string = string,\n TResource = unknown,\n >(\n condition: ConditionFn<TContext, TAction, TResource>\n ): ConditionFn<TContext, TAction, TResource> =>\n (context, action, resource) =>\n !condition(context, action, resource);\n\n/**\n * Returns a condition function that checks if a context property equals a value.\n *\n * @example\n * ```ts\n * rules: {\n * post: {\n * write: when(has(\"role\", \"admin\")), // Only admins can write\n * },\n * }\n * ```\n */\nexport const has =\n <TContext extends Context, K extends keyof TContext>(\n key: K,\n value: TContext[K]\n ): ConditionFn<TContext> =>\n (context) =>\n context[key] === value;\n\n/**\n * Collects all roles including inherited ones from a role hierarchy.\n *\n * @example\n * ```ts\n * type Role = \"guest\" | \"user\" | \"admin\";\n *\n * const hierarchy: RoleHierarchy<Role> = {\n * guest: [],\n * user: [\"guest\"],\n * admin: [\"user\"],\n * };\n *\n * collectInheritedRoles([\"admin\"], hierarchy);\n * // Returns: Set { \"admin\", \"user\", \"guest\" }\n * ```\n */\nexport const collectInheritedRoles = <TRole extends Role = Role>(\n roles: TRole[],\n hierarchy: RoleHierarchy<TRole>\n): Set<TRole> => {\n const inherited = new Set<TRole>();\n\n const add = (role: TRole): void => {\n if (inherited.has(role)) {\n return;\n }\n\n inherited.add(role);\n const parents = hierarchy[role] ?? [];\n for (const parent of parents) {\n add(parent);\n }\n };\n\n for (const role of roles) {\n add(role);\n }\n return inherited;\n};\n\n/**\n * Call signatures for {@link hasRole}, preserving the with/without hierarchy overloads.\n */\ninterface HasRoleFn {\n <\n TContext extends { role: Role | Role[] },\n TAction extends string = string,\n TResource = unknown,\n >(\n role: Role\n ): ConditionFn<TContext, TAction, TResource>;\n <\n TContext extends { role: TRole | TRole[] },\n TAction extends string = string,\n TResource = unknown,\n TRole extends Role = Role,\n >(\n role: TRole,\n hierarchy: RoleHierarchy<TRole>\n ): ConditionFn<TContext, TAction, TResource>;\n}\n\n/**\n * Returns a condition function that checks if the user has a specific role.\n * Supports role hierarchy for inherited permissions.\n *\n * @example\n * ```ts\n * // Without hierarchy\n * rules: {\n * post: {\n * delete: when(hasRole(\"admin\")),\n * },\n * }\n *\n * // With hierarchy\n * const hierarchy = {\n * guest: [],\n * user: [\"guest\"],\n * admin: [\"user\"],\n * };\n *\n * rules: {\n * post: {\n * read: when(hasRole(\"guest\", hierarchy)), // Admins and users can also read\n * },\n * }\n * ```\n */\nexport const hasRole: HasRoleFn =\n (\n role: Role,\n hierarchy?: RoleHierarchy\n ): ConditionFn<{ role: Role | Role[] }> =>\n (context) => {\n const userRoles = Array.isArray(context.role)\n ? context.role\n : [context.role];\n\n if (hierarchy === undefined) {\n return userRoles.includes(role);\n }\n\n const inherited = collectInheritedRoles(userRoles, hierarchy);\n return inherited.has(role);\n };\n\n/**\n * Splits a typed `resource:action` permission string into its parts.\n * Returns `null` when the string is malformed (missing/empty part or extra segments).\n */\nconst parsePermission = <\n TResources extends Resources,\n TActions extends Actions<TResources>,\n K extends keyof TResources & keyof TActions,\n>(\n permission: `${K & string}:${InferAction<TActions, K> & string}`\n): { action: InferAction<TActions, K>; resourceType: K } | null => {\n const [resourceTypeValue, actionValue, ...rest] = permission.split(\":\");\n if (\n resourceTypeValue === undefined ||\n resourceTypeValue.length === 0 ||\n actionValue === undefined ||\n actionValue.length === 0 ||\n rest.length > 0\n ) {\n return null;\n }\n\n return {\n action: actionValue,\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Parsed permission strings are constrained by the typed permission template.\n resourceType: resourceTypeValue as K,\n };\n};\n\n/**\n * Creates a type-safe policy from resource schemas, actions, and rules.\n *\n * @example\n * ```ts\n * import { z } from \"zod\";\n * import { createPolicy, allow, deny, when } from \"@zap-studio/permit\";\n * import type { Resources, Actions } from \"@zap-studio/permit/types\";\n *\n * // Define resource schemas\n * const resources = {\n * post: z.object({\n * id: z.string(),\n * authorId: z.string(),\n * visibility: z.enum([\"public\", \"private\"]),\n * }),\n * comment: z.object({\n * id: z.string(),\n * postId: z.string(),\n * authorId: z.string(),\n * }),\n * } satisfies Resources;\n *\n * // Define actions per resource\n * const actions = {\n * post: [\"read\", \"write\", \"delete\"],\n * comment: [\"read\", \"write\"],\n * } as const satisfies Actions<typeof resources>;\n *\n * // Define context type\n * type AppContext = { user: { id: string; role: string } };\n *\n * // Create the policy\n * const policy = createPolicy<AppContext>({\n * resources,\n * actions,\n * rules: {\n * post: {\n * read: when((ctx, action, resource) => resource.visibility === \"public\"),\n * write: when((ctx, action, resource) => ctx.user.id === resource.authorId),\n * delete: deny(),\n * },\n * comment: {\n * read: allow(),\n * write: when((ctx, action, resource) => ctx.user.id === resource.authorId),\n * },\n * },\n * });\n *\n * // Check permissions\n * const post = { id: \"1\", authorId: \"user-1\", visibility: \"public\" as const };\n * await policy.can(ctx, \"post:read\", post); // true\n * await policy.can(ctx, \"post:write\", post); // depends on ctx.user.id\n * ```\n */\nexport const createPolicy = <\n TContext extends Context,\n TResources extends Resources = Resources,\n TActions extends Actions<TResources> = Actions<TResources>,\n>(\n config: PermitConfig<TContext, TResources, TActions>\n): Policy<TContext, TResources, TActions> => {\n const { rules, resources, actions } = config;\n const validators = new Map<\n keyof TResources,\n (input: unknown) => Promise<StandardSchemaV1.Result<unknown>>\n >();\n\n const getValidatedResource = async <K extends keyof TResources>(\n resourceType: K,\n resource: InferResource<TResources, K>\n ): Promise<InferResource<TResources, K> | null> => {\n const validator = validators.get(resourceType);\n if (validator === undefined) {\n return null;\n }\n try {\n const result = await validator(resource);\n if (result.issues) {\n return null;\n }\n return result.value;\n } catch (error) {\n console.warn(\n `Resource validation failed for ${String(resourceType)}: ${String(error)}`\n );\n return null;\n }\n };\n\n const hasAllowedAction = <K extends keyof TResources & keyof TActions>(\n resourceType: K,\n action: InferAction<TActions, K>\n ): boolean => actions[resourceType]?.includes(action) ?? false;\n\n const evaluatePolicy = <K extends keyof TResources & keyof TActions>(\n context: TContext,\n resourceType: K,\n action: InferAction<TActions, K>,\n resource: InferResource<TResources, K>\n ): boolean => {\n const policyFn = rules[resourceType]?.[action];\n if (policyFn === undefined) {\n return false;\n }\n\n try {\n return policyFn(context, action, resource) === \"allow\";\n } catch (error) {\n console.warn(\n `Policy evaluation error for ${String(resourceType)}.${action}: ${String(error)}`\n );\n return false;\n }\n };\n\n for (const key of Object.keys(resources) as (keyof TResources)[]) {\n const schema = resources[key];\n if (schema === undefined) {\n throw new PolicyError(`Missing schema for resource: ${String(key)}`);\n }\n const validator = createStandardValidator(schema);\n validators.set(key, async (input: unknown) => await validator(input));\n }\n\n return {\n async can<K extends keyof TResources & keyof TActions>(\n context: TContext,\n permission: `${K & string}:${InferAction<TActions, K> & string}`,\n resource: InferResource<TResources, K>\n ): Promise<boolean> {\n const parsedPermission = parsePermission<TResources, TActions, K>(\n permission\n );\n if (parsedPermission === null) {\n return false;\n }\n\n const { action, resourceType } = parsedPermission;\n if (!hasAllowedAction(resourceType, action)) {\n return false;\n }\n\n const validatedResource = await getValidatedResource(\n resourceType,\n resource\n );\n if (validatedResource === null) {\n return false;\n }\n\n return evaluatePolicy(context, resourceType, action, validatedResource);\n },\n };\n};\n\nconst mergePoliciesWithStrategy = <\n TContext extends Context,\n TResources extends Resources = Resources,\n TActions extends Actions<TResources> = Actions<TResources>,\n>(\n policies: Policy<TContext, TResources, TActions>[],\n strategy: \"allow-overrides\" | \"deny-overrides\"\n): Policy<TContext, TResources, TActions> => ({\n async can<K extends keyof TResources & keyof TActions>(\n context: TContext,\n permission: `${K & string}:${InferAction<TActions, K> & string}`,\n resource: InferResource<TResources, K>\n ): Promise<boolean> {\n if (policies.length === 0) {\n return false;\n }\n for (const policy of policies) {\n // oxlint-disable-next-line no-await-in-loop -- Policies must evaluate sequentially to preserve short-circuit semantics.\n const allowed = await policy.can(context, permission, resource);\n\n if (strategy === \"allow-overrides\" && allowed) {\n return true;\n }\n if (strategy === \"deny-overrides\" && !allowed) {\n return false;\n }\n }\n return strategy === \"deny-overrides\";\n },\n});\n\n/**\n * Merges multiple policies into one using \"deny-overrides\" strategy.\n * If any policy denies, the merged policy denies. All must allow for the result to allow.\n *\n * @example\n * ```ts\n * const basePolicy = createPolicy({ ... });\n * const adminPolicy = createPolicy({ ... });\n *\n * const merged = mergePolicies(basePolicy, adminPolicy);\n * // Both policies must allow for the action to be permitted\n * ```\n */\nexport const mergePolicies = <\n TContext extends Context,\n TResources extends Resources = Resources,\n TActions extends Actions<TResources> = Actions<TResources>,\n>(\n ...policies: Policy<TContext, TResources, TActions>[]\n): Policy<TContext, TResources, TActions> =>\n mergePoliciesWithStrategy(policies, \"deny-overrides\");\n\n/**\n * Merges multiple policies into one using \"allow-overrides\" strategy.\n * If any policy allows, the merged policy allows. All must deny for the result to deny.\n *\n * @example\n * ```ts\n * const guestPolicy = createPolicy({ ... });\n * const memberPolicy = createPolicy({ ... });\n *\n * const merged = mergePoliciesAny(guestPolicy, memberPolicy);\n * // If either policy allows, the action is permitted\n * ```\n */\nexport const mergePoliciesAny = <\n TContext extends Context,\n TResources extends Resources = Resources,\n TActions extends Actions<TResources> = Actions<TResources>,\n>(\n ...policies: Policy<TContext, TResources, TActions>[]\n): Policy<TContext, TResources, TActions> =>\n mergePoliciesWithStrategy(policies, \"allow-overrides\");\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;KAaY;;;;;KAMA,QAAQ,sBAAsB;;;;KAK9B,KAAK,iCAAiC;;;;;;;;;;;;;;;;KAiBtC,cAAc,cAAc,OAAO,QAAQ,OAAO,OAAO;;;;;;;;;;;;;;;;KAiBzD,UAAU,wCAAwC,OAC5D,cACA;;;;;;;;;;;;;;;KAiBU,QAAQ,mBAAmB,gBACpC,WAAW;;;;KAMF,cACV,mBAAmB,WACnB,2BAA2B,cACzB,iBAAiB,YAAY,WAAW;;;;KAKhC,YACV,iBAAiB,mCACjB,gBAAgB,YACd,SAAS;;;;;;;;;;KAWD,gBACV,mBAAmB,WACnB,iBAAiB,QAAQ,kBAExB,WAAW,mBACJ,cAAc,cAAc,YAAY,UAAU,uBACpD,mBAAmB;;;;KAKf,SACV,iBAAiB,SACjB,iCACA,wBACG,SAAS,UAAU,QAAQ,SAAS,UAAU,cAAc;;;;KAKrD,YACV,iBAAiB,SACjB,iCACA,wBACG,SAAS,UAAU,QAAQ,SAAS,UAAU;;;;KAKvC,gBACV,iBAAiB,SACjB,iCACA,0BAEC,KAAK,WAAW,SAAS,UAAU,GAAG;;;;;KAO7B,MACV,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ,kBAE9C,WAAW,mBAAmB,WAAW,gBACxC,UACA,YAAY,UAAU,IACtB,cAAc,YAAY;;;;;;;;;;;;;;;UAkBb,aACf,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ;EAE/C,SAAS;EACT,WAAW;EACX,OAAO,MAAM,UAAU,YAAY;;;;;;;;;;;;;;;;;UAkBpB,OACf,iBAAiB,SACjB,mBAAmB,YAAY,WAC/B,iBAAiB,QAAQ,cAAc,QAAQ;;;;EAK/C,MAAM,gBAAgB,mBAAmB,UACvC,SAAS,UACT,eAAe,cAAc,YAAY,UAAU,eACnD,UAAU,cAAc,YAAY,OACjC"}