@hilbras/keystone 1.9.0 → 2.6.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.
Files changed (155) hide show
  1. package/CHANGELOG.md +459 -0
  2. package/README.md +163 -32
  3. package/dist/config.d.ts +8 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +8 -0
  6. package/dist/config.js.map +1 -1
  7. package/dist/db/migrations/0015_chief_vargas.sql +7 -0
  8. package/dist/db/migrations/0016_gorgeous_charles_xavier.sql +5 -0
  9. package/dist/db/migrations/0017_flashy_nekra.sql +1 -0
  10. package/dist/db/migrations/meta/0015_snapshot.json +4340 -0
  11. package/dist/db/migrations/meta/0016_snapshot.json +4363 -0
  12. package/dist/db/migrations/meta/0017_snapshot.json +4370 -0
  13. package/dist/db/migrations/meta/_journal.json +21 -0
  14. package/dist/db/schema.d.ts +138 -1
  15. package/dist/db/schema.d.ts.map +1 -1
  16. package/dist/db/schema.js +39 -1
  17. package/dist/db/schema.js.map +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +11 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/plugins/auth.d.ts +2 -0
  22. package/dist/plugins/auth.d.ts.map +1 -1
  23. package/dist/plugins/auth.js +21 -7
  24. package/dist/plugins/auth.js.map +1 -1
  25. package/dist/plugins/headerSanitization.d.ts +15 -0
  26. package/dist/plugins/headerSanitization.d.ts.map +1 -0
  27. package/dist/plugins/headerSanitization.js +39 -0
  28. package/dist/plugins/headerSanitization.js.map +1 -0
  29. package/dist/plugins/machinePrincipal.d.ts +28 -0
  30. package/dist/plugins/machinePrincipal.d.ts.map +1 -0
  31. package/dist/plugins/machinePrincipal.js +45 -0
  32. package/dist/plugins/machinePrincipal.js.map +1 -0
  33. package/dist/plugins/mtls.d.ts +21 -2
  34. package/dist/plugins/mtls.d.ts.map +1 -1
  35. package/dist/plugins/mtls.js +94 -47
  36. package/dist/plugins/mtls.js.map +1 -1
  37. package/dist/plugins/rateLimit.d.ts +5 -4
  38. package/dist/plugins/rateLimit.d.ts.map +1 -1
  39. package/dist/plugins/rateLimit.js +11 -8
  40. package/dist/plugins/rateLimit.js.map +1 -1
  41. package/dist/repositories/application.d.ts +1 -1
  42. package/dist/repositories/application.d.ts.map +1 -1
  43. package/dist/repositories/application.js +8 -2
  44. package/dist/repositories/application.js.map +1 -1
  45. package/dist/repositories/session.d.ts +1 -0
  46. package/dist/repositories/session.d.ts.map +1 -1
  47. package/dist/repositories/types.d.ts +5 -1
  48. package/dist/repositories/types.d.ts.map +1 -1
  49. package/dist/routes/admin/organizations.d.ts.map +1 -1
  50. package/dist/routes/admin/organizations.js +31 -2
  51. package/dist/routes/admin/organizations.js.map +1 -1
  52. package/dist/routes/apiKeys.d.ts.map +1 -1
  53. package/dist/routes/apiKeys.js +23 -5
  54. package/dist/routes/apiKeys.js.map +1 -1
  55. package/dist/routes/federation.d.ts.map +1 -1
  56. package/dist/routes/federation.js +8 -2
  57. package/dist/routes/federation.js.map +1 -1
  58. package/dist/routes/oauth.d.ts.map +1 -1
  59. package/dist/routes/oauth.js +38 -2
  60. package/dist/routes/oauth.js.map +1 -1
  61. package/dist/routes/oauth2.d.ts.map +1 -1
  62. package/dist/routes/oauth2.js +92 -13
  63. package/dist/routes/oauth2.js.map +1 -1
  64. package/dist/routes/profile.js +2 -2
  65. package/dist/routes/profile.js.map +1 -1
  66. package/dist/routes/saml.d.ts +24 -0
  67. package/dist/routes/saml.d.ts.map +1 -1
  68. package/dist/routes/saml.js +32 -3
  69. package/dist/routes/saml.js.map +1 -1
  70. package/dist/routes/serviceAccounts.d.ts.map +1 -1
  71. package/dist/routes/serviceAccounts.js +78 -2
  72. package/dist/routes/serviceAccounts.js.map +1 -1
  73. package/dist/routes/sessions.js +3 -3
  74. package/dist/routes/sessions.js.map +1 -1
  75. package/dist/routes/smsOtp.d.ts.map +1 -1
  76. package/dist/routes/smsOtp.js +6 -0
  77. package/dist/routes/smsOtp.js.map +1 -1
  78. package/dist/routes/totp.d.ts.map +1 -1
  79. package/dist/routes/totp.js +24 -10
  80. package/dist/routes/totp.js.map +1 -1
  81. package/dist/routes/webauthn.d.ts.map +1 -1
  82. package/dist/routes/webauthn.js +8 -2
  83. package/dist/routes/webauthn.js.map +1 -1
  84. package/dist/sdk/index.d.ts.map +1 -1
  85. package/dist/sdk/index.js.map +1 -1
  86. package/dist/sdk/types.d.ts +4 -1
  87. package/dist/sdk/types.d.ts.map +1 -1
  88. package/dist/services/application/organization.d.ts +5 -1
  89. package/dist/services/application/organization.d.ts.map +1 -1
  90. package/dist/services/application/organization.js.map +1 -1
  91. package/dist/services/connectors/google.d.ts +18 -1
  92. package/dist/services/connectors/google.d.ts.map +1 -1
  93. package/dist/services/connectors/google.js +25 -3
  94. package/dist/services/connectors/google.js.map +1 -1
  95. package/dist/services/connectors/oidc.d.ts +14 -2
  96. package/dist/services/connectors/oidc.d.ts.map +1 -1
  97. package/dist/services/connectors/oidc.js +29 -3
  98. package/dist/services/connectors/oidc.js.map +1 -1
  99. package/dist/services/connectors/types.d.ts +13 -1
  100. package/dist/services/connectors/types.d.ts.map +1 -1
  101. package/dist/services/domain/authentication.d.ts.map +1 -1
  102. package/dist/services/domain/authentication.js +36 -19
  103. package/dist/services/domain/authentication.js.map +1 -1
  104. package/dist/services/domain/organization.d.ts +5 -1
  105. package/dist/services/domain/organization.d.ts.map +1 -1
  106. package/dist/services/domain/organization.js.map +1 -1
  107. package/dist/services/events/types.d.ts +1 -1
  108. package/dist/services/events/types.d.ts.map +1 -1
  109. package/dist/services/events/validate.d.ts.map +1 -1
  110. package/dist/services/events/validate.js +6 -0
  111. package/dist/services/events/validate.js.map +1 -1
  112. package/dist/services/magicLinks.d.ts.map +1 -1
  113. package/dist/services/magicLinks.js +13 -9
  114. package/dist/services/magicLinks.js.map +1 -1
  115. package/dist/services/oauth2.d.ts +72 -2
  116. package/dist/services/oauth2.d.ts.map +1 -1
  117. package/dist/services/oauth2.js +106 -6
  118. package/dist/services/oauth2.js.map +1 -1
  119. package/dist/services/redirectUri.d.ts +56 -0
  120. package/dist/services/redirectUri.d.ts.map +1 -0
  121. package/dist/services/redirectUri.js +129 -0
  122. package/dist/services/redirectUri.js.map +1 -0
  123. package/dist/services/scopes.d.ts +113 -0
  124. package/dist/services/scopes.d.ts.map +1 -0
  125. package/dist/services/scopes.js +138 -0
  126. package/dist/services/scopes.js.map +1 -0
  127. package/dist/services/serviceAccounts.d.ts +20 -0
  128. package/dist/services/serviceAccounts.d.ts.map +1 -1
  129. package/dist/services/serviceAccounts.js +47 -1
  130. package/dist/services/serviceAccounts.js.map +1 -1
  131. package/dist/services/sessionRevocation.d.ts +76 -0
  132. package/dist/services/sessionRevocation.d.ts.map +1 -0
  133. package/dist/services/sessionRevocation.js +86 -0
  134. package/dist/services/sessionRevocation.js.map +1 -0
  135. package/dist/services/singleUse.d.ts +68 -0
  136. package/dist/services/singleUse.d.ts.map +1 -0
  137. package/dist/services/singleUse.js +54 -0
  138. package/dist/services/singleUse.js.map +1 -0
  139. package/dist/services/smsOtp.d.ts.map +1 -1
  140. package/dist/services/smsOtp.js +12 -8
  141. package/dist/services/smsOtp.js.map +1 -1
  142. package/dist/services/tokens.d.ts +2 -0
  143. package/dist/services/tokens.d.ts.map +1 -1
  144. package/dist/services/tokens.js +5 -0
  145. package/dist/services/tokens.js.map +1 -1
  146. package/dist/services/trustedProxies.d.ts +90 -0
  147. package/dist/services/trustedProxies.d.ts.map +1 -0
  148. package/dist/services/trustedProxies.js +283 -0
  149. package/dist/services/trustedProxies.js.map +1 -0
  150. package/dist/setup-server.js +2 -1
  151. package/dist/setup-server.js.map +1 -1
  152. package/dist/types.d.ts +2 -2
  153. package/dist/types.d.ts.map +1 -1
  154. package/dist/types.js.map +1 -1
  155. package/package.json +4 -5
