@c9up/warden 0.1.0 → 0.1.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.
Files changed (136) hide show
  1. package/dist/AuthManager.d.ts +98 -0
  2. package/dist/AuthManager.d.ts.map +1 -0
  3. package/dist/AuthManager.js +147 -0
  4. package/dist/AuthManager.js.map +1 -0
  5. package/dist/AuthRateLimiter.d.ts +29 -0
  6. package/dist/AuthRateLimiter.d.ts.map +1 -0
  7. package/dist/AuthRateLimiter.js +88 -0
  8. package/dist/AuthRateLimiter.js.map +1 -0
  9. package/dist/Guard.d.ts +26 -0
  10. package/dist/Guard.d.ts.map +1 -0
  11. package/dist/Guard.js +52 -0
  12. package/dist/Guard.js.map +1 -0
  13. package/dist/RefreshTokenStore.d.ts +34 -0
  14. package/dist/RefreshTokenStore.d.ts.map +1 -0
  15. package/dist/RefreshTokenStore.js +48 -0
  16. package/dist/RefreshTokenStore.js.map +1 -0
  17. package/dist/TokenBlacklist.d.ts +30 -0
  18. package/dist/TokenBlacklist.d.ts.map +1 -0
  19. package/dist/TokenBlacklist.js +50 -0
  20. package/dist/TokenBlacklist.js.map +1 -0
  21. package/dist/WardenProvider.d.ts +19 -0
  22. package/dist/WardenProvider.d.ts.map +1 -0
  23. package/dist/WardenProvider.js +61 -0
  24. package/dist/WardenProvider.js.map +1 -0
  25. package/dist/bouncer/AuthorizationResponse.d.ts +25 -0
  26. package/dist/bouncer/AuthorizationResponse.d.ts.map +1 -0
  27. package/dist/bouncer/AuthorizationResponse.js +31 -0
  28. package/dist/bouncer/AuthorizationResponse.js.map +1 -0
  29. package/dist/bouncer/BasePolicy.d.ts +47 -0
  30. package/dist/bouncer/BasePolicy.d.ts.map +1 -0
  31. package/dist/bouncer/BasePolicy.js +36 -0
  32. package/dist/bouncer/BasePolicy.js.map +1 -0
  33. package/dist/bouncer/Bouncer.d.ts +47 -0
  34. package/dist/bouncer/Bouncer.d.ts.map +1 -0
  35. package/dist/bouncer/Bouncer.js +134 -0
  36. package/dist/bouncer/Bouncer.js.map +1 -0
  37. package/dist/bouncer/PolicyAuthorizer.d.ts +24 -0
  38. package/dist/bouncer/PolicyAuthorizer.d.ts.map +1 -0
  39. package/dist/bouncer/PolicyAuthorizer.js +92 -0
  40. package/dist/bouncer/PolicyAuthorizer.js.map +1 -0
  41. package/dist/bouncer/decorators.d.ts +25 -0
  42. package/dist/bouncer/decorators.d.ts.map +1 -0
  43. package/dist/bouncer/decorators.js +36 -0
  44. package/dist/bouncer/decorators.js.map +1 -0
  45. package/dist/bouncer/evaluate.d.ts +36 -0
  46. package/dist/bouncer/evaluate.d.ts.map +1 -0
  47. package/dist/bouncer/evaluate.js +64 -0
  48. package/dist/bouncer/evaluate.js.map +1 -0
  49. package/dist/bouncer/policyContext.d.ts +29 -0
  50. package/dist/bouncer/policyContext.d.ts.map +1 -0
  51. package/dist/bouncer/policyContext.js +36 -0
  52. package/dist/bouncer/policyContext.js.map +1 -0
  53. package/dist/bouncer/types.d.ts +52 -0
  54. package/dist/bouncer/types.d.ts.map +1 -0
  55. package/dist/bouncer/types.js +9 -0
  56. package/dist/bouncer/types.js.map +1 -0
  57. package/dist/config.d.ts +42 -0
  58. package/dist/config.d.ts.map +1 -0
  59. package/dist/config.js +21 -0
  60. package/dist/config.js.map +1 -0
  61. package/dist/configure.d.ts +10 -0
  62. package/dist/configure.d.ts.map +1 -0
  63. package/dist/configure.js +44 -0
  64. package/dist/configure.js.map +1 -0
  65. package/dist/errors.d.ts +18 -0
  66. package/dist/errors.d.ts.map +1 -0
  67. package/dist/errors.js +21 -0
  68. package/dist/errors.js.map +1 -0
  69. package/dist/firstcontact/FirstContactManager.d.ts +25 -0
  70. package/dist/firstcontact/FirstContactManager.d.ts.map +1 -0
  71. package/dist/firstcontact/FirstContactManager.js +38 -0
  72. package/dist/firstcontact/FirstContactManager.js.map +1 -0
  73. package/dist/firstcontact/drivers/GitHubDriver.d.ts +14 -0
  74. package/dist/firstcontact/drivers/GitHubDriver.d.ts.map +1 -0
  75. package/dist/firstcontact/drivers/GitHubDriver.js +61 -0
  76. package/dist/firstcontact/drivers/GitHubDriver.js.map +1 -0
  77. package/dist/firstcontact/drivers/GoogleDriver.d.ts +14 -0
  78. package/dist/firstcontact/drivers/GoogleDriver.d.ts.map +1 -0
  79. package/dist/firstcontact/drivers/GoogleDriver.js +64 -0
  80. package/dist/firstcontact/drivers/GoogleDriver.js.map +1 -0
  81. package/dist/firstcontact/types.d.ts +34 -0
  82. package/dist/firstcontact/types.d.ts.map +1 -0
  83. package/dist/firstcontact/types.js +5 -0
  84. package/dist/firstcontact/types.js.map +1 -0
  85. package/dist/index.d.ts +38 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +27 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/middleware.d.ts +51 -0
  90. package/dist/middleware.d.ts.map +1 -0
  91. package/dist/middleware.js +201 -0
  92. package/dist/middleware.js.map +1 -0
  93. package/dist/native.d.ts +14 -0
  94. package/dist/native.d.ts.map +1 -0
  95. package/dist/native.js +39 -0
  96. package/dist/native.js.map +1 -0
  97. package/dist/rights/MemoryRightsStore.d.ts +29 -0
  98. package/dist/rights/MemoryRightsStore.d.ts.map +1 -0
  99. package/dist/rights/MemoryRightsStore.js +70 -0
  100. package/dist/rights/MemoryRightsStore.js.map +1 -0
  101. package/dist/rights/RightsResolver.d.ts +29 -0
  102. package/dist/rights/RightsResolver.d.ts.map +1 -0
  103. package/dist/rights/RightsResolver.js +73 -0
  104. package/dist/rights/RightsResolver.js.map +1 -0
  105. package/dist/rights/types.d.ts +55 -0
  106. package/dist/rights/types.d.ts.map +1 -0
  107. package/dist/rights/types.js +18 -0
  108. package/dist/rights/types.js.map +1 -0
  109. package/dist/services/main.d.ts +19 -0
  110. package/dist/services/main.d.ts.map +1 -0
  111. package/dist/services/main.js +32 -0
  112. package/dist/services/main.js.map +1 -0
  113. package/dist/standalone.d.ts +37 -0
  114. package/dist/standalone.d.ts.map +1 -0
  115. package/dist/standalone.js +92 -0
  116. package/dist/standalone.js.map +1 -0
  117. package/dist/strategies/ApiKeyStrategy.d.ts +28 -0
  118. package/dist/strategies/ApiKeyStrategy.d.ts.map +1 -0
  119. package/dist/strategies/ApiKeyStrategy.js +36 -0
  120. package/dist/strategies/ApiKeyStrategy.js.map +1 -0
  121. package/dist/strategies/JwtStrategy.d.ts +51 -0
  122. package/dist/strategies/JwtStrategy.d.ts.map +1 -0
  123. package/dist/strategies/JwtStrategy.js +150 -0
  124. package/dist/strategies/JwtStrategy.js.map +1 -0
  125. package/dist/strategies/SessionStrategy.d.ts +58 -0
  126. package/dist/strategies/SessionStrategy.d.ts.map +1 -0
  127. package/dist/strategies/SessionStrategy.js +70 -0
  128. package/dist/strategies/SessionStrategy.js.map +1 -0
  129. package/index.darwin-arm64.node +0 -0
  130. package/index.darwin-x64.node +0 -0
  131. package/index.linux-arm64-gnu.node +0 -0
  132. package/index.linux-x64-gnu.node +0 -0
  133. package/index.win32-x64-msvc.node +0 -0
  134. package/package.json +1 -1
  135. package/src/WardenProvider.ts +2 -2
  136. package/src/services/main.ts +8 -8
