@yielded/auth-persistence 0.1.0-beta.22 → 0.1.0-beta.24

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 (182) hide show
  1. package/README.md +11 -0
  2. package/dist/Adapter.d.mts +13 -5
  3. package/dist/Adapter.mjs +9 -2
  4. package/dist/OAuthPersistence.d.mts +87 -0
  5. package/dist/OAuthPersistence.mjs +125 -0
  6. package/dist/OAuthPersistence.mjs.map +1 -0
  7. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  8. package/dist/index.d.mts +3 -1
  9. package/dist/index.mjs +3 -1
  10. package/dist/internal/authority-snapshot.mjs +53 -0
  11. package/dist/internal/authority-snapshot.mjs.map +1 -0
  12. package/dist/internal/configuration.d.mts +1 -1
  13. package/dist/internal/configuration.mjs.map +1 -1
  14. package/dist/internal/models/oauth-connected-model.d.mts +294 -0
  15. package/dist/internal/models/oauth-connected-model.mjs +22 -0
  16. package/dist/internal/models/oauth-connected-model.mjs.map +1 -0
  17. package/dist/internal/models/oauth-model.d.mts +467 -0
  18. package/dist/internal/models/oauth-model.mjs +49 -0
  19. package/dist/internal/models/oauth-model.mjs.map +1 -0
  20. package/dist/internal/models/password-model.d.mts +4 -97
  21. package/dist/internal/models/password-model.mjs +0 -3
  22. package/dist/internal/models/password-model.mjs.map +1 -1
  23. package/dist/internal/native-sql-table.d.mts +34 -0
  24. package/dist/internal/native-sql-table.mjs +111 -0
  25. package/dist/internal/native-sql-table.mjs.map +1 -0
  26. package/dist/internal/oauth/accounts.d.mts +8 -0
  27. package/dist/internal/oauth/accounts.mjs +379 -0
  28. package/dist/internal/oauth/accounts.mjs.map +1 -0
  29. package/dist/internal/oauth/connected-access.d.mts +9 -0
  30. package/dist/internal/oauth/connected-access.mjs +229 -0
  31. package/dist/internal/oauth/connected-access.mjs.map +1 -0
  32. package/dist/internal/oauth/connected-collection.d.mts +7 -0
  33. package/dist/internal/oauth/connected-collection.mjs +214 -0
  34. package/dist/internal/oauth/connected-collection.mjs.map +1 -0
  35. package/dist/internal/oauth/connected-custody.d.mts +6 -0
  36. package/dist/internal/oauth/connected-custody.mjs +165 -0
  37. package/dist/internal/oauth/connected-custody.mjs.map +1 -0
  38. package/dist/internal/oauth/connected-flow.d.mts +7 -0
  39. package/dist/internal/oauth/connected-flow.mjs +324 -0
  40. package/dist/internal/oauth/connected-flow.mjs.map +1 -0
  41. package/dist/internal/oauth/connected-input.mjs +122 -0
  42. package/dist/internal/oauth/connected-input.mjs.map +1 -0
  43. package/dist/internal/oauth/connected-keys.d.mts +2 -0
  44. package/dist/internal/oauth/connected-keys.mjs +22 -0
  45. package/dist/internal/oauth/connected-keys.mjs.map +1 -0
  46. package/dist/internal/oauth/connected-maintenance.d.mts +9 -0
  47. package/dist/internal/oauth/connected-maintenance.mjs +226 -0
  48. package/dist/internal/oauth/connected-maintenance.mjs.map +1 -0
  49. package/dist/internal/oauth/connected-management.d.mts +9 -0
  50. package/dist/internal/oauth/connected-management.mjs +243 -0
  51. package/dist/internal/oauth/connected-management.mjs.map +1 -0
  52. package/dist/internal/oauth/connected-reference.mjs +63 -0
  53. package/dist/internal/oauth/connected-reference.mjs.map +1 -0
  54. package/dist/internal/oauth/connected-settlement.d.mts +8 -0
  55. package/dist/internal/oauth/connected-settlement.mjs +141 -0
  56. package/dist/internal/oauth/connected-settlement.mjs.map +1 -0
  57. package/dist/internal/oauth/connected-sign-in.d.mts +10 -0
  58. package/dist/internal/oauth/connected-sign-in.mjs +281 -0
  59. package/dist/internal/oauth/connected-sign-in.mjs.map +1 -0
  60. package/dist/internal/oauth/connected-state.d.mts +14 -0
  61. package/dist/internal/oauth/connected-state.mjs +469 -0
  62. package/dist/internal/oauth/connected-state.mjs.map +1 -0
  63. package/dist/internal/oauth/connected-target.d.mts +21 -0
  64. package/dist/internal/oauth/connected-target.mjs +117 -0
  65. package/dist/internal/oauth/connected-target.mjs.map +1 -0
  66. package/dist/internal/oauth/flow.d.mts +5 -0
  67. package/dist/internal/oauth/flow.mjs +279 -0
  68. package/dist/internal/oauth/flow.mjs.map +1 -0
  69. package/dist/internal/oauth/input.mjs +127 -0
  70. package/dist/internal/oauth/input.mjs.map +1 -0
  71. package/dist/internal/oauth/owner.d.mts +10 -0
  72. package/dist/internal/oauth/owner.mjs +10 -0
  73. package/dist/internal/oauth/owner.mjs.map +1 -0
  74. package/dist/internal/oauth/query-compiler.d.mts +7 -0
  75. package/dist/internal/oauth/query-compiler.mjs +9 -0
  76. package/dist/internal/oauth/query-compiler.mjs.map +1 -0
  77. package/dist/internal/oauth/registration.d.mts +7 -0
  78. package/dist/internal/oauth/registration.mjs +393 -0
  79. package/dist/internal/oauth/registration.mjs.map +1 -0
  80. package/dist/internal/oauth/state.mjs +107 -0
  81. package/dist/internal/oauth/state.mjs.map +1 -0
  82. package/dist/internal/oauth/target.d.mts +31 -0
  83. package/dist/internal/oauth/target.mjs +273 -0
  84. package/dist/internal/oauth/target.mjs.map +1 -0
  85. package/dist/internal/oauth-kernel.d.mts +1423 -0
  86. package/dist/internal/oauth-kernel.mjs +187 -0
  87. package/dist/internal/oauth-kernel.mjs.map +1 -0
  88. package/dist/internal/oauth-proxy.d.mts +31 -0
  89. package/dist/internal/oauth-proxy.mjs +129 -0
  90. package/dist/internal/oauth-proxy.mjs.map +1 -0
  91. package/dist/internal/passkey/target.d.mts +1 -1
  92. package/dist/internal/passkey-kernel.d.mts +5 -5
  93. package/dist/internal/passkeys.mjs +1 -1
  94. package/dist/internal/password-credentials.d.mts +11 -0
  95. package/dist/internal/password-credentials.mjs +121 -0
  96. package/dist/internal/password-credentials.mjs.map +1 -0
  97. package/dist/internal/password-kernel.d.mts +15 -28
  98. package/dist/internal/password-kernel.mjs +35 -236
  99. package/dist/internal/password-kernel.mjs.map +1 -1
  100. package/dist/internal/persistence.d.mts +2 -0
  101. package/dist/internal/persistence.mjs +5 -5
  102. package/dist/internal/persistence.mjs.map +1 -1
  103. package/dist/internal/query-operations.d.mts +2 -0
  104. package/dist/internal/session-kernel.d.mts +5 -3
  105. package/dist/internal/session-kernel.mjs +95 -29
  106. package/dist/internal/session-kernel.mjs.map +1 -1
  107. package/dist/internal/sql-oauth-connected-model.d.mts +29 -0
  108. package/dist/internal/sql-oauth-connected-model.mjs +7 -0
  109. package/dist/internal/sql-oauth-connected-model.mjs.map +1 -0
  110. package/dist/internal/sql-oauth-model.d.mts +60 -0
  111. package/dist/internal/sql-oauth-model.mjs +10 -0
  112. package/dist/internal/sql-oauth-model.mjs.map +1 -0
  113. package/dist/internal/sql-persistence.mjs +3 -1
  114. package/dist/internal/sql-persistence.mjs.map +1 -1
  115. package/dist/internal/sql-query.d.mts +12 -0
  116. package/dist/internal/sql-query.mjs +15 -18
  117. package/dist/internal/sql-query.mjs.map +1 -1
  118. package/dist/internal/sql-storage-validation.mjs +54 -0
  119. package/dist/internal/sql-storage-validation.mjs.map +1 -0
  120. package/dist/internal/storage-mapping.mjs +2 -67
  121. package/dist/internal/storage-mapping.mjs.map +1 -1
  122. package/dist/internal/storage-plans.d.mts +7 -0
  123. package/dist/internal/storage-plans.mjs +189 -0
  124. package/dist/internal/storage-plans.mjs.map +1 -0
  125. package/dist/internal/storage-tables.d.mts +0 -99
  126. package/dist/internal/storage-tables.mjs +0 -43
  127. package/dist/internal/storage-tables.mjs.map +1 -1
  128. package/dist/internal/storage-validation.d.mts +6 -1
  129. package/dist/internal/storage-validation.mjs +42 -1
  130. package/dist/internal/storage-validation.mjs.map +1 -1
  131. package/dist/internal/transaction-execution-kernel.d.mts +1 -1
  132. package/dist/internal/transaction-kernel.d.mts +1 -1
  133. package/dist/internal/transaction-kernel.mjs +3 -2
  134. package/dist/internal/transaction-kernel.mjs.map +1 -1
  135. package/package.json +1 -1
  136. package/src/Adapter.ts +97 -8
  137. package/src/OAuthPersistence.ts +427 -0
  138. package/src/index.ts +3 -0
  139. package/src/internal/authority-snapshot.ts +91 -0
  140. package/src/internal/configuration.ts +1 -8
  141. package/src/internal/models/oauth-connected-model.ts +396 -0
  142. package/src/internal/models/oauth-model.ts +708 -0
  143. package/src/internal/models/password-model.ts +0 -120
  144. package/src/internal/native-sql-table.ts +178 -0
  145. package/src/internal/oauth/accounts.ts +838 -0
  146. package/src/internal/oauth/connected-access.ts +388 -0
  147. package/src/internal/oauth/connected-collection.ts +345 -0
  148. package/src/internal/oauth/connected-custody.ts +308 -0
  149. package/src/internal/oauth/connected-flow.ts +562 -0
  150. package/src/internal/oauth/connected-input.ts +147 -0
  151. package/src/internal/oauth/connected-keys.ts +31 -0
  152. package/src/internal/oauth/connected-maintenance.ts +379 -0
  153. package/src/internal/oauth/connected-management.ts +391 -0
  154. package/src/internal/oauth/connected-reference.ts +135 -0
  155. package/src/internal/oauth/connected-settlement.ts +278 -0
  156. package/src/internal/oauth/connected-sign-in.ts +472 -0
  157. package/src/internal/oauth/connected-state.ts +924 -0
  158. package/src/internal/oauth/connected-target.ts +307 -0
  159. package/src/internal/oauth/flow.ts +505 -0
  160. package/src/internal/oauth/input.ts +201 -0
  161. package/src/internal/oauth/owner.ts +22 -0
  162. package/src/internal/oauth/query-compiler.ts +15 -0
  163. package/src/internal/oauth/registration.ts +676 -0
  164. package/src/internal/oauth/state.ts +218 -0
  165. package/src/internal/oauth/target.ts +803 -0
  166. package/src/internal/oauth-kernel.ts +294 -0
  167. package/src/internal/oauth-proxy.ts +176 -0
  168. package/src/internal/password-credentials.ts +245 -0
  169. package/src/internal/password-kernel.ts +98 -712
  170. package/src/internal/persistence.ts +5 -10
  171. package/src/internal/query-operations.ts +2 -0
  172. package/src/internal/session-kernel.ts +231 -81
  173. package/src/internal/sql-oauth-connected-model.ts +145 -0
  174. package/src/internal/sql-oauth-model.ts +263 -0
  175. package/src/internal/sql-persistence.ts +2 -0
  176. package/src/internal/sql-query.ts +16 -13
  177. package/src/internal/sql-storage-validation.ts +64 -0
  178. package/src/internal/storage-mapping.ts +0 -66
  179. package/src/internal/storage-plans.ts +218 -0
  180. package/src/internal/storage-tables.ts +0 -35
  181. package/src/internal/storage-validation.ts +58 -0
  182. package/src/internal/transaction-kernel.ts +6 -2