@@ -3,6 +3,7 @@ export declare function createServiceAccount(input: {
3
3
  orgId: string;
4
4
  name: string;
5
5
  description?: string;
6
+ certFingerprint?: string | null;
6
7
  }): Promise<ServiceAccount>;
7
8
  export declare function findServiceAccountsByOrgId(orgId: string): Promise<ServiceAccount[]>;
8
9
  export declare function findServiceAccountById(id: string, orgId: string): Promise<ServiceAccount | undefined>;
@@ -11,6 +12,25 @@ export declare function updateServiceAccount(id: string, orgId: string, updates:
11
12
  description: string;
12
13
  isActive: boolean;
13
14
  }>): Promise<ServiceAccount | undefined>;
15
+ /**
16
+ * Bind or clear the client certificate this account authenticates with.
17
+ *
18
+ * Clearing sets the column to null, which removes certificate authentication
19
+ * for the account entirely — an unbound account can only use an API key. The
20
+ * unique index on `cert_fingerprint` is what stops one certificate being bound
21
+ * to two accounts; a conflict surfaces as an error here rather than silently
22
+ * picking a winner.
23
+ *
24
+ * @throws if `fingerprint` is not a well-formed SHA-256 digest, or if the
25
+ * certificate is already bound to a different account.
26
+ */
27
+ export declare function setServiceAccountCertificate(id: string, orgId: string, fingerprint: string | null): Promise<ServiceAccount | undefined>;
28
+ /**
29
+ * Permanently stop an account authenticating. Kept separate from
30
+ * `isActive: false` so a later reactivation cannot silently restore access —
31
+ * reactivation requires clearing `revokedAt` deliberately.
32
+ */
33
+ export declare function revokeServiceAccount(id: string, orgId: string): Promise<ServiceAccount | undefined>;
14
34
  export declare function listServiceAccountApiKeys(serviceAccountId: string): Promise<{
15
35
  id: string;
16
36
  name: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"serviceAccounts.d.ts","sourceRoot":"","sources":["../../src/services/serviceAccounts.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEhF,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,cAAc,CAAC,CAU1B;AAED,wBAAsB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAMzF;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAarC;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,GACzE,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAOrC;AAED,wBAAsB,yBAAyB,CAAC,gBAAgB,EAAE,MAAM;;;;;;;;;KAcvE"}
1
+ {"version":3,"file":"serviceAccounts.d.ts","sourceRoot":"","sources":["../../src/services/serviceAccounts.ts"],"names":[],"mappings":"AAGA,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEhF,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,GAAG,OAAO,CAAC,cAAc,CAAC,CAW1B;AAED,wBAAsB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAMzF;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAarC;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,GACzE,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAOrC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,4BAA4B,CAChD,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAmBrC;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAOrC;AAED,wBAAsB,yBAAyB,CAAC,gBAAgB,EAAE,MAAM;;;;;;;;;KAcvE"}
@@ -1,4 +1,5 @@
1
- import { eq, and, sql } from "drizzle-orm";
1
+ import { eq, and, isNull, sql } from "drizzle-orm";
2
+ import { canonicalFingerprint, isValidFingerprint } from "./trustedProxies.js";
2
3
  import { db } from "../db/index.js";
3
4
  import { serviceAccounts, apiKeys } from "../db/schema.js";
4
5
  export async function createServiceAccount(input) {
@@ -8,6 +9,7 @@ export async function createServiceAccount(input) {
8
9
  orgId: input.orgId,
9
10
  name: input.name,
10
11
  description: input.description ?? null,
12
+ certFingerprint: input.certFingerprint ?? null,
11
13
  })
12
14
  .returning();
13
15
  return record;
@@ -35,6 +37,50 @@ export async function updateServiceAccount(id, orgId, updates) {
35
37
  .returning();
36
38
  return updated;
37
39
  }
40
+ /**
41
+ * Bind or clear the client certificate this account authenticates with.
42
+ *
43
+ * Clearing sets the column to null, which removes certificate authentication
44
+ * for the account entirely — an unbound account can only use an API key. The
45
+ * unique index on `cert_fingerprint` is what stops one certificate being bound
46
+ * to two accounts; a conflict surfaces as an error here rather than silently
47
+ * picking a winner.
48
+ *
49
+ * @throws if `fingerprint` is not a well-formed SHA-256 digest, or if the
50
+ * certificate is already bound to a different account.
51
+ */
52
+ export async function setServiceAccountCertificate(id, orgId, fingerprint) {
53
+ // Canonicalize here rather than trusting the caller. The hex and
54
+ // colon-separated spellings of one certificate must not become two bindings,
55
+ // and this is the only place every caller is guaranteed to pass through.
56
+ let canonical = null;
57
+ if (fingerprint !== null) {
58
+ const trimmed = fingerprint.trim();
59
+ if (!isValidFingerprint(trimmed)) {
60
+ throw new Error("fingerprint must be a SHA-256 digest (64 hex characters)");
61
+ }
62
+ canonical = canonicalFingerprint(trimmed);
63
+ }
64
+ const [updated] = await db
65
+ .update(serviceAccounts)
66
+ .set({ certFingerprint: canonical, updatedAt: sql `now()` })
67
+ .where(and(eq(serviceAccounts.id, id), eq(serviceAccounts.orgId, orgId)))
68
+ .returning();
69
+ return updated;
70
+ }
71
+ /**
72
+ * Permanently stop an account authenticating. Kept separate from
73
+ * `isActive: false` so a later reactivation cannot silently restore access —
74
+ * reactivation requires clearing `revokedAt` deliberately.
75
+ */
76
+ export async function revokeServiceAccount(id, orgId) {
77
+ const [updated] = await db
78
+ .update(serviceAccounts)
79
+ .set({ isActive: false, revokedAt: sql `now()`, updatedAt: sql `now()` })
80
+ .where(and(eq(serviceAccounts.id, id), eq(serviceAccounts.orgId, orgId), isNull(serviceAccounts.revokedAt)))
81
+ .returning();
82
+ return updated;
83
+ }
38
84
  export async function listServiceAccountApiKeys(serviceAccountId) {
39
85
  return db
40
86
  .select({
@@ -1 +1 @@
1
- {"version":3,"file":"serviceAccounts.js","sourceRoot":"","sources":["../../src/services/serviceAccounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAuB,MAAM,iBAAiB,CAAC;AAEhF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAI1C;IACC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE;SACtB,MAAM,CAAC,eAAe,CAAC;SACvB,MAAM,CAAC;QACN,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;KACvC,CAAC;SACD,SAAS,EAAE,CAAC;IACf,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,KAAa;IAC5D,OAAO,EAAE;SACN,MAAM,EAAE;SACR,IAAI,CAAC,eAAe,CAAC;SACrB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;SAChF,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,EAAU,EACV,KAAa;IAEb,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE;SACtB,MAAM,EAAE;SACR,IAAI,CAAC,eAAe,CAAC;SACrB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,EAC1B,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,EAChC,EAAE,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CACnC,CACF;SACA,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,EAAU,EACV,KAAa,EACb,OAA0E;IAE1E,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE;SACvB,MAAM,CAAC,eAAe,CAAC;SACvB,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,GAAG,CAAA,OAAO,EAAE,CAAC;SAC1C,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;SACxE,SAAS,EAAE,CAAC;IACf,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,gBAAwB;IACtE,OAAO,EAAE;SACN,MAAM,CAAC;QACN,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC;SACD,IAAI,CAAC,OAAO,CAAC;SACb,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"serviceAccounts.js","sourceRoot":"","sources":["../../src/services/serviceAccounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Centralized credential revocation.
3
+ *
4
+ * Every "this account should stop being logged in" operation routes through
5
+ * here. Before this existed, revocation was open-coded per call site, and the
6
+ * most important call site was missing entirely: completing a password reset
7
+ * changed the password and left every existing session and refresh token
8
+ * working. That defeats the purpose of a reset, which is the standard response
9
+ * to a suspected compromise — the intruder keeps their session.
10
+ *
11
+ * The primitives below are deliberately separate so a caller can be precise
12
+ * about what it invalidates, and so the composite operations are visibly
13
+ * composed rather than reimplemented at each site.
14
+ */
15
+ export interface RevocationCounts {
16
+ refreshTokens: number;
17
+ sessions: number;
18
+ recoveryCredentials: number;
19
+ }
20
+ export interface RevokeOptions {
21
+ /**
22
+ * Keep this session and its refresh token alive, for a change the user is
23
+ * making to their own account.
24
+ *
25
+ * Never pass it on a reset the user did not initiate themselves: the current
26
+ * session is precisely what an attacker would be holding, and preserving it
27
+ * would leave them in.
28
+ */
29
+ exceptSessionId?: string;
30
+ /** Keep this refresh token alive, for the same reason. */
31
+ exceptRefreshTokenId?: string;
32
+ }
33
+ /**
34
+ * Revoke the user's refresh tokens, so no further access token can be minted
35
+ * from an existing session.
36
+ */
37
+ export declare function revokeRefreshTokens(userId: string, options?: RevokeOptions): Promise<number>;
38
+ /**
39
+ * Revoke the user's authentication sessions.
40
+ *
41
+ * A revoked session stops authorising requests immediately; it is not merely
42
+ * hidden from a session list.
43
+ */
44
+ export declare function revokeAuthenticationSessions(userId: string, options?: RevokeOptions): Promise<number>;
45
+ /**
46
+ * Revoke outstanding recovery credentials.
47
+ *
48
+ * A reset token already sitting in someone's inbox stays valid until it
49
+ * expires unless it is spent here. Someone who intercepted an earlier reset
50
+ * email could otherwise complete it after the user had already recovered.
51
+ */
52
+ export declare function revokeRecoveryCredentials(userId: string): Promise<number>;
53
+ /**
54
+ * Log the user out everywhere: sessions and refresh tokens together.
55
+ *
56
+ * This is what most credential changes want. Revoking only one leaves a live
57
+ * credential behind: a session with no refresh token still authorises requests
58
+ * until it expires, and a refresh token with no session can still mint access
59
+ * tokens.
60
+ */
61
+ export declare function revokeUserSessions(userId: string, options?: RevokeOptions): Promise<RevocationCounts>;
62
+ /**
63
+ * Everything: sessions, refresh tokens, and outstanding recovery credentials.
64
+ *
65
+ * Used after a password reset.
66
+ *
67
+ * API keys are deliberately **not** revoked. They are separately issued,
68
+ * long-lived credentials belonging to integrations rather than to the person,
69
+ * and silently killing them on a password reset breaks deployments without
70
+ * improving the account's own security. The residual gap is real — an API key
71
+ * minted by an attacker who already held the password survives — and the right
72
+ * answer is key expiry and rotation rather than coupling key lifetime to a
73
+ * human's password.
74
+ */
75
+ export declare function revokeAllUserCredentials(userId: string, options?: RevokeOptions): Promise<RevocationCounts>;
76
+ //# sourceMappingURL=sessionRevocation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionRevocation.d.ts","sourceRoot":"","sources":["../../src/services/sessionRevocation.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAID;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/E;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CAI3B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CAK3B"}
@@ -0,0 +1,86 @@
1
+ import { and, eq, isNull, ne } from "drizzle-orm";
2
+ import { db } from "../db/index.js";
3
+ import { passwordResetTokens, refreshTokens, userSessions } from "../db/schema.js";
4
+ const EMPTY = { refreshTokens: 0, sessions: 0, recoveryCredentials: 0 };
5
+ /**
6
+ * Revoke the user's refresh tokens, so no further access token can be minted
7
+ * from an existing session.
8
+ */
9
+ export async function revokeRefreshTokens(userId, options = {}) {
10
+ const conditions = [eq(refreshTokens.userId, userId), isNull(refreshTokens.revokedAt)];
11
+ if (options.exceptRefreshTokenId) {
12
+ conditions.push(ne(refreshTokens.id, options.exceptRefreshTokenId));
13
+ }
14
+ const rows = await db
15
+ .update(refreshTokens)
16
+ .set({ revokedAt: new Date() })
17
+ .where(and(...conditions))
18
+ .returning({ id: refreshTokens.id });
19
+ return rows.length;
20
+ }
21
+ /**
22
+ * Revoke the user's authentication sessions.
23
+ *
24
+ * A revoked session stops authorising requests immediately; it is not merely
25
+ * hidden from a session list.
26
+ */
27
+ export async function revokeAuthenticationSessions(userId, options = {}) {
28
+ const conditions = [eq(userSessions.userId, userId), isNull(userSessions.revokedAt)];
29
+ if (options.exceptSessionId) {
30
+ conditions.push(ne(userSessions.id, options.exceptSessionId));
31
+ }
32
+ const rows = await db
33
+ .update(userSessions)
34
+ .set({ revokedAt: new Date() })
35
+ .where(and(...conditions))
36
+ .returning({ id: userSessions.id });
37
+ return rows.length;
38
+ }
39
+ /**
40
+ * Revoke outstanding recovery credentials.
41
+ *
42
+ * A reset token already sitting in someone's inbox stays valid until it
43
+ * expires unless it is spent here. Someone who intercepted an earlier reset
44
+ * email could otherwise complete it after the user had already recovered.
45
+ */
46
+ export async function revokeRecoveryCredentials(userId) {
47
+ const rows = await db
48
+ .update(passwordResetTokens)
49
+ .set({ usedAt: new Date() })
50
+ .where(and(eq(passwordResetTokens.userId, userId), isNull(passwordResetTokens.usedAt)))
51
+ .returning({ id: passwordResetTokens.id });
52
+ return rows.length;
53
+ }
54
+ /**
55
+ * Log the user out everywhere: sessions and refresh tokens together.
56
+ *
57
+ * This is what most credential changes want. Revoking only one leaves a live
58
+ * credential behind: a session with no refresh token still authorises requests
59
+ * until it expires, and a refresh token with no session can still mint access
60
+ * tokens.
61
+ */
62
+ export async function revokeUserSessions(userId, options = {}) {
63
+ const sessions = await revokeAuthenticationSessions(userId, options);
64
+ const refreshTokensRevoked = await revokeRefreshTokens(userId, options);
65
+ return { ...EMPTY, sessions, refreshTokens: refreshTokensRevoked };
66
+ }
67
+ /**
68
+ * Everything: sessions, refresh tokens, and outstanding recovery credentials.
69
+ *
70
+ * Used after a password reset.
71
+ *
72
+ * API keys are deliberately **not** revoked. They are separately issued,
73
+ * long-lived credentials belonging to integrations rather than to the person,
74
+ * and silently killing them on a password reset breaks deployments without
75
+ * improving the account's own security. The residual gap is real — an API key
76
+ * minted by an attacker who already held the password survives — and the right
77
+ * answer is key expiry and rotation rather than coupling key lifetime to a
78
+ * human's password.
79
+ */
80
+ export async function revokeAllUserCredentials(userId, options = {}) {
81
+ const sessions = await revokeAuthenticationSessions(userId, options);
82
+ const refreshTokensRevoked = await revokeRefreshTokens(userId, options);
83
+ const recoveryCredentials = await revokeRecoveryCredentials(userId);
84
+ return { sessions, refreshTokens: refreshTokensRevoked, recoveryCredentials };
85
+ }
86
+ //# sourceMappingURL=sessionRevocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionRevocation.js","sourceRoot":"","sources":["../../src/services/sessionRevocation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAqCnF,MAAM,KAAK,GAAqB,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC;AAE1F;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc,EACd,OAAO,GAAkB,EAAE;IAE3B,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IACvF,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;QACjC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,MAAM,CAAC,aAAa,CAAC;SACrB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;SAC9B,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;SACzB,SAAS,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,MAAc,EACd,OAAO,GAAkB,EAAE;IAE3B,MAAM,UAAU,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,MAAM,CAAC,YAAY,CAAC;SACpB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;SAC9B,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;SACzB,SAAS,CAAC,EAAE,EAAE,EAAE,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,MAAc;IAC5D,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,MAAM,CAAC,mBAAmB,CAAC;SAC3B,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;SAC3B,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;SACtF,SAAS,CAAC,EAAE,EAAE,EAAE,mBAAmB,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,OAAO,GAAkB,EAAE;IAE3B,MAAM,QAAQ,GAAG,MAAM,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrE,MAAM,oBAAoB,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxE,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,oBAAoB,EAAE,CAAC;AACrE,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAAc,EACd,OAAO,GAAkB,EAAE;IAE3B,MAAM,QAAQ,GAAG,MAAM,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrE,MAAM,oBAAoB,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxE,MAAM,mBAAmB,GAAG,MAAM,yBAAyB,CAAC,MAAM,CAAC,CAAC;IACpE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;AAChF,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { magicLinks, passwordResetTokens, smsOtpCodes } from "../db/schema.js";
2
+ /**
3
+ * Atomic consumption of single-use credentials.
4
+ *
5
+ * A single-use credential has one dangerous shape, and it is always the same:
6
+ *
7
+ * ```text
8
+ * SELECT ... WHERE used_at IS NULL <- conditional
9
+ * if (!row) return
10
+ * UPDATE ... SET used_at = now() <- UNCONDITIONAL: the race
11
+ * ```
12
+ *
13
+ * Between the SELECT and the UPDATE, any number of concurrent requests can pass
14
+ * the same check. A magic link redeemed by ten parallel requests logs in ten
15
+ * times; a password reset token spent ten times over writes ten different
16
+ * passwords, last writer winning.
17
+ *
18
+ * The fix is to make the write itself the gate:
19
+ *
20
+ * ```text
21
+ * UPDATE ... SET used_at = now()
22
+ * WHERE token_hash = ? AND expires_at > now() AND used_at IS NULL
23
+ * RETURNING ...
24
+ * ```
25
+ *
26
+ * PostgreSQL evaluates that predicate while holding a row lock, so exactly one
27
+ * transaction can update the row and see a returned row. Everyone else matches
28
+ * zero rows. The claim and the validation are one statement, so there is no
29
+ * window between them to lose.
30
+ *
31
+ * All consumption goes through here so the pattern exists once. A credential
32
+ * that consumes its own token inline is a credential that can be raced.
33
+ */
34
+ export type ConsumeOutcome =
35
+ /** This caller claimed the credential. */
36
+ "consumed"
37
+ /** A row exists but was already spent. Somebody replayed it. */
38
+ | "replayed"
39
+ /** A row exists but has passed its expiry. */
40
+ | "expired"
41
+ /** No row for this value. */
42
+ | "not_found";
43
+ export interface ConsumeResult<T> {
44
+ outcome: ConsumeOutcome;
45
+ /** Present only when `outcome` is `consumed`. */
46
+ record?: T;
47
+ /**
48
+ * Why the credential was refused. Set for `replayed` and `expired`; omitted
49
+ * for `not_found`, so a caller cannot distinguish "never existed" from
50
+ * "deleted", which is itself information.
51
+ */
52
+ reason?: "replayed" | "expired";
53
+ }
54
+ export type MagicLinkRow = typeof magicLinks.$inferSelect;
55
+ export type PasswordResetTokenRow = typeof passwordResetTokens.$inferSelect;
56
+ export type SmsOtpCodeRow = typeof smsOtpCodes.$inferSelect;
57
+ /** Atomically consume a magic link. */
58
+ export declare function consumeMagicLinkRow(tokenHash: string, now: Date): Promise<ConsumeResult<MagicLinkRow>>;
59
+ /** Atomically consume a password reset token. */
60
+ export declare function consumePasswordResetTokenRow(tokenHash: string, now: Date): Promise<ConsumeResult<PasswordResetTokenRow>>;
61
+ /**
62
+ * Atomically consume an SMS OTP code.
63
+ *
64
+ * Scoped to the user as well as the code. A code is six digits, so a lookup on
65
+ * the hash alone could let one user's code be spent against another's row.
66
+ */
67
+ export declare function consumeSmsOtpCodeRow(userId: string, codeHash: string, now: Date): Promise<ConsumeResult<SmsOtpCodeRow>>;
68
+ //# sourceMappingURL=singleUse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleUse.d.ts","sourceRoot":"","sources":["../../src/services/singleUse.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,MAAM,MAAM,cAAc;AACxB,0CAA0C;AACxC,UAAU;AACZ,gEAAgE;GAC9D,UAAU;AACZ,8CAA8C;GAC5C,SAAS;AACX,6BAA6B;GAC3B,WAAW,CAAC;AAEhB,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,OAAO,EAAE,cAAc,CAAC;IACxB,iDAAiD;IACjD,MAAM,CAAC,EAAE,CAAC,CAAC;IACX;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACjC;AAuED,MAAM,MAAM,YAAY,GAAG,OAAO,UAAU,CAAC,YAAY,CAAC;AAC1D,MAAM,MAAM,qBAAqB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAC;AAC5E,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AAE5D,uCAAuC;AACvC,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAEtC;AAED,iDAAiD;AACjD,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAO/C;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAQvC"}
@@ -0,0 +1,54 @@
1
+ import { and, eq, gt, isNull } from "drizzle-orm";
2
+ import { db } from "../db/index.js";
3
+ import { magicLinks, passwordResetTokens, smsOtpCodes } from "../db/schema.js";
4
+ async function claimAndClassify(table, hashColumn, hashValue, now, extra) {
5
+ const predicate = and(eq(hashColumn, hashValue), gt(table.expiresAt, now), isNull(table.usedAt), extra);
6
+ const claimed = (await db
7
+ .update(table)
8
+ .set({ usedAt: now })
9
+ .where(predicate)
10
+ .returning());
11
+ if (claimed.length === 1) {
12
+ return { outcome: "consumed", record: claimed[0] };
13
+ }
14
+ if (claimed.length > 1) {
15
+ // The hash column is not unique, so "single use" cannot mean anything.
16
+ throw new Error(`atomic claim matched ${claimed.length} rows; the hash column must be unique`);
17
+ }
18
+ // Why could we not claim it? Only worth distinguishing a replay, because that
19
+ // means the credential leaked and somebody came back with it.
20
+ const [existing] = (await db
21
+ .select()
22
+ .from(table)
23
+ .where(and(eq(hashColumn, hashValue), extra))
24
+ .limit(1));
25
+ if (!existing)
26
+ return { outcome: "not_found" };
27
+ if (existing.usedAt)
28
+ return { outcome: "replayed", reason: "replayed" };
29
+ if (existing.expiresAt.getTime() <= now.getTime()) {
30
+ return { outcome: "expired", reason: "expired" };
31
+ }
32
+ // Present, unused, and unexpired, yet the claim matched nothing: another
33
+ // transaction won the race between the two statements. From here that is a
34
+ // replay.
35
+ return { outcome: "replayed", reason: "replayed" };
36
+ }
37
+ /** Atomically consume a magic link. */
38
+ export function consumeMagicLinkRow(tokenHash, now) {
39
+ return claimAndClassify(magicLinks, magicLinks.tokenHash, tokenHash, now);
40
+ }
41
+ /** Atomically consume a password reset token. */
42
+ export function consumePasswordResetTokenRow(tokenHash, now) {
43
+ return claimAndClassify(passwordResetTokens, passwordResetTokens.tokenHash, tokenHash, now);
44
+ }
45
+ /**
46
+ * Atomically consume an SMS OTP code.
47
+ *
48
+ * Scoped to the user as well as the code. A code is six digits, so a lookup on
49
+ * the hash alone could let one user's code be spent against another's row.
50
+ */
51
+ export function consumeSmsOtpCodeRow(userId, codeHash, now) {
52
+ return claimAndClassify(smsOtpCodes, smsOtpCodes.codeHash, codeHash, now, eq(smsOtpCodes.userId, userId));
53
+ }
54
+ //# sourceMappingURL=singleUse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleUse.js","sourceRoot":"","sources":["../../src/services/singleUse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAY,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA4E/E,KAAK,UAAU,gBAAgB,CAC7B,KAAqB,EACrB,UAAoB,EACpB,SAAiB,EACjB,GAAS,EACT,KAAW;IAEX,MAAM,SAAS,GAAG,GAAG,CACnB,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EACzB,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,EACxB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EACpB,KAAK,CACN,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE;SACtB,MAAM,CAAC,KAAK,CAAC;SACb,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;SACpB,KAAK,CAAC,SAAS,CAAC;SAChB,SAAS,EAAE,CAAQ,CAAC;IAEvB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,uEAAuE;QACvE,MAAM,IAAI,KAAK,CACb,wBAAwB,OAAO,CAAC,MAAM,uCAAuC,CAC9E,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,8DAA8D;IAC9D,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE;SACzB,MAAM,EAAE;SACR,IAAI,CAAC,KAAK,CAAC;SACX,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;SAC5C,KAAK,CAAC,CAAC,CAAC,CAAQ,CAAC;IAEpB,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAC/C,IAAI,QAAQ,CAAC,MAAM;QAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACxE,IAAI,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACnD,CAAC;IAED,yEAAyE;IACzE,2EAA2E;IAC3E,UAAU;IACV,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACrD,CAAC;AAMD,uCAAuC;AACvC,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,GAAS;IAET,OAAO,gBAAgB,CAAe,UAAU,EAAE,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;AAC1F,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,4BAA4B,CAC1C,SAAiB,EACjB,GAAS;IAET,OAAO,gBAAgB,CACrB,mBAAmB,EACnB,mBAAmB,CAAC,SAAS,EAC7B,SAAS,EACT,GAAG,CACJ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAc,EACd,QAAgB,EAChB,GAAS;IAET,OAAO,gBAAgB,CACrB,WAAW,EACX,WAAW,CAAC,QAAQ,EACpB,QAAQ,EACR,GAAG,EACH,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAC/B,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"smsOtp.d.ts","sourceRoot":"","sources":["../../src/services/smsOtp.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAMhE,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAMD,wBAAsB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBjF;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqBjF;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOvE;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK1F"}
1
+ {"version":3,"file":"smsOtp.d.ts","sourceRoot":"","sources":["../../src/services/smsOtp.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAQhE,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAMD,wBAAsB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBjF;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAejF;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOvE;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK1F"}
@@ -1,8 +1,10 @@
1
1
  import crypto from "node:crypto";
2
- import { eq, and, gt, isNull } from "drizzle-orm";
2
+ import { eq } from "drizzle-orm";
3
3
  import { db } from "../db/index.js";
4
4
  import { smsOtpCodes, users } from "../db/schema.js";
5
5
  import { smsProvider } from "./sms.js";
6
+ import { consumeSmsOtpCodeRow } from "./singleUse.js";
7
+ import { emit } from "./events/bus.js";
6
8
  const CODE_TTL_SECONDS = 300;
7
9
  const CODE_LENGTH = 6;
8
10
  export function generateSmsCode() {
@@ -29,14 +31,16 @@ export async function sendSmsOtp(user, phoneNumber) {
29
31
  export async function verifySmsOtp(userId, code) {
30
32
  const codeHash = hashCode(code);
31
33
  const now = new Date();
32
- const [record] = await db
33
- .select()
34
- .from(smsOtpCodes)
35
- .where(and(eq(smsOtpCodes.userId, userId), eq(smsOtpCodes.codeHash, codeHash), gt(smsOtpCodes.expiresAt, now), isNull(smsOtpCodes.usedAt)))
36
- .limit(1);
37
- if (!record)
34
+ // Claim atomically, so a code cannot be spent by two parallel verifications.
35
+ // Scoped to the user as well as the hash: a six-digit code is short enough
36
+ // that a global lookup could collide across accounts.
37
+ const result = await consumeSmsOtpCodeRow(userId, codeHash, now);
38
+ if (result.outcome !== "consumed") {
39
+ if (result.reason === "replayed") {
40
+ emit({ type: "sms_otp_replayed", payload: { userId } });
41
+ }
38
42
  return false;
39
- await db.update(smsOtpCodes).set({ usedAt: now }).where(eq(smsOtpCodes.id, record.id));
43
+ }
40
44
  return true;
41
45
  }
42
46
  export async function hasVerifiedPhone(userId) {
@@ -1 +1 @@
1
- {"version":3,"file":"smsOtp.js","sourceRoot":"","sources":["../../src/services/smsOtp.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAa,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,MAAM,UAAU,eAAe;IAC7B,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAU,EAAE,WAAmB;IAC9D,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAEjE,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC;QAClC,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,WAAW;QACX,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC;QACxB,SAAS;KACV,CAAC,CAAC;IAEH,MAAM,WAAW,CAAC,IAAI,CAAC;QACrB,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,sCAAsC,IAAI,EAAE;KACnD,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc,EAAE,IAAY;IAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE;SACtB,MAAM,EAAE;SACR,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAClC,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,GAAG,CAAC,EAC9B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAC3B,CACF;SACA,KAAK,CAAC,CAAC,CAAC,CAAC;IAEZ,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAE1B,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACvF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAc;IACnD,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,EAAE;SACpB,MAAM,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC;SAC9C,IAAI,CAAC,KAAK,CAAC;SACX,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;SAC3B,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,OAAO,IAAI,EAAE,aAAa,IAAI,KAAK,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,WAAmB;IACzE,MAAM,EAAE;SACL,MAAM,CAAC,KAAK,CAAC;SACb,GAAG,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACzC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"smsOtp.js","sourceRoot":"","sources":["../../src/services/smsOtp.ts"],"names":[],"mappings":"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"}
@@ -66,6 +66,8 @@ export interface AccessTokenOptions {
66
66
  deviceFingerprint?: string;
67
67
  /** Proof that the MFA requirement for this user was satisfied. */
68
68
  mfaFactor?: MfaAssertion;
69
+ /** Scopes granted at the authorization step, carried on the refresh token. */
70
+ scopes?: string[];
69
71
  }
70
72
  export declare function createAccessToken(user: User, opts?: AccessTokenOptions): Promise<string>;
71
73
  export interface ApplicationAccessTokenOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/services/tokens.ts"],"names":[],"mappings":"AAWA,OAAO,EAKL,KAAK,IAAI,EACT,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAa/C,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAerD;AAED;;;GAGG;AACH,wBAAsB,YAAY,gCAGjC;AAED;;;GAGG;AACH,wBAAsB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GASlC;AAMD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3E;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAG,cAAc,CAAU;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,YAAY,MAAM,EAAE,MAAM,EAIzB;CACF;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,SAAS,CAAC,EAAE,YAAY,CAAC;CAC1B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B5F;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,6BAA6B,GAClC,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,WAAW,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,EAAE,CAAC,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,IAAI,GAAE,kBAAuB,EAC7B,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,QAAQ,CAAC,CAgCnB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAgB3E;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,EAAE,CAAC,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA+E1B;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrE;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9E;AAOD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/services/tokens.ts"],"names":[],"mappings":"AAWA,OAAO,EAKL,KAAK,IAAI,EACT,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAa/C,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAerD;AAED;;;GAGG;AACH,wBAAsB,YAAY,gCAGjC;AAED;;;GAGG;AACH,wBAAsB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GASlC;AAMD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3E;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAG,cAAc,CAAU;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,YAAY,MAAM,EAAE,MAAM,EAIzB;CACF;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B5F;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,6BAA6B,GAClC,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,WAAW,EAChB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,EAAE,CAAC,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,IAAI,GAAE,kBAAuB,EAC7B,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,QAAQ,CAAC,CAiCnB;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAgB3E;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,EAAE,CAAC,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAmF1B;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrE;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9E;AAOD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
@@ -157,6 +157,7 @@ export async function createTokenSet(user, ip, userAgent, opts = {}, deviceFinge
157
157
  userAgent: userAgent ?? null,
158
158
  deviceFingerprint: deviceFingerprint ?? null,
159
159
  mfaFactor: opts.mfaFactor ?? null,
160
+ scopes: opts.scopes ?? [],
160
161
  }).returning();
161
162
  try {
162
163
  const sessions = new SessionRepository();
@@ -246,6 +247,10 @@ export async function rotateRefreshToken(token, ip, userAgent, clientId, expecte
246
247
  orgId,
247
248
  clientId,
248
249
  deviceFingerprint: claimed.deviceFingerprint ?? undefined,
250
+ // Carried forward from the token being rotated. A refresh may narrow the
251
+ // grant but never widen it, so the stored set is authoritative rather than
252
+ // anything the caller supplies.
253
+ ...(claimed.scopes?.length ? { scopes: claimed.scopes } : {}),
249
254
  ...(claimed.mfaFactor
250
255
  ? { mfaFactor: claimed.mfaFactor }
251
256
  : {}),
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/services/tokens.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/services/tokens.ts"],"names":[],"mappings":"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"}