@@ -0,0 +1,29 @@
1
+ /**
2
+ * MemoryRightsStore — the shipped in-memory rights driver.
3
+ *
4
+ * Implements the read-only `RightsStore` contract and adds chainable seeding
5
+ * methods (`defineRole`/`assignRole`/`grant`/`revoke`) for app boot and tests.
6
+ * DB-backed drivers are a documented copy-in adapter, not a hard dependency —
7
+ * this driver keeps Warden's agnostic posture with zero new dependencies.
8
+ *
9
+ * Storage is Map-based, keyed by `scopeKey(scope)` then by role/userId, so
10
+ * `global` and `tenant:X` rights stay isolated (inheritance is the resolver's
11
+ * job, not the store's).
12
+ */
13
+ import { type RightsStore, type Scope } from "./types.js";
14
+ export declare class MemoryRightsStore implements RightsStore {
15
+ /** scopeKey → role → permissions */
16
+ private readonly roleDefs;
17
+ /** scopeKey → userId → roles */
18
+ private readonly userRoleMap;
19
+ /** scopeKey → userId → directly granted permissions */
20
+ private readonly userGrantMap;
21
+ rolePermissions(role: string, scope: Scope): Promise<readonly string[]>;
22
+ userRoles(userId: string, scope: Scope): Promise<readonly string[]>;
23
+ userGrants(userId: string, scope: Scope): Promise<readonly string[]>;
24
+ defineRole(role: string, permissions: readonly string[], scope?: Scope): this;
25
+ assignRole(userId: string, role: string, scope?: Scope): this;
26
+ grant(userId: string, permission: string, scope?: Scope): this;
27
+ revoke(userId: string, permission: string, scope?: Scope): this;
28
+ }
29
+ //# sourceMappingURL=MemoryRightsStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryRightsStore.d.ts","sourceRoot":"","sources":["../../src/rights/MemoryRightsStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,KAAK,EAAY,MAAM,YAAY,CAAC;AAEpE,qBAAa,iBAAkB,YAAW,WAAW;IACpD,oCAAoC;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+C;IACxE,gCAAgC;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+C;IAC3E,uDAAuD;IACvD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA+C;IAItE,eAAe,CACpB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,KAAK,GACV,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;IAIvB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;IAInE,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;IAM1E,UAAU,CACT,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,KAAK,GAAE,KAAgB,GACrB,IAAI;IAOP,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI;IAKvE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI;IAKxE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI;CAIzE"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * MemoryRightsStore — the shipped in-memory rights driver.
3
+ *
4
+ * Implements the read-only `RightsStore` contract and adds chainable seeding
5
+ * methods (`defineRole`/`assignRole`/`grant`/`revoke`) for app boot and tests.
6
+ * DB-backed drivers are a documented copy-in adapter, not a hard dependency —
7
+ * this driver keeps Warden's agnostic posture with zero new dependencies.
8
+ *
9
+ * Storage is Map-based, keyed by `scopeKey(scope)` then by role/userId, so
10
+ * `global` and `tenant:X` rights stay isolated (inheritance is the resolver's
11
+ * job, not the store's).
12
+ */
13
+ import { scopeKey } from "./types.js";
14
+ export class MemoryRightsStore {
15
+ /** scopeKey → role → permissions */
16
+ roleDefs = new Map();
17
+ /** scopeKey → userId → roles */
18
+ userRoleMap = new Map();
19
+ /** scopeKey → userId → directly granted permissions */
20
+ userGrantMap = new Map();
21
+ // — read contract —
22
+ async rolePermissions(role, scope) {
23
+ return snapshot(this.roleDefs.get(scopeKey(scope))?.get(role));
24
+ }
25
+ async userRoles(userId, scope) {
26
+ return snapshot(this.userRoleMap.get(scopeKey(scope))?.get(userId));
27
+ }
28
+ async userGrants(userId, scope) {
29
+ return snapshot(this.userGrantMap.get(scopeKey(scope))?.get(userId));
30
+ }
31
+ // — seeding (in-memory driver only; not part of RightsStore) —
32
+ defineRole(role, permissions, scope = "global") {
33
+ const set = bucket(this.roleDefs, scopeKey(scope), role);
34
+ set.clear();
35
+ for (const perm of permissions)
36
+ set.add(perm);
37
+ return this;
38
+ }
39
+ assignRole(userId, role, scope = "global") {
40
+ bucket(this.userRoleMap, scopeKey(scope), userId).add(role);
41
+ return this;
42
+ }
43
+ grant(userId, permission, scope = "global") {
44
+ bucket(this.userGrantMap, scopeKey(scope), userId).add(permission);
45
+ return this;
46
+ }
47
+ revoke(userId, permission, scope = "global") {
48
+ this.userGrantMap.get(scopeKey(scope))?.get(userId)?.delete(permission);
49
+ return this;
50
+ }
51
+ }
52
+ /** Defensive array snapshot — never hands back a live reference to internal state. */
53
+ function snapshot(set) {
54
+ return set ? [...set] : [];
55
+ }
56
+ /** Get-or-create the inner `Set` for `outer[key][inner]`. */
57
+ function bucket(outer, key, inner) {
58
+ let mid = outer.get(key);
59
+ if (!mid) {
60
+ mid = new Map();
61
+ outer.set(key, mid);
62
+ }
63
+ let set = mid.get(inner);
64
+ if (!set) {
65
+ set = new Set();
66
+ mid.set(inner, set);
67
+ }
68
+ return set;
69
+ }
70
+ //# sourceMappingURL=MemoryRightsStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryRightsStore.js","sourceRoot":"","sources":["../../src/rights/MemoryRightsStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * RightsResolver — computes a user's effective permissions for a scope.
3
+ *
4
+ * This is the unification point the epic calls `user.permissions`: every later
5
+ * authorization facet consults `resolve(user, scope)` instead of reading roles
6
+ * or permissions ad hoc.
7
+ *
8
+ * Resolution rules:
9
+ * - Scope chain: `["global"]` for global, `["global", { tenant }]` for a
10
+ * tenant scope — global rights are inherited into every tenant scope.
11
+ * - Roles: token-carried `user.roles` are global identity — they apply at
12
+ * the `global` link only; each scope additionally uses `store.userRoles(...)`.
13
+ * A global role's global permissions still inherit into tenant scopes via
14
+ * the chain, but a payload role never picks up a same-named tenant role's
15
+ * permissions (no cross-tenant escalation by name collision).
16
+ * - Permissions = (∪ over roles of `store.rolePermissions(...)`) ∪
17
+ * `store.userGrants(...)` (the ACL). The payload's `user.permissions` is
18
+ * NOT an input — permissions are derived from the rights model only.
19
+ * - Fail-closed: absent data contributes nothing and never throws.
20
+ * - Exact-match comparison; no wildcard or role-hierarchy expansion.
21
+ */
22
+ import type { UserPayload } from "../AuthManager.js";
23
+ import type { EffectivePermissions, RightsStore, Scope } from "./types.js";
24
+ export declare class RightsResolver {
25
+ private readonly store;
26
+ constructor(store: RightsStore);
27
+ resolve(user: UserPayload, scope?: Scope): Promise<EffectivePermissions>;
28
+ }
29
+ //# sourceMappingURL=RightsResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RightsResolver.d.ts","sourceRoot":"","sources":["../../src/rights/RightsResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAsB3E,qBAAa,cAAc;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAEzC,OAAO,CACZ,IAAI,EAAE,WAAW,EACjB,KAAK,GAAE,KAAgB,GACrB,OAAO,CAAC,oBAAoB,CAAC;CAgChC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * RightsResolver — computes a user's effective permissions for a scope.
3
+ *
4
+ * This is the unification point the epic calls `user.permissions`: every later
5
+ * authorization facet consults `resolve(user, scope)` instead of reading roles
6
+ * or permissions ad hoc.
7
+ *
8
+ * Resolution rules:
9
+ * - Scope chain: `["global"]` for global, `["global", { tenant }]` for a
10
+ * tenant scope — global rights are inherited into every tenant scope.
11
+ * - Roles: token-carried `user.roles` are global identity — they apply at
12
+ * the `global` link only; each scope additionally uses `store.userRoles(...)`.
13
+ * A global role's global permissions still inherit into tenant scopes via
14
+ * the chain, but a payload role never picks up a same-named tenant role's
15
+ * permissions (no cross-tenant escalation by name collision).
16
+ * - Permissions = (∪ over roles of `store.rolePermissions(...)`) ∪
17
+ * `store.userGrants(...)` (the ACL). The payload's `user.permissions` is
18
+ * NOT an input — permissions are derived from the rights model only.
19
+ * - Fail-closed: absent data contributes nothing and never throws.
20
+ * - Exact-match comparison; no wildcard or role-hierarchy expansion.
21
+ */
22
+ class ResolvedPermissions {
23
+ permissions;
24
+ roles;
25
+ scope;
26
+ constructor(permissions, roles, scope) {
27
+ this.permissions = permissions;
28
+ this.roles = roles;
29
+ this.scope = scope;
30
+ }
31
+ has(permission) {
32
+ return this.permissions.has(permission);
33
+ }
34
+ hasAll(permissions) {
35
+ return permissions.every((p) => this.permissions.has(p));
36
+ }
37
+ hasAny(permissions) {
38
+ return permissions.some((p) => this.permissions.has(p));
39
+ }
40
+ }
41
+ export class RightsResolver {
42
+ store;
43
+ constructor(store) {
44
+ this.store = store;
45
+ }
46
+ async resolve(user, scope = "global") {
47
+ const chain = scope === "global" ? ["global"] : ["global", scope];
48
+ const roles = new Set();
49
+ const permissions = new Set();
50
+ const payloadRoles = user.roles ?? [];
51
+ for (const link of chain) {
52
+ const storeRoles = await this.store.userRoles(user.id, link);
53
+ // Token-carried roles are global identity: they contribute at the
54
+ // `global` link only, so a payload role never inherits a same-named
55
+ // tenant role's permissions. A global role's global permissions still
56
+ // reach tenant scopes via the chain.
57
+ const scopeRoles = link === "global"
58
+ ? new Set([...payloadRoles, ...storeRoles])
59
+ : new Set(storeRoles);
60
+ for (const role of scopeRoles) {
61
+ roles.add(role);
62
+ for (const perm of await this.store.rolePermissions(role, link)) {
63
+ permissions.add(perm);
64
+ }
65
+ }
66
+ for (const grant of await this.store.userGrants(user.id, link)) {
67
+ permissions.add(grant);
68
+ }
69
+ }
70
+ return new ResolvedPermissions(permissions, roles, scope);
71
+ }
72
+ }
73
+ //# sourceMappingURL=RightsResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RightsResolver.js","sourceRoot":"","sources":["../../src/rights/RightsResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,MAAM,mBAAmB;IAEd;IACA;IACA;IAHV,YACU,WAAgC,EAChC,KAA0B,EAC1B,KAAY;QAFZ,gBAAW,GAAX,WAAW,CAAqB;QAChC,UAAK,GAAL,KAAK,CAAqB;QAC1B,UAAK,GAAL,KAAK,CAAO;IACnB,CAAC;IAEJ,GAAG,CAAC,UAAkB;QACrB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,CAAC,WAA8B;QACpC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,CAAC,WAA8B;QACpC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC;CACD;AAED,MAAM,OAAO,cAAc;IACG;IAA7B,YAA6B,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;IAAG,CAAC;IAEnD,KAAK,CAAC,OAAO,CACZ,IAAiB,EACjB,QAAe,QAAQ;QAEvB,MAAM,KAAK,GAAY,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE3E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QACtC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAEtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAC7D,kEAAkE;YAClE,oEAAoE;YACpE,sEAAsE;YACtE,qCAAqC;YACrC,MAAM,UAAU,GACf,IAAI,KAAK,QAAQ;gBAChB,CAAC,CAAC,IAAI,GAAG,CAAS,CAAC,GAAG,YAAY,EAAE,GAAG,UAAU,CAAC,CAAC;gBACnD,CAAC,CAAC,IAAI,GAAG,CAAS,UAAU,CAAC,CAAC;YAEhC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC/B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAChB,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;oBACjE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;YACF,CAAC;YAED,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;gBAChE,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;QACF,CAAC;QAED,OAAO,IAAI,mBAAmB,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;CACD"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Rights data model — Layer 1 of Warden's unified authorization (Epic 56).
3
+ *
4
+ * The single resolution point: `resolve(user, scope) → EffectivePermissions`.
5
+ * Roles → permissions (RBAC) and direct user → permission grants (ACL) are
6
+ * both keyed by scope (`global` | `{ tenant }`). The store contract is
7
+ * read-only; concrete drivers (the shipped in-memory one, or a copy-in DB
8
+ * adapter) provide seeding/mutation on top.
9
+ */
10
+ /**
11
+ * Resolution scope. `"global"` is the implicit single-tenant scope; a tenant
12
+ * scope is the discriminated object form so it stays type-distinguishable from
13
+ * the global sentinel at call sites.
14
+ */
15
+ export type Scope = "global" | {
16
+ readonly tenant: string;
17
+ };
18
+ /**
19
+ * The single unification point — a user's effective permissions within a scope.
20
+ */
21
+ export interface EffectivePermissions {
22
+ /** True iff the permission is in the resolved set (exact match). */
23
+ has(permission: string): boolean;
24
+ /** True iff ALL listed permissions are present (empty list ⇒ vacuously true). */
25
+ hasAll(permissions: readonly string[]): boolean;
26
+ /** True iff ANY listed permission is present (empty list ⇒ false). */
27
+ hasAny(permissions: readonly string[]): boolean;
28
+ /** The user's effective permissions in this scope (role-derived ∪ direct grants). */
29
+ readonly permissions: ReadonlySet<string>;
30
+ /** The roles that contributed (payload ∪ store, within the resolved scope incl. global). */
31
+ readonly roles: ReadonlySet<string>;
32
+ /** The scope this was resolved for. */
33
+ readonly scope: Scope;
34
+ }
35
+ /**
36
+ * Read contract consulted by the resolver. All methods scoped + async: a
37
+ * DB-backed adapter is inherently async, and the evaluation layer (56.2) is
38
+ * async end-to-end. Writes are NOT part of this contract — drivers add their
39
+ * own seeding API.
40
+ */
41
+ export interface RightsStore {
42
+ /** Permissions a role grants in the given scope (unknown role ⇒ []). */
43
+ rolePermissions(role: string, scope: Scope): Promise<readonly string[]>;
44
+ /** Roles assigned to a user in the given scope (none ⇒ []). */
45
+ userRoles(userId: string, scope: Scope): Promise<readonly string[]>;
46
+ /** Direct per-user permission grants (ACL) in the given scope (none ⇒ []). */
47
+ userGrants(userId: string, scope: Scope): Promise<readonly string[]>;
48
+ }
49
+ /**
50
+ * Stable string key for a scope. `"global"` → `"global"`,
51
+ * `{ tenant: "X" }` → `"tenant:X"`. Used by drivers to key their storage and
52
+ * by 56.3 when threading scope through the evaluation context.
53
+ */
54
+ export declare function scopeKey(scope: Scope): string;
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rights/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,oEAAoE;IACpE,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,iFAAiF;IACjF,MAAM,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IAChD,sEAAsE;IACtE,MAAM,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC;IAChD,qFAAqF;IACrF,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B,wEAAwE;IACxE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACxE,+DAA+D;IAC/D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACpE,8EAA8E;IAC9E,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CACrE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAE7C"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Rights data model — Layer 1 of Warden's unified authorization (Epic 56).
3
+ *
4
+ * The single resolution point: `resolve(user, scope) → EffectivePermissions`.
5
+ * Roles → permissions (RBAC) and direct user → permission grants (ACL) are
6
+ * both keyed by scope (`global` | `{ tenant }`). The store contract is
7
+ * read-only; concrete drivers (the shipped in-memory one, or a copy-in DB
8
+ * adapter) provide seeding/mutation on top.
9
+ */
10
+ /**
11
+ * Stable string key for a scope. `"global"` → `"global"`,
12
+ * `{ tenant: "X" }` → `"tenant:X"`. Used by drivers to key their storage and
13
+ * by 56.3 when threading scope through the evaluation context.
14
+ */
15
+ export function scopeKey(scope) {
16
+ return scope === "global" ? "global" : `tenant:${scope.tenant}`;
17
+ }
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/rights/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0CH;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAY;IACpC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,MAAM,EAAE,CAAC;AACjE,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Default `AuthManager` singleton — mirror of Adonis's
3
+ * `import auth from '@adonisjs/auth/services/main'` shape.
4
+ *
5
+ * import auth from '@c9up/warden/services/main'
6
+ *
7
+ * const result = await auth.verify(bearerToken)
8
+ * if (result.authenticated) { ... }
9
+ *
10
+ * Populated by `WardenProvider.boot()`.
11
+ */
12
+ import type { AuthManager } from "../AuthManager.js";
13
+ /** @internal Bind the singleton (called by WardenProvider). */
14
+ export declare function setAuth(value: AuthManager): void;
15
+ /** @internal Read the singleton (or `undefined` pre-boot). */
16
+ export declare function getAuth(): AuthManager | undefined;
17
+ declare const auth: AuthManager;
18
+ export default auth;
19
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,+DAA+D;AAC/D,wBAAgB,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAEhD;AAED,8DAA8D;AAC9D,wBAAgB,OAAO,IAAI,WAAW,GAAG,SAAS,CAEjD;AAED,QAAA,MAAM,IAAI,EAAE,WAWV,CAAC;AAEH,eAAe,IAAI,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Default `AuthManager` singleton — mirror of Adonis's
3
+ * `import auth from '@adonisjs/auth/services/main'` shape.
4
+ *
5
+ * import auth from '@c9up/warden/services/main'
6
+ *
7
+ * const result = await auth.verify(bearerToken)
8
+ * if (result.authenticated) { ... }
9
+ *
10
+ * Populated by `WardenProvider.boot()`.
11
+ */
12
+ let instance;
13
+ /** @internal Bind the singleton (called by WardenProvider). */
14
+ export function setAuth(value) {
15
+ instance = value;
16
+ }
17
+ /** @internal Read the singleton (or `undefined` pre-boot). */
18
+ export function getAuth() {
19
+ return instance;
20
+ }
21
+ const auth = new Proxy({}, {
22
+ get(_target, prop) {
23
+ if (!instance) {
24
+ throw new Error("[warden] AuthManager singleton accessed before WardenProvider.boot() ran. " +
25
+ "Check that `@c9up/warden/provider` is listed in your reamrc.ts providers.");
26
+ }
27
+ const value = Reflect.get(instance, prop, instance);
28
+ return typeof value === "function" ? value.bind(instance) : value;
29
+ },
30
+ });
31
+ export default auth;
32
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,IAAI,QAAiC,CAAC;AAEtC,+DAA+D;AAC/D,MAAM,UAAU,OAAO,CAAC,KAAkB;IACzC,QAAQ,GAAG,KAAK,CAAC;AAClB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,OAAO;IACtB,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,MAAM,IAAI,GAAgB,IAAI,KAAK,CAAC,EAAiB,EAAE;IACtD,GAAG,CAAC,OAAO,EAAE,IAAI;QAChB,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACd,4EAA4E;gBAC3E,2EAA2E,CAC5E,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACpD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,CAAC;CACD,CAAC,CAAC;AAEH,eAAe,IAAI,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Standalone Warden factory — works without the Ream IoC container.
3
+ *
4
+ * Same pattern as `createBlackhole()`: construct the auth manager from a
5
+ * config object, return a typed handle that Express/Fastify/Hono can use.
6
+ *
7
+ * @example Express
8
+ * import { createWarden } from '@c9up/warden/standalone'
9
+ * const warden = createWarden({
10
+ * defaultStrategy: 'jwt',
11
+ * jwt: { secret: '...', findUser: ..., verifyCredentials: ... },
12
+ * })
13
+ * app.use(warden.expressMiddleware())
14
+ *
15
+ * @example Manual
16
+ * const result = await warden.verify(token)
17
+ * if (!result.authenticated) return res.status(401).json(result)
18
+ */
19
+ import { AuthManager, type AuthResult, type UserPayload } from "./AuthManager.js";
20
+ import type { WardenConfig } from "./config.js";
21
+ export interface Warden {
22
+ /** Verify a bearer token. Returns auth result with user payload. */
23
+ verify(token: string, strategy?: string): Promise<AuthResult>;
24
+ /** Authenticate with credentials (email + password). */
25
+ authenticate(credentials: Record<string, unknown>, strategy?: string): Promise<AuthResult>;
26
+ /** Generate a JWT for a user (jwt strategy only). */
27
+ generateToken(user: UserPayload): Promise<string>;
28
+ /** The underlying AuthManager for advanced use. */
29
+ manager: AuthManager;
30
+ /** Express middleware — extracts Bearer token, verifies, attaches `req.auth`. */
31
+ expressMiddleware(): (req: Record<string, unknown>, res: Record<string, unknown>, next: () => void) => void;
32
+ }
33
+ /**
34
+ * Create a standalone Warden instance — no Ream container needed.
35
+ */
36
+ export declare function createWarden(config: WardenConfig): Warden;
37
+ //# sourceMappingURL=standalone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standalone.d.ts","sourceRoot":"","sources":["../src/standalone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACN,WAAW,EACX,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,WAAW,MAAM;IACtB,oEAAoE;IACpE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9D,wDAAwD;IACxD,YAAY,CACX,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,qDAAqD;IACrD,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,mDAAmD;IACnD,OAAO,EAAE,WAAW,CAAC;IACrB,iFAAiF;IACjF,iBAAiB,IAAI,CACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,IAAI,EAAE,MAAM,IAAI,KACZ,IAAI,CAAC;CACV;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CA6EzD"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Standalone Warden factory — works without the Ream IoC container.
3
+ *
4
+ * Same pattern as `createBlackhole()`: construct the auth manager from a
5
+ * config object, return a typed handle that Express/Fastify/Hono can use.
6
+ *
7
+ * @example Express
8
+ * import { createWarden } from '@c9up/warden/standalone'
9
+ * const warden = createWarden({
10
+ * defaultStrategy: 'jwt',
11
+ * jwt: { secret: '...', findUser: ..., verifyCredentials: ... },
12
+ * })
13
+ * app.use(warden.expressMiddleware())
14
+ *
15
+ * @example Manual
16
+ * const result = await warden.verify(token)
17
+ * if (!result.authenticated) return res.status(401).json(result)
18
+ */
19
+ import { AuthManager, } from "./AuthManager.js";
20
+ import { JwtStrategy } from "./strategies/JwtStrategy.js";
21
+ /**
22
+ * Create a standalone Warden instance — no Ream container needed.
23
+ */
24
+ export function createWarden(config) {
25
+ const strategies = {};
26
+ if (config.jwt) {
27
+ strategies.jwt = new JwtStrategy(config.jwt);
28
+ }
29
+ const manager = new AuthManager({
30
+ defaultStrategy: config.defaultStrategy ?? "jwt",
31
+ strategies,
32
+ });
33
+ return {
34
+ verify: (token, strategy) => manager.verify(token, strategy),
35
+ authenticate: (credentials, strategy) => manager.authenticate(credentials, strategy),
36
+ async generateToken(user) {
37
+ const jwt = manager.getStrategy("jwt");
38
+ return jwt.signToken(user);
39
+ },
40
+ manager,
41
+ expressMiddleware() {
42
+ return (req, res, next) => {
43
+ const headers = req.headers;
44
+ const authHeader = headers?.authorization ?? "";
45
+ const token = typeof authHeader === "string" && authHeader.startsWith("Bearer ")
46
+ ? authHeader.slice(7)
47
+ : "";
48
+ if (!token) {
49
+ res
50
+ .status(401)
51
+ .json({
52
+ error: {
53
+ code: "UNAUTHORIZED",
54
+ message: "Missing authentication token",
55
+ },
56
+ });
57
+ return;
58
+ }
59
+ manager
60
+ .verify(token)
61
+ .then((result) => {
62
+ if (!result.authenticated || !result.user) {
63
+ res
64
+ .status(401)
65
+ .json({
66
+ error: {
67
+ code: "UNAUTHORIZED",
68
+ message: result.error ?? "Authentication failed",
69
+ },
70
+ });
71
+ return;
72
+ }
73
+ // Attach auth result to the request object (Express convention).
74
+ req.auth = result;
75
+ req.user = result.user;
76
+ next();
77
+ })
78
+ .catch(() => {
79
+ res
80
+ .status(500)
81
+ .json({
82
+ error: {
83
+ code: "AUTH_ERROR",
84
+ message: "Internal authentication error",
85
+ },
86
+ });
87
+ });
88
+ };
89
+ },
90
+ };
91
+ }
92
+ //# sourceMappingURL=standalone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standalone.js","sourceRoot":"","sources":["../src/standalone.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACN,WAAW,GAGX,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAsB1D;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAChD,MAAM,UAAU,GAAgC,EAAE,CAAC;IAEnD,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QAChB,UAAU,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,KAAK;QAChD,UAAU;KACV,CAAC,CAAC;IAEH,OAAO;QACN,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC;QAC5D,YAAY,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,EAAE,CACvC,OAAO,CAAC,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC;QAE5C,KAAK,CAAC,aAAa,CAAC,IAAiB;YACpC,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,KAAK,CAAgB,CAAC;YACtD,OAAO,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO;QAEP,iBAAiB;YAChB,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;gBACzB,MAAM,OAAO,GAAG,GAAG,CAAC,OAA6C,CAAC;gBAClE,MAAM,UAAU,GAAG,OAAO,EAAE,aAAa,IAAI,EAAE,CAAC;gBAChD,MAAM,KAAK,GACV,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC;oBACjE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;oBACrB,CAAC,CAAC,EAAE,CAAC;gBAEP,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,GAAiE;yBAChE,MAAM,CAAC,GAAG,CAAC;yBACX,IAAI,CAAC;wBACL,KAAK,EAAE;4BACN,IAAI,EAAE,cAAc;4BACpB,OAAO,EAAE,8BAA8B;yBACvC;qBACD,CAAC,CAAC;oBACJ,OAAO;gBACR,CAAC;gBAED,OAAO;qBACL,MAAM,CAAC,KAAK,CAAC;qBACb,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;oBAChB,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;wBAC1C,GAAiE;6BAChE,MAAM,CAAC,GAAG,CAAC;6BACX,IAAI,CAAC;4BACL,KAAK,EAAE;gCACN,IAAI,EAAE,cAAc;gCACpB,OAAO,EAAE,MAAM,CAAC,KAAK,IAAI,uBAAuB;6BAChD;yBACD,CAAC,CAAC;wBACJ,OAAO;oBACR,CAAC;oBACD,iEAAiE;oBACjE,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC;oBAClB,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;oBACvB,IAAI,EAAE,CAAC;gBACR,CAAC,CAAC;qBACD,KAAK,CAAC,GAAG,EAAE;oBACV,GAAiE;yBAChE,MAAM,CAAC,GAAG,CAAC;yBACX,IAAI,CAAC;wBACL,KAAK,EAAE;4BACN,IAAI,EAAE,YAAY;4BAClB,OAAO,EAAE,+BAA+B;yBACxC;qBACD,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * API Key authentication strategy.
3
+ *
4
+ * Supports: Authorization: Bearer <key> or X-API-Key: <key>
5
+ *
6
+ * @implements MISS-8
7
+ */
8
+ import type { AuthResult, AuthStrategy, UserPayload } from "../AuthManager.js";
9
+ export interface ApiKeyConfig {
10
+ headerName?: string;
11
+ findByKey: (key: string) => Promise<{
12
+ user: UserPayload;
13
+ scopes?: string[];
14
+ } | null>;
15
+ }
16
+ export declare class ApiKeyStrategy implements AuthStrategy {
17
+ #private;
18
+ name: string;
19
+ constructor(config: ApiKeyConfig);
20
+ /** The HTTP header name to extract the API key from. */
21
+ get headerName(): string;
22
+ authenticate(_credentials: {
23
+ email: string;
24
+ password: string;
25
+ }): Promise<AuthResult>;
26
+ verify(token: string): Promise<AuthResult>;
27
+ }
28
+ //# sourceMappingURL=ApiKeyStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiKeyStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/ApiKeyStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,CACV,GAAG,EAAE,MAAM,KACP,OAAO,CAAC;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAC9D;AAED,qBAAa,cAAe,YAAW,YAAY;;IAClD,IAAI,SAAa;gBAIL,MAAM,EAAE,YAAY;IAKhC,wDAAwD;IACxD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAEK,YAAY,CAAC,YAAY,EAAE;QAChC,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,UAAU,CAAC;IAMjB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CAYhD"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * API Key authentication strategy.
3
+ *
4
+ * Supports: Authorization: Bearer <key> or X-API-Key: <key>
5
+ *
6
+ * @implements MISS-8
7
+ */
8
+ export class ApiKeyStrategy {
9
+ name = "api-key";
10
+ #config;
11
+ #headerName;
12
+ constructor(config) {
13
+ this.#config = config;
14
+ this.#headerName = config.headerName ?? "x-api-key";
15
+ }
16
+ /** The HTTP header name to extract the API key from. */
17
+ get headerName() {
18
+ return this.#headerName;
19
+ }
20
+ async authenticate(_credentials) {
21
+ throw new Error("ApiKeyStrategy does not support credential-based auth. Use verify() with the API key.");
22
+ }
23
+ async verify(token) {
24
+ const result = await this.#config.findByKey(token);
25
+ if (!result)
26
+ return { authenticated: false, error: "Invalid API key" };
27
+ const user = { ...result.user };
28
+ if (result.scopes && result.scopes.length > 0) {
29
+ // Merge scopes into permissions without mutating source object.
30
+ const merged = new Set([...(user.permissions ?? []), ...result.scopes]);
31
+ user.permissions = [...merged];
32
+ }
33
+ return { authenticated: true, user };
34
+ }
35
+ }
36
+ //# sourceMappingURL=ApiKeyStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiKeyStrategy.js","sourceRoot":"","sources":["../../src/strategies/ApiKeyStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,MAAM,OAAO,cAAc;IAC1B,IAAI,GAAG,SAAS,CAAC;IACjB,OAAO,CAAe;IACtB,WAAW,CAAS;IAEpB,YAAY,MAAoB;QAC/B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,IAAI,WAAW,CAAC;IACrD,CAAC;IAED,wDAAwD;IACxD,IAAI,UAAU;QACb,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,YAGlB;QACA,MAAM,IAAI,KAAK,CACd,uFAAuF,CACvF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;QAEvE,MAAM,IAAI,GAAgB,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/C,gEAAgE;YAChE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACxE,IAAI,CAAC,WAAW,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACtC,CAAC;CACD"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * JwtStrategy — HMAC-SHA256 JWT authentication strategy.
3
+ * All signing and verification runs through the Rust warden-engine via NAPI.
4
+ */
5
+ import type { AuthResult, AuthStrategy, UserPayload } from "../AuthManager.js";
6
+ import type { TokenBlacklist } from "../TokenBlacklist.js";
7
+ export interface JwtStrategyConfig {
8
+ /**
9
+ * Active signing secret. New tokens are always signed with this key.
10
+ * For zero-downtime key rotation, also pass `previousSecrets` — verify
11
+ * tries each entry until one matches, then `revoke()` the rotated key
12
+ * by removing it from the config on the next deploy.
13
+ */
14
+ secret: string;
15
+ /**
16
+ * Older secrets accepted at verify time but never used to sign new
17
+ * tokens. Empty / omitted by default. Order doesn't matter for
18
+ * correctness but ordering by recency keeps the common path fast.
19
+ */
20
+ previousSecrets?: readonly string[];
21
+ expiresInSeconds?: number;
22
+ findUser: (id: string) => Promise<UserPayload | null>;
23
+ verifyCredentials: (email: string, password: string) => Promise<UserPayload | null>;
24
+ /**
25
+ * Optional blacklist for revocation. When supplied, `verify` rejects
26
+ * tokens whose `jti` is present, and `revoke(token)` adds the token's
27
+ * `jti` to the blacklist for the remainder of its lifetime. Without a
28
+ * blacklist, `revoke()` throws — the call would be a no-op silently.
29
+ */
30
+ blacklist?: TokenBlacklist;
31
+ }
32
+ export declare class JwtStrategy implements AuthStrategy {
33
+ #private;
34
+ name: string;
35
+ constructor(config: JwtStrategyConfig);
36
+ authenticate(credentials: Record<string, unknown>): Promise<AuthResult>;
37
+ verify(token: string): Promise<AuthResult>;
38
+ signToken(user: UserPayload): string;
39
+ /**
40
+ * Revoke a token until its `exp` claim. Requires the strategy to be
41
+ * constructed with a `blacklist` driver — otherwise throws so that a
42
+ * caller assuming revocation does not silently succeed against
43
+ * a no-op implementation.
44
+ *
45
+ * Returns `true` when the token was added to the blacklist, `false` when
46
+ * the token is already expired (revocation is unnecessary) or unparseable.
47
+ */
48
+ revoke(token: string): Promise<boolean>;
49
+ }
50
+ export declare function generateJwtSecret(): string;
51
+ //# sourceMappingURL=JwtStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JwtStrategy.d.ts","sourceRoot":"","sources":["../../src/strategies/JwtStrategy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAwC3D,MAAM,WAAW,iBAAiB;IACjC;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACtD,iBAAiB,EAAE,CAClB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACjC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,qBAAa,WAAY,YAAW,YAAY;;IAC/C,IAAI,SAAS;gBAaD,MAAM,EAAE,iBAAiB;IAgC/B,YAAY,CACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,UAAU,CAAC;IAkBhB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAgChD,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAepC;;;;;;;;OAQG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAa7C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}