@@ -1 +1 @@
1
- {"version":3,"file":"storage-tables.mjs","names":[],"sources":["../../src/internal/storage-tables.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nexport const StorageColumn = Schema.Struct({\n name: Schema.NonEmptyString,\n type: Schema.Literals([\"text\", \"integer\", \"boolean\"]),\n nullable: Schema.optionalKey(Schema.Boolean),\n});\n\nexport const StorageTable = Schema.Struct({\n name: Schema.NonEmptyString,\n schema: Schema.optionalKey(Schema.NonEmptyString),\n columns: Schema.Record(Schema.String, StorageColumn),\n unique: Schema.Array(Schema.Array(Schema.String)),\n});\n\nexport type StorageTable = typeof StorageTable.Type;\n\nconst text = { type: \"text\" as const };\nconst integer = { type: \"integer\" as const };\nconst boolean = { type: \"boolean\" as const };\nconst optionalText = { ...text, nullable: true };\nconst optionalInteger = { ...integer, nullable: true };\n\nconst spec = <C extends Readonly<Record<string, Omit<typeof StorageColumn.Type, \"name\">>>>(\n columns: C,\n unique: ReadonlyArray<ReadonlyArray<Extract<keyof C, string>>>,\n) => ({ columns, unique });\n\n/** Logical roles are independent of table names and migration ownership. */\nexport const storageTables = {\n subjects: spec({ id: text, active: boolean, securityRevision: text }, [[\"id\"]]),\n identifiers: spec(\n {\n namespace: text,\n value: text,\n subjectId: text,\n revision: text,\n verifiedAt: optionalInteger,\n active: boolean,\n },\n [[\"namespace\", \"value\"]],\n ),\n credentials: spec({ credentialId: text, subjectId: text, revision: text, active: boolean }, [\n [\"credentialId\"],\n ]),\n passwords: spec(\n {\n moduleId: text,\n subjectId: text,\n credentialId: text,\n credentialRevision: text,\n verifierVersion: text,\n verifier: text,\n normalization: text,\n },\n [\n [\"moduleId\", \"subjectId\"],\n [\"moduleId\", \"credentialId\"],\n ],\n ),\n passwordAttempts: spec(\n {\n moduleId: text,\n action: text,\n attemptId: text,\n identifierNamespace: text,\n identifierValue: text,\n subjectId: optionalText,\n credentialId: optionalText,\n securityRevision: optionalText,\n credentialRevision: optionalText,\n verifierVersion: optionalText,\n identifierBindingRevision: optionalText,\n admittedAt: integer,\n deadline: integer,\n retentionUntil: integer,\n state: text,\n },\n [[\"moduleId\", \"attemptId\"]],\n ),\n passwordScopes: spec({ moduleId: text, action: text, scopeKind: text, scopeKey: text }, [\n [\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\"],\n ]),\n passwordCharges: spec(\n {\n moduleId: text,\n action: text,\n scopeKind: text,\n scopeKey: text,\n attemptId: text,\n occurredAt: integer,\n retentionUntil: integer,\n },\n [[\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\", \"attemptId\"]],\n ),\n passwordCommands: spec(\n {\n moduleId: text,\n commandId: text,\n action: text,\n bindingDigest: text,\n decision: text,\n retentionUntil: integer,\n },\n [[\"moduleId\", \"commandId\"]],\n ),\n passwordRegistrations: spec({ moduleId: text, requestId: text }, [[\"moduleId\", \"requestId\"]]),\n emailCredentials: spec(\n {\n moduleId: text,\n subjectId: text,\n credentialId: text,\n identifierNamespace: text,\n identifierValue: text,\n credentialRevision: text,\n active: boolean,\n },\n [\n [\"moduleId\", \"credentialId\"],\n [\"moduleId\", \"identifierNamespace\", \"identifierValue\"],\n ],\n ),\n emailCommands: spec(\n { moduleId: text, commandId: text, action: text, bindingDigest: text, retentionUntil: integer },\n [[\"moduleId\", \"commandId\"]],\n ),\n phoneState: spec({ scope: text, state: text, version: text }, [[\"scope\"]]),\n passkeyCredentials: spec(\n {\n credentialId: text,\n subjectId: text,\n rpId: text,\n protocolCredentialId: text,\n credentialKey: text,\n handleKey: text,\n userHandle: text,\n publicKey: text,\n algorithm: integer,\n profile: text,\n credentialRevision: text,\n active: boolean,\n primarySignIn: boolean,\n enrollmentUserVerified: boolean,\n backupEligible: boolean,\n backupState: boolean,\n counter: integer,\n maximumCounter: integer,\n name: text,\n createdAt: integer,\n lastUsedAt: optionalInteger,\n },\n [[\"credentialId\"], [\"credentialKey\"]],\n ),\n passkeyOwnership: spec(\n {\n credentialKey: text,\n rpId: text,\n protocolCredentialId: text,\n subjectId: optionalText,\n credentialId: optionalText,\n state: text,\n version: text,\n reservationId: optionalText,\n },\n [[\"credentialKey\"]],\n ),\n passkeyHandles: spec(\n {\n handleKey: text,\n rpId: text,\n userHandle: text,\n subjectId: optionalText,\n state: text,\n version: text,\n reservationId: optionalText,\n },\n [[\"handleKey\"], [\"rpId\", \"subjectId\"]],\n ),\n passkeyModules: spec(\n {\n moduleId: text,\n active: boolean,\n policyRevision: text,\n policy: text,\n },\n [[\"moduleId\"]],\n ),\n passkeyFlows: spec(\n {\n moduleId: text,\n flowId: text,\n commandId: text,\n purpose: text,\n state: text,\n version: text,\n generation: integer,\n snapshot: text,\n policySnapshot: text,\n requestBindingVerifier: text,\n requestBindingExpiresAt: integer,\n issuedAt: integer,\n expiresAt: integer,\n retentionUntil: integer,\n claimId: optionalText,\n claimedAt: optionalInteger,\n claimExpiresAt: optionalInteger,\n credentialSnapshot: optionalText,\n subjectScope: optionalText,\n targetScope: optionalText,\n },\n [\n [\"moduleId\", \"flowId\"],\n [\"moduleId\", \"commandId\"],\n ],\n ),\n passkeyAdmissions: spec(\n {\n authorityScope: text,\n moduleId: text,\n version: text,\n ownerMarker: text,\n admittedAt: optionalInteger,\n },\n [[\"authorityScope\", \"moduleId\"]],\n ),\n passkeyCharges: spec(\n {\n moduleId: text,\n flowId: text,\n purpose: text,\n kind: text,\n scope: text,\n originalWindowMillis: integer,\n admittedAt: optionalInteger,\n retainUntil: optionalInteger,\n version: text,\n ownerMarker: text,\n },\n [[\"moduleId\", \"flowId\", \"kind\"]],\n ),\n passkeyCommands: spec(\n {\n moduleId: text,\n commandId: text,\n subjectId: text,\n credentialId: text,\n intent: text,\n decision: text,\n retentionUntil: integer,\n version: text,\n },\n [[\"moduleId\", \"commandId\"]],\n ),\n proofRequests: spec(\n {\n moduleId: text,\n requestId: text,\n fingerprint: text,\n proofId: text,\n purpose: text,\n keyId: text,\n createdAt: integer,\n retentionUntil: integer,\n receipt: text,\n },\n [[\"moduleId\", \"requestId\"]],\n ),\n proofSeries: spec(\n {\n moduleId: text,\n purpose: text,\n scopeKey: text,\n activeProofId: optionalText,\n lastIssueAt: optionalInteger,\n version: text,\n },\n [[\"moduleId\", \"purpose\", \"scopeKey\"]],\n ),\n proofGenerations: spec(\n {\n moduleId: text,\n purpose: text,\n proofId: text,\n requestId: text,\n seriesKey: text,\n deliveryId: text,\n binding: text,\n verifierKeyId: text,\n verifierDigest: text,\n issuedAt: integer,\n expiresAt: integer,\n version: text,\n state: text,\n sendCount: integer,\n deliveryState: text,\n claimVersion: optionalText,\n claimDeadline: optionalInteger,\n retryAt: optionalInteger,\n deliveryRetryMillis: integer,\n retentionUntil: integer,\n fingerprint: text,\n },\n [\n [\"moduleId\", \"proofId\"],\n [\"moduleId\", \"deliveryId\"],\n ],\n ),\n proofContinuations: spec(\n {\n moduleId: text,\n purpose: text,\n continuationId: text,\n digest: text,\n proofId: text,\n seriesKey: text,\n binding: text,\n expiresAt: integer,\n consumed: boolean,\n version: text,\n retentionUntil: integer,\n },\n [\n [\"moduleId\", \"continuationId\"],\n [\"moduleId\", \"digest\"],\n ],\n ),\n proofScopes: spec(\n { moduleId: text, purpose: text, action: text, scopeKind: text, scopeKey: text },\n [[\"moduleId\", \"purpose\", \"action\", \"scopeKind\", \"scopeKey\"]],\n ),\n proofAbuse: spec(\n {\n moduleId: text,\n purpose: text,\n action: text,\n scopeKind: text,\n scopeKey: text,\n commandId: text,\n occurredAt: integer,\n retentionUntil: integer,\n },\n [[\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\", \"commandId\"]],\n ),\n proofFailures: spec(\n {\n moduleId: text,\n purpose: text,\n seriesKey: text,\n commandId: text,\n occurredAt: integer,\n retentionUntil: integer,\n },\n [[\"moduleId\", \"seriesKey\", \"commandId\"]],\n ),\n proofCommands: spec(\n { moduleId: text, commandId: text, kind: text, decision: text, retentionUntil: integer },\n [[\"moduleId\", \"commandId\"]],\n ),\n sessions: spec(\n {\n sessionId: text,\n subjectId: text,\n digest: text,\n version: text,\n securityRevision: text,\n issuedAt: integer,\n expiresAt: integer,\n absoluteExpiresAt: integer,\n record: text,\n },\n [[\"sessionId\"], [\"digest\"]],\n ),\n sessionFlows: spec(\n {\n flowId: text,\n subjectId: text,\n state: text,\n pendingDigest: optionalText,\n dedupUntil: integer,\n },\n [[\"flowId\"]],\n ),\n} as const;\n\nexport type StorageRole = keyof typeof storageTables;\n\nexport const tableDefinition = (\n role: StorageRole,\n name: string,\n subjectType: \"text\" | \"integer\" = \"text\",\n): StorageTable => {\n const table = storageTables[role];\n\n return {\n name,\n columns: Object.fromEntries(\n Object.entries(table.columns).map(([key, column]) => [\n key,\n {\n ...column,\n name: key.replace(/[A-Z]/g, (letter) => \"_\" + letter.toLowerCase()),\n ...(key === \"subjectId\" ? { type: subjectType } : {}),\n },\n ]),\n ),\n unique: table.unique,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"storage-tables.mjs","names":[],"sources":["../../src/internal/storage-tables.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nexport const StorageColumn = Schema.Struct({\n name: Schema.NonEmptyString,\n type: Schema.Literals([\"text\", \"integer\", \"boolean\"]),\n nullable: Schema.optionalKey(Schema.Boolean),\n});\n\nexport const StorageTable = Schema.Struct({\n name: Schema.NonEmptyString,\n schema: Schema.optionalKey(Schema.NonEmptyString),\n columns: Schema.Record(Schema.String, StorageColumn),\n unique: Schema.Array(Schema.Array(Schema.String)),\n});\n\nexport type StorageTable = typeof StorageTable.Type;\n\nconst text = { type: \"text\" as const };\nconst integer = { type: \"integer\" as const };\nconst boolean = { type: \"boolean\" as const };\nconst optionalText = { ...text, nullable: true };\nconst optionalInteger = { ...integer, nullable: true };\n\nconst spec = <C extends Readonly<Record<string, Omit<typeof StorageColumn.Type, \"name\">>>>(\n columns: C,\n unique: ReadonlyArray<ReadonlyArray<Extract<keyof C, string>>>,\n) => ({ columns, unique });\n\n/** Logical roles are independent of table names and migration ownership. */\nexport const storageTables = {\n subjects: spec({ id: text, active: boolean, securityRevision: text }, [[\"id\"]]),\n identifiers: spec(\n {\n namespace: text,\n value: text,\n subjectId: text,\n revision: text,\n verifiedAt: optionalInteger,\n active: boolean,\n },\n [[\"namespace\", \"value\"]],\n ),\n credentials: spec({ credentialId: text, subjectId: text, revision: text, active: boolean }, [\n [\"credentialId\"],\n ]),\n passwords: spec(\n {\n moduleId: text,\n subjectId: text,\n credentialId: text,\n credentialRevision: text,\n verifierVersion: text,\n verifier: text,\n normalization: text,\n },\n [\n [\"moduleId\", \"subjectId\"],\n [\"moduleId\", \"credentialId\"],\n ],\n ),\n passwordCommands: spec(\n {\n moduleId: text,\n commandId: text,\n action: text,\n bindingDigest: text,\n decision: text,\n retentionUntil: integer,\n },\n [[\"moduleId\", \"commandId\"]],\n ),\n passwordRegistrations: spec({ moduleId: text, requestId: text }, [[\"moduleId\", \"requestId\"]]),\n emailCredentials: spec(\n {\n moduleId: text,\n subjectId: text,\n credentialId: text,\n identifierNamespace: text,\n identifierValue: text,\n credentialRevision: text,\n active: boolean,\n },\n [\n [\"moduleId\", \"credentialId\"],\n [\"moduleId\", \"identifierNamespace\", \"identifierValue\"],\n ],\n ),\n emailCommands: spec(\n { moduleId: text, commandId: text, action: text, bindingDigest: text, retentionUntil: integer },\n [[\"moduleId\", \"commandId\"]],\n ),\n phoneState: spec({ scope: text, state: text, version: text }, [[\"scope\"]]),\n passkeyCredentials: spec(\n {\n credentialId: text,\n subjectId: text,\n rpId: text,\n protocolCredentialId: text,\n credentialKey: text,\n handleKey: text,\n userHandle: text,\n publicKey: text,\n algorithm: integer,\n profile: text,\n credentialRevision: text,\n active: boolean,\n primarySignIn: boolean,\n enrollmentUserVerified: boolean,\n backupEligible: boolean,\n backupState: boolean,\n counter: integer,\n maximumCounter: integer,\n name: text,\n createdAt: integer,\n lastUsedAt: optionalInteger,\n },\n [[\"credentialId\"], [\"credentialKey\"]],\n ),\n passkeyOwnership: spec(\n {\n credentialKey: text,\n rpId: text,\n protocolCredentialId: text,\n subjectId: optionalText,\n credentialId: optionalText,\n state: text,\n version: text,\n reservationId: optionalText,\n },\n [[\"credentialKey\"]],\n ),\n passkeyHandles: spec(\n {\n handleKey: text,\n rpId: text,\n userHandle: text,\n subjectId: optionalText,\n state: text,\n version: text,\n reservationId: optionalText,\n },\n [[\"handleKey\"], [\"rpId\", \"subjectId\"]],\n ),\n passkeyModules: spec(\n {\n moduleId: text,\n active: boolean,\n policyRevision: text,\n policy: text,\n },\n [[\"moduleId\"]],\n ),\n passkeyFlows: spec(\n {\n moduleId: text,\n flowId: text,\n commandId: text,\n purpose: text,\n state: text,\n version: text,\n generation: integer,\n snapshot: text,\n policySnapshot: text,\n requestBindingVerifier: text,\n requestBindingExpiresAt: integer,\n issuedAt: integer,\n expiresAt: integer,\n retentionUntil: integer,\n claimId: optionalText,\n claimedAt: optionalInteger,\n claimExpiresAt: optionalInteger,\n credentialSnapshot: optionalText,\n subjectScope: optionalText,\n targetScope: optionalText,\n },\n [\n [\"moduleId\", \"flowId\"],\n [\"moduleId\", \"commandId\"],\n ],\n ),\n passkeyAdmissions: spec(\n {\n authorityScope: text,\n moduleId: text,\n version: text,\n ownerMarker: text,\n admittedAt: optionalInteger,\n },\n [[\"authorityScope\", \"moduleId\"]],\n ),\n passkeyCharges: spec(\n {\n moduleId: text,\n flowId: text,\n purpose: text,\n kind: text,\n scope: text,\n originalWindowMillis: integer,\n admittedAt: optionalInteger,\n retainUntil: optionalInteger,\n version: text,\n ownerMarker: text,\n },\n [[\"moduleId\", \"flowId\", \"kind\"]],\n ),\n passkeyCommands: spec(\n {\n moduleId: text,\n commandId: text,\n subjectId: text,\n credentialId: text,\n intent: text,\n decision: text,\n retentionUntil: integer,\n version: text,\n },\n [[\"moduleId\", \"commandId\"]],\n ),\n proofRequests: spec(\n {\n moduleId: text,\n requestId: text,\n fingerprint: text,\n proofId: text,\n purpose: text,\n keyId: text,\n createdAt: integer,\n retentionUntil: integer,\n receipt: text,\n },\n [[\"moduleId\", \"requestId\"]],\n ),\n proofSeries: spec(\n {\n moduleId: text,\n purpose: text,\n scopeKey: text,\n activeProofId: optionalText,\n lastIssueAt: optionalInteger,\n version: text,\n },\n [[\"moduleId\", \"purpose\", \"scopeKey\"]],\n ),\n proofGenerations: spec(\n {\n moduleId: text,\n purpose: text,\n proofId: text,\n requestId: text,\n seriesKey: text,\n deliveryId: text,\n binding: text,\n verifierKeyId: text,\n verifierDigest: text,\n issuedAt: integer,\n expiresAt: integer,\n version: text,\n state: text,\n sendCount: integer,\n deliveryState: text,\n claimVersion: optionalText,\n claimDeadline: optionalInteger,\n retryAt: optionalInteger,\n deliveryRetryMillis: integer,\n retentionUntil: integer,\n fingerprint: text,\n },\n [\n [\"moduleId\", \"proofId\"],\n [\"moduleId\", \"deliveryId\"],\n ],\n ),\n proofContinuations: spec(\n {\n moduleId: text,\n purpose: text,\n continuationId: text,\n digest: text,\n proofId: text,\n seriesKey: text,\n binding: text,\n expiresAt: integer,\n consumed: boolean,\n version: text,\n retentionUntil: integer,\n },\n [\n [\"moduleId\", \"continuationId\"],\n [\"moduleId\", \"digest\"],\n ],\n ),\n proofScopes: spec(\n { moduleId: text, purpose: text, action: text, scopeKind: text, scopeKey: text },\n [[\"moduleId\", \"purpose\", \"action\", \"scopeKind\", \"scopeKey\"]],\n ),\n proofAbuse: spec(\n {\n moduleId: text,\n purpose: text,\n action: text,\n scopeKind: text,\n scopeKey: text,\n commandId: text,\n occurredAt: integer,\n retentionUntil: integer,\n },\n [[\"moduleId\", \"action\", \"scopeKind\", \"scopeKey\", \"commandId\"]],\n ),\n proofFailures: spec(\n {\n moduleId: text,\n purpose: text,\n seriesKey: text,\n commandId: text,\n occurredAt: integer,\n retentionUntil: integer,\n },\n [[\"moduleId\", \"seriesKey\", \"commandId\"]],\n ),\n proofCommands: spec(\n { moduleId: text, commandId: text, kind: text, decision: text, retentionUntil: integer },\n [[\"moduleId\", \"commandId\"]],\n ),\n sessions: spec(\n {\n sessionId: text,\n subjectId: text,\n digest: text,\n version: text,\n securityRevision: text,\n issuedAt: integer,\n expiresAt: integer,\n absoluteExpiresAt: integer,\n record: text,\n },\n [[\"sessionId\"], [\"digest\"]],\n ),\n sessionFlows: spec(\n {\n flowId: text,\n subjectId: text,\n state: text,\n pendingDigest: optionalText,\n dedupUntil: integer,\n },\n [[\"flowId\"]],\n ),\n} as const;\n\nexport type StorageRole = keyof typeof storageTables;\n\nexport const tableDefinition = (\n role: StorageRole,\n name: string,\n subjectType: \"text\" | \"integer\" = \"text\",\n): StorageTable => {\n const table = storageTables[role];\n\n return {\n name,\n columns: Object.fromEntries(\n Object.entries(table.columns).map(([key, column]) => [\n key,\n {\n ...column,\n name: key.replace(/[A-Z]/g, (letter) => \"_\" + letter.toLowerCase()),\n ...(key === \"subjectId\" ? { type: subjectType } : {}),\n },\n ]),\n ),\n unique: table.unique,\n };\n};\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
+ import "./transaction-kernel.mjs";
1
2
  import "./storage-tables.mjs";
2
3
  import { PersistenceConfigurationError } from "./configuration.mjs";
3
- import { Effect } from "effect";
4
+ import { Effect, Schema } from "effect";
4
5
  import { SqlClient } from "effect/sql/SqlClient";
5
6
  //#region src/internal/storage-validation.d.ts
6
7
  /** Physical metadata needed for catalog validation; value codecs remain adapter-owned. */
@@ -11,6 +12,10 @@ export interface PhysicalStorageTable {
11
12
  readonly name: string;
12
13
  }>>;
13
14
  }
15
+ export interface PhysicalTextColumn {
16
+ readonly table: Pick<PhysicalStorageTable, "name" | "schema">;
17
+ readonly name: string;
18
+ }
14
19
  /** Share metadata only while constructing one service graph. Captured contexts
15
20
  * cannot reuse it after acquisition succeeds, fails, or is interrupted. */
16
21
  export declare const withStorageValidation: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
@@ -1,4 +1,5 @@
1
1
  import { PersistenceConfigurationError } from "./configuration.mjs";
2
+ import { NativeDatabase } from "./transaction-kernel.mjs";
2
3
  import { Context, Effect, Schema } from "effect";
3
4
  import { SqlClient } from "effect/sql/SqlClient";
4
5
  //#region src/internal/storage-validation.ts
@@ -27,6 +28,46 @@ const MysqlIndexes = Schema.Array(Schema.Struct({
27
28
  }));
28
29
  const quote = (value) => "\"" + value.replaceAll("\"", "\"\"") + "\"";
29
30
  const qualifiedTableName = (table) => (table.schema === void 0 ? "" : quote(table.schema) + ".") + quote(table.name);
31
+ const TextColumns = Schema.Array(Schema.Struct({
32
+ type: Schema.String,
33
+ collation: Schema.String
34
+ }));
35
+ /** One acquisition-only read: presence/unique-key validation does not establish
36
+ * equality compatibility. SQLite's pragma omits column collations, so only
37
+ * ordinary TEXT tables with no COLLATE declaration qualify (default BINARY). */
38
+ const canJoinTextColumns = Effect.fnUntraced(function* (left, right) {
39
+ if (left === void 0 || right === void 0) return false;
40
+ const { $client } = yield* NativeDatabase;
41
+ const client = $client.withoutTransforms();
42
+ const columns = [left, right];
43
+ if (client.onDialectOrElse({
44
+ sqlite: () => true,
45
+ orElse: () => false
46
+ }) && columns.some((c) => c.table.schema !== void 0 && c.table.schema !== "main")) return false;
47
+ const rows = yield* client.onDialectOrElse({
48
+ pg: () => client`
49
+ select a.atttypid::text as type, a.attcollation::text as collation
50
+ from (values ${client.join(", ", false)(columns.map((c) => client`(${qualifiedTableName(c.table)}::text, ${c.name}::text)`))}) requested(relation, name)
51
+ join pg_attribute a on a.attrelid = to_regclass(requested.relation)
52
+ and a.attname = requested.name and a.attnum > 0 and not a.attisdropped
53
+ where a.atttypid in ('text'::regtype, 'varchar'::regtype)`,
54
+ sqlite: () => client`
55
+ with requested(relation, name) as (values ${client.join(", ", false)(columns.map((c) => client`(${c.table.name}, ${c.name})`))})
56
+ select 'text' as type, 'BINARY' as collation from requested
57
+ join sqlite_schema s on s.name = requested.relation and s.type = 'table'
58
+ join pragma_table_info(requested.relation) c on c.name = requested.name
59
+ where upper(c.type) = 'TEXT' and instr(lower(s.sql), 'collate') = 0`,
60
+ mysql: () => client`
61
+ select c.data_type as type, c.collation_name as collation
62
+ from (${client.join(" union all ", false)(columns.map((c) => client`select ${c.table.schema ?? null} as schema_name, ${c.table.name} as table_name, ${c.name} as column_name`))}) requested
63
+ join information_schema.columns c
64
+ on c.table_schema = coalesce(requested.schema_name, database())
65
+ and c.table_name = requested.table_name and c.column_name = requested.column_name
66
+ where c.data_type in ('varchar', 'text', 'tinytext', 'mediumtext', 'longtext')`,
67
+ orElse: () => Effect.succeed([])
68
+ }).pipe(Effect.flatMap(Schema.decodeUnknownEffect(TextColumns)));
69
+ return rows.length === 2 && rows[0]?.type === rows[1]?.type && rows[0]?.collation === rows[1]?.collation;
70
+ });
30
71
  const validateKeys = Effect.fnUntraced(function* (table, required, physicalKeys) {
31
72
  for (const keys of required) {
32
73
  const columns = keys.map((key) => table.columns[key]?.name);
@@ -140,6 +181,6 @@ const validateStorage = (dialect, table, required) => validateStorageBatch(diale
140
181
  required
141
182
  }]);
142
183
  //#endregion
143
- export { qualifiedTableName, validateStorage, validateStorageBatch, withStorageValidation };
184
+ export { canJoinTextColumns, qualifiedTableName, validateStorage, validateStorageBatch, withStorageValidation };
144
185
 
145
186
  //# sourceMappingURL=storage-validation.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage-validation.mjs","names":[],"sources":["../../src/internal/storage-validation.ts"],"sourcesContent":["import { Context, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\n\nimport { PersistenceConfigurationError } from \"./configuration\";\nimport type { StorageTable } from \"./storage-tables\";\n\nconst Columns = Schema.Array(Schema.String);\nconst Keys = Schema.Array(Columns);\nconst Metadata = Schema.Struct({ relation: Schema.String, columns: Columns, keys: Keys });\nconst PgMetadata = Schema.Array(Metadata);\n\nconst SqliteMetadata = Schema.Array(\n Schema.Struct({\n relation: Schema.String,\n columns: Schema.fromJsonString(Columns),\n keys: Schema.fromJsonString(Keys),\n }),\n);\n\nconst MysqlColumns = Schema.Array(Schema.Struct({ relation: Schema.String, name: Schema.String }));\n\nconst MysqlIndexes = Schema.Array(\n Schema.Struct({\n relation: Schema.String,\n name: Schema.String,\n columnName: Schema.NullOr(Schema.String),\n prefix: Schema.NullOr(Schema.Number),\n }),\n);\n\nconst quote = (value: string) => '\"' + value.replaceAll('\"', '\"\"') + '\"';\n\n/** Physical metadata needed for catalog validation; value codecs remain adapter-owned. */\nexport interface PhysicalStorageTable {\n readonly name: string;\n readonly schema?: string;\n readonly columns: Readonly<Record<string, { readonly name: string }>>;\n}\n\nexport const qualifiedTableName = (table: Pick<StorageTable, \"name\" | \"schema\">) =>\n (table.schema === undefined ? \"\" : quote(table.schema) + \".\") + quote(table.name);\n\nconst validateKeys = Effect.fnUntraced(function* (\n table: PhysicalStorageTable,\n required: ReadonlyArray<ReadonlyArray<string>>,\n physicalKeys: ReadonlyArray<ReadonlyArray<string>>,\n) {\n for (const keys of required) {\n const columns = keys.map((key) => table.columns[key]?.name);\n\n if (\n columns.some((column) => column === undefined) ||\n !physicalKeys.some(\n // A stronger key also guarantees the required tuple's uniqueness.\n (actual) =>\n actual.length > 0 &&\n actual.length <= columns.length &&\n actual.every((column) => columns.includes(column)),\n )\n )\n return yield* PersistenceConfigurationError.make({\n reason: `Missing unique key on ${table.name} (${keys.join(\", \")})`,\n });\n }\n});\n\ninterface MetadataCache {\n active: boolean;\n readonly clients: Map<SqlClient, Map<string, typeof Metadata.Type>>;\n}\n\nconst CurrentMetadata = Context.Reference<MetadataCache | undefined>(\n \"@yielded/auth-persistence/StorageMetadata\",\n { defaultValue: () => undefined },\n);\n\n/** Share metadata only while constructing one service graph. Captured contexts\n * cannot reuse it after acquisition succeeds, fails, or is interrupted. */\nexport const withStorageValidation = Effect.fnUntraced(function* <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.fn.Return<A, E, R> {\n const parent = yield* CurrentMetadata;\n\n if (parent?.active) return yield* effect;\n const cache: MetadataCache = { active: true, clients: new Map() };\n\n return yield* effect.pipe(\n Effect.provideService(CurrentMetadata, cache),\n Effect.ensuring(\n Effect.sync(() => {\n cache.active = false;\n cache.clients.clear();\n }),\n ),\n );\n});\n\n/** Requirements checked against one physical catalog snapshot. */\nexport interface StorageValidation {\n readonly table: PhysicalStorageTable;\n readonly required: ReadonlyArray<ReadonlyArray<string>>;\n}\n\n/** Batch physical metadata reads, reusing only the current acquisition snapshot.\n * Every requirement is still checked; later acquisitions read fresh metadata. */\nexport const validateStorageBatch = Effect.fnUntraced(\n function* (dialect: \"pg\" | \"mysql\" | \"sqlite\", requirements: ReadonlyArray<StorageValidation>) {\n if (requirements.length === 0) return;\n if (\n dialect === \"sqlite\" &&\n requirements.some(({ table }) => table.schema !== undefined && table.schema !== \"main\")\n )\n return yield* PersistenceConfigurationError.make({\n reason: \"SQLite storage must belong to the main database\",\n });\n const client = yield* SqlClient;\n const cache = yield* CurrentMetadata;\n\n const byRelation = cache?.active\n ? (cache.clients.get(client) ?? new Map<string, typeof Metadata.Type>())\n : new Map<string, typeof Metadata.Type>();\n\n if (cache?.active) cache.clients.set(client, byRelation);\n\n const tables = new Map(requirements.map(({ table }) => [qualifiedTableName(table), table]));\n\n const missing = [...tables.entries()].filter(\n ([relation]) => !byRelation.has(`${dialect}:${relation}`),\n );\n\n const relations = missing.map(([relation]) => relation);\n\n if (relations.length > 0) {\n const metadata = yield* dialect === \"sqlite\"\n ? Effect.gen(function* () {\n const requested = client.join(\n \", \",\n false,\n )(missing.map(([relation, table]) => client`(${relation}, ${table.name})`));\n\n return yield* client`\n with requested(relation, name) as (values ${requested})\n select requested.relation,\n (select json_group_array(name) from pragma_table_info(requested.name)) as columns,\n (select json_group_array(json(storage_key.columns)) from (\n select json_group_array(name) as columns from (\n select name from pragma_table_info(requested.name) where pk > 0 order by pk\n )\n union all\n select (select json_group_array(name) from pragma_index_info(i.name)) as columns\n from pragma_index_list(requested.name) i\n where i.\"unique\" = 1 and i.partial = 0\n and not exists(select 1 from pragma_index_info(i.name) where name is null)\n ) storage_key where json_array_length(storage_key.columns) > 0) as keys\n from requested\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(SqliteMetadata)));\n })\n : dialect === \"mysql\"\n ? Effect.gen(function* () {\n const requested = client.join(\n \" union all \",\n false,\n )(\n missing.map(\n ([relation, table]) =>\n client`select ${relation} as relation, ${table.schema ?? null} as schemaName, ${table.name} as tableName`,\n ),\n );\n\n const columns = yield* client`\n select requested.relation, c.column_name as name\n from (${requested}) requested join information_schema.columns c\n on c.table_schema = coalesce(requested.schemaName, database()) and c.table_name = requested.tableName\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(MysqlColumns)));\n\n const indexes = yield* client`\n select requested.relation, i.index_name as name, i.column_name as columnName, i.sub_part as prefix\n from (${requested}) requested join information_schema.statistics i\n on i.table_schema = coalesce(requested.schemaName, database()) and i.table_name = requested.tableName\n where i.non_unique = 0 order by requested.relation, i.index_name, i.seq_in_index\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(MysqlIndexes)));\n\n return relations.map((relation) => {\n const grouped = new Map<string, Array<(typeof indexes)[number]>>();\n\n for (const index of indexes) {\n if (index.relation !== relation) continue;\n const entries = grouped.get(index.name) ?? [];\n\n entries.push(index);\n grouped.set(index.name, entries);\n }\n\n return {\n relation,\n columns: columns\n .filter((column) => column.relation === relation)\n .map((column) => column.name),\n keys: [...grouped.values()]\n .filter((entries) =>\n entries.every((entry) => entry.columnName !== null && entry.prefix === null),\n )\n .map((entries) =>\n entries.flatMap((entry) =>\n entry.columnName === null ? [] : [entry.columnName],\n ),\n ),\n };\n });\n })\n : Effect.gen(function* () {\n const requested = client.join(\n \", \",\n false,\n )(relations.map((relation) => client`(${relation}::text)`));\n\n return yield* client`\n select requested.relation,\n array(select a.attname::text from pg_attribute a\n where a.attrelid = to_regclass(requested.relation)\n and a.attnum > 0 and not a.attisdropped) as columns,\n coalesce((select jsonb_agg(storage_key.columns) from (\n select array_agg(a.attname::text order by k.ordinality) as columns\n from pg_index i\n cross join lateral unnest(i.indkey) with ordinality as k(attnum, ordinality)\n join pg_attribute a on a.attrelid = i.indrelid and a.attnum = k.attnum\n where i.indrelid = to_regclass(requested.relation)\n and i.indisunique and i.indisvalid and i.indimmediate\n and i.indpred is null and i.indexprs is null\n and k.ordinality <= i.indnkeyatts\n group by i.indexrelid\n ) storage_key), '[]'::jsonb) as keys\n from (values ${requested}) requested(relation)\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(PgMetadata)));\n });\n\n for (const row of metadata) byRelation.set(`${dialect}:${row.relation}`, row);\n }\n\n for (const { table, required } of requirements) {\n const relation = qualifiedTableName(table);\n const actual = byRelation.get(`${dialect}:${relation}`);\n\n for (const column of Object.values(table.columns)) {\n if (actual === undefined || !actual.columns.includes(column.name))\n return yield* PersistenceConfigurationError.make({\n reason: `Missing SQL column ${relation}.${column.name}`,\n });\n }\n yield* validateKeys(table, required, actual?.keys ?? []);\n }\n },\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : PersistenceConfigurationError.make({ reason: \"Cannot validate SQL storage metadata\" }),\n ),\n);\n\n/** Validate physical columns and unconditional uniqueness before operations run. */\nexport const validateStorage = (\n dialect: \"pg\" | \"mysql\" | \"sqlite\",\n table: PhysicalStorageTable,\n required: ReadonlyArray<ReadonlyArray<string>>,\n) => validateStorageBatch(dialect, [{ table, required }]);\n"],"mappings":"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"}
1
+ {"version":3,"file":"storage-validation.mjs","names":[],"sources":["../../src/internal/storage-validation.ts"],"sourcesContent":["import { Context, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\n\nimport { PersistenceConfigurationError } from \"./configuration\";\nimport type { StorageTable } from \"./storage-tables\";\nimport { NativeDatabase } from \"./transaction-kernel\";\n\nconst Columns = Schema.Array(Schema.String);\nconst Keys = Schema.Array(Columns);\nconst Metadata = Schema.Struct({ relation: Schema.String, columns: Columns, keys: Keys });\nconst PgMetadata = Schema.Array(Metadata);\n\nconst SqliteMetadata = Schema.Array(\n Schema.Struct({\n relation: Schema.String,\n columns: Schema.fromJsonString(Columns),\n keys: Schema.fromJsonString(Keys),\n }),\n);\n\nconst MysqlColumns = Schema.Array(Schema.Struct({ relation: Schema.String, name: Schema.String }));\n\nconst MysqlIndexes = Schema.Array(\n Schema.Struct({\n relation: Schema.String,\n name: Schema.String,\n columnName: Schema.NullOr(Schema.String),\n prefix: Schema.NullOr(Schema.Number),\n }),\n);\n\nconst quote = (value: string) => '\"' + value.replaceAll('\"', '\"\"') + '\"';\n\n/** Physical metadata needed for catalog validation; value codecs remain adapter-owned. */\nexport interface PhysicalStorageTable {\n readonly name: string;\n readonly schema?: string;\n readonly columns: Readonly<Record<string, { readonly name: string }>>;\n}\n\nexport const qualifiedTableName = (table: Pick<StorageTable, \"name\" | \"schema\">) =>\n (table.schema === undefined ? \"\" : quote(table.schema) + \".\") + quote(table.name);\n\nexport interface PhysicalTextColumn {\n readonly table: Pick<PhysicalStorageTable, \"name\" | \"schema\">;\n readonly name: string;\n}\n\nconst TextColumns = Schema.Array(Schema.Struct({ type: Schema.String, collation: Schema.String }));\n\n/** One acquisition-only read: presence/unique-key validation does not establish\n * equality compatibility. SQLite's pragma omits column collations, so only\n * ordinary TEXT tables with no COLLATE declaration qualify (default BINARY). */\nexport const canJoinTextColumns = Effect.fnUntraced(function* (\n left: PhysicalTextColumn | undefined,\n right: PhysicalTextColumn | undefined,\n) {\n if (left === undefined || right === undefined) return false;\n const { $client } = yield* NativeDatabase;\n const client = $client.withoutTransforms();\n const columns = [left, right];\n\n if (\n client.onDialectOrElse({ sqlite: () => true, orElse: () => false }) &&\n columns.some((c) => c.table.schema !== undefined && c.table.schema !== \"main\")\n )\n return false;\n\n const query = client.onDialectOrElse({\n pg: () => client`\n select a.atttypid::text as type, a.attcollation::text as collation\n from (values ${client.join(\", \", false)(columns.map((c) => client`(${qualifiedTableName(c.table)}::text, ${c.name}::text)`))}) requested(relation, name)\n join pg_attribute a on a.attrelid = to_regclass(requested.relation)\n and a.attname = requested.name and a.attnum > 0 and not a.attisdropped\n where a.atttypid in ('text'::regtype, 'varchar'::regtype)`,\n sqlite: () => client`\n with requested(relation, name) as (values ${client.join(\", \", false)(columns.map((c) => client`(${c.table.name}, ${c.name})`))})\n select 'text' as type, 'BINARY' as collation from requested\n join sqlite_schema s on s.name = requested.relation and s.type = 'table'\n join pragma_table_info(requested.relation) c on c.name = requested.name\n where upper(c.type) = 'TEXT' and instr(lower(s.sql), 'collate') = 0`,\n mysql: () => client`\n select c.data_type as type, c.collation_name as collation\n from (${client.join(\" union all \", false)(columns.map((c) => client`select ${c.table.schema ?? null} as schema_name, ${c.table.name} as table_name, ${c.name} as column_name`))}) requested\n join information_schema.columns c\n on c.table_schema = coalesce(requested.schema_name, database())\n and c.table_name = requested.table_name and c.column_name = requested.column_name\n where c.data_type in ('varchar', 'text', 'tinytext', 'mediumtext', 'longtext')`,\n orElse: () => Effect.succeed([]),\n });\n\n const rows = yield* query.pipe(Effect.flatMap(Schema.decodeUnknownEffect(TextColumns)));\n\n return (\n rows.length === 2 &&\n rows[0]?.type === rows[1]?.type &&\n rows[0]?.collation === rows[1]?.collation\n );\n});\n\nconst validateKeys = Effect.fnUntraced(function* (\n table: PhysicalStorageTable,\n required: ReadonlyArray<ReadonlyArray<string>>,\n physicalKeys: ReadonlyArray<ReadonlyArray<string>>,\n) {\n for (const keys of required) {\n const columns = keys.map((key) => table.columns[key]?.name);\n\n if (\n columns.some((column) => column === undefined) ||\n !physicalKeys.some(\n // A stronger key also guarantees the required tuple's uniqueness.\n (actual) =>\n actual.length > 0 &&\n actual.length <= columns.length &&\n actual.every((column) => columns.includes(column)),\n )\n )\n return yield* PersistenceConfigurationError.make({\n reason: `Missing unique key on ${table.name} (${keys.join(\", \")})`,\n });\n }\n});\n\ninterface MetadataCache {\n active: boolean;\n readonly clients: Map<SqlClient, Map<string, typeof Metadata.Type>>;\n}\n\nconst CurrentMetadata = Context.Reference<MetadataCache | undefined>(\n \"@yielded/auth-persistence/StorageMetadata\",\n { defaultValue: () => undefined },\n);\n\n/** Share metadata only while constructing one service graph. Captured contexts\n * cannot reuse it after acquisition succeeds, fails, or is interrupted. */\nexport const withStorageValidation = Effect.fnUntraced(function* <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.fn.Return<A, E, R> {\n const parent = yield* CurrentMetadata;\n\n if (parent?.active) return yield* effect;\n const cache: MetadataCache = { active: true, clients: new Map() };\n\n return yield* effect.pipe(\n Effect.provideService(CurrentMetadata, cache),\n Effect.ensuring(\n Effect.sync(() => {\n cache.active = false;\n cache.clients.clear();\n }),\n ),\n );\n});\n\n/** Requirements checked against one physical catalog snapshot. */\nexport interface StorageValidation {\n readonly table: PhysicalStorageTable;\n readonly required: ReadonlyArray<ReadonlyArray<string>>;\n}\n\n/** Batch physical metadata reads, reusing only the current acquisition snapshot.\n * Every requirement is still checked; later acquisitions read fresh metadata. */\nexport const validateStorageBatch = Effect.fnUntraced(\n function* (dialect: \"pg\" | \"mysql\" | \"sqlite\", requirements: ReadonlyArray<StorageValidation>) {\n if (requirements.length === 0) return;\n if (\n dialect === \"sqlite\" &&\n requirements.some(({ table }) => table.schema !== undefined && table.schema !== \"main\")\n )\n return yield* PersistenceConfigurationError.make({\n reason: \"SQLite storage must belong to the main database\",\n });\n const client = yield* SqlClient;\n const cache = yield* CurrentMetadata;\n\n const byRelation = cache?.active\n ? (cache.clients.get(client) ?? new Map<string, typeof Metadata.Type>())\n : new Map<string, typeof Metadata.Type>();\n\n if (cache?.active) cache.clients.set(client, byRelation);\n\n const tables = new Map(requirements.map(({ table }) => [qualifiedTableName(table), table]));\n\n const missing = [...tables.entries()].filter(\n ([relation]) => !byRelation.has(`${dialect}:${relation}`),\n );\n\n const relations = missing.map(([relation]) => relation);\n\n if (relations.length > 0) {\n const metadata = yield* dialect === \"sqlite\"\n ? Effect.gen(function* () {\n const requested = client.join(\n \", \",\n false,\n )(missing.map(([relation, table]) => client`(${relation}, ${table.name})`));\n\n return yield* client`\n with requested(relation, name) as (values ${requested})\n select requested.relation,\n (select json_group_array(name) from pragma_table_info(requested.name)) as columns,\n (select json_group_array(json(storage_key.columns)) from (\n select json_group_array(name) as columns from (\n select name from pragma_table_info(requested.name) where pk > 0 order by pk\n )\n union all\n select (select json_group_array(name) from pragma_index_info(i.name)) as columns\n from pragma_index_list(requested.name) i\n where i.\"unique\" = 1 and i.partial = 0\n and not exists(select 1 from pragma_index_info(i.name) where name is null)\n ) storage_key where json_array_length(storage_key.columns) > 0) as keys\n from requested\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(SqliteMetadata)));\n })\n : dialect === \"mysql\"\n ? Effect.gen(function* () {\n const requested = client.join(\n \" union all \",\n false,\n )(\n missing.map(\n ([relation, table]) =>\n client`select ${relation} as relation, ${table.schema ?? null} as schemaName, ${table.name} as tableName`,\n ),\n );\n\n const columns = yield* client`\n select requested.relation, c.column_name as name\n from (${requested}) requested join information_schema.columns c\n on c.table_schema = coalesce(requested.schemaName, database()) and c.table_name = requested.tableName\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(MysqlColumns)));\n\n const indexes = yield* client`\n select requested.relation, i.index_name as name, i.column_name as columnName, i.sub_part as prefix\n from (${requested}) requested join information_schema.statistics i\n on i.table_schema = coalesce(requested.schemaName, database()) and i.table_name = requested.tableName\n where i.non_unique = 0 order by requested.relation, i.index_name, i.seq_in_index\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(MysqlIndexes)));\n\n return relations.map((relation) => {\n const grouped = new Map<string, Array<(typeof indexes)[number]>>();\n\n for (const index of indexes) {\n if (index.relation !== relation) continue;\n const entries = grouped.get(index.name) ?? [];\n\n entries.push(index);\n grouped.set(index.name, entries);\n }\n\n return {\n relation,\n columns: columns\n .filter((column) => column.relation === relation)\n .map((column) => column.name),\n keys: [...grouped.values()]\n .filter((entries) =>\n entries.every((entry) => entry.columnName !== null && entry.prefix === null),\n )\n .map((entries) =>\n entries.flatMap((entry) =>\n entry.columnName === null ? [] : [entry.columnName],\n ),\n ),\n };\n });\n })\n : Effect.gen(function* () {\n const requested = client.join(\n \", \",\n false,\n )(relations.map((relation) => client`(${relation}::text)`));\n\n return yield* client`\n select requested.relation,\n array(select a.attname::text from pg_attribute a\n where a.attrelid = to_regclass(requested.relation)\n and a.attnum > 0 and not a.attisdropped) as columns,\n coalesce((select jsonb_agg(storage_key.columns) from (\n select array_agg(a.attname::text order by k.ordinality) as columns\n from pg_index i\n cross join lateral unnest(i.indkey) with ordinality as k(attnum, ordinality)\n join pg_attribute a on a.attrelid = i.indrelid and a.attnum = k.attnum\n where i.indrelid = to_regclass(requested.relation)\n and i.indisunique and i.indisvalid and i.indimmediate\n and i.indpred is null and i.indexprs is null\n and k.ordinality <= i.indnkeyatts\n group by i.indexrelid\n ) storage_key), '[]'::jsonb) as keys\n from (values ${requested}) requested(relation)\n `.pipe(Effect.flatMap(Schema.decodeUnknownEffect(PgMetadata)));\n });\n\n for (const row of metadata) byRelation.set(`${dialect}:${row.relation}`, row);\n }\n\n for (const { table, required } of requirements) {\n const relation = qualifiedTableName(table);\n const actual = byRelation.get(`${dialect}:${relation}`);\n\n for (const column of Object.values(table.columns)) {\n if (actual === undefined || !actual.columns.includes(column.name))\n return yield* PersistenceConfigurationError.make({\n reason: `Missing SQL column ${relation}.${column.name}`,\n });\n }\n yield* validateKeys(table, required, actual?.keys ?? []);\n }\n },\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : PersistenceConfigurationError.make({ reason: \"Cannot validate SQL storage metadata\" }),\n ),\n);\n\n/** Validate physical columns and unconditional uniqueness before operations run. */\nexport const validateStorage = (\n dialect: \"pg\" | \"mysql\" | \"sqlite\",\n table: PhysicalStorageTable,\n required: ReadonlyArray<ReadonlyArray<string>>,\n) => validateStorageBatch(dialect, [{ table, required }]);\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { NativeDatabase, TransactionNativeDatabase, TransactionOwner, makeTransactionKernel } from "./transaction-kernel.mjs";
2
2
  import { Context, Crypto, Effect, PlatformError } from "effect";
3
+ import { Statement } from "effect/sql/Statement";
3
4
  import { CurrentCommitJournal, HookConfigurationError, LifecycleHooks } from "@yielded/auth/Hooks";
4
5
  import * as SqlClient$1 from "effect/sql/SqlClient";
5
- import { Statement } from "effect/sql/Statement";
6
6
  import * as SqlError$1 from "effect/sql/SqlError";
7
7
  //#region src/internal/transaction-execution-kernel.d.ts
8
8
  export interface TransactionTargetConfiguration<Failure> {
@@ -1,8 +1,8 @@
1
1
  import { QueryOperations, SqlColumn, SqlExpression, SqlFragment } from "./query-operations.mjs";
2
2
  import { Context, Effect } from "effect";
3
+ import { Statement } from "effect/sql/Statement";
3
4
  import { CommitJournal, PreparedCommit } from "@yielded/auth/Hooks";
4
5
  import * as SqlClient$1 from "effect/sql/SqlClient";
5
- import { Statement } from "effect/sql/Statement";
6
6
  import { SqlError } from "effect/sql/SqlError";
7
7
  //#region src/internal/transaction-kernel.d.ts
8
8
  type Table = object;
@@ -121,8 +121,9 @@ const makeTransactionKernel = (operations) => {
121
121
  const conditionHolds = (condition) => Effect.gen(function* () {
122
122
  const query = queryCondition(condition);
123
123
  const rows = yield* configuration.dialect === "sqlite" ? toStatement(query) : query;
124
- invariant(rows.length === 1);
125
- return rows[0].value === 1;
124
+ const row = rows[0];
125
+ invariant(rows.length === 1 && row !== void 0);
126
+ return Object.values(row)[0] === 1;
126
127
  });
127
128
  const guardedQuery = (table, where, values, guard) => {
128
129
  invariant(Number.isSafeInteger(guard.rows) && guard.rows > 0 && guard.rows <= 128);
@@ -1 +1 @@
1
- {"version":3,"file":"transaction-kernel.mjs","names":[],"sources":["../../src/internal/transaction-kernel.ts"],"sourcesContent":["import { type CommitJournal, type PreparedCommit } from \"@yielded/auth/Hooks\";\nimport { reportAuthFailure } from \"@yielded/auth/Persistence\";\n/* oxlint-disable no-explicit-any -- existing storage kernels erase foreign table shapes; domain errors remain typed. */\nimport { Cause, Context, Effect } from \"effect\";\nimport type * as SqlClient from \"effect/sql/SqlClient\";\nimport type { SqlError } from \"effect/sql/SqlError\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport type {\n SqlExpression as SQL,\n QueryFailure,\n QueryOperations,\n SqlFragment,\n SqlColumn,\n} from \"./query-operations\";\n\ntype Table = object;\n\nexport type Row = Record<string, any>;\n\n/** Only query-builder/table shapes are erased here. Installed native\n * queries have captured clients, and their error channel remains explicit. */\ntype NativeQuery<A> = Effect.Effect<A, QueryFailure | SqlError>;\n\nexport interface TransactionNativeDatabase {\n readonly $client: SqlClient.SqlClient & {\n readonly batch: (statements: ReadonlyArray<Statement<any>>) => Effect.Effect<any, SqlError>;\n };\n readonly transaction: <A, E, R>(\n body: (transaction: any) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SqlError, R>;\n}\n\n/** Captured root database for service construction and pre-transaction catalog checks.\n * Active transactions remain owned by their coordinator and journal. */\nexport class NativeDatabase extends Context.Service<NativeDatabase, TransactionNativeDatabase>()(\n \"effect-auth/persistence/NativeDatabase\",\n) {}\n\nexport interface Observation {\n readonly table: Table;\n readonly where: SQL;\n rows: ReadonlyArray<Row>;\n}\n\n/** Expressions deliberately do not replace observed values. Read only semantic\n * columns when telemetry changes atomically, and state the physical result. */\nexport interface GuardedUpdate {\n readonly rows: number;\n readonly postcondition: SQL;\n}\n\nexport interface TransactionOwner<Failure> {\n readonly database: any;\n readonly journal: CommitJournal;\n readonly marker: string;\n readonly batch: boolean;\n readonly observations: Observation[];\n readonly postconditions: Array<SQL | (() => SQL)>;\n readonly statements: Statement<any>[];\n readonly guards: PreparedCommit<void>[];\n exact(table: Table, row: Row): SQL;\n read(\n table: Table,\n where: SQL,\n options?: {\n readonly lock?: boolean;\n readonly limit?: number;\n readonly observe?: boolean;\n readonly admissionOnly?: boolean;\n readonly takeOnly?: boolean;\n readonly orderBy?: any;\n readonly columns?: ReadonlyArray<string>;\n },\n ): Effect.Effect<Observation, Failure>;\n write(query: any): Effect.Effect<void, Failure>;\n insert(\n table: Table,\n values: Row,\n key: Row,\n absent?: boolean,\n ): Effect.Effect<Observation, Failure>;\n update(table: Table, key: Row, values: Row): Effect.Effect<void, Failure>;\n updateGuarded(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n /** Internal SQL only, run once after application work and before final guards. */\n finalUpdate(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n remove(table: Table, key: Row): Effect.Effect<void, Failure>;\n check(condition: SQL): Effect.Effect<boolean, Failure>;\n now(clock: { readonly engineNowMillis: SQL }): Effect.Effect<number, Failure>;\n finish(): Effect.Effect<void, Failure>;\n}\n\nexport const makeTransactionKernel = <\n Fragment extends SqlFragment = SqlFragment,\n Column extends SqlColumn = SqlColumn,\n>(\n operations: QueryOperations<Fragment, Column>,\n) => {\n const { eq, getTableColumns, isNull, sql, balancedD1And, compactD1GeneratedStatement } =\n operations;\n\n const isUnavailableCause = <Failure>(cause: Cause.Cause<unknown>, unavailable: () => Failure) => {\n const expected = unavailable();\n\n const tag =\n typeof expected === \"object\" && expected !== null && \"_tag\" in expected\n ? expected._tag\n : undefined;\n\n return (\n tag !== undefined &&\n cause.reasons.length > 0 &&\n cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n typeof reason.error === \"object\" &&\n reason.error !== null &&\n \"_tag\" in reason.error &&\n reason.error._tag === tag,\n )\n );\n };\n\n /** Report once, before an adapter replaces the raw cause with its public\n * unavailable error. Already translated failures stay quiet at outer owners. */\n const reportTransactionFailure = <A, E, R, Failure>(\n effect: Effect.Effect<A, E, R>,\n unavailable: () => Failure,\n ): Effect.Effect<A, E, R> =>\n Effect.catchCause(effect, (cause) =>\n isUnavailableCause(cause, unavailable)\n ? Effect.failCause(cause)\n : reportAuthFailure(\"auth-persistence\", cause).pipe(\n Effect.andThen(Effect.failCause(cause)),\n ),\n );\n\n const both = (...parts: ReadonlyArray<SQL | undefined>) => balancedD1And(...parts) ?? sql`1 = 1`;\n\n const makeTransactionRows = <Failure>(unavailable: () => Failure) => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const col = (table: Table, key: string) => {\n const value = getTableColumns(table)[key];\n\n invariant(value !== undefined);\n\n return value;\n };\n\n const equal = (table: Table, values: Row) =>\n both(\n ...Object.entries(values).map(([key, value]) =>\n value === null ? isNull(col(table, key)) : eq(col(table, key), value),\n ),\n );\n\n /** Mapped driver values use plain data, Dates and binary views. Application\n * identity classes are reconstructed by the mapped codecs, never cloned here. */\n const copiedRow = (row: Row) => {\n const seen = new WeakSet<object>();\n\n const supported = (value: unknown): void => {\n if (value === null || typeof value !== \"object\" || seen.has(value)) return;\n seen.add(value);\n if (value instanceof Date || value instanceof ArrayBuffer || ArrayBuffer.isView(value))\n return;\n invariant(\n Array.isArray(value) ||\n Object.getPrototypeOf(value) === Object.prototype ||\n Object.getPrototypeOf(value) === null,\n );\n for (const item of Object.values(value)) supported(item);\n };\n\n supported(row);\n\n return structuredClone(row);\n };\n\n const nativeKey = (value: unknown): string => {\n const packed = (tag: string, text: string) => tag + text.length + \":\" + text;\n\n if (value instanceof Date) return packed(\"date\", value.toISOString());\n if (typeof value === \"bigint\") return packed(\"bigint\", value.toString());\n\n const bytes =\n value instanceof ArrayBuffer\n ? new Uint8Array(value)\n : ArrayBuffer.isView(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : undefined;\n\n if (bytes !== undefined) return packed(\"bytes\", Array.from(bytes).join(\",\"));\n if (value === null || typeof value !== \"object\") return packed(typeof value, String(value));\n if (Array.isArray(value)) return packed(\"array\", value.map(nativeKey).join(\"\"));\n invariant(\n Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null,\n );\n\n return packed(\n \"object\",\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([name, item]) => nativeKey(name) + nativeKey(item))\n .join(\"\"),\n );\n };\n\n const matchesNativeRow = (table: Table, row: Row, key: Row) =>\n Object.entries(key).every(([name, value]) => {\n if (value === null || row[name] === null) return value === row[name];\n const column = col(table, name);\n\n return (\n nativeKey(column.mapToDriverValue(row[name])) ===\n nativeKey(column.mapToDriverValue(value))\n );\n });\n\n return { col, equal, copiedRow, matchesNativeRow };\n };\n\n const makeTransactionOwner = <Failure>(\n database: any,\n journal: CommitJournal,\n marker: string,\n unavailable: () => Failure,\n configuration: {\n readonly client?: any;\n readonly batch: boolean;\n readonly locking: boolean;\n readonly mysql: boolean;\n readonly dialect: \"pg\" | \"mysql\" | \"sqlite\";\n },\n ): TransactionOwner<Failure> => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const { col, equal, matchesNativeRow } = makeTransactionRows(unavailable);\n let phase: \"open\" | \"finishing\" | \"finished\" = \"open\";\n let poisoned = false;\n const open = () => invariant(phase === \"open\" && !poisoned);\n\n const result = <A, E>(effect: Effect.Effect<A, E>) =>\n effect.pipe(\n (operation) => reportTransactionFailure(operation, unavailable),\n Effect.mapError(unavailable),\n Effect.catchDefect(() => Effect.fail(unavailable())),\n Effect.onExit((exit) =>\n Effect.sync(() => {\n if (exit._tag === \"Failure\") poisoned = true;\n }),\n ),\n );\n\n const observations: Observation[] = [];\n const statements: Statement<any>[] = [];\n const postconditions: Array<SQL | (() => SQL)> = [];\n const guards: PreparedCommit<void>[] = [];\n const finalUpdates: Array<{ readonly query: any; readonly guard: GuardedUpdate }> = [];\n\n const exactRow = (table: Table, row: Row) =>\n both(\n ...Object.entries(row).map(([key, value]) => {\n if (typeof value !== \"string\") return equal(table, { [key]: value });\n\n const column = col(table, key),\n bound = sql.param(value, column);\n\n return configuration.dialect === \"mysql\"\n ? sql`binary ${column} = binary ${bound}`\n : configuration.dialect === \"pg\"\n ? sql`convert_to(cast(${column} as text), 'UTF8') = convert_to(cast(${bound} as text), 'UTF8')`\n : sql`cast(${column} as blob) = cast(${bound} as blob)`;\n }),\n );\n\n const toStatement = (query: any): Statement<any> => {\n const rendered = query.toSQL();\n const client = configuration.client ?? database.$client;\n\n return compactD1GeneratedStatement(\n client,\n client.unsafe(rendered.sql, rendered.params),\n unavailable,\n );\n };\n\n const assertion = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else json_extract('[]', ${\"$[oauth-owner-\" + marker + \"]\"}) end`,\n })\n .from(sql`(select 1) as oauth_assertion`);\n\n const observedConditions = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => [\n sql`(select count(*) from ${table} where ${where}) = ${rows.length}`,\n ...rows.map(\n (row) => sql`exists(select 1 from ${table} where ${both(where, exactRow(table, row))})`,\n ),\n ];\n\n // All chunks remain inside the same native owner or atomic D1 batch. A single\n // wide row is compacted; separate observations cannot accumulate unbounded\n // bind parameters or expression depth in one final SELECT.\n const chunks = (conditions: ReadonlyArray<SQL>) => {\n const output: SQL[] = [];\n let pending: SQL[] = [];\n\n for (const condition of conditions) {\n const candidate = [...pending, condition];\n const rendered = assertion(both(...candidate)).toSQL();\n\n if (\n pending.length > 0 &&\n (rendered.params.length > 96 || new TextEncoder().encode(rendered.sql).length > 48_000)\n ) {\n output.push(both(...pending));\n pending = [condition];\n } else pending = candidate;\n }\n if (pending.length > 0) output.push(both(...pending));\n\n return output;\n };\n\n const appendAssertions = (conditions: ReadonlyArray<SQL>) => {\n for (const condition of chunks(conditions))\n statements.push(toStatement(assertion(condition)));\n };\n\n const observed = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => {\n const observation = { table, where, rows };\n\n observations.push(observation);\n\n return observation;\n };\n\n const queryCondition = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else 0 end`.mapWith(Number).as(\"value\"),\n })\n .from(sql`(select 1) as oauth_guard`);\n\n const conditionHolds = (condition: SQL) =>\n Effect.gen(function* () {\n const query = queryCondition(condition);\n\n const rows: ReadonlyArray<Row> = yield* configuration.dialect === \"sqlite\"\n ? toStatement(query)\n : (query as NativeQuery<Row[]>);\n\n invariant(rows.length === 1);\n\n return rows[0]!.value === 1;\n });\n\n const guardedQuery = (table: Table, where: SQL, values: Row, guard: GuardedUpdate) => {\n invariant(Number.isSafeInteger(guard.rows) && guard.rows > 0 && guard.rows <= 128);\n\n return { query: database.update(table).set(values).where(where), guard: { ...guard } };\n };\n\n const applyGuarded = (entry: { readonly query: any; readonly guard: GuardedUpdate }) =>\n Effect.gen(function* () {\n if (configuration.batch) {\n statements.push(toStatement(entry.query));\n statements.push(toStatement(assertion(sql`changes() = ${entry.guard.rows}`)));\n appendAssertions([entry.guard.postcondition]);\n } else {\n if (configuration.mysql) {\n // mysql2 reports matched rows (FOUND_ROWS), including a telemetry no-op.\n const changed = yield* entry.query as NativeQuery<{ readonly affectedRows: number }>;\n\n invariant(changed.affectedRows === entry.guard.rows);\n } else {\n const changed = yield* entry.query.returning({ value: sql`1` }) as NativeQuery<\n ReadonlyArray<Row>\n >;\n\n invariant(changed.length === entry.guard.rows);\n }\n invariant(yield* conditionHolds(entry.guard.postcondition));\n }\n });\n\n const owner: TransactionOwner<Failure> = {\n database,\n journal,\n marker,\n batch: configuration.batch,\n observations,\n statements,\n postconditions,\n guards,\n exact: exactRow,\n read: (table, where, options = {}) =>\n result(\n Effect.gen(function* () {\n open();\n const limit = options.limit ?? 64;\n\n let query = database\n .select(\n options.columns === undefined\n ? undefined\n : Object.fromEntries(options.columns.map((key) => [key, col(table, key)])),\n )\n .from(table)\n .where(where)\n .limit(options.takeOnly ? limit : limit + 1);\n\n if (options.orderBy !== undefined) query = query.orderBy(options.orderBy);\n if (options.lock !== false && configuration.locking) query = query.for(\"update\");\n const rows: Row[] = yield* query as NativeQuery<Row[]>;\n\n invariant(rows.length <= limit);\n if (configuration.batch && (options.observe !== false || options.admissionOnly))\n appendAssertions(observedConditions(table, where, rows));\n\n return options.observe === false || options.admissionOnly\n ? { table, where, rows }\n : observed(table, where, rows);\n }),\n ),\n write: (query) =>\n result(\n Effect.gen(function* () {\n open();\n if (configuration.batch) statements.push(toStatement(query));\n else yield* query as NativeQuery<unknown>;\n }),\n ),\n insert: (table, values, key, absent = false) =>\n result(\n Effect.gen(function* () {\n open();\n let query = database.insert(table).values(values);\n\n if (absent)\n query = configuration.mysql\n ? query.onDuplicateKeyUpdate({\n set: { [Object.keys(key)[0]!]: col(table, Object.keys(key)[0]!) },\n })\n : query.onConflictDoNothing();\n yield* owner.write(query);\n const where = equal(table, key);\n\n if (configuration.batch) return observed(table, where, [values]);\n const found = yield* owner.read(table, where, { limit: 1 });\n const markerColumn = Object.keys(values).find((key) => values[key] === marker);\n\n if (!absent || (markerColumn !== undefined && found.rows[0]?.[markerColumn] === marker))\n invariant(\n yield* owner.check(\n sql`exists(select 1 from ${table} where ${both(where, exactRow(table, values))})`,\n ),\n );\n\n return found;\n }),\n ),\n update: (table, key, values) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.update(table).set(values).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.map((row) =>\n matchesNativeRow(table, row, key) ? { ...row, ...values } : row,\n );\n }),\n ),\n updateGuarded: (table, where, values, guard) =>\n result(\n Effect.gen(function* () {\n open();\n const entry = guardedQuery(table, where, values, guard);\n\n yield* applyGuarded(entry);\n postconditions.push(entry.guard.postcondition);\n }),\n ),\n finalUpdate: (table, where, values, guard) =>\n result(\n Effect.sync(() => {\n open();\n invariant(finalUpdates.length < 128);\n finalUpdates.push(guardedQuery(table, where, values, guard));\n }),\n ),\n remove: (table, key) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.delete(table).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.filter(\n (row) => !matchesNativeRow(table, row, key),\n );\n }),\n ),\n check: (condition) =>\n result(\n Effect.gen(function* () {\n open();\n const holds = yield* conditionHolds(condition);\n\n if (configuration.batch)\n statements.push(toStatement(assertion(holds ? condition : sql`not (${condition})`)));\n\n return holds;\n }),\n ),\n now: (clock) =>\n result(\n Effect.gen(function* () {\n open();\n\n const rows: Row[] = yield* database\n .select({\n value: sql`${clock.engineNowMillis}`.mapWith(Number),\n })\n .from(sql`(select 1) as oauth_clock`) as NativeQuery<Row[]>;\n\n const value = rows[0]?.value;\n\n invariant(Number.isSafeInteger(value) && value >= 0);\n\n return value as number;\n }),\n ),\n finish: () =>\n result(\n Effect.gen(function* () {\n open();\n phase = \"finishing\";\n Object.freeze(observations);\n Object.freeze(postconditions);\n Object.freeze(guards);\n Object.freeze(finalUpdates);\n\n // Close registration before any late-bound SQL predicate is materialized.\n // No callback is invoked after the first final write.\n const conditions: SQL[] = observations.flatMap((observation) =>\n observedConditions(observation.table, observation.where, observation.rows),\n );\n\n conditions.push(\n ...postconditions.map((condition) =>\n typeof condition === \"function\" ? condition() : condition,\n ),\n );\n conditions.push(...finalUpdates.map((entry) => entry.guard.postcondition));\n for (const guard of guards) {\n const status = yield* Effect.result(guard.read);\n\n invariant(status._tag === \"Failure\" && status.failure._tag === \"CommitPending\");\n }\n invariant(!poisoned);\n for (const entry of finalUpdates) yield* applyGuarded(entry);\n if (configuration.batch) appendAssertions(conditions);\n else\n for (const condition of chunks(conditions))\n invariant(yield* conditionHolds(condition));\n invariant(!poisoned);\n }).pipe(\n Effect.ensuring(\n Effect.sync(() => {\n phase = \"finished\";\n }),\n ),\n ),\n ),\n };\n\n return owner;\n };\n\n return { reportTransactionFailure, both, makeTransactionRows, makeTransactionOwner };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"transaction-kernel.mjs","names":[],"sources":["../../src/internal/transaction-kernel.ts"],"sourcesContent":["import { type CommitJournal, type PreparedCommit } from \"@yielded/auth/Hooks\";\nimport { reportAuthFailure } from \"@yielded/auth/Persistence\";\n/* oxlint-disable no-explicit-any -- existing storage kernels erase foreign table shapes; domain errors remain typed. */\nimport { Cause, Context, Effect } from \"effect\";\nimport type * as SqlClient from \"effect/sql/SqlClient\";\nimport type { SqlError } from \"effect/sql/SqlError\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport type {\n SqlExpression as SQL,\n QueryFailure,\n QueryOperations,\n SqlFragment,\n SqlColumn,\n} from \"./query-operations\";\n\ntype Table = object;\n\nexport type Row = Record<string, any>;\n\n/** Only query-builder/table shapes are erased here. Installed native\n * queries have captured clients, and their error channel remains explicit. */\ntype NativeQuery<A> = Effect.Effect<A, QueryFailure | SqlError>;\n\nexport interface TransactionNativeDatabase {\n readonly $client: SqlClient.SqlClient & {\n readonly batch: (statements: ReadonlyArray<Statement<any>>) => Effect.Effect<any, SqlError>;\n };\n readonly transaction: <A, E, R>(\n body: (transaction: any) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SqlError, R>;\n}\n\n/** Captured root database for service construction and pre-transaction catalog checks.\n * Active transactions remain owned by their coordinator and journal. */\nexport class NativeDatabase extends Context.Service<NativeDatabase, TransactionNativeDatabase>()(\n \"effect-auth/persistence/NativeDatabase\",\n) {}\n\nexport interface Observation {\n readonly table: Table;\n readonly where: SQL;\n rows: ReadonlyArray<Row>;\n}\n\n/** Expressions deliberately do not replace observed values. Read only semantic\n * columns when telemetry changes atomically, and state the physical result. */\nexport interface GuardedUpdate {\n readonly rows: number;\n readonly postcondition: SQL;\n}\n\nexport interface TransactionOwner<Failure> {\n readonly database: any;\n readonly journal: CommitJournal;\n readonly marker: string;\n readonly batch: boolean;\n readonly observations: Observation[];\n readonly postconditions: Array<SQL | (() => SQL)>;\n readonly statements: Statement<any>[];\n readonly guards: PreparedCommit<void>[];\n exact(table: Table, row: Row): SQL;\n read(\n table: Table,\n where: SQL,\n options?: {\n readonly lock?: boolean;\n readonly limit?: number;\n readonly observe?: boolean;\n readonly admissionOnly?: boolean;\n readonly takeOnly?: boolean;\n readonly orderBy?: any;\n readonly columns?: ReadonlyArray<string>;\n },\n ): Effect.Effect<Observation, Failure>;\n write(query: any): Effect.Effect<void, Failure>;\n insert(\n table: Table,\n values: Row,\n key: Row,\n absent?: boolean,\n ): Effect.Effect<Observation, Failure>;\n update(table: Table, key: Row, values: Row): Effect.Effect<void, Failure>;\n updateGuarded(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n /** Internal SQL only, run once after application work and before final guards. */\n finalUpdate(\n table: Table,\n where: SQL,\n values: Row,\n guard: GuardedUpdate,\n ): Effect.Effect<void, Failure>;\n remove(table: Table, key: Row): Effect.Effect<void, Failure>;\n check(condition: SQL): Effect.Effect<boolean, Failure>;\n now(clock: { readonly engineNowMillis: SQL }): Effect.Effect<number, Failure>;\n finish(): Effect.Effect<void, Failure>;\n}\n\nexport const makeTransactionKernel = <\n Fragment extends SqlFragment = SqlFragment,\n Column extends SqlColumn = SqlColumn,\n>(\n operations: QueryOperations<Fragment, Column>,\n) => {\n const { eq, getTableColumns, isNull, sql, balancedD1And, compactD1GeneratedStatement } =\n operations;\n\n const isUnavailableCause = <Failure>(cause: Cause.Cause<unknown>, unavailable: () => Failure) => {\n const expected = unavailable();\n\n const tag =\n typeof expected === \"object\" && expected !== null && \"_tag\" in expected\n ? expected._tag\n : undefined;\n\n return (\n tag !== undefined &&\n cause.reasons.length > 0 &&\n cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n typeof reason.error === \"object\" &&\n reason.error !== null &&\n \"_tag\" in reason.error &&\n reason.error._tag === tag,\n )\n );\n };\n\n /** Report once, before an adapter replaces the raw cause with its public\n * unavailable error. Already translated failures stay quiet at outer owners. */\n const reportTransactionFailure = <A, E, R, Failure>(\n effect: Effect.Effect<A, E, R>,\n unavailable: () => Failure,\n ): Effect.Effect<A, E, R> =>\n Effect.catchCause(effect, (cause) =>\n isUnavailableCause(cause, unavailable)\n ? Effect.failCause(cause)\n : reportAuthFailure(\"auth-persistence\", cause).pipe(\n Effect.andThen(Effect.failCause(cause)),\n ),\n );\n\n const both = (...parts: ReadonlyArray<SQL | undefined>) => balancedD1And(...parts) ?? sql`1 = 1`;\n\n const makeTransactionRows = <Failure>(unavailable: () => Failure) => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const col = (table: Table, key: string) => {\n const value = getTableColumns(table)[key];\n\n invariant(value !== undefined);\n\n return value;\n };\n\n const equal = (table: Table, values: Row) =>\n both(\n ...Object.entries(values).map(([key, value]) =>\n value === null ? isNull(col(table, key)) : eq(col(table, key), value),\n ),\n );\n\n /** Mapped driver values use plain data, Dates and binary views. Application\n * identity classes are reconstructed by the mapped codecs, never cloned here. */\n const copiedRow = (row: Row) => {\n const seen = new WeakSet<object>();\n\n const supported = (value: unknown): void => {\n if (value === null || typeof value !== \"object\" || seen.has(value)) return;\n seen.add(value);\n if (value instanceof Date || value instanceof ArrayBuffer || ArrayBuffer.isView(value))\n return;\n invariant(\n Array.isArray(value) ||\n Object.getPrototypeOf(value) === Object.prototype ||\n Object.getPrototypeOf(value) === null,\n );\n for (const item of Object.values(value)) supported(item);\n };\n\n supported(row);\n\n return structuredClone(row);\n };\n\n const nativeKey = (value: unknown): string => {\n const packed = (tag: string, text: string) => tag + text.length + \":\" + text;\n\n if (value instanceof Date) return packed(\"date\", value.toISOString());\n if (typeof value === \"bigint\") return packed(\"bigint\", value.toString());\n\n const bytes =\n value instanceof ArrayBuffer\n ? new Uint8Array(value)\n : ArrayBuffer.isView(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : undefined;\n\n if (bytes !== undefined) return packed(\"bytes\", Array.from(bytes).join(\",\"));\n if (value === null || typeof value !== \"object\") return packed(typeof value, String(value));\n if (Array.isArray(value)) return packed(\"array\", value.map(nativeKey).join(\"\"));\n invariant(\n Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null,\n );\n\n return packed(\n \"object\",\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([name, item]) => nativeKey(name) + nativeKey(item))\n .join(\"\"),\n );\n };\n\n const matchesNativeRow = (table: Table, row: Row, key: Row) =>\n Object.entries(key).every(([name, value]) => {\n if (value === null || row[name] === null) return value === row[name];\n const column = col(table, name);\n\n return (\n nativeKey(column.mapToDriverValue(row[name])) ===\n nativeKey(column.mapToDriverValue(value))\n );\n });\n\n return { col, equal, copiedRow, matchesNativeRow };\n };\n\n const makeTransactionOwner = <Failure>(\n database: any,\n journal: CommitJournal,\n marker: string,\n unavailable: () => Failure,\n configuration: {\n readonly client?: any;\n readonly batch: boolean;\n readonly locking: boolean;\n readonly mysql: boolean;\n readonly dialect: \"pg\" | \"mysql\" | \"sqlite\";\n },\n ): TransactionOwner<Failure> => {\n const invariant: (value: unknown) => asserts value = (value) => {\n if (!value) throw unavailable();\n };\n\n const { col, equal, matchesNativeRow } = makeTransactionRows(unavailable);\n let phase: \"open\" | \"finishing\" | \"finished\" = \"open\";\n let poisoned = false;\n const open = () => invariant(phase === \"open\" && !poisoned);\n\n const result = <A, E>(effect: Effect.Effect<A, E>) =>\n effect.pipe(\n (operation) => reportTransactionFailure(operation, unavailable),\n Effect.mapError(unavailable),\n Effect.catchDefect(() => Effect.fail(unavailable())),\n Effect.onExit((exit) =>\n Effect.sync(() => {\n if (exit._tag === \"Failure\") poisoned = true;\n }),\n ),\n );\n\n const observations: Observation[] = [];\n const statements: Statement<any>[] = [];\n const postconditions: Array<SQL | (() => SQL)> = [];\n const guards: PreparedCommit<void>[] = [];\n const finalUpdates: Array<{ readonly query: any; readonly guard: GuardedUpdate }> = [];\n\n const exactRow = (table: Table, row: Row) =>\n both(\n ...Object.entries(row).map(([key, value]) => {\n if (typeof value !== \"string\") return equal(table, { [key]: value });\n\n const column = col(table, key),\n bound = sql.param(value, column);\n\n return configuration.dialect === \"mysql\"\n ? sql`binary ${column} = binary ${bound}`\n : configuration.dialect === \"pg\"\n ? sql`convert_to(cast(${column} as text), 'UTF8') = convert_to(cast(${bound} as text), 'UTF8')`\n : sql`cast(${column} as blob) = cast(${bound} as blob)`;\n }),\n );\n\n const toStatement = (query: any): Statement<any> => {\n const rendered = query.toSQL();\n const client = configuration.client ?? database.$client;\n\n return compactD1GeneratedStatement(\n client,\n client.unsafe(rendered.sql, rendered.params),\n unavailable,\n );\n };\n\n const assertion = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else json_extract('[]', ${\"$[oauth-owner-\" + marker + \"]\"}) end`,\n })\n .from(sql`(select 1) as oauth_assertion`);\n\n const observedConditions = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => [\n sql`(select count(*) from ${table} where ${where}) = ${rows.length}`,\n ...rows.map(\n (row) => sql`exists(select 1 from ${table} where ${both(where, exactRow(table, row))})`,\n ),\n ];\n\n // All chunks remain inside the same native owner or atomic D1 batch. A single\n // wide row is compacted; separate observations cannot accumulate unbounded\n // bind parameters or expression depth in one final SELECT.\n const chunks = (conditions: ReadonlyArray<SQL>) => {\n const output: SQL[] = [];\n let pending: SQL[] = [];\n\n for (const condition of conditions) {\n const candidate = [...pending, condition];\n const rendered = assertion(both(...candidate)).toSQL();\n\n if (\n pending.length > 0 &&\n (rendered.params.length > 96 || new TextEncoder().encode(rendered.sql).length > 48_000)\n ) {\n output.push(both(...pending));\n pending = [condition];\n } else pending = candidate;\n }\n if (pending.length > 0) output.push(both(...pending));\n\n return output;\n };\n\n const appendAssertions = (conditions: ReadonlyArray<SQL>) => {\n for (const condition of chunks(conditions))\n statements.push(toStatement(assertion(condition)));\n };\n\n const observed = (table: Table, where: SQL, rows: ReadonlyArray<Row>) => {\n const observation = { table, where, rows };\n\n observations.push(observation);\n\n return observation;\n };\n\n const queryCondition = (condition: SQL) =>\n database\n .select({\n value: sql`case when ${condition} then 1 else 0 end`.mapWith(Number).as(\"value\"),\n })\n .from(sql`(select 1) as oauth_guard`);\n\n const conditionHolds = (condition: SQL) =>\n Effect.gen(function* () {\n const query = queryCondition(condition);\n\n const rows: ReadonlyArray<Row> = yield* configuration.dialect === \"sqlite\"\n ? toStatement(query)\n : (query as NativeQuery<Row[]>);\n\n const row = rows[0];\n\n invariant(rows.length === 1 && row !== undefined);\n\n // SQLite executes the raw statement, before logical field decoding.\n // This query projects one value; its alias belongs to the adapter compiler.\n return Object.values(row)[0] === 1;\n });\n\n const guardedQuery = (table: Table, where: SQL, values: Row, guard: GuardedUpdate) => {\n invariant(Number.isSafeInteger(guard.rows) && guard.rows > 0 && guard.rows <= 128);\n\n return { query: database.update(table).set(values).where(where), guard: { ...guard } };\n };\n\n const applyGuarded = (entry: { readonly query: any; readonly guard: GuardedUpdate }) =>\n Effect.gen(function* () {\n if (configuration.batch) {\n statements.push(toStatement(entry.query));\n statements.push(toStatement(assertion(sql`changes() = ${entry.guard.rows}`)));\n appendAssertions([entry.guard.postcondition]);\n } else {\n if (configuration.mysql) {\n // mysql2 reports matched rows (FOUND_ROWS), including a telemetry no-op.\n const changed = yield* entry.query as NativeQuery<{ readonly affectedRows: number }>;\n\n invariant(changed.affectedRows === entry.guard.rows);\n } else {\n const changed = yield* entry.query.returning({ value: sql`1` }) as NativeQuery<\n ReadonlyArray<Row>\n >;\n\n invariant(changed.length === entry.guard.rows);\n }\n invariant(yield* conditionHolds(entry.guard.postcondition));\n }\n });\n\n const owner: TransactionOwner<Failure> = {\n database,\n journal,\n marker,\n batch: configuration.batch,\n observations,\n statements,\n postconditions,\n guards,\n exact: exactRow,\n read: (table, where, options = {}) =>\n result(\n Effect.gen(function* () {\n open();\n const limit = options.limit ?? 64;\n\n let query = database\n .select(\n options.columns === undefined\n ? undefined\n : Object.fromEntries(options.columns.map((key) => [key, col(table, key)])),\n )\n .from(table)\n .where(where)\n .limit(options.takeOnly ? limit : limit + 1);\n\n if (options.orderBy !== undefined) query = query.orderBy(options.orderBy);\n if (options.lock !== false && configuration.locking) query = query.for(\"update\");\n const rows: Row[] = yield* query as NativeQuery<Row[]>;\n\n invariant(rows.length <= limit);\n if (configuration.batch && (options.observe !== false || options.admissionOnly))\n appendAssertions(observedConditions(table, where, rows));\n\n return options.observe === false || options.admissionOnly\n ? { table, where, rows }\n : observed(table, where, rows);\n }),\n ),\n write: (query) =>\n result(\n Effect.gen(function* () {\n open();\n if (configuration.batch) statements.push(toStatement(query));\n else yield* query as NativeQuery<unknown>;\n }),\n ),\n insert: (table, values, key, absent = false) =>\n result(\n Effect.gen(function* () {\n open();\n let query = database.insert(table).values(values);\n\n if (absent)\n query = configuration.mysql\n ? query.onDuplicateKeyUpdate({\n set: { [Object.keys(key)[0]!]: col(table, Object.keys(key)[0]!) },\n })\n : query.onConflictDoNothing();\n yield* owner.write(query);\n const where = equal(table, key);\n\n if (configuration.batch) return observed(table, where, [values]);\n const found = yield* owner.read(table, where, { limit: 1 });\n const markerColumn = Object.keys(values).find((key) => values[key] === marker);\n\n if (!absent || (markerColumn !== undefined && found.rows[0]?.[markerColumn] === marker))\n invariant(\n yield* owner.check(\n sql`exists(select 1 from ${table} where ${both(where, exactRow(table, values))})`,\n ),\n );\n\n return found;\n }),\n ),\n update: (table, key, values) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.update(table).set(values).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.map((row) =>\n matchesNativeRow(table, row, key) ? { ...row, ...values } : row,\n );\n }),\n ),\n updateGuarded: (table, where, values, guard) =>\n result(\n Effect.gen(function* () {\n open();\n const entry = guardedQuery(table, where, values, guard);\n\n yield* applyGuarded(entry);\n postconditions.push(entry.guard.postcondition);\n }),\n ),\n finalUpdate: (table, where, values, guard) =>\n result(\n Effect.sync(() => {\n open();\n invariant(finalUpdates.length < 128);\n finalUpdates.push(guardedQuery(table, where, values, guard));\n }),\n ),\n remove: (table, key) =>\n result(\n Effect.gen(function* () {\n open();\n yield* owner.write(database.delete(table).where(equal(table, key)));\n for (const observation of observations)\n if (observation.table === table)\n observation.rows = observation.rows.filter(\n (row) => !matchesNativeRow(table, row, key),\n );\n }),\n ),\n check: (condition) =>\n result(\n Effect.gen(function* () {\n open();\n const holds = yield* conditionHolds(condition);\n\n if (configuration.batch)\n statements.push(toStatement(assertion(holds ? condition : sql`not (${condition})`)));\n\n return holds;\n }),\n ),\n now: (clock) =>\n result(\n Effect.gen(function* () {\n open();\n\n const rows: Row[] = yield* database\n .select({\n value: sql`${clock.engineNowMillis}`.mapWith(Number),\n })\n .from(sql`(select 1) as oauth_clock`) as NativeQuery<Row[]>;\n\n const value = rows[0]?.value;\n\n invariant(Number.isSafeInteger(value) && value >= 0);\n\n return value as number;\n }),\n ),\n finish: () =>\n result(\n Effect.gen(function* () {\n open();\n phase = \"finishing\";\n Object.freeze(observations);\n Object.freeze(postconditions);\n Object.freeze(guards);\n Object.freeze(finalUpdates);\n\n // Close registration before any late-bound SQL predicate is materialized.\n // No callback is invoked after the first final write.\n const conditions: SQL[] = observations.flatMap((observation) =>\n observedConditions(observation.table, observation.where, observation.rows),\n );\n\n conditions.push(\n ...postconditions.map((condition) =>\n typeof condition === \"function\" ? condition() : condition,\n ),\n );\n conditions.push(...finalUpdates.map((entry) => entry.guard.postcondition));\n for (const guard of guards) {\n const status = yield* Effect.result(guard.read);\n\n invariant(status._tag === \"Failure\" && status.failure._tag === \"CommitPending\");\n }\n invariant(!poisoned);\n for (const entry of finalUpdates) yield* applyGuarded(entry);\n if (configuration.batch) appendAssertions(conditions);\n else\n for (const condition of chunks(conditions))\n invariant(yield* conditionHolds(condition));\n invariant(!poisoned);\n }).pipe(\n Effect.ensuring(\n Effect.sync(() => {\n phase = \"finished\";\n }),\n ),\n ),\n ),\n };\n\n return owner;\n };\n\n return { reportTransactionFailure, both, makeTransactionRows, makeTransactionOwner };\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@yielded/auth-persistence","version":"0.1.0-beta.22","dependencies":{"@yielded/auth":"0.1.0-beta.22"},"devDependencies":{"@effect/platform-node":"4.0.0","@effect/sql-libsql":"4.0.0","@effect/sql-sqlite-node":"4.0.0","@effect/vitest":"4.0.0","@yielded/crypto":"0.1.0-beta.22","@yielded/jose":"0.1.0-beta.22","effect":"4.0.0","typescript":"7.0.2","vite-plus":"0.3.3"},"peerDependencies":{"effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./Adapter":{"types":"./dist/Adapter.d.mts","default":"./dist/Adapter.mjs"}},"description":"Direct Effect SQL persistence and shared storage contracts for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
1
+ {"name":"@yielded/auth-persistence","version":"0.1.0-beta.24","dependencies":{"@yielded/auth":"0.1.0-beta.24"},"devDependencies":{"@effect/platform-node":"4.0.0","@effect/sql-libsql":"4.0.0","@effect/sql-sqlite-node":"4.0.0","@effect/vitest":"4.0.0","@yielded/crypto":"0.1.0-beta.24","@yielded/jose":"0.1.0-beta.24","effect":"4.0.0","typescript":"7.0.2","vite-plus":"0.3.3"},"peerDependencies":{"effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./Adapter":{"types":"./dist/Adapter.d.mts","default":"./dist/Adapter.mjs"},"./OAuthPersistence":{"types":"./dist/OAuthPersistence.d.mts","default":"./dist/OAuthPersistence.mjs"}},"description":"Direct Effect SQL persistence and shared storage contracts for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
package/src/Adapter.ts CHANGED
@@ -99,18 +99,10 @@ export {
99
99
  } from "./internal/models/passkey-write-model";
100
100
 
101
101
  export {
102
- type PasswordAttemptAction,
103
- type PasswordAttemptState,
104
- type PasswordRateScopeKind,
105
- type PasswordScopeKeys,
106
102
  type PasswordSubjectTable,
107
103
  type PasswordIdentifierTable,
108
104
  type PasswordAuthorityCredentialTable,
109
105
  type PasswordCredentialTable,
110
- type PasswordAttemptRecord,
111
- type PasswordAttemptTable,
112
- type PasswordRateScopeTable,
113
- type PasswordChargeTable,
114
106
  type PasswordCommandTable,
115
107
  type RequiredPasswordConstraints,
116
108
  requiredPasswordConstraints,
@@ -197,6 +189,12 @@ export {
197
189
 
198
190
  export { requireStandalone } from "./internal/standalone";
199
191
 
192
+ export {
193
+ makeOAuthProxyPersistence,
194
+ oauthProxyColumns,
195
+ type OAuthProxySqlTable,
196
+ } from "./internal/oauth-proxy";
197
+
200
198
  export {
201
199
  decodeStepUpIntent,
202
200
  encodeStepUpIntent,
@@ -304,3 +302,94 @@ export {
304
302
  type PhysicalStorageTable,
305
303
  type StorageValidation,
306
304
  } from "./internal/storage-validation";
305
+
306
+ export {
307
+ makeNativeSqlTables,
308
+ nativeSqlAlias,
309
+ type NativeSqlTables,
310
+ type SqlTable,
311
+ } from "./internal/native-sql-table";
312
+
313
+ export { samePasswordCredentialSnapshot } from "./internal/password-credentials";
314
+
315
+ export { makeOAuthKernel, type OAuthKernel } from "./internal/oauth-kernel";
316
+
317
+ export type {
318
+ OAuthTargetConfiguration,
319
+ OAuthCoordinatorError,
320
+ OAuthExecution,
321
+ } from "./internal/oauth/target";
322
+
323
+ export { storageKeyPlans } from "./internal/storage-plans";
324
+
325
+ export {
326
+ type OAuthFlowState,
327
+ type OAuthTupleState,
328
+ type OAuthRegistrationState,
329
+ type OAuthAction,
330
+ type OAuthClock,
331
+ type OAuthSubjectReadTable,
332
+ type OAuthSubjectTable,
333
+ type OAuthOwnershipReadTable,
334
+ type OAuthOwnershipTable,
335
+ type OAuthCredentialReadTable,
336
+ type OAuthCredentialTable,
337
+ type OAuthAuthorityReadTable,
338
+ type OAuthAuthorityTable,
339
+ type OAuthFlowTable,
340
+ type OAuthTupleAuthorityTable,
341
+ type OAuthRegistrationIntentTable,
342
+ type OAuthRegistrationCommandTable,
343
+ type OAuthUnlinkCommandTable,
344
+ type OAuthEligibilityFact,
345
+ type OAuthEligibilityTable,
346
+ type OAuthMetadataPolicy,
347
+ type OAuthCleanupTable,
348
+ type OAuthRegistrationEligibility,
349
+ type OAuthD1Mapping,
350
+ requiredOAuthSignInConstraints,
351
+ requiredOAuthTupleConstraints,
352
+ requiredOAuthRegistrationConstraints,
353
+ requiredOAuthAccountsConstraints,
354
+ type OAuthSignInMapping,
355
+ type OAuthOwnershipMutation,
356
+ type OAuthRegistrationIntentMapping,
357
+ type OAuthRegistrationBase,
358
+ type OAuthRegistrationGuardTable,
359
+ type OAuthRegistrationGuardDescriptor,
360
+ oauthRegistrationGuardTable,
361
+ type OAuthRegistrationMapping,
362
+ type OAuthEligibilityDescriptor,
363
+ oauthEligibilityTable,
364
+ type OAuthCleanupDescriptor,
365
+ oauthCleanupTable,
366
+ type OAuthReferenceGuardTable,
367
+ type OAuthReferenceGuardDescriptor,
368
+ oauthReferenceGuardTable,
369
+ type OAuthAccountsMapping,
370
+ type OAuthRegistrationAuthority,
371
+ } from "./internal/models/oauth-model";
372
+
373
+ export {
374
+ type OAuthConnectedAction,
375
+ type OAuthConnectedSubjectTable,
376
+ type OAuthConnectedOrderCodec,
377
+ type OAuthConnectedFlowTable,
378
+ type OAuthConnectedGrantTable,
379
+ type OAuthConnectedClientRegistrationTable,
380
+ type OAuthConnectedCohortTable,
381
+ type OAuthConnectedAdmissionTable,
382
+ type OAuthConnectedCommandTable,
383
+ type OAuthConnectedRevocationJobTable,
384
+ type OAuthConnectedPolicyInput,
385
+ type OAuthConnectedPolicyGuardTable,
386
+ type OAuthConnectedPolicyGuard,
387
+ oauthConnectedPolicyGuard,
388
+ type OAuthConnectedSqlPolicy,
389
+ requiredOAuthConnectedConstraints,
390
+ requiredOAuthConnectedRevocationConstraints,
391
+ type OAuthConnectedOwnershipRead,
392
+ type OAuthConnectedAuthorityMapping,
393
+ type OAuthConnectedMapping,
394
+ type OAuthConnectedRevocationMapping,
395
+ } from "./internal/models/oauth-connected-model";