@vielzeug/ward 1.0.2 → 1.0.4
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 +44 -50
- package/dist/_match.cjs +1 -1
- package/dist/_match.cjs.map +1 -1
- package/dist/_match.d.ts.map +1 -1
- package/dist/_match.js +16 -16
- package/dist/_match.js.map +1 -1
- package/dist/devtools.cjs.map +1 -1
- package/dist/devtools.d.ts +2 -2
- package/dist/devtools.js.map +1 -1
- package/dist/factory.cjs +1 -1
- package/dist/factory.cjs.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +29 -20
- package/dist/factory.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/middleware.cjs +1 -1
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.ts +17 -24
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +21 -9
- package/dist/middleware.js.map +1 -1
- package/dist/types.d.ts +41 -145
- package/dist/types.d.ts.map +1 -1
- package/dist/ward.cjs +1 -1
- package/dist/ward.cjs.map +1 -1
- package/dist/ward.iife.js +1 -1
- package/dist/ward.iife.js.map +1 -1
- package/dist/ward.js +1 -1
- package/dist/ward.js.map +1 -1
- package/package.json +6 -3
- package/dist/_dev.cjs +0 -2
- package/dist/_dev.cjs.map +0 -1
- package/dist/_dev.d.ts +0 -2
- package/dist/_dev.d.ts.map +0 -1
- package/dist/_dev.js +0 -9
- package/dist/_dev.js.map +0 -1
package/dist/middleware.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.cjs","names":[],"sources":["../src/middleware.ts"],"sourcesContent":["import type { Principal, Ward, WardDecision } from './types';\n\nexport type WardRequest = Record<string, unknown>;\nexport type PrincipalExtractor<TReq extends WardRequest = WardRequest> = (req: TReq) => Principal | Promise<Principal>;\n\nexport type GuardResult<TAction extends string, TData> =\n | { granted: true; principal: Principal }\n | {\n decision: WardDecision<TAction, TData>;\n granted: false;\n principal: Principal;\n reason: 'explicit-deny' | 'no-matching-rule';\n };\n\
|
|
1
|
+
{"version":3,"file":"middleware.cjs","names":[],"sources":["../src/middleware.ts"],"sourcesContent":["import type { Principal, Ward, WardDecision } from './types';\n\nexport type WardRequest = Record<string, unknown>;\nexport type PrincipalExtractor<TReq extends WardRequest = WardRequest> = (req: TReq) => Principal | Promise<Principal>;\n\nexport type GuardResult<TAction extends string, TData> =\n | { granted: true; principal: Principal }\n | {\n decision: WardDecision<TAction, TData>;\n granted: false;\n principal: Principal;\n reason: 'explicit-deny' | 'no-matching-rule';\n };\n\nexport type GuardRequestInput<TAction extends string, TData> = {\n action: TAction;\n data?: TData;\n principal: Principal;\n resource: string;\n ward: Ward<TAction, TData>;\n};\n\nexport type GuardRequestWithInput<TAction extends string, TData, TReq extends WardRequest> = {\n action: TAction;\n data?: TData;\n extractPrincipal: PrincipalExtractor<TReq>;\n req: TReq;\n resource: string;\n ward: Ward<TAction, TData>;\n};\n\nexport function guardRequest<TAction extends string, TData>(\n input: GuardRequestInput<TAction, TData>,\n): GuardResult<TAction, TData> {\n const decision = input.ward.explain({\n action: input.action,\n data: input.data,\n principal: input.principal,\n resource: input.resource,\n });\n\n if (decision.allowed) {\n return { granted: true, principal: input.principal };\n }\n\n return { decision, granted: false, principal: input.principal, reason: decision.reason };\n}\n\nexport async function guardRequestWith<TAction extends string, TData, TReq extends WardRequest>(\n input: GuardRequestWithInput<TAction, TData, TReq>,\n): Promise<GuardResult<TAction, TData>> {\n const principal = await input.extractPrincipal(input.req);\n\n return guardRequest({\n action: input.action,\n data: input.data,\n principal,\n resource: input.resource,\n ward: input.ward,\n });\n}\n"],"mappings":"AA+BA,SAAgB,EACd,EAC6B,CAC7B,IAAM,EAAW,EAAM,KAAK,QAAQ,CAClC,OAAQ,EAAM,OACd,KAAM,EAAM,KACZ,UAAW,EAAM,UACjB,SAAU,EAAM,QAClB,CAAC,EAMD,OAJI,EAAS,QACJ,CAAE,QAAS,GAAM,UAAW,EAAM,SAAU,EAG9C,CAAE,WAAU,QAAS,GAAO,UAAW,EAAM,UAAW,OAAQ,EAAS,MAAO,CACzF,CAEA,eAAsB,EACpB,EACsC,CACtC,IAAM,EAAY,MAAM,EAAM,iBAAiB,EAAM,GAAG,EAExD,OAAO,EAAa,CAClB,OAAQ,EAAM,OACd,KAAM,EAAM,KACZ,YACA,SAAU,EAAM,SAChB,KAAM,EAAM,IACd,CAAC,CACH"}
|
package/dist/middleware.d.ts
CHANGED
|
@@ -10,28 +10,21 @@ export type GuardResult<TAction extends string, TData> = {
|
|
|
10
10
|
principal: Principal;
|
|
11
11
|
reason: 'explicit-deny' | 'no-matching-rule';
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export declare function
|
|
30
|
-
/**
|
|
31
|
-
* Evaluates a ward decision by first extracting the principal from a request object,
|
|
32
|
-
* then running the authorization check. The extractor may be async (e.g. to verify a JWT).
|
|
33
|
-
*
|
|
34
|
-
* Use `guardRequest` instead when the principal is already resolved.
|
|
35
|
-
*/
|
|
36
|
-
export declare function guardRequestWith<TAction extends string, TData, TReq extends WardRequest>(ward: Ward<TAction, TData>, req: TReq, extractPrincipal: PrincipalExtractor<TReq>, resource: string, action: TAction, data?: TData): Promise<GuardResult<TAction, TData>>;
|
|
13
|
+
export type GuardRequestInput<TAction extends string, TData> = {
|
|
14
|
+
action: TAction;
|
|
15
|
+
data?: TData;
|
|
16
|
+
principal: Principal;
|
|
17
|
+
resource: string;
|
|
18
|
+
ward: Ward<TAction, TData>;
|
|
19
|
+
};
|
|
20
|
+
export type GuardRequestWithInput<TAction extends string, TData, TReq extends WardRequest> = {
|
|
21
|
+
action: TAction;
|
|
22
|
+
data?: TData;
|
|
23
|
+
extractPrincipal: PrincipalExtractor<TReq>;
|
|
24
|
+
req: TReq;
|
|
25
|
+
resource: string;
|
|
26
|
+
ward: Ward<TAction, TData>;
|
|
27
|
+
};
|
|
28
|
+
export declare function guardRequest<TAction extends string, TData>(input: GuardRequestInput<TAction, TData>): GuardResult<TAction, TData>;
|
|
29
|
+
export declare function guardRequestWith<TAction extends string, TData, TReq extends WardRequest>(input: GuardRequestWithInput<TAction, TData, TReq>): Promise<GuardResult<TAction, TData>>;
|
|
37
30
|
//# sourceMappingURL=middleware.d.ts.map
|
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE7D,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAClD,MAAM,MAAM,kBAAkB,CAAC,IAAI,SAAS,WAAW,GAAG,WAAW,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AAEvH,MAAM,MAAM,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,KAAK,IACjD;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,GACvC;IACE,QAAQ,EAAE,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,EAAE,KAAK,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,kBAAkB,CAAC;CAC9C,CAAC;AAEN
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE7D,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAClD,MAAM,MAAM,kBAAkB,CAAC,IAAI,SAAS,WAAW,GAAG,WAAW,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AAEvH,MAAM,MAAM,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,KAAK,IACjD;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,GACvC;IACE,QAAQ,EAAE,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,EAAE,KAAK,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,eAAe,GAAG,kBAAkB,CAAC;CAC9C,CAAC;AAEN,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,MAAM,EAAE,KAAK,IAAI;IAC7D,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,qBAAqB,CAAC,OAAO,SAAS,MAAM,EAAE,KAAK,EAAE,IAAI,SAAS,WAAW,IAAI;IAC3F,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,gBAAgB,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC3C,GAAG,EAAE,IAAI,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;CAC5B,CAAC;AAEF,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,KAAK,EACxD,KAAK,EAAE,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,GACvC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAa7B;AAED,wBAAsB,gBAAgB,CAAC,OAAO,SAAS,MAAM,EAAE,KAAK,EAAE,IAAI,SAAS,WAAW,EAC5F,KAAK,EAAE,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GACjD,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAUtC"}
|
package/dist/middleware.js
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
//#region src/middleware.ts
|
|
2
|
-
function e(e
|
|
3
|
-
let
|
|
4
|
-
|
|
2
|
+
function e(e) {
|
|
3
|
+
let t = e.ward.explain({
|
|
4
|
+
action: e.action,
|
|
5
|
+
data: e.data,
|
|
6
|
+
principal: e.principal,
|
|
7
|
+
resource: e.resource
|
|
8
|
+
});
|
|
9
|
+
return t.allowed ? {
|
|
5
10
|
granted: !0,
|
|
6
|
-
principal:
|
|
11
|
+
principal: e.principal
|
|
7
12
|
} : {
|
|
8
|
-
decision:
|
|
13
|
+
decision: t,
|
|
9
14
|
granted: !1,
|
|
10
|
-
principal:
|
|
11
|
-
reason:
|
|
15
|
+
principal: e.principal,
|
|
16
|
+
reason: t.reason
|
|
12
17
|
};
|
|
13
18
|
}
|
|
14
|
-
async function t(t
|
|
15
|
-
|
|
19
|
+
async function t(t) {
|
|
20
|
+
let n = await t.extractPrincipal(t.req);
|
|
21
|
+
return e({
|
|
22
|
+
action: t.action,
|
|
23
|
+
data: t.data,
|
|
24
|
+
principal: n,
|
|
25
|
+
resource: t.resource,
|
|
26
|
+
ward: t.ward
|
|
27
|
+
});
|
|
16
28
|
}
|
|
17
29
|
//#endregion
|
|
18
30
|
export { e as guardRequest, t as guardRequestWith };
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","names":[],"sources":["../src/middleware.ts"],"sourcesContent":["import type { Principal, Ward, WardDecision } from './types';\n\nexport type WardRequest = Record<string, unknown>;\nexport type PrincipalExtractor<TReq extends WardRequest = WardRequest> = (req: TReq) => Principal | Promise<Principal>;\n\nexport type GuardResult<TAction extends string, TData> =\n | { granted: true; principal: Principal }\n | {\n decision: WardDecision<TAction, TData>;\n granted: false;\n principal: Principal;\n reason: 'explicit-deny' | 'no-matching-rule';\n };\n\
|
|
1
|
+
{"version":3,"file":"middleware.js","names":[],"sources":["../src/middleware.ts"],"sourcesContent":["import type { Principal, Ward, WardDecision } from './types';\n\nexport type WardRequest = Record<string, unknown>;\nexport type PrincipalExtractor<TReq extends WardRequest = WardRequest> = (req: TReq) => Principal | Promise<Principal>;\n\nexport type GuardResult<TAction extends string, TData> =\n | { granted: true; principal: Principal }\n | {\n decision: WardDecision<TAction, TData>;\n granted: false;\n principal: Principal;\n reason: 'explicit-deny' | 'no-matching-rule';\n };\n\nexport type GuardRequestInput<TAction extends string, TData> = {\n action: TAction;\n data?: TData;\n principal: Principal;\n resource: string;\n ward: Ward<TAction, TData>;\n};\n\nexport type GuardRequestWithInput<TAction extends string, TData, TReq extends WardRequest> = {\n action: TAction;\n data?: TData;\n extractPrincipal: PrincipalExtractor<TReq>;\n req: TReq;\n resource: string;\n ward: Ward<TAction, TData>;\n};\n\nexport function guardRequest<TAction extends string, TData>(\n input: GuardRequestInput<TAction, TData>,\n): GuardResult<TAction, TData> {\n const decision = input.ward.explain({\n action: input.action,\n data: input.data,\n principal: input.principal,\n resource: input.resource,\n });\n\n if (decision.allowed) {\n return { granted: true, principal: input.principal };\n }\n\n return { decision, granted: false, principal: input.principal, reason: decision.reason };\n}\n\nexport async function guardRequestWith<TAction extends string, TData, TReq extends WardRequest>(\n input: GuardRequestWithInput<TAction, TData, TReq>,\n): Promise<GuardResult<TAction, TData>> {\n const principal = await input.extractPrincipal(input.req);\n\n return guardRequest({\n action: input.action,\n data: input.data,\n principal,\n resource: input.resource,\n ward: input.ward,\n });\n}\n"],"mappings":";AA+BA,SAAgB,EACd,GAC6B;CAC7B,IAAM,IAAW,EAAM,KAAK,QAAQ;EAClC,QAAQ,EAAM;EACd,MAAM,EAAM;EACZ,WAAW,EAAM;EACjB,UAAU,EAAM;CAClB,CAAC;CAMD,OAJI,EAAS,UACJ;EAAE,SAAS;EAAM,WAAW,EAAM;CAAU,IAG9C;EAAE;EAAU,SAAS;EAAO,WAAW,EAAM;EAAW,QAAQ,EAAS;CAAO;AACzF;AAEA,eAAsB,EACpB,GACsC;CACtC,IAAM,IAAY,MAAM,EAAM,iBAAiB,EAAM,GAAG;CAExD,OAAO,EAAa;EAClB,QAAQ,EAAM;EACd,MAAM,EAAM;EACZ;EACA,UAAU,EAAM;EAChB,MAAM,EAAM;CACd,CAAC;AACH"}
|
package/dist/types.d.ts
CHANGED
|
@@ -10,14 +10,6 @@ export type RuleContext<TData = unknown> = {
|
|
|
10
10
|
principal: UserPrincipal;
|
|
11
11
|
};
|
|
12
12
|
export type WardPredicate<TData = unknown> = (ctx: RuleContext<TData>) => boolean;
|
|
13
|
-
/**
|
|
14
|
-
* A single authorization rule. `role` accepts a string or string array — it is
|
|
15
|
-
* normalized to `readonly string[]` internally. `priority` defaults to `0`.
|
|
16
|
-
* The compiled rule object returned from decisions is frozen and must not be mutated.
|
|
17
|
-
*
|
|
18
|
-
* A rule matches if the principal holds ANY of the listed roles (OR semantics).
|
|
19
|
-
* Use `WILDCARD` to match all authenticated principals.
|
|
20
|
-
*/
|
|
21
13
|
export type WardRule<TAction extends string = string, TData = unknown> = {
|
|
22
14
|
action: TAction | typeof WILDCARD;
|
|
23
15
|
effect: 'allow' | 'deny';
|
|
@@ -26,14 +18,6 @@ export type WardRule<TAction extends string = string, TData = unknown> = {
|
|
|
26
18
|
role: string | readonly string[];
|
|
27
19
|
when?: WardPredicate<TData>;
|
|
28
20
|
};
|
|
29
|
-
/**
|
|
30
|
-
* The result of an authorization decision.
|
|
31
|
-
*
|
|
32
|
-
* Three distinct variants for precise narrowing:
|
|
33
|
-
* - `allowed: true` — access granted; the winning rule is always present.
|
|
34
|
-
* - `allowed: false, reason: 'explicit-deny'` — a deny rule matched; the winning rule is present.
|
|
35
|
-
* - `allowed: false, reason: 'no-matching-rule'` — no rule matched; no rule is attached.
|
|
36
|
-
*/
|
|
37
21
|
export type WardDecision<TAction extends string = string, TData = unknown> = {
|
|
38
22
|
allowed: true;
|
|
39
23
|
rule: Readonly<WardRule<TAction, TData>>;
|
|
@@ -50,143 +34,82 @@ export type WardCheck<TAction extends string = string, TData = unknown> = {
|
|
|
50
34
|
data?: TData;
|
|
51
35
|
resource: string;
|
|
52
36
|
};
|
|
53
|
-
/**
|
|
54
|
-
* The result of a single check in `checkAll` — a `WardDecision` annotated with
|
|
55
|
-
* the originating `resource` and `action` so callers do not need to zip by index.
|
|
56
|
-
*/
|
|
57
37
|
export type WardDecisionResult<TAction extends string = string, TData = unknown> = WardDecision<TAction, TData> & {
|
|
58
38
|
action: TAction;
|
|
59
39
|
resource: string;
|
|
60
40
|
};
|
|
41
|
+
export type WardDecisionInput<TAction extends string = string, TData = unknown> = {
|
|
42
|
+
action: TAction;
|
|
43
|
+
data?: TData;
|
|
44
|
+
principal: Principal;
|
|
45
|
+
resource: string;
|
|
46
|
+
};
|
|
47
|
+
export type WardAllowedActionsInput<TAction extends string = string, TData = unknown> = {
|
|
48
|
+
data?: TData;
|
|
49
|
+
knownActions: readonly TAction[];
|
|
50
|
+
principal: Principal;
|
|
51
|
+
resource: string;
|
|
52
|
+
};
|
|
53
|
+
export type WardRulesInScopeInput<TData = unknown> = {
|
|
54
|
+
data?: TData;
|
|
55
|
+
principal: Principal;
|
|
56
|
+
resource: string;
|
|
57
|
+
};
|
|
58
|
+
export type BoundWardDecisionInput<TAction extends string = string, TData = unknown> = {
|
|
59
|
+
action: TAction;
|
|
60
|
+
data?: TData;
|
|
61
|
+
resource: string;
|
|
62
|
+
};
|
|
63
|
+
export type BoundWardAllowedActionsInput<TAction extends string = string, TData = unknown> = {
|
|
64
|
+
data?: TData;
|
|
65
|
+
knownActions: readonly TAction[];
|
|
66
|
+
resource: string;
|
|
67
|
+
};
|
|
68
|
+
export type BoundWardRulesInScopeInput<TData = unknown> = {
|
|
69
|
+
data?: TData;
|
|
70
|
+
resource: string;
|
|
71
|
+
};
|
|
61
72
|
export type ConflictKind = 'duplicate' | 'shadowed';
|
|
62
|
-
/**
|
|
63
|
-
* Describes a rule conflict detected at creation time.
|
|
64
|
-
*
|
|
65
|
-
* Two variants, narrowable by `kind`:
|
|
66
|
-
*
|
|
67
|
-
* - `'duplicate'`: two **predicate-free** rules have identical (role set, resource, action) —
|
|
68
|
-
* one can never affect the outcome because the other always fires first.
|
|
69
|
-
* Fields: `ruleA`/`indexA` (first declared, wins) and `ruleB`/`indexB` (unreachable).
|
|
70
|
-
*
|
|
71
|
-
* - `'shadowed'`: the `shadowingRule` has a higher or equal effective rank AND its
|
|
72
|
-
* patterns are at least as broad as `shadowedRule`'s, AND it carries **no** `when`
|
|
73
|
-
* predicate — so `shadowedRule` can never win.
|
|
74
|
-
*
|
|
75
|
-
* Rules that carry a `when` predicate are excluded from both checks because their
|
|
76
|
-
* applicability can only be determined at runtime, not statically.
|
|
77
|
-
*/
|
|
78
73
|
export type WardConflict<TAction extends string = string, TData = unknown> = {
|
|
79
|
-
/** Index of the first-declared (winning) rule in the input array. */
|
|
80
74
|
indexA: number;
|
|
81
|
-
/** Index of the second-declared (unreachable) rule in the input array. */
|
|
82
75
|
indexB: number;
|
|
83
76
|
kind: 'duplicate';
|
|
84
|
-
/** First-declared rule (the one that always wins). */
|
|
85
77
|
ruleA: Readonly<WardRule<TAction, TData>>;
|
|
86
|
-
/** Second-declared rule (the unreachable duplicate). */
|
|
87
78
|
ruleB: Readonly<WardRule<TAction, TData>>;
|
|
88
79
|
} | {
|
|
89
80
|
kind: 'shadowed';
|
|
90
|
-
/** Index of the rule that can never win. */
|
|
91
81
|
shadowedIndex: number;
|
|
92
|
-
/** The rule that can never win. */
|
|
93
82
|
shadowedRule: Readonly<WardRule<TAction, TData>>;
|
|
94
|
-
/** Index of the rule that always wins instead. */
|
|
95
83
|
shadowingIndex: number;
|
|
96
|
-
/** The rule that always wins instead. */
|
|
97
84
|
shadowingRule: Readonly<WardRule<TAction, TData>>;
|
|
98
85
|
};
|
|
99
|
-
/** One candidate entry in a `WardTrace` — shows why it won or lost. */
|
|
100
86
|
export type WardTraceCandidate<TAction extends string = string, TData = unknown> = {
|
|
101
|
-
/** Original index of this rule in the input array passed to `createWard`. */
|
|
102
87
|
index: number;
|
|
103
88
|
priority: number;
|
|
104
89
|
rule: Readonly<WardRule<TAction, TData>>;
|
|
105
90
|
score: number;
|
|
106
91
|
won: boolean;
|
|
107
92
|
};
|
|
108
|
-
/**
|
|
109
|
-
* Full decision trace returned by `ward.trace()`.
|
|
110
|
-
* Lists every rule that matched the request (before winner selection) so you can
|
|
111
|
-
* see exactly which rule won and why other candidates lost.
|
|
112
|
-
*/
|
|
113
93
|
export type WardTrace<TAction extends string = string, TData = unknown> = {
|
|
114
94
|
candidates: WardTraceCandidate<TAction, TData>[];
|
|
115
95
|
decision: WardDecision<TAction, TData>;
|
|
116
96
|
};
|
|
117
97
|
export type Ward<TAction extends string = string, TData = unknown> = {
|
|
118
|
-
|
|
119
|
-
* Returns allowed concrete actions for a principal on a resource.
|
|
120
|
-
* Pass `knownActions` to resolve wildcard-action rules.
|
|
121
|
-
*
|
|
122
|
-
* **Does not invoke the logger** — this is a side-effect-free enumeration helper.
|
|
123
|
-
* Use `checkAll` if you need an auditable batch decision that fires the logger
|
|
124
|
-
* for each action checked.
|
|
125
|
-
*/
|
|
126
|
-
allowedActions(principal: Principal, resource: string, knownActions: readonly TAction[], data?: TData): TAction[];
|
|
127
|
-
/** Evaluates multiple checks and returns one `WardDecisionResult` per check. Invokes the logger for each. */
|
|
98
|
+
allowedActions(input: WardAllowedActionsInput<TAction, TData>): TAction[];
|
|
128
99
|
checkAll(principal: Principal, checks: readonly WardCheck<TAction, TData>[]): WardDecisionResult<TAction, TData>[];
|
|
129
|
-
/** Returns all rule conflicts in the policy. Lazily computed and cached (and frozen) after first call. @complexity O(n²) */
|
|
130
100
|
detectConflicts(): readonly WardConflict<TAction, TData>[];
|
|
131
|
-
|
|
132
|
-
explain(principal: Principal, resource: string, action: TAction, data?: TData): WardDecision<TAction, TData>;
|
|
101
|
+
explain(input: WardDecisionInput<TAction, TData>): WardDecision<TAction, TData>;
|
|
133
102
|
forUser(principal: UserPrincipal): BoundWard<TAction, TData>;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
* condition — useful for introspection. Pass `data` to apply predicates and get the runtime-accurate set.
|
|
138
|
-
*
|
|
139
|
-
* **Does not invoke the logger.**
|
|
140
|
-
*/
|
|
141
|
-
rulesInScope(principal: Principal, resource: string, data?: TData): ReadonlyArray<Readonly<WardRule<TAction, TData>>>;
|
|
142
|
-
/** Returns the full decision trace showing all matching candidates and why the winner was selected. **Does not invoke the logger** — use `explain` when you need the logger to fire. */
|
|
143
|
-
trace(principal: Principal, resource: string, action: TAction, data?: TData): WardTrace<TAction, TData>;
|
|
144
|
-
};
|
|
145
|
-
/**
|
|
146
|
-
* A principal-bound view of a Ward. All methods are identical to `Ward` but
|
|
147
|
-
* without the leading `principal` argument — it is captured at `forUser()` time.
|
|
148
|
-
* `forUser` and `detectConflicts` are not available on a bound view.
|
|
149
|
-
*/
|
|
103
|
+
rulesInScope(input: WardRulesInScopeInput<TData>): ReadonlyArray<Readonly<WardRule<TAction, TData>>>;
|
|
104
|
+
trace(input: WardDecisionInput<TAction, TData>): WardTrace<TAction, TData>;
|
|
105
|
+
};
|
|
150
106
|
export type BoundWard<TAction extends string = string, TData = unknown> = {
|
|
151
|
-
|
|
152
|
-
* Returns allowed concrete actions for this principal on a resource.
|
|
153
|
-
* Pass `knownActions` to resolve wildcard-action rules.
|
|
154
|
-
*
|
|
155
|
-
* @remarks Side-effect-free enumeration helper — does **not** invoke the logger.
|
|
156
|
-
* Use `checkAll` if you need an auditable batch decision.
|
|
157
|
-
*/
|
|
158
|
-
allowedActions(resource: string, knownActions: readonly TAction[], data?: TData): TAction[];
|
|
159
|
-
/** Evaluates multiple checks in a single call and returns one `WardDecisionResult` per check. */
|
|
107
|
+
allowedActions(input: BoundWardAllowedActionsInput<TAction, TData>): TAction[];
|
|
160
108
|
checkAll(checks: readonly WardCheck<TAction, TData>[]): WardDecisionResult<TAction, TData>[];
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
* When `data` is omitted, predicate-gated rules are included without evaluating their `when` condition.
|
|
166
|
-
*
|
|
167
|
-
* **Does not invoke the logger.**
|
|
168
|
-
*/
|
|
169
|
-
rulesInScope(resource: string, data?: TData): ReadonlyArray<Readonly<WardRule<TAction, TData>>>;
|
|
170
|
-
/** Returns the full decision trace showing all matching candidates and why the winner was selected. **Does not invoke the logger** — use `explain` when you need the logger to fire. */
|
|
171
|
-
trace(resource: string, action: TAction, data?: TData): WardTrace<TAction, TData>;
|
|
172
|
-
};
|
|
173
|
-
/**
|
|
174
|
-
* Logger context passed to `WardOptions.logger` on every decision.
|
|
175
|
-
*
|
|
176
|
-
* Structurally identical to `WardDecision` plus the request fields, so you can
|
|
177
|
-
* narrow `rule` with the same `if (ctx.allowed)` pattern you already know.
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* ```ts
|
|
181
|
-
* createWard(rules, {
|
|
182
|
-
* logger: (ctx) => {
|
|
183
|
-
* if (ctx.allowed) {
|
|
184
|
-
* console.log(ctx.rule.role); // no ?. needed
|
|
185
|
-
* }
|
|
186
|
-
* },
|
|
187
|
-
* });
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
109
|
+
explain(input: BoundWardDecisionInput<TAction, TData>): WardDecision<TAction, TData>;
|
|
110
|
+
rulesInScope(input: BoundWardRulesInScopeInput<TData>): ReadonlyArray<Readonly<WardRule<TAction, TData>>>;
|
|
111
|
+
trace(input: BoundWardDecisionInput<TAction, TData>): WardTrace<TAction, TData>;
|
|
112
|
+
};
|
|
190
113
|
export type WardLoggerContext<TAction extends string = string, TData = unknown> = WardDecision<TAction, TData> & {
|
|
191
114
|
action: TAction;
|
|
192
115
|
data?: TData;
|
|
@@ -195,35 +118,8 @@ export type WardLoggerContext<TAction extends string = string, TData = unknown>
|
|
|
195
118
|
};
|
|
196
119
|
export type WardOptions<TAction extends string = string, TData = unknown> = {
|
|
197
120
|
logger?: (context: WardLoggerContext<TAction, TData>) => void;
|
|
198
|
-
/**
|
|
199
|
-
* Maximum number of conflicts returned by `detectConflicts()`. Defaults to `Infinity`.
|
|
200
|
-
* Use to cap the O(n²) overhead for large auto-generated policies.
|
|
201
|
-
* Setting this to `0` disables conflict detection entirely — `detectConflicts()` will always return `[]`.
|
|
202
|
-
*/
|
|
203
121
|
maxConflicts?: number;
|
|
204
|
-
/**
|
|
205
|
-
* Called synchronously for each detected rule conflict immediately after
|
|
206
|
-
* the ward is compiled. Use this to surface conflicts as warnings or errors.
|
|
207
|
-
*
|
|
208
|
-
* @example
|
|
209
|
-
* ```ts
|
|
210
|
-
* createWard(rules, {
|
|
211
|
-
* onConflict: (c) => c.kind === 'duplicate'
|
|
212
|
-
* ? console.warn(`[ward] duplicate: Rule[${c.indexB}] unreachable (Rule[${c.indexA}] always wins)`)
|
|
213
|
-
* : console.warn(`[ward] shadowed: Rule[${c.shadowedIndex}] by Rule[${c.shadowingIndex}]`),
|
|
214
|
-
* });
|
|
215
|
-
* ```
|
|
216
|
-
*/
|
|
217
122
|
onConflict?: (conflict: WardConflict<TAction, TData>) => void;
|
|
218
|
-
/**
|
|
219
|
-
* When `true`, `createWard` throws immediately if any rule conflicts are
|
|
220
|
-
* detected. Use `detectConflicts()` on the returned ward for non-throwing
|
|
221
|
-
* inspection.
|
|
222
|
-
*
|
|
223
|
-
* @remarks When both `strict` and `onConflict` are set, `onConflict` is
|
|
224
|
-
* called for each conflict **before** the throw, so all conflicts are
|
|
225
|
-
* reported even in strict mode.
|
|
226
|
-
*/
|
|
227
123
|
strict?: boolean;
|
|
228
124
|
};
|
|
229
125
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,IAAI,CAAC;AAE7C,MAAM,MAAM,WAAW,CAAC,KAAK,GAAG,OAAO,IAAI;IACzC,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,aAAa,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,KAAK,GAAG,OAAO,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC;AAElF
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/ward.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`*`,t=`anonymous`;function n(e,t,n,r,i){return r.map(r=>({action:r,effect:e,...i?.priority===void 0?{}:{priority:i.priority},resource:n,role:t,...i?.when===void 0?{}:{when:i.when}}))}function r(e,t,r,i){return n(`allow`,e,t,r,i)}function i(e,t,r,i){return n(`deny`,e,t,r,i)}var a={and(...e){return t=>e.every(e=>e(t))},not(e){return t=>!e(t)},or(...e){return t=>e.some(e=>e(t))},owns(e){return({data:t,principal:n})=>{if(!t||typeof t!=`object`)return!1;let r=t;return Object.hasOwn(r,e)?r[e]===n.id:!1}}};function o(e){return a.owns(e)}var s=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},c=class extends s{},l=class extends s{ruleIndex;constructor(e,t){let n=t instanceof Error?t.message:String(t);super(`Rule[${e}] threw: ${n}`,{cause:t}),this.ruleIndex=e}};function u(e,t){let n=`Rule[${t}]`,r=Array.isArray(e.role)?e.role:[e.role];if(r.length===0||r.some(e=>typeof e!=`string`||!e.trim()))throw new c(`${n}.role must be a non-empty string or non-empty array of strings`);if(typeof e.resource!=`string`||!e.resource.trim())throw new c(`${n}.resource must be a non-empty string`);if(e.resource.endsWith(`:`))throw new c(`${n}.resource '${String(e.resource)}' ends with ':' — did you mean '${String(e.resource)}*'?`);if(typeof e.action!=`string`||!e.action.trim())throw new c(`${n}.action must be a non-empty string`);if(e.action.endsWith(`:`))throw new c(`${n}.action '${String(e.action)}' ends with ':' — did you mean '${String(e.action)}*'?`);if(e.effect!==`allow`&&e.effect!==`deny`)throw new c(`${n}.effect must be "allow" or "deny"`);if(e.priority!==void 0&&(typeof e.priority!=`number`||!Number.isFinite(e.priority)))throw new c(`${n}.priority must be a finite number`);if(e.when!==void 0&&typeof e.when!=`function`)throw new c(`${n}.when must be a function`)}function d(e){return e===`*`?0:e.endsWith(`:*`)?1:2}function f(e){return+!e.role.includes(`*`)+d(e.resource)+d(e.action)}function p(e,t){u(e,t);let n=Array.isArray(e.role)?[...e.role]:[e.role],r=Object.freeze([...new Set(n)]),i=Object.freeze({action:e.action,effect:e.effect,priority:e.priority??0,resource:e.resource,role:r,...e.when===void 0?{}:{when:e.when}}),a=f(i),o=i.priority;return{denyBonus:+(i.effect===`deny`),index:t,priority:o,roles:r,rule:i,score:a}}
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`*`,t=`anonymous`;function n(e,t,n,r,i){return r.map(r=>({action:r,effect:e,...i?.priority===void 0?{}:{priority:i.priority},resource:n,role:t,...i?.when===void 0?{}:{when:i.when}}))}function r(e,t,r,i){return n(`allow`,e,t,r,i)}function i(e,t,r,i){return n(`deny`,e,t,r,i)}var a={and(...e){return t=>e.every(e=>e(t))},not(e){return t=>!e(t)},or(...e){return t=>e.some(e=>e(t))},owns(e){return({data:t,principal:n})=>{if(!t||typeof t!=`object`)return!1;let r=t;return Object.hasOwn(r,e)?r[e]===n.id:!1}}};function o(e){return a.owns(e)}var s=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},c=class extends s{},l=class extends s{ruleIndex;constructor(e,t){let n=t instanceof Error?t.message:String(t);super(`Rule[${e}] threw: ${n}`,{cause:t}),this.ruleIndex=e}};function u(e,t){let n=`Rule[${t}]`,r=Array.isArray(e.role)?e.role:[e.role];if(r.length===0||r.some(e=>typeof e!=`string`||!e.trim()))throw new c(`${n}.role must be a non-empty string or non-empty array of strings`);if(typeof e.resource!=`string`||!e.resource.trim())throw new c(`${n}.resource must be a non-empty string`);if(e.resource.endsWith(`:`))throw new c(`${n}.resource '${String(e.resource)}' ends with ':' — did you mean '${String(e.resource)}*'?`);if(typeof e.action!=`string`||!e.action.trim())throw new c(`${n}.action must be a non-empty string`);if(e.action.endsWith(`:`))throw new c(`${n}.action '${String(e.action)}' ends with ':' — did you mean '${String(e.action)}*'?`);if(e.effect!==`allow`&&e.effect!==`deny`)throw new c(`${n}.effect must be "allow" or "deny"`);if(e.priority!==void 0&&(typeof e.priority!=`number`||!Number.isFinite(e.priority)))throw new c(`${n}.priority must be a finite number`);if(e.when!==void 0&&typeof e.when!=`function`)throw new c(`${n}.when must be a function`)}function d(e){return e===`*`?0:e.endsWith(`:*`)?1:2}function f(e){return+!e.role.includes(`*`)+d(e.resource)+d(e.action)}function p(e,t){u(e,t);let n=Array.isArray(e.role)?[...e.role]:[e.role],r=Object.freeze([...new Set(n)]),i=Object.freeze({action:e.action,effect:e.effect,priority:e.priority??0,resource:e.resource,role:r,...e.when===void 0?{}:{when:e.when}}),a=f(i),o=i.priority;return{denyBonus:+(i.effect===`deny`),index:t,priority:o,roles:r,rule:i,score:a}}function m(e,t){if(e===`*`||e===t)return!0;if(e.endsWith(`:*`)){let n=e.slice(0,-1);return t.startsWith(n)}return!1}function h(e,t){return e===`*`?!0:t===`*`?!1:e.endsWith(`:*`)?t.startsWith(e.slice(0,-1)):e===t}function g(e){if(typeof e!=`object`||!e)throw new c(`Invalid principal: expected { id: string, roles: string[] }`);let t=e;if(typeof t.id!=`string`||!t.id.trim())throw new c(`Invalid principal: id must be a non-empty string`);if(!Array.isArray(t.roles)||t.roles.some(e=>typeof e!=`string`||!e.trim()))throw new c(`Invalid principal: roles must be an array of non-empty strings`)}function _(e){e!==null&&g(e)}function v(e,n){return n===null?e.includes(t):e.every(e=>e===`anonymous`)?!1:e.includes(`*`)?!0:e.some(e=>n.roles.includes(e))}function y(e,t,n,r,i,a=!1){if(!v(e.roles,t)||!m(e.rule.resource,n)||r!==void 0&&!m(e.rule.action,r))return!1;if(a||!e.rule.when)return!0;if(t===null)return!1;try{let n=e.rule.when({data:i,principal:t});if(n instanceof Promise)throw TypeError(`Rule[${e.index}] when() returned a Promise. Async predicates are not supported — use a synchronous predicate.`);return n}catch(t){throw new l(e.index,t)}}function b(e,t){return t.priority>e.priority||t.priority===e.priority&&t.score>e.score||t.priority===e.priority&&t.score===e.score&&t.denyBonus>e.denyBonus}function x(e,t,n,r,i){let a;for(let o of e)y(o,t,n,r,i)&&(!a||b(a,o))&&(a=o);return a}function S(e){return e?e.rule.effect===`deny`?{allowed:!1,reason:`explicit-deny`,rule:e.rule}:{allowed:!0,rule:e.rule}:{allowed:!1,reason:`no-matching-rule`}}function C(e,n){let r=n.includes(t),i=n.some(e=>e!==t);return r&&!e.includes(`anonymous`)?!1:i?e.includes(`*`)?!0:n.filter(e=>e!==t).every(t=>e.includes(t)):!0}function w(e,t){if(e.length!==t.length)return!1;let n=new Set(e);return t.every(e=>n.has(e))}function T(e,t){return C(e.roles,t.roles)&&h(e.rule.resource,t.rule.resource)&&h(e.rule.action,t.rule.action)}function E(e,t){let n=[];for(let r=0;r<e.length&&n.length<t;r++)for(let i=r+1;i<e.length&&n.length<t;i++){let t=e[r],a=e[i];if(!t.rule.when&&!a.rule.when&&w(t.roles,a.roles)&&t.rule.resource===a.rule.resource&&t.rule.action===a.rule.action){n.push({indexA:t.index,indexB:a.index,kind:`duplicate`,ruleA:t.rule,ruleB:a.rule});continue}let o=b(t,a);!o&&!t.rule.when&&T(t,a)?n.push({kind:`shadowed`,shadowedIndex:a.index,shadowedRule:a.rule,shadowingIndex:t.index,shadowingRule:t.rule}):o&&!a.rule.when&&T(a,t)&&n.push({kind:`shadowed`,shadowedIndex:t.index,shadowedRule:t.rule,shadowingIndex:a.index,shadowingRule:a.rule})}return n}function D(e,t,n,r,i){let a=new Set,o=[];for(let s of r)a.has(s)||(a.add(s),x(e,t,n,s,i)?.rule.effect===`allow`&&o.push(s));return o}function O(e,t,n,r){let i=r===void 0,a=[];for(let o of e)y(o,t,n,void 0,r,i)&&a.push(o.rule);return a}function k(e=[],t={}){let{logger:n,maxConflicts:r=1/0}=t,i=e.map((e,t)=>p(e,t));function a(e,t,r,i,a){n&&n({...a,action:r,data:i,principal:e,resource:t})}function o(e,t,n,r){let o=S(x(i,e,t,n,r));return a(e,t,n,r,o),o}function s(e){let{action:t,data:n,principal:r,resource:i}=e;return _(r),o(r,i,t,n)}function l(e,t){return t.map(t=>({...o(e,t.resource,t.action,t.data),action:t.action,resource:t.resource}))}function u(e,t){return t.length===0?[]:(_(e),l(e,t))}function d(e){let{data:t,knownActions:n,principal:r,resource:a}=e;return _(r),D(i,r,a,n,t)}function f(e){let{data:t,principal:n,resource:r}=e;return _(n),O(i,n,r,t)}function m(e){let{action:t,data:n,principal:r,resource:a}=e;_(r);let o=[];for(let e of i)y(e,r,a,t,n)&&o.push(e);let s;for(let e of o)(!s||b(s,e))&&(s=e);let c=S(s);return{candidates:o.map(e=>({index:e.index,priority:e.priority,rule:e.rule,score:e.score,won:e===s})),decision:c}}function h(e){g(e);let t={attributes:e.attributes?structuredClone(e.attributes):void 0,id:e.id,roles:[...e.roles]};return{allowedActions:e=>D(i,t,e.resource,e.knownActions,e.data),checkAll:e=>e.length===0?[]:l(t,e),explain:e=>o(t,e.resource,e.action,e.data),rulesInScope:e=>O(i,t,e.resource,e.data),trace:e=>m({action:e.action,data:e.data,principal:t,resource:e.resource})}}let v;function C(){return v??=Object.freeze(E(i,r))}if(t.strict||t.onConflict){let e=C();if(e.length>0&&(t.onConflict&&e.forEach(t.onConflict),t.strict)){let t=e.map(e=>e.kind===`duplicate`?`Rule[${e.indexB}] ${e.kind} of Rule[${e.indexA}]`:`Rule[${e.shadowedIndex}] ${e.kind} by Rule[${e.shadowingIndex}]`).join(`; `);throw new c(`${e.length} rule conflict(s) detected: ${t}`)}}return{allowedActions:d,checkAll:u,detectConflicts:C,explain:s,forUser:h,rulesInScope:f,trace:m}}function A(e){let t=e.ward.explain({action:e.action,data:e.data,principal:e.principal,resource:e.resource});return t.allowed?{granted:!0,principal:e.principal}:{decision:t,granted:!1,principal:e.principal,reason:t.reason}}async function j(e){let t=await e.extractPrincipal(e.req);return A({action:e.action,data:e.data,principal:t,resource:e.resource,ward:e.ward})}exports.ANONYMOUS=t,exports.WILDCARD=e,exports.WardConfigError=c,exports.WardError=s,exports.WardPredicateError=l,exports.allow=r,exports.createWard=k,exports.deny=i,exports.guardRequest=A,exports.guardRequestWith=j,exports.matchesPattern=m,exports.owns=o,exports.patternCovers=h,exports.predicate=a,exports.ruleFor=n;
|
|
2
2
|
//# sourceMappingURL=ward.cjs.map
|