@yielded/auth-persistence-drizzle 0.1.0-beta.18 → 0.1.0-beta.20

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 (130) hide show
  1. package/README.md +8 -1
  2. package/dist/D1.d.mts +8 -8
  3. package/dist/Libsql.d.mts +38 -38
  4. package/dist/Mysql2.d.mts +51 -51
  5. package/dist/Pglite.d.mts +51 -51
  6. package/dist/Postgres.d.mts +38 -38
  7. package/dist/SqliteBun.d.mts +51 -51
  8. package/dist/SqliteDo.d.mts +112 -134
  9. package/dist/SqliteDo.mjs +30 -45
  10. package/dist/SqliteDo.mjs.map +1 -1
  11. package/dist/SqliteNode.d.mts +44 -44
  12. package/dist/SqliteWasm.d.mts +38 -38
  13. package/dist/drizzle/crypto.mjs +11 -0
  14. package/dist/drizzle/crypto.mjs.map +1 -0
  15. package/dist/drizzle/d1-identity.mjs +2 -2
  16. package/dist/drizzle/d1-identity.mjs.map +1 -1
  17. package/dist/drizzle/d1-oauth.d.mts +11 -11
  18. package/dist/drizzle/d1-oauth.mjs.map +1 -1
  19. package/dist/drizzle/d1-passkey.d.mts +6 -6
  20. package/dist/drizzle/d1-passkey.mjs.map +1 -1
  21. package/dist/drizzle/d1-passwords.d.mts +1 -1
  22. package/dist/drizzle/d1-phone.d.mts +3 -3
  23. package/dist/drizzle/d1-phone.mjs.map +1 -1
  24. package/dist/drizzle/d1-proofs.d.mts +1 -1
  25. package/dist/drizzle/d1-sessions.d.mts +1 -1
  26. package/dist/drizzle/d1-totp.d.mts +3 -3
  27. package/dist/drizzle/d1-totp.mjs.map +1 -1
  28. package/dist/drizzle/mysql-identity.mjs +2 -2
  29. package/dist/drizzle/mysql-identity.mjs.map +1 -1
  30. package/dist/drizzle/oauth-accounts.mjs +9 -8
  31. package/dist/drizzle/oauth-accounts.mjs.map +1 -1
  32. package/dist/drizzle/oauth-connected-collection.mjs +1 -1
  33. package/dist/drizzle/oauth-connected-collection.mjs.map +1 -1
  34. package/dist/drizzle/oauth-connected-custody.mjs +5 -4
  35. package/dist/drizzle/oauth-connected-custody.mjs.map +1 -1
  36. package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
  37. package/dist/drizzle/oauth-connected-flow.mjs +8 -7
  38. package/dist/drizzle/oauth-connected-flow.mjs.map +1 -1
  39. package/dist/drizzle/oauth-connected-management.mjs +3 -2
  40. package/dist/drizzle/oauth-connected-management.mjs.map +1 -1
  41. package/dist/drizzle/oauth-connected-reference.mjs +8 -4
  42. package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
  43. package/dist/drizzle/oauth-connected-settlement.mjs +4 -4
  44. package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -1
  45. package/dist/drizzle/oauth-connected-sign-in.mjs +11 -10
  46. package/dist/drizzle/oauth-connected-sign-in.mjs.map +1 -1
  47. package/dist/drizzle/oauth-connected-state.d.mts +13 -13
  48. package/dist/drizzle/oauth-connected-state.mjs +23 -20
  49. package/dist/drizzle/oauth-connected-state.mjs.map +1 -1
  50. package/dist/drizzle/oauth-connected-target.d.mts +9 -9
  51. package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
  52. package/dist/drizzle/oauth-drivers.mjs.map +1 -1
  53. package/dist/drizzle/oauth-flow.mjs +1 -1
  54. package/dist/drizzle/oauth-flow.mjs.map +1 -1
  55. package/dist/drizzle/oauth-model.d.mts +4 -4
  56. package/dist/drizzle/oauth-model.mjs.map +1 -1
  57. package/dist/drizzle/oauth-registration.mjs +2 -2
  58. package/dist/drizzle/oauth-registration.mjs.map +1 -1
  59. package/dist/drizzle/oauth-state.mjs +11 -12
  60. package/dist/drizzle/oauth-state.mjs.map +1 -1
  61. package/dist/drizzle/oauth-target.d.mts +4 -4
  62. package/dist/drizzle/oauth-target.mjs.map +1 -1
  63. package/dist/drizzle/passkey-drivers.mjs.map +1 -1
  64. package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
  65. package/dist/drizzle/passkey-write-target.d.mts +1 -1
  66. package/dist/drizzle/password-prepared-state.mjs +1 -1
  67. package/dist/drizzle/pg-identity.mjs +2 -2
  68. package/dist/drizzle/pg-identity.mjs.map +1 -1
  69. package/dist/drizzle/phone-model.d.mts +2 -2
  70. package/dist/drizzle/phone-model.mjs +3 -3
  71. package/dist/drizzle/phone-model.mjs.map +1 -1
  72. package/dist/drizzle/phone-target.d.mts +1 -1
  73. package/dist/drizzle/phone-target.mjs +2 -2
  74. package/dist/drizzle/phone-target.mjs.map +1 -1
  75. package/dist/drizzle/sqlite-do-database.d.mts +29 -0
  76. package/dist/drizzle/sqlite-do-database.mjs +45 -0
  77. package/dist/drizzle/sqlite-do-database.mjs.map +1 -0
  78. package/dist/drizzle/sqlite-emails.mjs.map +1 -1
  79. package/dist/drizzle/sqlite-identity.mjs +2 -2
  80. package/dist/drizzle/sqlite-identity.mjs.map +1 -1
  81. package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
  82. package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
  83. package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
  84. package/dist/drizzle/storage-validation.mjs +17 -9
  85. package/dist/drizzle/storage-validation.mjs.map +1 -1
  86. package/dist/drizzle/totp-state.mjs +8 -8
  87. package/dist/drizzle/totp-state.mjs.map +1 -1
  88. package/dist/drizzle/totp-target.d.mts +1 -1
  89. package/dist/drizzle/totp-target.mjs +2 -2
  90. package/dist/drizzle/totp-target.mjs.map +1 -1
  91. package/package.json +1 -1
  92. package/src/SqliteDo.ts +63 -70
  93. package/src/drizzle/crypto.ts +14 -0
  94. package/src/drizzle/d1-identity.ts +2 -2
  95. package/src/drizzle/d1-oauth.ts +14 -5
  96. package/src/drizzle/d1-passkey.ts +5 -1
  97. package/src/drizzle/d1-phone.ts +2 -1
  98. package/src/drizzle/d1-totp.ts +6 -2
  99. package/src/drizzle/mysql-identity.ts +2 -2
  100. package/src/drizzle/oauth-accounts.ts +14 -13
  101. package/src/drizzle/oauth-connected-collection.ts +1 -1
  102. package/src/drizzle/oauth-connected-custody.ts +8 -6
  103. package/src/drizzle/oauth-connected-drivers.ts +9 -3
  104. package/src/drizzle/oauth-connected-flow.ts +6 -6
  105. package/src/drizzle/oauth-connected-management.ts +1 -1
  106. package/src/drizzle/oauth-connected-reference.ts +14 -9
  107. package/src/drizzle/oauth-connected-settlement.ts +4 -4
  108. package/src/drizzle/oauth-connected-sign-in.ts +11 -10
  109. package/src/drizzle/oauth-connected-state.ts +40 -25
  110. package/src/drizzle/oauth-connected-target.ts +9 -5
  111. package/src/drizzle/oauth-drivers.ts +13 -5
  112. package/src/drizzle/oauth-flow.ts +1 -1
  113. package/src/drizzle/oauth-model.ts +4 -4
  114. package/src/drizzle/oauth-registration.ts +2 -2
  115. package/src/drizzle/oauth-state.ts +17 -15
  116. package/src/drizzle/oauth-target.ts +11 -3
  117. package/src/drizzle/passkey-drivers.ts +7 -3
  118. package/src/drizzle/passkey-write-drivers.ts +11 -2
  119. package/src/drizzle/pg-identity.ts +2 -2
  120. package/src/drizzle/phone-model.ts +3 -3
  121. package/src/drizzle/phone-target.ts +11 -4
  122. package/src/drizzle/sqlite-do-database.ts +87 -0
  123. package/src/drizzle/sqlite-emails.ts +1 -1
  124. package/src/drizzle/sqlite-identity.ts +2 -2
  125. package/src/drizzle/sqlite-passwords.ts +1 -1
  126. package/src/drizzle/sqlite-proofs.ts +2 -2
  127. package/src/drizzle/sqlite-sessions.ts +2 -2
  128. package/src/drizzle/storage-validation.ts +15 -6
  129. package/src/drizzle/totp-state.ts +8 -8
  130. package/src/drizzle/totp-target.ts +11 -5
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-connected-flow.mjs","names":["S.clientKey","S.configuration","S.current","S.useAuthority","S.action","client","S.client","S.readGrant","S.nativeCopy","S.touchScope","S.nextOrder","S.nativeOrder","S.orderNumber","S.cohort"],"sources":["../../src/drizzle/oauth-connected-flow.ts"],"sourcesContent":["import {\n OAuthAccountRevision,\n snapshotOAuthSync,\n type OAuthConnectedPersistence,\n} from \"@yielded/auth/OAuth\";\nimport * as M from \"@yielded/auth/OAuth\";\n/* oxlint-disable no-explicit-any -- private mapped rows; public adapters retain native IDs and closed Effects. */\nimport { sql } from \"drizzle-orm\";\nimport { Effect } from \"effect\";\n\nimport * as S from \"./oauth-connected-state\";\nimport { both, copiedRow, equal, CurrentOAuthTransaction } from \"./oauth-owner\";\nimport { acquireTuple, readTuple } from \"./oauth-registration\";\nimport { digest, invariant, oauthIdentityKey, sameIdentity, sameRevision } from \"./oauth-state\";\n\nexport type Input<K extends keyof OAuthConnectedPersistence[\"Service\"]> = Parameters<\n OAuthConnectedPersistence[\"Service\"][K]\n>[0];\n\nexport const pending = Effect.fn(\"oauthConnected.pending\")(function* (\n mapping: S.Authority,\n access: M.OAuthConnectedAccess,\n lock = true,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const f = mapping.flow;\n\n const read = yield* owner.read(\n f.table,\n equal(f.table, { [f.moduleId]: access.moduleId, [f.flowId]: access.flowId }),\n { limit: 1, lock, observe: lock },\n );\n\n const row = read.rows[0];\n\n if (row === undefined || row[f.snapshot] === null) return undefined;\n\n const flow = S.flowStorage.decode(row[f.snapshot]),\n c = flow.context;\n\n const native = yield* mapping.subjectId.toNative(c.revision.subjectId);\n\n invariant(\n row[f.moduleId] === c.moduleId &&\n row[f.flowId] === c.flowId &&\n row[f.commandId] === c.commandId &&\n mapping.subjectId.equals(native, row[f.subjectId]) &&\n row[f.clientKey] === S.clientKey(S.configuration(flow)) &&\n row[f.stateDigest] === c.stateDigest &&\n mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&\n mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,\n );\n\n const matches =\n c.moduleId === access.moduleId &&\n c.generation === access.generation &&\n c.flowId === access.flowId &&\n c.revision.subjectId === access.subjectId &&\n c.provider === access.provider &&\n c.callbackId === access.callbackId &&\n c.stateDigest === access.stateDigest &&\n c.requestBindingVerifier === access.requestBindingVerifier &&\n c.requestBindingExpiresAtMillis === access.requestBindingExpiresAtMillis &&\n (c.responseIssuerMode === \"required\"\n ? access.responseIssuer === c.issuer\n : access.responseIssuer === undefined);\n\n return matches ? { row, flow, native } : undefined;\n});\n\nexport const live = (flow: M.OAuthConnectedPendingFlow, now: number) =>\n flow.context.issuedAtMillis <= now &&\n now < flow.context.expiresAtMillis &&\n flow.context.expiresAtMillis <= flow.context.requestBindingExpiresAtMillis &&\n flow.retentionUntilMillis >= flow.context.expiresAtMillis + flow.context.claimLifetimeMillis;\n\nexport const expected = (flow: M.OAuthConnectedPendingFlow) => ({\n moduleId: flow.context.moduleId,\n flowId: flow.context.flowId,\n commandId: flow.context.commandId,\n revision: flow.context.revision,\n intent: S.contextStorage.encode(flow.context),\n maximumAgeMillis: flow.context.maximumEvidenceAgeMillis,\n configuration: S.configuration(flow),\n});\n\nconst retain = Effect.fn(\"oauthConnected.retain\")(function* (\n mapping: S.Mapping,\n input:\n | ({ readonly _tag: \"Prepare\" } & Input<\"prepare\">)\n | ({ readonly _tag: \"Issue\" } & Input<\"issue\">),\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const flow = snapshotOAuthSync(M.OAuthConnectedPendingFlow, input.flow),\n c = flow.context;\n\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n if (found === undefined) return { _tag: \"Rejected\" } as const;\n if (input._tag === \"Prepare\") {\n if (\n input.authorization.moduleId !== c.moduleId ||\n !sameRevision(input.authorization.revision, c.revision) ||\n !sameRevision(found.revision, c.revision) ||\n (yield* S.useAuthority(mapping, input.authorization, \"metadata\")) === undefined\n )\n return { _tag: \"Rejected\" } as const;\n } else if (!(yield* S.action(mapping, found, input.authorization, \"issue\", expected(flow))))\n return { _tag: \"Rejected\" } as const;\n if (c.profile.revocation === \"cohort\") invariant(mapping.revocation.mode === \"cohort\");\n const client = yield* S.client(mapping, S.configuration(flow), true);\n\n invariant(client !== undefined);\n\n const now = yield* owner.now(mapping.clock),\n f = mapping.flow;\n\n if (!live(flow, now)) return { _tag: \"Rejected\" } as const;\n if (c.reconnect !== undefined) {\n const original = yield* S.readGrant(mapping, c.moduleId, c.reconnect.grantId, false);\n\n if (\n original === undefined ||\n original.context.subjectId !== c.revision.subjectId ||\n !sameTarget(c.reconnect, original.context)\n )\n return { _tag: \"Rejected\" } as const;\n owner.postconditions.push(\n sql`exists(select 1 from ${mapping.grant.table} where ${owner.exact(mapping.grant.table, original.row)})`,\n );\n }\n const key = { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId };\n const prior = yield* owner.read(f.table, equal(f.table, key), { limit: 1 });\n\n const command = yield* owner.read(\n f.table,\n equal(f.table, { [f.moduleId]: c.moduleId, [f.commandId]: c.commandId }),\n { limit: 1 },\n );\n\n owner.postconditions.push(\n sql`${mapping.clock.engineNowMillis} >= ${c.issuedAtMillis} and ${mapping.clock.engineNowMillis} < ${c.expiresAtMillis}`,\n );\n if (input._tag === \"Issue\") {\n const row = prior.rows[0];\n\n if (\n row === undefined ||\n command.rows[0] === undefined ||\n row[f.state] !== \"Prepared\" ||\n row[f.snapshot] !== S.flowStorage.encode(flow) ||\n command.rows[0][f.flowId] !== c.flowId\n )\n return { _tag: \"Rejected\" } as const;\n yield* owner.update(\n f.table,\n { ...key, [f.state]: \"Prepared\", [f.version]: row[f.version] },\n { [f.state]: \"Pending\", [f.version]: owner.marker },\n );\n owner.postconditions.push(\n sql`exists(select 1 from ${f.table} where ${equal(f.table, { ...key, [f.state]: \"Pending\", [f.version]: owner.marker })})`,\n );\n\n return { _tag: \"Issued\", flow } as const;\n }\n if (prior.rows.length || command.rows.length) return { _tag: \"Rejected\" } as const;\n\n const values = {\n ...f.encodeInsert({\n flow: snapshotOAuthSync(M.OAuthConnectedPendingFlow, flow),\n subjectId: S.nativeCopy(found.nativeId),\n }),\n ...key,\n [f.commandId]: c.commandId,\n [f.subjectId]: found.nativeId,\n [f.clientKey]: client.id,\n [f.cohortKey]: null,\n [f.state]: \"Prepared\",\n [f.version]: owner.marker,\n [f.stateDigest]: c.stateDigest,\n [f.snapshot]: S.flowStorage.encode(flow),\n [f.claimId]: null,\n [f.claimDigest]: null,\n [f.claimOrder]: null,\n [f.claimedAt]: null,\n [f.claimExpiresAt]: null,\n [f.expiresAt]: mapping.clock.encodeInstant(c.expiresAtMillis),\n [f.retentionUntil]: mapping.clock.encodeInstant(flow.retentionUntilMillis),\n [f.work]: \"None\",\n [f.custody]: null,\n };\n\n const inserted = yield* owner.insert(f.table, values, key, true);\n\n prior.rows = inserted.rows;\n command.rows = inserted.rows;\n if (inserted.rows[0]?.[f.version] !== owner.marker) return { _tag: \"Rejected\" } as const;\n\n return { _tag: \"Issued\", flow } as const;\n});\n\nexport const prepare = (mapping: S.Mapping, input: Input<\"prepare\">) =>\n retain(mapping, { _tag: \"Prepare\", ...input });\n\nexport const issue = (mapping: S.Mapping, input: Input<\"issue\">) =>\n retain(mapping, { _tag: \"Issue\", ...input });\n\nexport const inspectPrepared = Effect.fn(\"oauthConnected.inspectPrepared\")(function* (\n mapping: S.Mapping,\n access: M.OAuthConnectedPreparedAccess,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const found = yield* S.current(mapping, access.subjectId);\n\n if (found === undefined) return undefined;\n const f = mapping.flow;\n\n const read = yield* owner.read(\n f.table,\n equal(f.table, {\n [f.moduleId]: access.moduleId,\n [f.flowId]: access.flowId,\n [f.subjectId]: found.nativeId,\n }),\n { limit: 1 },\n );\n\n const row = read.rows[0];\n\n if (row === undefined || row[f.state] !== \"Prepared\" || row[f.snapshot] === null)\n return undefined;\n const flow = S.flowStorage.decode(row[f.snapshot]);\n const c = flow.context;\n\n invariant(\n row[f.moduleId] === c.moduleId &&\n row[f.flowId] === c.flowId &&\n row[f.commandId] === c.commandId &&\n mapping.subjectId.equals(found.nativeId, row[f.subjectId]) &&\n row[f.clientKey] === S.clientKey(S.configuration(flow)) &&\n row[f.stateDigest] === c.stateDigest &&\n mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&\n mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,\n );\n const now = yield* owner.now(mapping.clock);\n\n return c.moduleId === access.moduleId &&\n c.generation === access.generation &&\n c.flowId === access.flowId &&\n c.commandId === access.commandId &&\n c.revision.subjectId === access.subjectId &&\n sameRevision(found.revision, c.revision) &&\n c.requestBindingVerifier === access.requestBindingVerifier &&\n c.requestBindingExpiresAtMillis === access.requestBindingExpiresAtMillis &&\n live(flow, now)\n ? flow\n : undefined;\n});\n\nexport const sameTarget = (target: M.OAuthConnectedTarget, context: M.OAuthConnectedTokenContext) =>\n target.grantId === context.grantId &&\n target.grantVersion === context.grantVersion &&\n target.tokenVersion === context.tokenVersion &&\n target.cohortGeneration === context.cohortGeneration &&\n sameIdentity(target.identity, context.identity) &&\n S.tokenContextStorage.encode({ ...context, configuration: target.configuration }) ===\n S.tokenContextStorage.encode(context);\n\nexport const capture = Effect.fn(\"oauthConnected.capture\")(function* (\n mapping: S.Mapping,\n input: Input<\"capture\">,\n) {\n const found = yield* S.current(mapping, input.subjectId);\n\n if (found === undefined) return undefined;\n if (input.grantId === undefined)\n return { revision: snapshotOAuthSync(OAuthAccountRevision, found.revision) };\n const grant = yield* S.readGrant(mapping, input.moduleId, input.grantId, false);\n\n if (grant === undefined || grant.context.subjectId !== input.subjectId) return undefined;\n\n return {\n revision: snapshotOAuthSync(OAuthAccountRevision, found.revision),\n target: snapshotOAuthSync(M.OAuthConnectedTarget, grant.context),\n };\n});\n\nexport const preflight = Effect.fn(\"oauthConnected.preflight\")(function* (\n mapping: S.Mapping,\n input: Input<\"preflight\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const read = yield* pending(mapping, input);\n const now = yield* owner.now(mapping.clock);\n\n if (read === undefined || read.row[mapping.flow.state] !== \"Pending\" || !live(read.flow, now))\n return undefined;\n\n return read.flow;\n});\n\nexport const claim = Effect.fn(\"oauthConnected.claim\")(function* (\n mapping: S.Mapping,\n input: Input<\"claim\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const flow = snapshotOAuthSync(M.OAuthConnectedPendingFlow, input.flow),\n c = flow.context;\n\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n if (\n found === undefined ||\n !(yield* S.action(mapping, found, input.authorization, \"claim\", expected(flow)))\n )\n return { _tag: \"Rejected\" } as const;\n const client = yield* S.client(mapping, S.configuration(flow), false);\n\n if (client === undefined) return { _tag: \"Rejected\" } as const;\n\n const read = yield* pending(mapping, input.access),\n now = yield* owner.now(mapping.clock),\n f = mapping.flow;\n\n if (\n read === undefined ||\n read.row[f.state] !== \"Pending\" ||\n S.flowStorage.encode(read.flow) !== S.flowStorage.encode(flow) ||\n !live(flow, now)\n )\n return { _tag: \"Rejected\" } as const;\n const expires = now + c.claimLifetimeMillis;\n\n invariant(Number.isSafeInteger(expires) && expires <= flow.retentionUntilMillis);\n yield* S.touchScope(mapping, client.scope);\n const order = yield* S.nextOrder(mapping, client);\n\n const claimed = snapshotOAuthSync(M.OAuthConnectedClaim, {\n flow,\n claimId: input.claimId,\n claimedAtMillis: now,\n claimExpiresAtMillis: expires,\n order: String(order),\n });\n\n yield* owner.update(\n f.table,\n {\n [f.moduleId]: c.moduleId,\n [f.flowId]: c.flowId,\n [f.state]: \"Pending\",\n [f.version]: read.row[f.version],\n },\n {\n [f.state]: \"Claimed\",\n [f.claimId]: claimed.claimId,\n [f.claimDigest]: digest(S.claimStorage.encode(claimed)),\n [f.claimOrder]: mapping.order.encode(order),\n [f.claimedAt]: mapping.clock.encodeInstant(now),\n [f.claimExpiresAt]: mapping.clock.encodeInstant(expires),\n [f.work]: \"Unresolved\",\n [f.version]: owner.marker,\n },\n );\n owner.postconditions.push(\n sql`${mapping.clock.engineNowMillis} >= ${now} and ${mapping.clock.engineNowMillis} < ${Math.min(c.expiresAtMillis, expires)}`,\n );\n\n return { _tag: \"Claimed\", claim: claimed } as const;\n});\n\nexport const exact = Effect.fn(\"oauthConnected.exactClaim\")(function* (\n mapping: S.Authority,\n claim: M.OAuthConnectedClaim,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const f = mapping.flow,\n c = claim.flow.context;\n\n const read = yield* owner.read(\n f.table,\n equal(f.table, { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId }),\n { limit: 1 },\n );\n\n const row = read.rows[0];\n\n if (\n row === undefined ||\n row[f.work] !== \"Unresolved\" ||\n row[f.claimId] !== claim.claimId ||\n row[f.claimDigest] !== digest(S.claimStorage.encode(claim))\n )\n return undefined;\n const native = yield* mapping.subjectId.toNative(c.revision.subjectId);\n\n invariant(\n row[f.commandId] === c.commandId &&\n mapping.subjectId.equals(native, row[f.subjectId]) &&\n row[f.stateDigest] === c.stateDigest &&\n mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&\n mapping.clock.decodeInstant(row[f.retentionUntil]) === claim.flow.retentionUntilMillis &&\n row[f.clientKey] === S.clientKey(S.configuration(claim.flow)) &&\n S.nativeOrder(mapping, row[f.claimOrder]) === S.orderNumber(claim.order) &&\n mapping.clock.decodeInstant(row[f.claimedAt]) === claim.claimedAtMillis &&\n mapping.clock.decodeInstant(row[f.claimExpiresAt]) === claim.claimExpiresAtMillis,\n );\n const now = yield* owner.now(mapping.clock);\n\n invariant(now >= claim.claimedAtMillis);\n\n return { row, now, active: row[f.state] === \"Claimed\" && now < claim.claimExpiresAtMillis };\n});\n\nexport const terminal = Effect.fn(\"oauthConnected.terminal\")(function* (\n mapping: S.Authority,\n claim: M.OAuthConnectedClaim,\n state: string,\n work: \"Resolved\" | \"Unresolved\",\n custody?: { cohort: string; sealed?: M.OAuthConnectedStoredGrant },\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const f = mapping.flow,\n c = claim.flow.context;\n\n yield* owner.update(\n f.table,\n { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId, [f.claimId]: claim.claimId },\n {\n [f.state]: state,\n [f.snapshot]: null,\n [f.work]: work,\n [f.cohortKey]: custody?.cohort ?? null,\n [f.custody]: custody?.sealed === undefined ? null : S.grantStorage.encode(custody.sealed),\n [f.version]: owner.marker,\n },\n );\n});\n\nexport const inspectTuple = Effect.fn(\"oauthConnected.inspectTuple\")(function* (\n mapping: S.Authority,\n identity: M.OAuthConnectedTokenContext[\"identity\"],\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const t = mapping.ownership.tuple,\n key = oauthIdentityKey(identity);\n\n const read = yield* owner.read(t.table, equal(t.table, { [t.identityKey]: key }), { limit: 1 });\n const row = read.rows[0];\n\n if (row !== undefined) {\n invariant(\n row[t.provider] === identity.provider &&\n row[t.issuer] === identity.issuer &&\n row[t.externalSubject] === identity.subject &&\n [\"Owned\", \"Unowned\", \"Reserved\"].includes(row[t.state]),\n );\n }\n if (mapping.ownership.mode === \"separate\") {\n const o = mapping.ownership.external;\n\n const external = yield* owner.read(o.table, equal(o.table, { [o.identityKey]: key }), {\n limit: 1,\n });\n\n if (row?.[t.state] === \"Owned\") {\n const e = external.rows[0];\n\n invariant(\n e !== undefined &&\n e[o.provider] === identity.provider &&\n e[o.issuer] === identity.issuer &&\n e[o.externalSubject] === identity.subject &&\n mapping.subjectId.equals(o.decodeSubjectId(copiedRow(e)), row[t.subjectId]),\n );\n const condition = sql`exists(select 1 from ${o.table} where ${both(equal(o.table, { [o.identityKey]: key }), o.ownedCondition)})`;\n\n invariant(yield* owner.check(condition));\n owner.postconditions.push(condition);\n } else invariant(external.rows.length === 0);\n }\n\n return { key, row };\n});\n\nexport const inspectGrant = Effect.fn(\"oauthConnected.inspectGrant\")(function* (\n mapping: S.Mapping,\n input: Input<\"inspectGrant\">,\n) {\n const c = input.claim.flow.context;\n\n if (input.identity.provider !== c.provider || input.identity.issuer !== c.issuer)\n return { _tag: \"Rejected\" } as const;\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n if (found === undefined || !sameRevision(found.revision, c.revision))\n return { _tag: \"Rejected\" } as const;\n const cl = yield* S.client(mapping, S.configuration(input.claim.flow), false);\n\n if (cl === undefined) return { _tag: \"Rejected\" } as const;\n\n const tuple = yield* inspectTuple(mapping, input.identity),\n t = mapping.ownership.tuple;\n\n if (\n tuple.row?.[t.state] === \"Reserved\" ||\n (tuple.row?.[t.state] === \"Owned\" &&\n !mapping.subjectId.equals(tuple.row[t.subjectId], found.nativeId))\n )\n return { _tag: \"Conflict\" } as const;\n const co = yield* S.cohort(mapping, cl.id, tuple.key, false);\n const claimed = yield* exact(mapping, input.claim);\n\n if (claimed === undefined) return { _tag: \"Rejected\" } as const;\n if (c.reconnect !== undefined && !sameIdentity(c.reconnect.identity, input.identity))\n return { _tag: \"Conflict\" } as const;\n\n return co.blocked || S.orderNumber(input.claim.order) <= co.cutoff || !claimed.active\n ? ({ _tag: \"Quarantine\", cohortGeneration: co.generation } as const)\n : ({ _tag: \"Target\", cohortGeneration: co.generation } as const);\n});\n\n/** Global tuple acquisition is shared with registration/accounts. */\nexport { acquireTuple, readTuple };\n"],"mappings":"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"}
1
+ {"version":3,"file":"oauth-connected-flow.mjs","names":["S.clientKey","S.configuration","S.current","S.useAuthority","S.action","client","S.client","S.readGrant","S.nativeCopy","S.touchScope","S.nextOrder","S.nativeOrder","S.orderNumber","S.cohort"],"sources":["../../src/drizzle/oauth-connected-flow.ts"],"sourcesContent":["import {\n OAuthAccountRevision,\n snapshotOAuthSync,\n type OAuthConnectedPersistence,\n} from \"@yielded/auth/OAuth\";\nimport * as M from \"@yielded/auth/OAuth\";\n/* oxlint-disable no-explicit-any -- private mapped rows; public adapters retain native IDs and closed Effects. */\nimport { sql } from \"drizzle-orm\";\nimport { Effect } from \"effect\";\n\nimport * as S from \"./oauth-connected-state\";\nimport { both, copiedRow, equal, CurrentOAuthTransaction } from \"./oauth-owner\";\nimport { acquireTuple, readTuple } from \"./oauth-registration\";\nimport { digest, invariant, oauthIdentityKey, sameIdentity, sameRevision } from \"./oauth-state\";\n\nexport type Input<K extends keyof OAuthConnectedPersistence[\"Service\"]> = Parameters<\n OAuthConnectedPersistence[\"Service\"][K]\n>[0];\n\nexport const pending = Effect.fn(\"oauthConnected.pending\")(function* (\n mapping: S.Authority,\n access: M.OAuthConnectedAccess,\n lock = true,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const f = mapping.flow;\n\n const read = yield* owner.read(\n f.table,\n equal(f.table, { [f.moduleId]: access.moduleId, [f.flowId]: access.flowId }),\n { limit: 1, lock, observe: lock },\n );\n\n const row = read.rows[0];\n\n if (row === undefined || row[f.snapshot] === null) return undefined;\n\n const flow = S.flowStorage.decode(row[f.snapshot]),\n c = flow.context;\n\n const native = yield* mapping.subjectId.toNative(c.revision.subjectId);\n\n invariant(\n row[f.moduleId] === c.moduleId &&\n row[f.flowId] === c.flowId &&\n row[f.commandId] === c.commandId &&\n mapping.subjectId.equals(native, row[f.subjectId]) &&\n row[f.clientKey] === (yield* S.clientKey(S.configuration(flow))) &&\n row[f.stateDigest] === c.stateDigest &&\n mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&\n mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,\n );\n\n const matches =\n c.moduleId === access.moduleId &&\n c.generation === access.generation &&\n c.flowId === access.flowId &&\n c.revision.subjectId === access.subjectId &&\n c.provider === access.provider &&\n c.callbackId === access.callbackId &&\n c.stateDigest === access.stateDigest &&\n c.requestBindingVerifier === access.requestBindingVerifier &&\n c.requestBindingExpiresAtMillis === access.requestBindingExpiresAtMillis &&\n (c.responseIssuerMode === \"required\"\n ? access.responseIssuer === c.issuer\n : access.responseIssuer === undefined);\n\n return matches ? { row, flow, native } : undefined;\n});\n\nexport const live = (flow: M.OAuthConnectedPendingFlow, now: number) =>\n flow.context.issuedAtMillis <= now &&\n now < flow.context.expiresAtMillis &&\n flow.context.expiresAtMillis <= flow.context.requestBindingExpiresAtMillis &&\n flow.retentionUntilMillis >= flow.context.expiresAtMillis + flow.context.claimLifetimeMillis;\n\nexport const expected = (flow: M.OAuthConnectedPendingFlow) => ({\n moduleId: flow.context.moduleId,\n flowId: flow.context.flowId,\n commandId: flow.context.commandId,\n revision: flow.context.revision,\n intent: S.contextStorage.encode(flow.context),\n maximumAgeMillis: flow.context.maximumEvidenceAgeMillis,\n configuration: S.configuration(flow),\n});\n\nconst retain = Effect.fn(\"oauthConnected.retain\")(function* (\n mapping: S.Mapping,\n input:\n | ({ readonly _tag: \"Prepare\" } & Input<\"prepare\">)\n | ({ readonly _tag: \"Issue\" } & Input<\"issue\">),\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const flow = snapshotOAuthSync(M.OAuthConnectedPendingFlow, input.flow),\n c = flow.context;\n\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n if (found === undefined) return { _tag: \"Rejected\" } as const;\n if (input._tag === \"Prepare\") {\n if (\n input.authorization.moduleId !== c.moduleId ||\n !sameRevision(input.authorization.revision, c.revision) ||\n !sameRevision(found.revision, c.revision) ||\n (yield* S.useAuthority(mapping, input.authorization, \"metadata\")) === undefined\n )\n return { _tag: \"Rejected\" } as const;\n } else if (!(yield* S.action(mapping, found, input.authorization, \"issue\", expected(flow))))\n return { _tag: \"Rejected\" } as const;\n if (c.profile.revocation === \"cohort\") invariant(mapping.revocation.mode === \"cohort\");\n const client = yield* S.client(mapping, S.configuration(flow), true);\n\n invariant(client !== undefined);\n\n const now = yield* owner.now(mapping.clock),\n f = mapping.flow;\n\n if (!live(flow, now)) return { _tag: \"Rejected\" } as const;\n if (c.reconnect !== undefined) {\n const original = yield* S.readGrant(mapping, c.moduleId, c.reconnect.grantId, false);\n\n if (\n original === undefined ||\n original.context.subjectId !== c.revision.subjectId ||\n !sameTarget(c.reconnect, original.context)\n )\n return { _tag: \"Rejected\" } as const;\n owner.postconditions.push(\n sql`exists(select 1 from ${mapping.grant.table} where ${owner.exact(mapping.grant.table, original.row)})`,\n );\n }\n const key = { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId };\n const prior = yield* owner.read(f.table, equal(f.table, key), { limit: 1 });\n\n const command = yield* owner.read(\n f.table,\n equal(f.table, { [f.moduleId]: c.moduleId, [f.commandId]: c.commandId }),\n { limit: 1 },\n );\n\n owner.postconditions.push(\n sql`${mapping.clock.engineNowMillis} >= ${c.issuedAtMillis} and ${mapping.clock.engineNowMillis} < ${c.expiresAtMillis}`,\n );\n if (input._tag === \"Issue\") {\n const row = prior.rows[0];\n\n if (\n row === undefined ||\n command.rows[0] === undefined ||\n row[f.state] !== \"Prepared\" ||\n row[f.snapshot] !== S.flowStorage.encode(flow) ||\n command.rows[0][f.flowId] !== c.flowId\n )\n return { _tag: \"Rejected\" } as const;\n yield* owner.update(\n f.table,\n { ...key, [f.state]: \"Prepared\", [f.version]: row[f.version] },\n { [f.state]: \"Pending\", [f.version]: owner.marker },\n );\n owner.postconditions.push(\n sql`exists(select 1 from ${f.table} where ${equal(f.table, { ...key, [f.state]: \"Pending\", [f.version]: owner.marker })})`,\n );\n\n return { _tag: \"Issued\", flow } as const;\n }\n if (prior.rows.length || command.rows.length) return { _tag: \"Rejected\" } as const;\n\n const values = {\n ...f.encodeInsert({\n flow: snapshotOAuthSync(M.OAuthConnectedPendingFlow, flow),\n subjectId: S.nativeCopy(found.nativeId),\n }),\n ...key,\n [f.commandId]: c.commandId,\n [f.subjectId]: found.nativeId,\n [f.clientKey]: client.id,\n [f.cohortKey]: null,\n [f.state]: \"Prepared\",\n [f.version]: owner.marker,\n [f.stateDigest]: c.stateDigest,\n [f.snapshot]: S.flowStorage.encode(flow),\n [f.claimId]: null,\n [f.claimDigest]: null,\n [f.claimOrder]: null,\n [f.claimedAt]: null,\n [f.claimExpiresAt]: null,\n [f.expiresAt]: mapping.clock.encodeInstant(c.expiresAtMillis),\n [f.retentionUntil]: mapping.clock.encodeInstant(flow.retentionUntilMillis),\n [f.work]: \"None\",\n [f.custody]: null,\n };\n\n const inserted = yield* owner.insert(f.table, values, key, true);\n\n prior.rows = inserted.rows;\n command.rows = inserted.rows;\n if (inserted.rows[0]?.[f.version] !== owner.marker) return { _tag: \"Rejected\" } as const;\n\n return { _tag: \"Issued\", flow } as const;\n});\n\nexport const prepare = (mapping: S.Mapping, input: Input<\"prepare\">) =>\n retain(mapping, { _tag: \"Prepare\", ...input });\n\nexport const issue = (mapping: S.Mapping, input: Input<\"issue\">) =>\n retain(mapping, { _tag: \"Issue\", ...input });\n\nexport const inspectPrepared = Effect.fn(\"oauthConnected.inspectPrepared\")(function* (\n mapping: S.Mapping,\n access: M.OAuthConnectedPreparedAccess,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const found = yield* S.current(mapping, access.subjectId);\n\n if (found === undefined) return undefined;\n const f = mapping.flow;\n\n const read = yield* owner.read(\n f.table,\n equal(f.table, {\n [f.moduleId]: access.moduleId,\n [f.flowId]: access.flowId,\n [f.subjectId]: found.nativeId,\n }),\n { limit: 1 },\n );\n\n const row = read.rows[0];\n\n if (row === undefined || row[f.state] !== \"Prepared\" || row[f.snapshot] === null)\n return undefined;\n const flow = S.flowStorage.decode(row[f.snapshot]);\n const c = flow.context;\n\n invariant(\n row[f.moduleId] === c.moduleId &&\n row[f.flowId] === c.flowId &&\n row[f.commandId] === c.commandId &&\n mapping.subjectId.equals(found.nativeId, row[f.subjectId]) &&\n row[f.clientKey] === (yield* S.clientKey(S.configuration(flow))) &&\n row[f.stateDigest] === c.stateDigest &&\n mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&\n mapping.clock.decodeInstant(row[f.retentionUntil]) === flow.retentionUntilMillis,\n );\n const now = yield* owner.now(mapping.clock);\n\n return c.moduleId === access.moduleId &&\n c.generation === access.generation &&\n c.flowId === access.flowId &&\n c.commandId === access.commandId &&\n c.revision.subjectId === access.subjectId &&\n sameRevision(found.revision, c.revision) &&\n c.requestBindingVerifier === access.requestBindingVerifier &&\n c.requestBindingExpiresAtMillis === access.requestBindingExpiresAtMillis &&\n live(flow, now)\n ? flow\n : undefined;\n});\n\nexport const sameTarget = (target: M.OAuthConnectedTarget, context: M.OAuthConnectedTokenContext) =>\n target.grantId === context.grantId &&\n target.grantVersion === context.grantVersion &&\n target.tokenVersion === context.tokenVersion &&\n target.cohortGeneration === context.cohortGeneration &&\n sameIdentity(target.identity, context.identity) &&\n S.tokenContextStorage.encode({ ...context, configuration: target.configuration }) ===\n S.tokenContextStorage.encode(context);\n\nexport const capture = Effect.fn(\"oauthConnected.capture\")(function* (\n mapping: S.Mapping,\n input: Input<\"capture\">,\n) {\n const found = yield* S.current(mapping, input.subjectId);\n\n if (found === undefined) return undefined;\n if (input.grantId === undefined)\n return { revision: snapshotOAuthSync(OAuthAccountRevision, found.revision) };\n const grant = yield* S.readGrant(mapping, input.moduleId, input.grantId, false);\n\n if (grant === undefined || grant.context.subjectId !== input.subjectId) return undefined;\n\n return {\n revision: snapshotOAuthSync(OAuthAccountRevision, found.revision),\n target: snapshotOAuthSync(M.OAuthConnectedTarget, grant.context),\n };\n});\n\nexport const preflight = Effect.fn(\"oauthConnected.preflight\")(function* (\n mapping: S.Mapping,\n input: Input<\"preflight\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const read = yield* pending(mapping, input);\n const now = yield* owner.now(mapping.clock);\n\n if (read === undefined || read.row[mapping.flow.state] !== \"Pending\" || !live(read.flow, now))\n return undefined;\n\n return read.flow;\n});\n\nexport const claim = Effect.fn(\"oauthConnected.claim\")(function* (\n mapping: S.Mapping,\n input: Input<\"claim\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const flow = snapshotOAuthSync(M.OAuthConnectedPendingFlow, input.flow),\n c = flow.context;\n\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n if (\n found === undefined ||\n !(yield* S.action(mapping, found, input.authorization, \"claim\", expected(flow)))\n )\n return { _tag: \"Rejected\" } as const;\n const client = yield* S.client(mapping, S.configuration(flow), false);\n\n if (client === undefined) return { _tag: \"Rejected\" } as const;\n\n const read = yield* pending(mapping, input.access),\n now = yield* owner.now(mapping.clock),\n f = mapping.flow;\n\n if (\n read === undefined ||\n read.row[f.state] !== \"Pending\" ||\n S.flowStorage.encode(read.flow) !== S.flowStorage.encode(flow) ||\n !live(flow, now)\n )\n return { _tag: \"Rejected\" } as const;\n const expires = now + c.claimLifetimeMillis;\n\n invariant(Number.isSafeInteger(expires) && expires <= flow.retentionUntilMillis);\n yield* S.touchScope(mapping, client.scope);\n const order = yield* S.nextOrder(mapping, client);\n\n const claimed = snapshotOAuthSync(M.OAuthConnectedClaim, {\n flow,\n claimId: input.claimId,\n claimedAtMillis: now,\n claimExpiresAtMillis: expires,\n order: String(order),\n });\n\n yield* owner.update(\n f.table,\n {\n [f.moduleId]: c.moduleId,\n [f.flowId]: c.flowId,\n [f.state]: \"Pending\",\n [f.version]: read.row[f.version],\n },\n {\n [f.state]: \"Claimed\",\n [f.claimId]: claimed.claimId,\n [f.claimDigest]: yield* digest(S.claimStorage.encode(claimed)),\n [f.claimOrder]: mapping.order.encode(order),\n [f.claimedAt]: mapping.clock.encodeInstant(now),\n [f.claimExpiresAt]: mapping.clock.encodeInstant(expires),\n [f.work]: \"Unresolved\",\n [f.version]: owner.marker,\n },\n );\n owner.postconditions.push(\n sql`${mapping.clock.engineNowMillis} >= ${now} and ${mapping.clock.engineNowMillis} < ${Math.min(c.expiresAtMillis, expires)}`,\n );\n\n return { _tag: \"Claimed\", claim: claimed } as const;\n});\n\nexport const exact = Effect.fn(\"oauthConnected.exactClaim\")(function* (\n mapping: S.Authority,\n claim: M.OAuthConnectedClaim,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const f = mapping.flow,\n c = claim.flow.context;\n\n const read = yield* owner.read(\n f.table,\n equal(f.table, { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId }),\n { limit: 1 },\n );\n\n const row = read.rows[0];\n\n if (\n row === undefined ||\n row[f.work] !== \"Unresolved\" ||\n row[f.claimId] !== claim.claimId ||\n row[f.claimDigest] !== (yield* digest(S.claimStorage.encode(claim)))\n )\n return undefined;\n const native = yield* mapping.subjectId.toNative(c.revision.subjectId);\n\n invariant(\n row[f.commandId] === c.commandId &&\n mapping.subjectId.equals(native, row[f.subjectId]) &&\n row[f.stateDigest] === c.stateDigest &&\n mapping.clock.decodeInstant(row[f.expiresAt]) === c.expiresAtMillis &&\n mapping.clock.decodeInstant(row[f.retentionUntil]) === claim.flow.retentionUntilMillis &&\n row[f.clientKey] === (yield* S.clientKey(S.configuration(claim.flow))) &&\n S.nativeOrder(mapping, row[f.claimOrder]) === S.orderNumber(claim.order) &&\n mapping.clock.decodeInstant(row[f.claimedAt]) === claim.claimedAtMillis &&\n mapping.clock.decodeInstant(row[f.claimExpiresAt]) === claim.claimExpiresAtMillis,\n );\n const now = yield* owner.now(mapping.clock);\n\n invariant(now >= claim.claimedAtMillis);\n\n return { row, now, active: row[f.state] === \"Claimed\" && now < claim.claimExpiresAtMillis };\n});\n\nexport const terminal = Effect.fn(\"oauthConnected.terminal\")(function* (\n mapping: S.Authority,\n claim: M.OAuthConnectedClaim,\n state: string,\n work: \"Resolved\" | \"Unresolved\",\n custody?: { cohort: string; sealed?: M.OAuthConnectedStoredGrant },\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const f = mapping.flow,\n c = claim.flow.context;\n\n yield* owner.update(\n f.table,\n { [f.moduleId]: c.moduleId, [f.flowId]: c.flowId, [f.claimId]: claim.claimId },\n {\n [f.state]: state,\n [f.snapshot]: null,\n [f.work]: work,\n [f.cohortKey]: custody?.cohort ?? null,\n [f.custody]: custody?.sealed === undefined ? null : S.grantStorage.encode(custody.sealed),\n [f.version]: owner.marker,\n },\n );\n});\n\nexport const inspectTuple = Effect.fn(\"oauthConnected.inspectTuple\")(function* (\n mapping: S.Authority,\n identity: M.OAuthConnectedTokenContext[\"identity\"],\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const t = mapping.ownership.tuple,\n key = yield* oauthIdentityKey(identity);\n\n const read = yield* owner.read(t.table, equal(t.table, { [t.identityKey]: key }), { limit: 1 });\n const row = read.rows[0];\n\n if (row !== undefined) {\n invariant(\n row[t.provider] === identity.provider &&\n row[t.issuer] === identity.issuer &&\n row[t.externalSubject] === identity.subject &&\n [\"Owned\", \"Unowned\", \"Reserved\"].includes(row[t.state]),\n );\n }\n if (mapping.ownership.mode === \"separate\") {\n const o = mapping.ownership.external;\n\n const external = yield* owner.read(o.table, equal(o.table, { [o.identityKey]: key }), {\n limit: 1,\n });\n\n if (row?.[t.state] === \"Owned\") {\n const e = external.rows[0];\n\n invariant(\n e !== undefined &&\n e[o.provider] === identity.provider &&\n e[o.issuer] === identity.issuer &&\n e[o.externalSubject] === identity.subject &&\n mapping.subjectId.equals(o.decodeSubjectId(copiedRow(e)), row[t.subjectId]),\n );\n const condition = sql`exists(select 1 from ${o.table} where ${both(equal(o.table, { [o.identityKey]: key }), o.ownedCondition)})`;\n\n invariant(yield* owner.check(condition));\n owner.postconditions.push(condition);\n } else invariant(external.rows.length === 0);\n }\n\n return { key, row };\n});\n\nexport const inspectGrant = Effect.fn(\"oauthConnected.inspectGrant\")(function* (\n mapping: S.Mapping,\n input: Input<\"inspectGrant\">,\n) {\n const c = input.claim.flow.context;\n\n if (input.identity.provider !== c.provider || input.identity.issuer !== c.issuer)\n return { _tag: \"Rejected\" } as const;\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n if (found === undefined || !sameRevision(found.revision, c.revision))\n return { _tag: \"Rejected\" } as const;\n const cl = yield* S.client(mapping, S.configuration(input.claim.flow), false);\n\n if (cl === undefined) return { _tag: \"Rejected\" } as const;\n\n const tuple = yield* inspectTuple(mapping, input.identity),\n t = mapping.ownership.tuple;\n\n if (\n tuple.row?.[t.state] === \"Reserved\" ||\n (tuple.row?.[t.state] === \"Owned\" &&\n !mapping.subjectId.equals(tuple.row[t.subjectId], found.nativeId))\n )\n return { _tag: \"Conflict\" } as const;\n const co = yield* S.cohort(mapping, cl.id, tuple.key, false);\n const claimed = yield* exact(mapping, input.claim);\n\n if (claimed === undefined) return { _tag: \"Rejected\" } as const;\n if (c.reconnect !== undefined && !sameIdentity(c.reconnect.identity, input.identity))\n return { _tag: \"Conflict\" } as const;\n\n return co.blocked || S.orderNumber(input.claim.order) <= co.cutoff || !claimed.active\n ? ({ _tag: \"Quarantine\", cohortGeneration: co.generation } as const)\n : ({ _tag: \"Target\", cohortGeneration: co.generation } as const);\n});\n\n/** Global tuple acquisition is shared with registration/accounts. */\nexport { acquireTuple, readTuple };\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import { digest, invariant } from "./oauth-state.mjs";
1
+ import { digest } from "./crypto.mjs";
2
+ import { invariant } from "./oauth-state.mjs";
2
3
  import { both } from "./transaction-owner.mjs";
3
4
  import { CurrentOAuthTransaction, col, equal } from "./oauth-owner.mjs";
4
5
  import { action, client, cohort, commandStorage, current, disconnectStorage, disconnectedStorage, jobTable, nativeCopy, readGrant, summaryStorage, useAuthority } from "./oauth-connected-state.mjs";
@@ -211,7 +212,7 @@ const disconnect = Effect.fn("oauthConnected.disconnect")(function* (mapping, in
211
212
  [d.grantId]: token.grantId,
212
213
  [d.intent]: commandStorage.encode({
213
214
  context: token,
214
- originalDigest: digest(disconnectStorage.encode(input.grant)),
215
+ originalDigest: yield* digest(disconnectStorage.encode(input.grant)),
215
216
  ...input.revocation === void 0 ? {} : { revocationJobId: input.revocation.context.jobId }
216
217
  }),
217
218
  [d.decision]: disconnectedStorage.encode(result),
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-connected-management.mjs","names":["S.useAuthority","S.jobTable","A.locked","S.current","S.action","client","S.client","F.inspectTuple","cohort","S.cohort","S.readGrant","C.sameContext","C.fence","C.storeJob","S.nativeCopy","C.clear"],"sources":["../../src/drizzle/oauth-connected-management.ts"],"sourcesContent":["import * as M from \"@yielded/auth/OAuth\";\nimport { snapshotOAuthSync } from \"@yielded/auth/OAuth\";\nimport { asc, eq, gt, lte } from \"drizzle-orm\";\nimport { Effect } from \"effect\";\n\nimport * as A from \"./oauth-connected-access\";\nimport * as C from \"./oauth-connected-custody\";\nimport * as F from \"./oauth-connected-flow\";\nimport * as S from \"./oauth-connected-state\";\nimport { both, col, equal, CurrentOAuthTransaction } from \"./oauth-owner\";\nimport { digest, invariant } from \"./oauth-state\";\n\nexport const list = Effect.fn(\"oauthConnected.list\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"list\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const found = yield* S.useAuthority(mapping, input.authorization, \"metadata\");\n\n if (found === undefined) return { items: [] };\n invariant(Number.isSafeInteger(input.limit) && input.limit >= 1 && input.limit <= 100);\n\n const g = mapping.grant,\n h = mapping.cohort,\n j = S.jobTable(mapping);\n\n const cursor = input.cursor === undefined ? undefined : M.OAuthGrantId.make(input.cursor);\n\n const where = both(\n equal(g.table, { [g.moduleId]: input.authorization.moduleId, [g.subjectId]: found.nativeId }),\n cursor === undefined ? undefined : gt(col(g.table, g.grantId), cursor),\n input.authorization.grantId === undefined\n ? undefined\n : eq(col(g.table, g.grantId), input.authorization.grantId),\n input.authorization.profileKey === undefined\n ? undefined\n : eq(col(g.table, g.profileKey), input.authorization.profileKey),\n );\n\n const columns = [\n g.moduleId,\n g.grantId,\n g.subjectId,\n g.identityKey,\n g.clientKey,\n g.cohortKey,\n g.cohortGeneration,\n g.profileKey,\n g.state,\n g.summary,\n g.revocationJobId,\n g.version,\n ];\n\n const read = yield* owner.read(g.table, where, {\n columns,\n limit: input.limit + 1,\n takeOnly: true,\n observe: false,\n lock: false,\n orderBy: asc(col(g.table, g.grantId)),\n });\n\n const more = read.rows.length > input.limit,\n rows = read.rows.slice(0, input.limit),\n last = rows.at(-1)?.[g.grantId];\n\n owner.observations.push({\n table: g.table,\n where: more ? both(where, lte(col(g.table, g.grantId), last)) : where,\n rows,\n });\n const items: Array<typeof M.OAuthConnectedSummary.Type> = [];\n\n for (const row of rows) {\n const summary = S.summaryStorage.decode(row[g.summary]);\n\n invariant(\n summary.grantId === row[g.grantId] &&\n summary.profileKey === row[g.profileKey] &&\n mapping.subjectId.equals(found.nativeId, row[g.subjectId]),\n );\n\n const co = yield* owner.read(h.table, equal(h.table, { [h.cohortKey]: row[g.cohortKey] }), {\n limit: 1,\n lock: false,\n });\n\n const cr = co.rows[0];\n\n invariant(\n cr !== undefined &&\n cr[h.clientKey] === row[g.clientKey] &&\n cr[h.identityKey] === row[g.identityKey],\n );\n let status = row[g.state] as (typeof M.OAuthConnectedSummary.Type)[\"status\"];\n\n if (\n status !== \"Disconnected\" &&\n (cr[h.state] !== \"Open\" || cr[h.generation] !== row[g.cohortGeneration])\n )\n status = \"ReauthorizationRequired\";\n let remote = summary.remoteRevocation;\n\n if (row[g.revocationJobId] !== null) {\n if (j === undefined) remote = \"Unknown\";\n else {\n const job = yield* owner.read(\n j.table,\n equal(j.table, { [j.jobId]: row[g.revocationJobId] }),\n {\n limit: 1,\n lock: false,\n columns: [j.jobId, j.moduleId, j.grantId, j.cohortKey, j.state],\n },\n );\n\n const jr = job.rows[0];\n\n invariant(\n jr !== undefined &&\n jr[j.moduleId] === row[g.moduleId] &&\n jr[j.grantId] === row[g.grantId] &&\n jr[j.cohortKey] === row[g.cohortKey],\n );\n remote =\n jr[j.state] === \"Confirmed\"\n ? \"Confirmed\"\n : jr[j.state] === \"Unknown\"\n ? \"Unknown\"\n : \"Pending\";\n }\n }\n items.push(\n snapshotOAuthSync(M.OAuthConnectedSummary, { ...summary, status, remoteRevocation: remote }),\n );\n }\n\n return { items, ...(more ? { cursor: last as string } : {}) };\n});\n\nconst command = Effect.fn(\"oauthConnected.disconnectCommand\")(function* (\n mapping: S.Mapping,\n moduleId: string,\n commandId: string,\n lock = true,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const d = mapping.command,\n read = yield* owner.read(\n d.table,\n equal(d.table, { [d.moduleId]: moduleId, [d.commandId]: commandId }),\n { limit: 1, lock, observe: lock },\n );\n\n const row = read.rows[0];\n\n if (row === undefined) return { read };\n\n const grant = S.commandStorage.decode(row[d.intent]),\n result = S.disconnectedStorage.decode(row[d.decision]);\n\n const native = yield* mapping.subjectId.toNative(grant.context.subjectId);\n\n invariant(\n grant.context.moduleId === moduleId &&\n grant.context.grantId === row[d.grantId] &&\n result.grantId === grant.context.grantId &&\n mapping.subjectId.equals(native, row[d.subjectId]) &&\n !result.replayed,\n );\n\n return { read, row, grant, result };\n});\n\nexport const inspectDisconnect = Effect.fn(\"oauthConnected.inspectDisconnect\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"inspectDisconnect\">,\n) {\n const found = yield* S.useAuthority(mapping, input.authorization, \"metadata\");\n\n if (\n found === undefined ||\n input.subjectId !== found.revision.subjectId ||\n input.moduleId !== input.authorization.moduleId\n )\n return { _tag: \"Rejected\" } as const;\n const discovered = yield* command(mapping, input.moduleId, input.commandId, false);\n\n if (discovered.row !== undefined) {\n if (\n discovered.grant.context.subjectId !== input.subjectId ||\n discovered.grant.context.grantId !== input.grantId\n )\n return { _tag: \"Conflict\" } as const;\n if (\n (yield* S.useAuthority(\n mapping,\n input.authorization,\n \"metadata\",\n discovered.grant.context,\n )) === undefined\n )\n return { _tag: \"Rejected\" } as const;\n const prior = yield* command(mapping, input.moduleId, input.commandId);\n const d = mapping.command;\n\n if (\n prior.row === undefined ||\n prior.row[d.intent] !== discovered.row[d.intent] ||\n prior.row[d.decision] !== discovered.row[d.decision] ||\n prior.row[d.version] !== discovered.row[d.version]\n )\n return { _tag: \"Rejected\" } as const;\n\n return { _tag: \"Replay\", result: { ...prior.result, replayed: true } } as const;\n }\n const read = yield* A.locked(mapping, input.authorization, input.grantId, \"metadata\");\n\n if (read === undefined) return { _tag: \"Rejected\" } as const;\n const finalCommand = yield* command(mapping, input.moduleId, input.commandId);\n\n if (finalCommand.row !== undefined) return { _tag: \"Rejected\" } as const;\n\n return {\n _tag: \"Target\",\n grant: {\n context: read.grant.context,\n ...(read.grant.sealed === undefined ? {} : { sealed: read.grant.sealed }),\n },\n revision: read.found.revision,\n } as const;\n});\n\nexport const disconnect = Effect.fn(\"oauthConnected.disconnect\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"disconnect\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const token = input.grant.context,\n found = yield* S.current(mapping, token.subjectId);\n\n if (\n found === undefined ||\n input.moduleId !== token.moduleId ||\n !(yield* S.action(mapping, found, input.authorization, \"disconnect\", {\n moduleId: input.moduleId,\n flowId: input.commandId,\n commandId: input.commandId,\n revision: input.authorization.challenge.revision,\n intent: S.disconnectStorage.encode(input.grant),\n maximumAgeMillis: 300000,\n configuration: token.configuration,\n grant: token,\n }))\n )\n return { _tag: \"Rejected\" } as const;\n const client = yield* S.client(mapping, token.configuration, false);\n\n if (client === undefined) return { _tag: \"Rejected\" } as const;\n\n const tuple = yield* F.inspectTuple(mapping, token.identity),\n t = mapping.ownership.tuple;\n\n if (\n tuple.row?.[t.state] !== \"Owned\" ||\n !mapping.subjectId.equals(tuple.row[t.subjectId], found.nativeId)\n )\n return { _tag: \"Conflict\" } as const;\n const cohort = yield* S.cohort(mapping, client.id, tuple.key, false);\n\n invariant(cohort.row !== undefined);\n\n const read = yield* S.readGrant(mapping, input.moduleId, token.grantId),\n g = mapping.grant;\n\n if (\n read === undefined ||\n !C.sameContext(read.context, token) ||\n S.disconnectStorage.encode({\n context: read.context,\n ...(read.sealed === undefined ? {} : { sealed: read.sealed }),\n }) !== S.disconnectStorage.encode(input.grant)\n )\n return { _tag: \"Conflict\" } as const;\n const prior = yield* command(mapping, input.moduleId, input.commandId);\n\n // Only inspectDisconnect exposes replay. Mutation replay cannot repeat effects.\n if (prior.row !== undefined) return { _tag: \"Conflict\" } as const;\n\n const now = yield* owner.now(mapping.clock),\n wasOpen = !cohort.blocked;\n\n invariant(input.retentionUntilMillis >= now && input.retentionUntilMillis <= now + 2592000000);\n const affected = yield* C.fence(mapping, client, cohort);\n let remote: (typeof M.OAuthConnectedSummary.Type)[\"remoteRevocation\"] = \"Unsupported\";\n\n if (input.revocation !== undefined) {\n yield* C.storeJob(mapping, input.revocation, token, found.nativeId, now);\n remote = \"Pending\";\n } else if (token.configuration.profile.revocation === \"cohort\") {\n invariant(read.sealed === undefined);\n remote = \"Unknown\";\n }\n\n const result = snapshotOAuthSync(M.OAuthConnectedDisconnected, {\n _tag: \"Disconnected\",\n grantId: token.grantId,\n remoteRevocation: remote,\n affectedGrantCount: affected,\n replayed: false,\n });\n\n yield* owner.update(\n g.table,\n { [g.moduleId]: input.moduleId, [g.grantId]: token.grantId },\n {\n [g.state]: \"Disconnected\",\n [g.activeIdentityKey]: null,\n [g.sealed]: null,\n [g.revocationJobId]: input.revocation?.context.jobId ?? read.row[g.revocationJobId],\n [g.version]: owner.marker,\n },\n );\n\n const d = mapping.command,\n key = { [d.moduleId]: input.moduleId, [d.commandId]: input.commandId };\n\n const inserted = yield* owner.insert(\n d.table,\n {\n ...d.encodeInsert({\n commandId: input.commandId,\n grant: snapshotOAuthSync(M.OAuthConnectedDisconnectGrant, input.grant),\n subjectId: S.nativeCopy(found.nativeId),\n }),\n ...key,\n [d.subjectId]: found.nativeId,\n [d.grantId]: token.grantId,\n [d.intent]: S.commandStorage.encode({\n context: token,\n originalDigest: digest(S.disconnectStorage.encode(input.grant)),\n ...(input.revocation === undefined\n ? {}\n : { revocationJobId: input.revocation.context.jobId }),\n }),\n [d.decision]: S.disconnectedStorage.encode(result),\n [d.retentionUntil]: mapping.clock.encodeInstant(input.retentionUntilMillis),\n [d.version]: owner.marker,\n },\n key,\n );\n\n prior.read.rows = inserted.rows;\n if (\n wasOpen &&\n input.revocation === undefined &&\n token.configuration.profile.revocation === \"unsupported\"\n )\n yield* C.clear(mapping, client, cohort, undefined, true);\n\n return result;\n});\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,OAAO,OAAO,GAAG,qBAAqB,CAAC,CAAC,WACnD,SACA,OACA;CACA,MAAM,QAAQ,OAAO;CACrB,MAAM,QAAQ,OAAOA,aAAe,SAAS,MAAM,eAAe,UAAU;CAE5E,IAAI,UAAU,KAAA,GAAW,OAAO,EAAE,OAAO,CAAC,EAAE;CAC5C,UAAU,OAAO,cAAc,MAAM,KAAK,KAAK,MAAM,SAAS,KAAK,MAAM,SAAS,GAAG;CAErF,MAAM,IAAI,QAAQ,OAChB,IAAI,QAAQ,QACZ,IAAIC,SAAW,OAAO;CAExB,MAAM,SAAS,MAAM,WAAW,KAAA,IAAY,KAAA,IAAY,EAAE,aAAa,KAAK,MAAM,MAAM;CAExF,MAAM,QAAQ,KACZ,MAAM,EAAE,OAAO;GAAG,EAAE,WAAW,MAAM,cAAc;GAAW,EAAE,YAAY,MAAM;CAAS,CAAC,GAC5F,WAAW,KAAA,IAAY,KAAA,IAAY,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GACrE,MAAM,cAAc,YAAY,KAAA,IAC5B,KAAA,IACA,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,cAAc,OAAO,GAC3D,MAAM,cAAc,eAAe,KAAA,IAC/B,KAAA,IACA,GAAG,IAAI,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,cAAc,UAAU,CACnE;CAEA,MAAM,UAAU;EACd,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;EACF,EAAE;CACJ;CAEA,MAAM,OAAO,OAAO,MAAM,KAAK,EAAE,OAAO,OAAO;EAC7C;EACA,OAAO,MAAM,QAAQ;EACrB,UAAU;EACV,SAAS;EACT,MAAM;EACN,SAAS,IAAI,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;CACtC,CAAC;CAED,MAAM,OAAO,KAAK,KAAK,SAAS,MAAM,OACpC,OAAO,KAAK,KAAK,MAAM,GAAG,MAAM,KAAK,GACrC,OAAO,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE;CAEzB,MAAM,aAAa,KAAK;EACtB,OAAO,EAAE;EACT,OAAO,OAAO,KAAK,OAAO,IAAI,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,IAAI;EAChE;CACF,CAAC;CACD,MAAM,QAAoD,CAAC;CAE3D,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,UAAA,eAA2B,OAAO,IAAI,EAAE,QAAQ;EAEtD,UACE,QAAQ,YAAY,IAAI,EAAE,YACxB,QAAQ,eAAe,IAAI,EAAE,eAC7B,QAAQ,UAAU,OAAO,MAAM,UAAU,IAAI,EAAE,UAAU,CAC7D;EAOA,MAAM,MAAK,OALO,MAAM,KAAK,EAAE,OAAO,MAAM,EAAE,OAAO,GAAG,EAAE,YAAY,IAAI,EAAE,WAAW,CAAC,GAAG;GACzF,OAAO;GACP,MAAM;EACR,CAAC,EAAA,CAEa,KAAK;EAEnB,UACE,OAAO,KAAA,KACL,GAAG,EAAE,eAAe,IAAI,EAAE,cAC1B,GAAG,EAAE,iBAAiB,IAAI,EAAE,YAChC;EACA,IAAI,SAAS,IAAI,EAAE;EAEnB,IACE,WAAW,mBACV,GAAG,EAAE,WAAW,UAAU,GAAG,EAAE,gBAAgB,IAAI,EAAE,oBAEtD,SAAS;EACX,IAAI,SAAS,QAAQ;EAErB,IAAI,IAAI,EAAE,qBAAqB,MAAM;GACnC,IAAI,MAAM,KAAA,GAAW,SAAS;QACzB;IAWH,MAAM,MAAK,OAVQ,MAAM,KACvB,EAAE,OACF,MAAM,EAAE,OAAO,GAAG,EAAE,QAAQ,IAAI,EAAE,iBAAiB,CAAC,GACpD;KACE,OAAO;KACP,MAAM;KACN,SAAS;MAAC,EAAE;MAAO,EAAE;MAAU,EAAE;MAAS,EAAE;MAAW,EAAE;KAAK;IAChE,CACF,EAAA,CAEe,KAAK;IAEpB,UACE,OAAO,KAAA,KACL,GAAG,EAAE,cAAc,IAAI,EAAE,aACzB,GAAG,EAAE,aAAa,IAAI,EAAE,YACxB,GAAG,EAAE,eAAe,IAAI,EAAE,UAC9B;IACA,SACE,GAAG,EAAE,WAAW,cACZ,cACA,GAAG,EAAE,WAAW,YACd,YACA;GACV;EACF;EACA,MAAM,KACJ,kBAAkB,EAAE,uBAAuB;GAAE,GAAG;GAAS;GAAQ,kBAAkB;EAAO,CAAC,CAC7F;CACF;CAEA,OAAO;EAAE;EAAO,GAAI,OAAO,EAAE,QAAQ,KAAe,IAAI,CAAC;CAAG;AAC9D,CAAC;AAED,MAAM,UAAU,OAAO,GAAG,kCAAkC,CAAC,CAAC,WAC5D,SACA,UACA,WACA,OAAO,MACP;CACA,MAAM,QAAQ,OAAO;CAErB,MAAM,IAAI,QAAQ,SAChB,OAAO,OAAO,MAAM,KAClB,EAAE,OACF,MAAM,EAAE,OAAO;GAAG,EAAE,WAAW;GAAW,EAAE,YAAY;CAAU,CAAC,GACnE;EAAE,OAAO;EAAG;EAAM,SAAS;CAAK,CAClC;CAEF,MAAM,MAAM,KAAK,KAAK;CAEtB,IAAI,QAAQ,KAAA,GAAW,OAAO,EAAE,KAAK;CAErC,MAAM,QAAA,eAAyB,OAAO,IAAI,EAAE,OAAO,GACjD,SAAA,oBAA+B,OAAO,IAAI,EAAE,SAAS;CAEvD,MAAM,SAAS,OAAO,QAAQ,UAAU,SAAS,MAAM,QAAQ,SAAS;CAExE,UACE,MAAM,QAAQ,aAAa,YACzB,MAAM,QAAQ,YAAY,IAAI,EAAE,YAChC,OAAO,YAAY,MAAM,QAAQ,WACjC,QAAQ,UAAU,OAAO,QAAQ,IAAI,EAAE,UAAU,KACjD,CAAC,OAAO,QACZ;CAEA,OAAO;EAAE;EAAM;EAAK;EAAO;CAAO;AACpC,CAAC;AAED,MAAa,oBAAoB,OAAO,GAAG,kCAAkC,CAAC,CAAC,WAC7E,SACA,OACA;CACA,MAAM,QAAQ,OAAOD,aAAe,SAAS,MAAM,eAAe,UAAU;CAE5E,IACE,UAAU,KAAA,KACV,MAAM,cAAc,MAAM,SAAS,aACnC,MAAM,aAAa,MAAM,cAAc,UAEvC,OAAO,EAAE,MAAM,WAAW;CAC5B,MAAM,aAAa,OAAO,QAAQ,SAAS,MAAM,UAAU,MAAM,WAAW,KAAK;CAEjF,IAAI,WAAW,QAAQ,KAAA,GAAW;EAChC,IACE,WAAW,MAAM,QAAQ,cAAc,MAAM,aAC7C,WAAW,MAAM,QAAQ,YAAY,MAAM,SAE3C,OAAO,EAAE,MAAM,WAAW;EAC5B,KACG,OAAOA,aACN,SACA,MAAM,eACN,YACA,WAAW,MAAM,OACnB,OAAO,KAAA,GAEP,OAAO,EAAE,MAAM,WAAW;EAC5B,MAAM,QAAQ,OAAO,QAAQ,SAAS,MAAM,UAAU,MAAM,SAAS;EACrE,MAAM,IAAI,QAAQ;EAElB,IACE,MAAM,QAAQ,KAAA,KACd,MAAM,IAAI,EAAE,YAAY,WAAW,IAAI,EAAE,WACzC,MAAM,IAAI,EAAE,cAAc,WAAW,IAAI,EAAE,aAC3C,MAAM,IAAI,EAAE,aAAa,WAAW,IAAI,EAAE,UAE1C,OAAO,EAAE,MAAM,WAAW;EAE5B,OAAO;GAAE,MAAM;GAAU,QAAQ;IAAE,GAAG,MAAM;IAAQ,UAAU;GAAK;EAAE;CACvE;CACA,MAAM,OAAO,OAAOE,OAAS,SAAS,MAAM,eAAe,MAAM,SAAS,UAAU;CAEpF,IAAI,SAAS,KAAA,GAAW,OAAO,EAAE,MAAM,WAAW;CAGlD,KAAI,OAFwB,QAAQ,SAAS,MAAM,UAAU,MAAM,SAAS,EAAA,CAE3D,QAAQ,KAAA,GAAW,OAAO,EAAE,MAAM,WAAW;CAE9D,OAAO;EACL,MAAM;EACN,OAAO;GACL,SAAS,KAAK,MAAM;GACpB,GAAI,KAAK,MAAM,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,KAAK,MAAM,OAAO;EACzE;EACA,UAAU,KAAK,MAAM;CACvB;AACF,CAAC;AAED,MAAa,aAAa,OAAO,GAAG,2BAA2B,CAAC,CAAC,WAC/D,SACA,OACA;CACA,MAAM,QAAQ,OAAO;CAErB,MAAM,QAAQ,MAAM,MAAM,SACxB,QAAQ,OAAOC,QAAU,SAAS,MAAM,SAAS;CAEnD,IACE,UAAU,KAAA,KACV,MAAM,aAAa,MAAM,YACzB,EAAE,OAAOC,OAAS,SAAS,OAAO,MAAM,eAAe,cAAc;EACnE,UAAU,MAAM;EAChB,QAAQ,MAAM;EACd,WAAW,MAAM;EACjB,UAAU,MAAM,cAAc,UAAU;EACxC,QAAA,kBAA4B,OAAO,MAAM,KAAK;EAC9C,kBAAkB;EAClB,eAAe,MAAM;EACrB,OAAO;CACT,CAAC,IAED,OAAO,EAAE,MAAM,WAAW;CAC5B,MAAMC,WAAS,OAAOC,OAAS,SAAS,MAAM,eAAe,KAAK;CAElE,IAAID,aAAW,KAAA,GAAW,OAAO,EAAE,MAAM,WAAW;CAEpD,MAAM,QAAQ,OAAOE,aAAe,SAAS,MAAM,QAAQ,GACzD,IAAI,QAAQ,UAAU;CAExB,IACE,MAAM,MAAM,EAAE,WAAW,WACzB,CAAC,QAAQ,UAAU,OAAO,MAAM,IAAI,EAAE,YAAY,MAAM,QAAQ,GAEhE,OAAO,EAAE,MAAM,WAAW;CAC5B,MAAMC,WAAS,OAAOC,OAAS,SAASJ,SAAO,IAAI,MAAM,KAAK,KAAK;CAEnE,UAAUG,SAAO,QAAQ,KAAA,CAAS;CAElC,MAAM,OAAO,OAAOE,UAAY,SAAS,MAAM,UAAU,MAAM,OAAO,GACpE,IAAI,QAAQ;CAEd,IACE,SAAS,KAAA,KACT,CAACC,YAAc,KAAK,SAAS,KAAK,KAAA,kBACd,OAAO;EACzB,SAAS,KAAK;EACd,GAAI,KAAK,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO;CAC7D,CAAC,MAAA,kBAA0B,OAAO,MAAM,KAAK,GAE7C,OAAO,EAAE,MAAM,WAAW;CAC5B,MAAM,QAAQ,OAAO,QAAQ,SAAS,MAAM,UAAU,MAAM,SAAS;CAGrE,IAAI,MAAM,QAAQ,KAAA,GAAW,OAAO,EAAE,MAAM,WAAW;CAEvD,MAAM,MAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,GACxC,UAAU,CAACH,SAAO;CAEpB,UAAU,MAAM,wBAAwB,OAAO,MAAM,wBAAwB,MAAM,MAAU;CAC7F,MAAM,WAAW,OAAOI,MAAQ,SAASP,UAAQG,QAAM;CACvD,IAAI,SAAoE;CAExE,IAAI,MAAM,eAAe,KAAA,GAAW;EAClC,OAAOK,SAAW,SAAS,MAAM,YAAY,OAAO,MAAM,UAAU,GAAG;EACvE,SAAS;CACX,OAAO,IAAI,MAAM,cAAc,QAAQ,eAAe,UAAU;EAC9D,UAAU,KAAK,WAAW,KAAA,CAAS;EACnC,SAAS;CACX;CAEA,MAAM,SAAS,kBAAkB,EAAE,4BAA4B;EAC7D,MAAM;EACN,SAAS,MAAM;EACf,kBAAkB;EAClB,oBAAoB;EACpB,UAAU;CACZ,CAAC;CAED,OAAO,MAAM,OACX,EAAE,OACF;GAAG,EAAE,WAAW,MAAM;GAAW,EAAE,UAAU,MAAM;CAAQ,GAC3D;GACG,EAAE,QAAQ;GACV,EAAE,oBAAoB;GACtB,EAAE,SAAS;GACX,EAAE,kBAAkB,MAAM,YAAY,QAAQ,SAAS,KAAK,IAAI,EAAE;GAClE,EAAE,UAAU,MAAM;CACrB,CACF;CAEA,MAAM,IAAI,QAAQ,SAChB,MAAM;GAAG,EAAE,WAAW,MAAM;GAAW,EAAE,YAAY,MAAM;CAAU;CAEvE,MAAM,WAAW,OAAO,MAAM,OAC5B,EAAE,OACF;EACE,GAAG,EAAE,aAAa;GAChB,WAAW,MAAM;GACjB,OAAO,kBAAkB,EAAE,+BAA+B,MAAM,KAAK;GACrE,WAAWC,WAAa,MAAM,QAAQ;EACxC,CAAC;EACD,GAAG;GACF,EAAE,YAAY,MAAM;GACpB,EAAE,UAAU,MAAM;GAClB,EAAE,SAAA,eAA0B,OAAO;GAClC,SAAS;GACT,gBAAgB,OAAA,kBAA2B,OAAO,MAAM,KAAK,CAAC;GAC9D,GAAI,MAAM,eAAe,KAAA,IACrB,CAAC,IACD,EAAE,iBAAiB,MAAM,WAAW,QAAQ,MAAM;EACxD,CAAC;GACA,EAAE,WAAA,oBAAiC,OAAO,MAAM;GAChD,EAAE,iBAAiB,QAAQ,MAAM,cAAc,MAAM,oBAAoB;GACzE,EAAE,UAAU,MAAM;CACrB,GACA,GACF;CAEA,MAAM,KAAK,OAAO,SAAS;CAC3B,IACE,WACA,MAAM,eAAe,KAAA,KACrB,MAAM,cAAc,QAAQ,eAAe,eAE3C,OAAOC,MAAQ,SAASV,UAAQG,UAAQ,KAAA,GAAW,IAAI;CAEzD,OAAO;AACT,CAAC"}
1
+ {"version":3,"file":"oauth-connected-management.mjs","names":["S.useAuthority","S.jobTable","A.locked","S.current","S.action","client","S.client","F.inspectTuple","cohort","S.cohort","S.readGrant","C.sameContext","C.fence","C.storeJob","S.nativeCopy","C.clear"],"sources":["../../src/drizzle/oauth-connected-management.ts"],"sourcesContent":["import * as M from \"@yielded/auth/OAuth\";\nimport { snapshotOAuthSync } from \"@yielded/auth/OAuth\";\nimport { asc, eq, gt, lte } from \"drizzle-orm\";\nimport { Effect } from \"effect\";\n\nimport * as A from \"./oauth-connected-access\";\nimport * as C from \"./oauth-connected-custody\";\nimport * as F from \"./oauth-connected-flow\";\nimport * as S from \"./oauth-connected-state\";\nimport { both, col, equal, CurrentOAuthTransaction } from \"./oauth-owner\";\nimport { digest, invariant } from \"./oauth-state\";\n\nexport const list = Effect.fn(\"oauthConnected.list\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"list\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const found = yield* S.useAuthority(mapping, input.authorization, \"metadata\");\n\n if (found === undefined) return { items: [] };\n invariant(Number.isSafeInteger(input.limit) && input.limit >= 1 && input.limit <= 100);\n\n const g = mapping.grant,\n h = mapping.cohort,\n j = S.jobTable(mapping);\n\n const cursor = input.cursor === undefined ? undefined : M.OAuthGrantId.make(input.cursor);\n\n const where = both(\n equal(g.table, { [g.moduleId]: input.authorization.moduleId, [g.subjectId]: found.nativeId }),\n cursor === undefined ? undefined : gt(col(g.table, g.grantId), cursor),\n input.authorization.grantId === undefined\n ? undefined\n : eq(col(g.table, g.grantId), input.authorization.grantId),\n input.authorization.profileKey === undefined\n ? undefined\n : eq(col(g.table, g.profileKey), input.authorization.profileKey),\n );\n\n const columns = [\n g.moduleId,\n g.grantId,\n g.subjectId,\n g.identityKey,\n g.clientKey,\n g.cohortKey,\n g.cohortGeneration,\n g.profileKey,\n g.state,\n g.summary,\n g.revocationJobId,\n g.version,\n ];\n\n const read = yield* owner.read(g.table, where, {\n columns,\n limit: input.limit + 1,\n takeOnly: true,\n observe: false,\n lock: false,\n orderBy: asc(col(g.table, g.grantId)),\n });\n\n const more = read.rows.length > input.limit,\n rows = read.rows.slice(0, input.limit),\n last = rows.at(-1)?.[g.grantId];\n\n owner.observations.push({\n table: g.table,\n where: more ? both(where, lte(col(g.table, g.grantId), last)) : where,\n rows,\n });\n const items: Array<typeof M.OAuthConnectedSummary.Type> = [];\n\n for (const row of rows) {\n const summary = S.summaryStorage.decode(row[g.summary]);\n\n invariant(\n summary.grantId === row[g.grantId] &&\n summary.profileKey === row[g.profileKey] &&\n mapping.subjectId.equals(found.nativeId, row[g.subjectId]),\n );\n\n const co = yield* owner.read(h.table, equal(h.table, { [h.cohortKey]: row[g.cohortKey] }), {\n limit: 1,\n lock: false,\n });\n\n const cr = co.rows[0];\n\n invariant(\n cr !== undefined &&\n cr[h.clientKey] === row[g.clientKey] &&\n cr[h.identityKey] === row[g.identityKey],\n );\n let status = row[g.state] as (typeof M.OAuthConnectedSummary.Type)[\"status\"];\n\n if (\n status !== \"Disconnected\" &&\n (cr[h.state] !== \"Open\" || cr[h.generation] !== row[g.cohortGeneration])\n )\n status = \"ReauthorizationRequired\";\n let remote = summary.remoteRevocation;\n\n if (row[g.revocationJobId] !== null) {\n if (j === undefined) remote = \"Unknown\";\n else {\n const job = yield* owner.read(\n j.table,\n equal(j.table, { [j.jobId]: row[g.revocationJobId] }),\n {\n limit: 1,\n lock: false,\n columns: [j.jobId, j.moduleId, j.grantId, j.cohortKey, j.state],\n },\n );\n\n const jr = job.rows[0];\n\n invariant(\n jr !== undefined &&\n jr[j.moduleId] === row[g.moduleId] &&\n jr[j.grantId] === row[g.grantId] &&\n jr[j.cohortKey] === row[g.cohortKey],\n );\n remote =\n jr[j.state] === \"Confirmed\"\n ? \"Confirmed\"\n : jr[j.state] === \"Unknown\"\n ? \"Unknown\"\n : \"Pending\";\n }\n }\n items.push(\n snapshotOAuthSync(M.OAuthConnectedSummary, { ...summary, status, remoteRevocation: remote }),\n );\n }\n\n return { items, ...(more ? { cursor: last as string } : {}) };\n});\n\nconst command = Effect.fn(\"oauthConnected.disconnectCommand\")(function* (\n mapping: S.Mapping,\n moduleId: string,\n commandId: string,\n lock = true,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const d = mapping.command,\n read = yield* owner.read(\n d.table,\n equal(d.table, { [d.moduleId]: moduleId, [d.commandId]: commandId }),\n { limit: 1, lock, observe: lock },\n );\n\n const row = read.rows[0];\n\n if (row === undefined) return { read };\n\n const grant = S.commandStorage.decode(row[d.intent]),\n result = S.disconnectedStorage.decode(row[d.decision]);\n\n const native = yield* mapping.subjectId.toNative(grant.context.subjectId);\n\n invariant(\n grant.context.moduleId === moduleId &&\n grant.context.grantId === row[d.grantId] &&\n result.grantId === grant.context.grantId &&\n mapping.subjectId.equals(native, row[d.subjectId]) &&\n !result.replayed,\n );\n\n return { read, row, grant, result };\n});\n\nexport const inspectDisconnect = Effect.fn(\"oauthConnected.inspectDisconnect\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"inspectDisconnect\">,\n) {\n const found = yield* S.useAuthority(mapping, input.authorization, \"metadata\");\n\n if (\n found === undefined ||\n input.subjectId !== found.revision.subjectId ||\n input.moduleId !== input.authorization.moduleId\n )\n return { _tag: \"Rejected\" } as const;\n const discovered = yield* command(mapping, input.moduleId, input.commandId, false);\n\n if (discovered.row !== undefined) {\n if (\n discovered.grant.context.subjectId !== input.subjectId ||\n discovered.grant.context.grantId !== input.grantId\n )\n return { _tag: \"Conflict\" } as const;\n if (\n (yield* S.useAuthority(\n mapping,\n input.authorization,\n \"metadata\",\n discovered.grant.context,\n )) === undefined\n )\n return { _tag: \"Rejected\" } as const;\n const prior = yield* command(mapping, input.moduleId, input.commandId);\n const d = mapping.command;\n\n if (\n prior.row === undefined ||\n prior.row[d.intent] !== discovered.row[d.intent] ||\n prior.row[d.decision] !== discovered.row[d.decision] ||\n prior.row[d.version] !== discovered.row[d.version]\n )\n return { _tag: \"Rejected\" } as const;\n\n return { _tag: \"Replay\", result: { ...prior.result, replayed: true } } as const;\n }\n const read = yield* A.locked(mapping, input.authorization, input.grantId, \"metadata\");\n\n if (read === undefined) return { _tag: \"Rejected\" } as const;\n const finalCommand = yield* command(mapping, input.moduleId, input.commandId);\n\n if (finalCommand.row !== undefined) return { _tag: \"Rejected\" } as const;\n\n return {\n _tag: \"Target\",\n grant: {\n context: read.grant.context,\n ...(read.grant.sealed === undefined ? {} : { sealed: read.grant.sealed }),\n },\n revision: read.found.revision,\n } as const;\n});\n\nexport const disconnect = Effect.fn(\"oauthConnected.disconnect\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"disconnect\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const token = input.grant.context,\n found = yield* S.current(mapping, token.subjectId);\n\n if (\n found === undefined ||\n input.moduleId !== token.moduleId ||\n !(yield* S.action(mapping, found, input.authorization, \"disconnect\", {\n moduleId: input.moduleId,\n flowId: input.commandId,\n commandId: input.commandId,\n revision: input.authorization.challenge.revision,\n intent: S.disconnectStorage.encode(input.grant),\n maximumAgeMillis: 300000,\n configuration: token.configuration,\n grant: token,\n }))\n )\n return { _tag: \"Rejected\" } as const;\n const client = yield* S.client(mapping, token.configuration, false);\n\n if (client === undefined) return { _tag: \"Rejected\" } as const;\n\n const tuple = yield* F.inspectTuple(mapping, token.identity),\n t = mapping.ownership.tuple;\n\n if (\n tuple.row?.[t.state] !== \"Owned\" ||\n !mapping.subjectId.equals(tuple.row[t.subjectId], found.nativeId)\n )\n return { _tag: \"Conflict\" } as const;\n const cohort = yield* S.cohort(mapping, client.id, tuple.key, false);\n\n invariant(cohort.row !== undefined);\n\n const read = yield* S.readGrant(mapping, input.moduleId, token.grantId),\n g = mapping.grant;\n\n if (\n read === undefined ||\n !C.sameContext(read.context, token) ||\n S.disconnectStorage.encode({\n context: read.context,\n ...(read.sealed === undefined ? {} : { sealed: read.sealed }),\n }) !== S.disconnectStorage.encode(input.grant)\n )\n return { _tag: \"Conflict\" } as const;\n const prior = yield* command(mapping, input.moduleId, input.commandId);\n\n // Only inspectDisconnect exposes replay. Mutation replay cannot repeat effects.\n if (prior.row !== undefined) return { _tag: \"Conflict\" } as const;\n\n const now = yield* owner.now(mapping.clock),\n wasOpen = !cohort.blocked;\n\n invariant(input.retentionUntilMillis >= now && input.retentionUntilMillis <= now + 2592000000);\n const affected = yield* C.fence(mapping, client, cohort);\n let remote: (typeof M.OAuthConnectedSummary.Type)[\"remoteRevocation\"] = \"Unsupported\";\n\n if (input.revocation !== undefined) {\n yield* C.storeJob(mapping, input.revocation, token, found.nativeId, now);\n remote = \"Pending\";\n } else if (token.configuration.profile.revocation === \"cohort\") {\n invariant(read.sealed === undefined);\n remote = \"Unknown\";\n }\n\n const result = snapshotOAuthSync(M.OAuthConnectedDisconnected, {\n _tag: \"Disconnected\",\n grantId: token.grantId,\n remoteRevocation: remote,\n affectedGrantCount: affected,\n replayed: false,\n });\n\n yield* owner.update(\n g.table,\n { [g.moduleId]: input.moduleId, [g.grantId]: token.grantId },\n {\n [g.state]: \"Disconnected\",\n [g.activeIdentityKey]: null,\n [g.sealed]: null,\n [g.revocationJobId]: input.revocation?.context.jobId ?? read.row[g.revocationJobId],\n [g.version]: owner.marker,\n },\n );\n\n const d = mapping.command,\n key = { [d.moduleId]: input.moduleId, [d.commandId]: input.commandId };\n\n const inserted = yield* owner.insert(\n d.table,\n {\n ...d.encodeInsert({\n commandId: input.commandId,\n grant: snapshotOAuthSync(M.OAuthConnectedDisconnectGrant, input.grant),\n subjectId: S.nativeCopy(found.nativeId),\n }),\n ...key,\n [d.subjectId]: found.nativeId,\n [d.grantId]: token.grantId,\n [d.intent]: S.commandStorage.encode({\n context: token,\n originalDigest: yield* digest(S.disconnectStorage.encode(input.grant)),\n ...(input.revocation === undefined\n ? {}\n : { revocationJobId: input.revocation.context.jobId }),\n }),\n [d.decision]: S.disconnectedStorage.encode(result),\n [d.retentionUntil]: mapping.clock.encodeInstant(input.retentionUntilMillis),\n [d.version]: owner.marker,\n },\n key,\n );\n\n prior.read.rows = inserted.rows;\n if (\n wasOpen &&\n input.revocation === undefined &&\n token.configuration.profile.revocation === \"unsupported\"\n )\n yield* C.clear(mapping, client, cohort, undefined, true);\n\n return result;\n});\n"],"mappings":"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"}
@@ -4,6 +4,7 @@ import { both } from "./transaction-owner.mjs";
4
4
  import { col, equal } from "./oauth-owner.mjs";
5
5
  import { scopeKey } from "./oauth-connected-state.mjs";
6
6
  import { eq, is, sql } from "drizzle-orm";
7
+ import { Effect } from "effect";
7
8
  import { MySqlTable } from "drizzle-orm/mysql-core/table";
8
9
  import { PgTable } from "drizzle-orm/pg-core/table";
9
10
  //#region src/drizzle/oauth-connected-reference.ts
@@ -19,10 +20,13 @@ const oauthConnectedOwnershipReferences = (original) => {
19
20
  connectedReferenceGuards: [oauthReferenceGuardTable({
20
21
  table: c.table,
21
22
  orderBy: c.clientKey,
22
- condition: (input) => both(equal(c.table, {
23
- [c.clientKey]: scopeKey(input.identity.provider, input.identity.issuer),
24
- [c.counter]: mapping.order.encode(0)
25
- }), exactText(c.table, c.provider, input.identity.provider), exactText(c.table, c.issuer, input.identity.issuer), exactText(c.table, c.clientRegistrationId, ""))
23
+ condition: (input) => Effect.gen(function* () {
24
+ const key = yield* scopeKey(input.identity.provider, input.identity.issuer);
25
+ return both(equal(c.table, {
26
+ [c.clientKey]: key,
27
+ [c.counter]: mapping.order.encode(0)
28
+ }), exactText(c.table, c.provider, input.identity.provider), exactText(c.table, c.issuer, input.identity.issuer), exactText(c.table, c.clientRegistrationId, ""));
29
+ })
26
30
  })],
27
31
  connectedReference: (input) => connectedReferenceCondition(mapping, input.identityKey)
28
32
  });
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-connected-reference.mjs","names":[],"sources":["../../src/drizzle/oauth-connected-reference.ts"],"sourcesContent":["import { eq, is, sql, type SQL, type Table } from \"drizzle-orm\";\nimport { MySqlTable } from \"drizzle-orm/mysql-core/table\";\nimport { PgTable } from \"drizzle-orm/pg-core/table\";\n\nimport type { OAuthConnectedMapping } from \"./oauth-connected-model\";\nimport { scopeKey, type Mapping } from \"./oauth-connected-state\";\nimport { oauthReferenceGuardTable, type OAuthReferenceGuardDescriptor } from \"./oauth-model\";\nimport { both, col, equal } from \"./oauth-owner\";\nimport { captureOAuthMapping } from \"./oauth-state\";\n\nconst exactText = (table: Table, key: string, value: string) => {\n const column = col(table, key),\n bound = sql.param(value, column);\n\n return is(table, MySqlTable)\n ? sql`binary ${column} = binary ${bound}`\n : is(table, PgTable)\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/** Compose Accounts.Unlink with this connected authority. The stable scope lock\n * serializes unknown claims across every client registration for an issuer. */\nexport const oauthConnectedOwnershipReferences = <\n S extends Table,\n AC extends Table,\n T extends Table,\n O extends Table,\n F extends Table,\n G extends Table,\n C extends Table,\n H extends Table,\n A extends Table,\n D extends Table,\n N,\n J extends Table,\n>(\n original: OAuthConnectedMapping<S, AC, T, O, F, G, C, H, A, D, N, J>,\n): {\n readonly connectedReferenceGuards: ReadonlyArray<OAuthReferenceGuardDescriptor<N>>;\n readonly connectedReference: (input: {\n readonly identityKey: string;\n readonly subjectId: N;\n }) => SQL;\n} => {\n const mapping = captureOAuthMapping(original),\n c = mapping.client;\n\n return Object.freeze({\n connectedReferenceGuards: [\n oauthReferenceGuardTable<C, N>({\n table: c.table,\n orderBy: c.clientKey,\n condition: (input) =>\n both(\n equal(c.table, {\n [c.clientKey]: scopeKey(input.identity.provider, input.identity.issuer),\n [c.counter]: mapping.order.encode(0),\n }),\n exactText(c.table, c.provider, input.identity.provider),\n exactText(c.table, c.issuer, input.identity.issuer),\n exactText(c.table, c.clientRegistrationId, \"\"),\n ),\n }),\n ],\n connectedReference: (input) => connectedReferenceCondition(mapping, input.identityKey),\n });\n};\n\nexport const connectedReferenceCondition = (\n mapping: Mapping,\n identityKey: string | SQL,\n knownIdentity?: { readonly provider: string | SQL; readonly issuer: string | SQL },\n) => {\n const c = mapping.client,\n t = mapping.ownership.tuple,\n f = mapping.flow,\n g = mapping.grant,\n h = mapping.cohort,\n a = mapping.admission,\n j = mapping.revocation.mode === \"cohort\" ? mapping.revocation.job : undefined;\n\n const tuple = equal(t.table, { [t.identityKey]: identityKey });\n const knownFlow = sql`exists(select 1 from ${h.table} where ${col(h.table, h.cohortKey)} = ${col(f.table, f.cohortKey)} and ${col(h.table, h.identityKey)} = ${identityKey})`;\n\n const unknownFlow =\n knownIdentity === undefined\n ? sql`${col(f.table, f.cohortKey)} is null and exists(select 1 from ${c.table} where ${col(c.table, c.clientKey)} = ${col(f.table, f.clientKey)} and exists(select 1 from ${t.table} where ${tuple} and ${col(c.table, c.provider)} = ${col(t.table, t.provider)} and ${col(c.table, c.issuer)} = ${col(t.table, t.issuer)}))`\n : sql`${col(f.table, f.cohortKey)} is null and exists(select 1 from ${c.table} where ${col(c.table, c.clientKey)} = ${col(f.table, f.clientKey)} and ${col(c.table, c.provider)} = ${knownIdentity.provider} and ${col(c.table, c.issuer)} = ${knownIdentity.issuer})`;\n\n const related = [f, g, h, ...(j === undefined ? [] : [j])];\n\n return sql`(${sql.join(\n [\n sql`exists(select 1 from ${g.table} where ${eq(col(g.table, g.identityKey), identityKey)})`,\n sql`exists(select 1 from ${a.table} where ${eq(col(a.table, a.identityKey), identityKey)})`,\n sql`exists(select 1 from ${h.table} where ${both(eq(col(h.table, h.identityKey), identityKey), eq(col(h.table, h.state), \"Blocked\"))})`,\n sql`exists(select 1 from ${f.table} where ${col(f.table, f.work)} = 'Unresolved' and (${knownFlow} or (${unknownFlow})))`,\n ...(j === undefined\n ? []\n : [\n sql`exists(select 1 from ${j.table} where ${eq(col(j.table, j.identityKey), identityKey)})`,\n ]),\n // A missing real client cannot turn erased unknown work into absence.\n ...related.map(\n (v) =>\n sql`exists(select 1 from ${v.table} where not exists(select 1 from ${c.table} where ${col(c.table, c.clientKey)} = ${col(v.table, v.clientKey)}))`,\n ),\n ],\n sql` or `,\n )})`;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"oauth-connected-reference.mjs","names":[],"sources":["../../src/drizzle/oauth-connected-reference.ts"],"sourcesContent":["import { eq, is, sql, type SQL, type Table } from \"drizzle-orm\";\nimport { MySqlTable } from \"drizzle-orm/mysql-core/table\";\nimport { PgTable } from \"drizzle-orm/pg-core/table\";\nimport { Effect } from \"effect\";\n\nimport type { OAuthConnectedMapping } from \"./oauth-connected-model\";\nimport { scopeKey, type Mapping } from \"./oauth-connected-state\";\nimport { oauthReferenceGuardTable, type OAuthReferenceGuardDescriptor } from \"./oauth-model\";\nimport { both, col, equal } from \"./oauth-owner\";\nimport { captureOAuthMapping } from \"./oauth-state\";\n\nconst exactText = (table: Table, key: string, value: string) => {\n const column = col(table, key),\n bound = sql.param(value, column);\n\n return is(table, MySqlTable)\n ? sql`binary ${column} = binary ${bound}`\n : is(table, PgTable)\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/** Compose Accounts.Unlink with this connected authority. The stable scope lock\n * serializes unknown claims across every client registration for an issuer. */\nexport const oauthConnectedOwnershipReferences = <\n S extends Table,\n AC extends Table,\n T extends Table,\n O extends Table,\n F extends Table,\n G extends Table,\n C extends Table,\n H extends Table,\n A extends Table,\n D extends Table,\n N,\n J extends Table,\n>(\n original: OAuthConnectedMapping<S, AC, T, O, F, G, C, H, A, D, N, J>,\n): {\n readonly connectedReferenceGuards: ReadonlyArray<OAuthReferenceGuardDescriptor<N>>;\n readonly connectedReference: (input: {\n readonly identityKey: string;\n readonly subjectId: N;\n }) => SQL;\n} => {\n const mapping = captureOAuthMapping(original),\n c = mapping.client;\n\n return Object.freeze({\n connectedReferenceGuards: [\n oauthReferenceGuardTable<C, N>({\n table: c.table,\n orderBy: c.clientKey,\n condition: (input) =>\n Effect.gen(function* () {\n const key = yield* scopeKey(input.identity.provider, input.identity.issuer);\n\n return both(\n equal(c.table, {\n [c.clientKey]: key,\n [c.counter]: mapping.order.encode(0),\n }),\n exactText(c.table, c.provider, input.identity.provider),\n exactText(c.table, c.issuer, input.identity.issuer),\n exactText(c.table, c.clientRegistrationId, \"\"),\n );\n }),\n }),\n ],\n connectedReference: (input) => connectedReferenceCondition(mapping, input.identityKey),\n });\n};\n\nexport const connectedReferenceCondition = (\n mapping: Mapping,\n identityKey: string | SQL,\n knownIdentity?: { readonly provider: string | SQL; readonly issuer: string | SQL },\n) => {\n const c = mapping.client,\n t = mapping.ownership.tuple,\n f = mapping.flow,\n g = mapping.grant,\n h = mapping.cohort,\n a = mapping.admission,\n j = mapping.revocation.mode === \"cohort\" ? mapping.revocation.job : undefined;\n\n const tuple = equal(t.table, { [t.identityKey]: identityKey });\n const knownFlow = sql`exists(select 1 from ${h.table} where ${col(h.table, h.cohortKey)} = ${col(f.table, f.cohortKey)} and ${col(h.table, h.identityKey)} = ${identityKey})`;\n\n const unknownFlow =\n knownIdentity === undefined\n ? sql`${col(f.table, f.cohortKey)} is null and exists(select 1 from ${c.table} where ${col(c.table, c.clientKey)} = ${col(f.table, f.clientKey)} and exists(select 1 from ${t.table} where ${tuple} and ${col(c.table, c.provider)} = ${col(t.table, t.provider)} and ${col(c.table, c.issuer)} = ${col(t.table, t.issuer)}))`\n : sql`${col(f.table, f.cohortKey)} is null and exists(select 1 from ${c.table} where ${col(c.table, c.clientKey)} = ${col(f.table, f.clientKey)} and ${col(c.table, c.provider)} = ${knownIdentity.provider} and ${col(c.table, c.issuer)} = ${knownIdentity.issuer})`;\n\n const related = [f, g, h, ...(j === undefined ? [] : [j])];\n\n return sql`(${sql.join(\n [\n sql`exists(select 1 from ${g.table} where ${eq(col(g.table, g.identityKey), identityKey)})`,\n sql`exists(select 1 from ${a.table} where ${eq(col(a.table, a.identityKey), identityKey)})`,\n sql`exists(select 1 from ${h.table} where ${both(eq(col(h.table, h.identityKey), identityKey), eq(col(h.table, h.state), \"Blocked\"))})`,\n sql`exists(select 1 from ${f.table} where ${col(f.table, f.work)} = 'Unresolved' and (${knownFlow} or (${unknownFlow})))`,\n ...(j === undefined\n ? []\n : [\n sql`exists(select 1 from ${j.table} where ${eq(col(j.table, j.identityKey), identityKey)})`,\n ]),\n // A missing real client cannot turn erased unknown work into absence.\n ...related.map(\n (v) =>\n sql`exists(select 1 from ${v.table} where not exists(select 1 from ${c.table} where ${col(c.table, c.clientKey)} = ${col(v.table, v.clientKey)}))`,\n ),\n ],\n sql` or `,\n )})`;\n};\n"],"mappings":"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"}
@@ -19,9 +19,9 @@ const activateGrant = Effect.fn("oauthConnected.activateGrant")(function* (mappi
19
19
  const owner = yield* CurrentOAuthTransaction;
20
20
  const token = grant.context;
21
21
  const g = mapping.grant;
22
- const identityKey = oauthIdentityKey(token.identity);
23
- const clientKey$1 = clientKey(token.configuration);
24
- const cohortKey$1 = cohortKey(clientKey$1, identityKey);
22
+ const identityKey = yield* oauthIdentityKey(token.identity);
23
+ const clientKey$1 = yield* clientKey(token.configuration);
24
+ const cohortKey$1 = yield* cohortKey(clientKey$1, identityKey);
25
25
  const values = {
26
26
  ...g.encodeInsert({
27
27
  grant: snapshotOAuthSync(M.OAuthConnectedStoredGrant, grant),
@@ -72,7 +72,7 @@ const settle = Effect.fn("oauthConnected.settle")(function* (mapping, input) {
72
72
  return { _tag: state };
73
73
  }
74
74
  const grant = snapshotOAuthSync(M.OAuthConnectedStoredGrant, out.grant), token = grant.context;
75
- invariant(token.moduleId === c.moduleId && token.subjectId === c.revision.subjectId && token.grantId === c.grantId && token.identity.provider === c.provider && token.identity.issuer === c.issuer && clientKey(token.configuration) === cl.id && tokenContextStorage.encode({
75
+ invariant(token.moduleId === c.moduleId && token.subjectId === c.revision.subjectId && token.grantId === c.grantId && token.identity.provider === c.provider && token.identity.issuer === c.issuer && (yield* clientKey(token.configuration)) === cl.id && tokenContextStorage.encode({
76
76
  ...token,
77
77
  configuration: configuration(input.claim.flow)
78
78
  }) === tokenContextStorage.encode(token));
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-connected-settlement.mjs","names":["clientKey","S.clientKey","cohortKey","S.cohortKey","S.nativeCopy","C.summary","S.retainedUntil","S.current","S.action","F.expected","S.client","S.configuration","F.exact","F.terminal","F.readTuple","S.cohort","S.readGrant","F.sameTarget","C.noFormerOwner","S.orderNumber","F.acquireTuple","C.fence","C.storeJob"],"sources":["../../src/drizzle/oauth-connected-settlement.ts"],"sourcesContent":["import * as M from \"@yielded/auth/OAuth\";\nimport { snapshotOAuthSync } from \"@yielded/auth/OAuth\";\nimport { ne, sql } from \"drizzle-orm\";\nimport { Effect } from \"effect\";\n\nimport * as C from \"./oauth-connected-custody\";\nimport * as F from \"./oauth-connected-flow\";\nimport * as S from \"./oauth-connected-state\";\nimport { both, col, equal, CurrentOAuthTransaction } from \"./oauth-owner\";\nimport { invariant, sameIdentity, oauthIdentityKey } from \"./oauth-state\";\n\nexport const validMetadata = (context: M.OAuthConnectedTokenContext, now: number) => {\n const m = context.metadata,\n p = context.configuration.profile;\n\n return (\n p.provider === context.identity.provider &&\n context.configuration.provider === context.identity.provider &&\n context.configuration.issuer === context.identity.issuer &&\n m.obtainedAtMillis <= now &&\n m.useUntilMillis > m.obtainedAtMillis &&\n m.useUntilMillis <= m.obtainedAtMillis + p.maximumAccessLifetimeMillis &&\n (m.accessExpiresAtMillis === undefined || m.useUntilMillis <= m.accessExpiresAtMillis) &&\n m.scopes.every((v) => p.scopes.includes(v)) &&\n m.resources.every((v) => p.resources.includes(v)) &&\n new Set(m.scopes).size === m.scopes.length &&\n new Set(m.resources).size === m.resources.length &&\n (m.refreshUseUntilMillis === undefined ||\n (p.retention === \"access-and-refresh\" &&\n p.maximumRefreshLifetimeMillis !== undefined &&\n m.refreshUseUntilMillis > m.obtainedAtMillis &&\n m.refreshUseUntilMillis <= m.obtainedAtMillis + p.maximumRefreshLifetimeMillis &&\n (m.refreshExpiresAtMillis === undefined ||\n m.refreshUseUntilMillis <= m.refreshExpiresAtMillis)))\n );\n};\n\n/** The only writer that activates or replaces a confirmed connected grant. */\nexport const activateGrant = Effect.fn(\"oauthConnected.activateGrant\")(function* (\n mapping: S.Mapping,\n grant: M.OAuthConnectedStoredGrant,\n native: unknown,\n now: number,\n replacing: boolean,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const token = grant.context;\n const g = mapping.grant;\n const identityKey = oauthIdentityKey(token.identity);\n const clientKey = S.clientKey(token.configuration);\n const cohortKey = S.cohortKey(clientKey, identityKey);\n\n const values = {\n ...g.encodeInsert({\n grant: snapshotOAuthSync(M.OAuthConnectedStoredGrant, grant),\n subjectId: S.nativeCopy(native),\n }),\n [g.moduleId]: token.moduleId,\n [g.grantId]: token.grantId,\n [g.subjectId]: native,\n [g.identityKey]: identityKey,\n [g.activeIdentityKey]: identityKey,\n [g.clientKey]: clientKey,\n [g.cohortKey]: cohortKey,\n [g.profileKey]: token.configuration.profile.key,\n [g.grantVersion]: token.grantVersion,\n [g.tokenVersion]: token.tokenVersion,\n [g.cohortGeneration]: token.cohortGeneration,\n [g.state]: \"Active\",\n [g.version]: owner.marker,\n [g.context]: S.tokenContextStorage.encode(token),\n [g.sealed]: S.sealedStorage.encode(grant.sealed),\n [g.summary]: S.summaryStorage.encode(C.summary(token)),\n [g.revocationJobId]: null,\n [g.refreshWork]: \"None\",\n [g.refreshClaim]: null,\n [g.refreshClaimExpiresAt]: null,\n [g.retentionUntil]: mapping.clock.encodeInstant(\n S.retainedUntil(\n mapping,\n Math.max(now, token.metadata.useUntilMillis, token.metadata.refreshUseUntilMillis ?? 0),\n ),\n ),\n };\n\n if (!replacing) {\n yield* owner.insert(g.table, values, {\n [g.moduleId]: token.moduleId,\n [g.grantId]: token.grantId,\n });\n } else\n yield* owner.update(\n g.table,\n { [g.moduleId]: token.moduleId, [g.grantId]: token.grantId },\n values,\n );\n});\n\nexport const settle = Effect.fn(\"oauthConnected.settle\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"settle\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const c = input.claim.flow.context,\n out = input.outcome;\n\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n const authorized =\n found !== undefined &&\n (yield* S.action(mapping, found, input.authorization, \"settle\", F.expected(input.claim.flow)));\n\n const cl = yield* S.client(mapping, S.configuration(input.claim.flow), false);\n\n if (cl === undefined) return { _tag: \"Rejected\" } as const;\n if (out._tag !== \"Verified\" && out._tag !== \"Quarantined\") {\n const claimed = yield* F.exact(mapping, input.claim);\n\n if (claimed === undefined) return { _tag: \"Rejected\" } as const;\n const state = out._tag === \"Unissued\" ? \"Rejected\" : out._tag;\n\n yield* F.terminal(\n mapping,\n input.claim,\n state,\n out._tag === \"Cancelled\" || out._tag === \"Unissued\" ? \"Resolved\" : \"Unresolved\",\n );\n\n return { _tag: state } as\n | { readonly _tag: \"Cancelled\" }\n | { readonly _tag: \"Rejected\" }\n | { readonly _tag: \"Conflict\" }\n | { readonly _tag: \"Ambiguous\" };\n }\n\n const grant = snapshotOAuthSync(M.OAuthConnectedStoredGrant, out.grant),\n token = grant.context;\n\n invariant(\n token.moduleId === c.moduleId &&\n token.subjectId === c.revision.subjectId &&\n token.grantId === c.grantId &&\n token.identity.provider === c.provider &&\n token.identity.issuer === c.issuer &&\n S.clientKey(token.configuration) === cl.id &&\n S.tokenContextStorage.encode({\n ...token,\n configuration: S.configuration(input.claim.flow),\n }) === S.tokenContextStorage.encode(token),\n );\n const native = yield* mapping.subjectId.toNative(c.revision.subjectId);\n\n const tuple = yield* F.readTuple(mapping.ownership, token.identity),\n t = mapping.ownership.tuple;\n\n if (\n tuple.row[t.state] === \"Reserved\" ||\n (tuple.row[t.state] === \"Owned\" && !mapping.subjectId.equals(tuple.row[t.subjectId], native))\n ) {\n const claimed = yield* F.exact(mapping, input.claim);\n\n if (claimed !== undefined) yield* F.terminal(mapping, input.claim, \"Conflict\", \"Unresolved\");\n\n return { _tag: \"Conflict\" } as const;\n }\n const co = yield* S.cohort(mapping, cl.id, tuple.key, true);\n const original = yield* S.readGrant(mapping, c.moduleId, c.grantId);\n const g = mapping.grant;\n\n const other = yield* owner.read(\n g.table,\n both(\n equal(g.table, {\n [g.moduleId]: c.moduleId,\n [g.subjectId]: native,\n [g.profileKey]: c.profile.key,\n [g.activeIdentityKey]: tuple.key,\n }),\n ne(col(g.table, g.grantId), c.grantId),\n ),\n { limit: 1 },\n );\n\n const claimed = yield* F.exact(mapping, input.claim);\n\n if (claimed === undefined) return { _tag: \"Rejected\" } as const;\n invariant(\n token.exchangeOrder === input.claim.order &&\n validMetadata(token, claimed.now) &&\n token.metadata.obtainedAtMillis >= input.claim.claimedAtMillis,\n );\n const reconnect = c.reconnect;\n\n const targetOkay =\n reconnect === undefined\n ? original === undefined\n : original !== undefined &&\n F.sameTarget(reconnect, original.context) &&\n sameIdentity(reconnect.identity, token.identity) &&\n original.row[g.refreshWork] !== \"Unresolved\";\n\n const previousSafe = yield* C.noFormerOwner(mapping, tuple.key, cl.id, native);\n\n const active =\n out._tag === \"Verified\" &&\n authorized &&\n claimed.active &&\n c.profile.issuance === \"active\" &&\n token.metadata.useUntilMillis > claimed.now &&\n !co.blocked &&\n co.generation === token.cohortGeneration &&\n S.orderNumber(input.claim.order) > co.cutoff &&\n targetOkay &&\n other.rows.length === 0 &&\n previousSafe;\n\n if (!active) {\n // Foreign historical custody never authorizes a new remote operation.\n if (!previousSafe) {\n yield* F.terminal(mapping, input.claim, \"Conflict\", \"Unresolved\");\n\n return { _tag: \"Conflict\" } as const;\n }\n if (tuple.row[t.state] === \"Unowned\")\n yield* F.acquireTuple(mapping.ownership, token.identity, tuple.key, S.nativeCopy(native));\n yield* C.fence(mapping, cl, co);\n if (out.cleanup !== undefined) {\n yield* C.storeJob(mapping, out.cleanup, token, native, claimed.now);\n yield* F.terminal(mapping, input.claim, \"Quarantined\", \"Resolved\", { cohort: co.id });\n } else\n yield* F.terminal(mapping, input.claim, \"Quarantined\", \"Unresolved\", {\n cohort: co.id,\n sealed: grant,\n });\n\n return { _tag: targetOkay && other.rows.length === 0 ? \"Rejected\" : \"Conflict\" } as\n | { readonly _tag: \"Rejected\" }\n | { readonly _tag: \"Conflict\" };\n }\n if (tuple.row[t.state] === \"Unowned\")\n yield* F.acquireTuple(mapping.ownership, token.identity, tuple.key, S.nativeCopy(native));\n\n yield* activateGrant(mapping, grant, native, claimed.now, original !== undefined);\n yield* F.terminal(mapping, input.claim, \"Connected\", \"Resolved\", { cohort: co.id });\n owner.postconditions.push(\n sql`${mapping.clock.engineNowMillis} >= ${claimed.now} and ${mapping.clock.engineNowMillis} < ${Math.min(input.claim.claimExpiresAtMillis, token.metadata.useUntilMillis)}`,\n );\n\n return { _tag: \"Connected\", grant } as const;\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"oauth-connected-settlement.mjs","names":["clientKey","S.clientKey","cohortKey","S.cohortKey","S.nativeCopy","C.summary","S.retainedUntil","S.current","S.action","F.expected","S.client","S.configuration","F.exact","F.terminal","F.readTuple","S.cohort","S.readGrant","F.sameTarget","C.noFormerOwner","S.orderNumber","F.acquireTuple","C.fence","C.storeJob"],"sources":["../../src/drizzle/oauth-connected-settlement.ts"],"sourcesContent":["import * as M from \"@yielded/auth/OAuth\";\nimport { snapshotOAuthSync } from \"@yielded/auth/OAuth\";\nimport { ne, sql } from \"drizzle-orm\";\nimport { Effect } from \"effect\";\n\nimport * as C from \"./oauth-connected-custody\";\nimport * as F from \"./oauth-connected-flow\";\nimport * as S from \"./oauth-connected-state\";\nimport { both, col, equal, CurrentOAuthTransaction } from \"./oauth-owner\";\nimport { invariant, sameIdentity, oauthIdentityKey } from \"./oauth-state\";\n\nexport const validMetadata = (context: M.OAuthConnectedTokenContext, now: number) => {\n const m = context.metadata,\n p = context.configuration.profile;\n\n return (\n p.provider === context.identity.provider &&\n context.configuration.provider === context.identity.provider &&\n context.configuration.issuer === context.identity.issuer &&\n m.obtainedAtMillis <= now &&\n m.useUntilMillis > m.obtainedAtMillis &&\n m.useUntilMillis <= m.obtainedAtMillis + p.maximumAccessLifetimeMillis &&\n (m.accessExpiresAtMillis === undefined || m.useUntilMillis <= m.accessExpiresAtMillis) &&\n m.scopes.every((v) => p.scopes.includes(v)) &&\n m.resources.every((v) => p.resources.includes(v)) &&\n new Set(m.scopes).size === m.scopes.length &&\n new Set(m.resources).size === m.resources.length &&\n (m.refreshUseUntilMillis === undefined ||\n (p.retention === \"access-and-refresh\" &&\n p.maximumRefreshLifetimeMillis !== undefined &&\n m.refreshUseUntilMillis > m.obtainedAtMillis &&\n m.refreshUseUntilMillis <= m.obtainedAtMillis + p.maximumRefreshLifetimeMillis &&\n (m.refreshExpiresAtMillis === undefined ||\n m.refreshUseUntilMillis <= m.refreshExpiresAtMillis)))\n );\n};\n\n/** The only writer that activates or replaces a confirmed connected grant. */\nexport const activateGrant = Effect.fn(\"oauthConnected.activateGrant\")(function* (\n mapping: S.Mapping,\n grant: M.OAuthConnectedStoredGrant,\n native: unknown,\n now: number,\n replacing: boolean,\n) {\n const owner = yield* CurrentOAuthTransaction;\n const token = grant.context;\n const g = mapping.grant;\n const identityKey = yield* oauthIdentityKey(token.identity);\n const clientKey = yield* S.clientKey(token.configuration);\n const cohortKey = yield* S.cohortKey(clientKey, identityKey);\n\n const values = {\n ...g.encodeInsert({\n grant: snapshotOAuthSync(M.OAuthConnectedStoredGrant, grant),\n subjectId: S.nativeCopy(native),\n }),\n [g.moduleId]: token.moduleId,\n [g.grantId]: token.grantId,\n [g.subjectId]: native,\n [g.identityKey]: identityKey,\n [g.activeIdentityKey]: identityKey,\n [g.clientKey]: clientKey,\n [g.cohortKey]: cohortKey,\n [g.profileKey]: token.configuration.profile.key,\n [g.grantVersion]: token.grantVersion,\n [g.tokenVersion]: token.tokenVersion,\n [g.cohortGeneration]: token.cohortGeneration,\n [g.state]: \"Active\",\n [g.version]: owner.marker,\n [g.context]: S.tokenContextStorage.encode(token),\n [g.sealed]: S.sealedStorage.encode(grant.sealed),\n [g.summary]: S.summaryStorage.encode(C.summary(token)),\n [g.revocationJobId]: null,\n [g.refreshWork]: \"None\",\n [g.refreshClaim]: null,\n [g.refreshClaimExpiresAt]: null,\n [g.retentionUntil]: mapping.clock.encodeInstant(\n S.retainedUntil(\n mapping,\n Math.max(now, token.metadata.useUntilMillis, token.metadata.refreshUseUntilMillis ?? 0),\n ),\n ),\n };\n\n if (!replacing) {\n yield* owner.insert(g.table, values, {\n [g.moduleId]: token.moduleId,\n [g.grantId]: token.grantId,\n });\n } else\n yield* owner.update(\n g.table,\n { [g.moduleId]: token.moduleId, [g.grantId]: token.grantId },\n values,\n );\n});\n\nexport const settle = Effect.fn(\"oauthConnected.settle\")(function* (\n mapping: S.Mapping,\n input: F.Input<\"settle\">,\n) {\n const owner = yield* CurrentOAuthTransaction;\n\n const c = input.claim.flow.context,\n out = input.outcome;\n\n const found = yield* S.current(mapping, c.revision.subjectId);\n\n const authorized =\n found !== undefined &&\n (yield* S.action(mapping, found, input.authorization, \"settle\", F.expected(input.claim.flow)));\n\n const cl = yield* S.client(mapping, S.configuration(input.claim.flow), false);\n\n if (cl === undefined) return { _tag: \"Rejected\" } as const;\n if (out._tag !== \"Verified\" && out._tag !== \"Quarantined\") {\n const claimed = yield* F.exact(mapping, input.claim);\n\n if (claimed === undefined) return { _tag: \"Rejected\" } as const;\n const state = out._tag === \"Unissued\" ? \"Rejected\" : out._tag;\n\n yield* F.terminal(\n mapping,\n input.claim,\n state,\n out._tag === \"Cancelled\" || out._tag === \"Unissued\" ? \"Resolved\" : \"Unresolved\",\n );\n\n return { _tag: state } as\n | { readonly _tag: \"Cancelled\" }\n | { readonly _tag: \"Rejected\" }\n | { readonly _tag: \"Conflict\" }\n | { readonly _tag: \"Ambiguous\" };\n }\n\n const grant = snapshotOAuthSync(M.OAuthConnectedStoredGrant, out.grant),\n token = grant.context;\n\n invariant(\n token.moduleId === c.moduleId &&\n token.subjectId === c.revision.subjectId &&\n token.grantId === c.grantId &&\n token.identity.provider === c.provider &&\n token.identity.issuer === c.issuer &&\n (yield* S.clientKey(token.configuration)) === cl.id &&\n S.tokenContextStorage.encode({\n ...token,\n configuration: S.configuration(input.claim.flow),\n }) === S.tokenContextStorage.encode(token),\n );\n const native = yield* mapping.subjectId.toNative(c.revision.subjectId);\n\n const tuple = yield* F.readTuple(mapping.ownership, token.identity),\n t = mapping.ownership.tuple;\n\n if (\n tuple.row[t.state] === \"Reserved\" ||\n (tuple.row[t.state] === \"Owned\" && !mapping.subjectId.equals(tuple.row[t.subjectId], native))\n ) {\n const claimed = yield* F.exact(mapping, input.claim);\n\n if (claimed !== undefined) yield* F.terminal(mapping, input.claim, \"Conflict\", \"Unresolved\");\n\n return { _tag: \"Conflict\" } as const;\n }\n const co = yield* S.cohort(mapping, cl.id, tuple.key, true);\n const original = yield* S.readGrant(mapping, c.moduleId, c.grantId);\n const g = mapping.grant;\n\n const other = yield* owner.read(\n g.table,\n both(\n equal(g.table, {\n [g.moduleId]: c.moduleId,\n [g.subjectId]: native,\n [g.profileKey]: c.profile.key,\n [g.activeIdentityKey]: tuple.key,\n }),\n ne(col(g.table, g.grantId), c.grantId),\n ),\n { limit: 1 },\n );\n\n const claimed = yield* F.exact(mapping, input.claim);\n\n if (claimed === undefined) return { _tag: \"Rejected\" } as const;\n invariant(\n token.exchangeOrder === input.claim.order &&\n validMetadata(token, claimed.now) &&\n token.metadata.obtainedAtMillis >= input.claim.claimedAtMillis,\n );\n const reconnect = c.reconnect;\n\n const targetOkay =\n reconnect === undefined\n ? original === undefined\n : original !== undefined &&\n F.sameTarget(reconnect, original.context) &&\n sameIdentity(reconnect.identity, token.identity) &&\n original.row[g.refreshWork] !== \"Unresolved\";\n\n const previousSafe = yield* C.noFormerOwner(mapping, tuple.key, cl.id, native);\n\n const active =\n out._tag === \"Verified\" &&\n authorized &&\n claimed.active &&\n c.profile.issuance === \"active\" &&\n token.metadata.useUntilMillis > claimed.now &&\n !co.blocked &&\n co.generation === token.cohortGeneration &&\n S.orderNumber(input.claim.order) > co.cutoff &&\n targetOkay &&\n other.rows.length === 0 &&\n previousSafe;\n\n if (!active) {\n // Foreign historical custody never authorizes a new remote operation.\n if (!previousSafe) {\n yield* F.terminal(mapping, input.claim, \"Conflict\", \"Unresolved\");\n\n return { _tag: \"Conflict\" } as const;\n }\n if (tuple.row[t.state] === \"Unowned\")\n yield* F.acquireTuple(mapping.ownership, token.identity, tuple.key, S.nativeCopy(native));\n yield* C.fence(mapping, cl, co);\n if (out.cleanup !== undefined) {\n yield* C.storeJob(mapping, out.cleanup, token, native, claimed.now);\n yield* F.terminal(mapping, input.claim, \"Quarantined\", \"Resolved\", { cohort: co.id });\n } else\n yield* F.terminal(mapping, input.claim, \"Quarantined\", \"Unresolved\", {\n cohort: co.id,\n sealed: grant,\n });\n\n return { _tag: targetOkay && other.rows.length === 0 ? \"Rejected\" : \"Conflict\" } as\n | { readonly _tag: \"Rejected\" }\n | { readonly _tag: \"Conflict\" };\n }\n if (tuple.row[t.state] === \"Unowned\")\n yield* F.acquireTuple(mapping.ownership, token.identity, tuple.key, S.nativeCopy(native));\n\n yield* activateGrant(mapping, grant, native, claimed.now, original !== undefined);\n yield* F.terminal(mapping, input.claim, \"Connected\", \"Resolved\", { cohort: co.id });\n owner.postconditions.push(\n sql`${mapping.clock.engineNowMillis} >= ${claimed.now} and ${mapping.clock.engineNowMillis} < ${Math.min(input.claim.claimExpiresAtMillis, token.metadata.useUntilMillis)}`,\n );\n\n return { _tag: \"Connected\", grant } as const;\n});\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import { digest, invariant, oauthIdentityKey, sameIdentity, sameRevision, storage, unavailable } from "./oauth-state.mjs";
1
+ import { digest } from "./crypto.mjs";
2
+ import { invariant, oauthIdentityKey, sameIdentity, sameRevision, storage, unavailable } from "./oauth-state.mjs";
2
3
  import { both } from "./transaction-owner.mjs";
3
4
  import { CurrentOAuthTransaction, equal } from "./oauth-owner.mjs";
4
5
  import { exactClaim } from "./oauth-flow.mjs";
@@ -64,7 +65,7 @@ const claimSignIn = Effect.fn("oauthConnected.claimSignIn")(function* (mapping,
64
65
  [f.stateDigest]: c.stateDigest,
65
66
  [f.snapshot]: null,
66
67
  [f.claimId]: claim.claimId,
67
- [f.claimDigest]: digest(reservationStorage.encode(reservation)),
68
+ [f.claimDigest]: yield* digest(reservationStorage.encode(reservation)),
68
69
  [f.claimOrder]: mapping.order.encode(order),
69
70
  [f.claimedAt]: mapping.clock.encodeInstant(claim.claimedAtMillis),
70
71
  [f.claimExpiresAt]: mapping.clock.encodeInstant(claim.claimExpiresAtMillis),
@@ -86,8 +87,8 @@ const exact = Effect.fn("oauthConnected.exactSignIn")(function* (mapping, reserv
86
87
  [f.flowId]: c.flowId
87
88
  };
88
89
  const row = (yield* owner.read(f.table, equal(f.table, key), { limit: 1 })).rows[0];
89
- if (row === void 0 || row[f.work] !== "Unresolved" || row[f.claimId] !== reservation.claim.claimId || row[f.claimDigest] !== digest(reservationStorage.encode(reservation))) return void 0;
90
- invariant(row[f.subjectId] === null && row[f.commandId] === c.commandId && row[f.clientKey] === clientKey(reservation.configuration) && nativeOrder(mapping, row[f.claimOrder]) === orderNumber(reservation.order));
90
+ if (row === void 0 || row[f.work] !== "Unresolved" || row[f.claimId] !== reservation.claim.claimId || row[f.claimDigest] !== (yield* digest(reservationStorage.encode(reservation)))) return void 0;
91
+ invariant(row[f.subjectId] === null && row[f.commandId] === c.commandId && row[f.clientKey] === (yield* clientKey(reservation.configuration)) && nativeOrder(mapping, row[f.claimOrder]) === orderNumber(reservation.order));
91
92
  const now = yield* owner.now(mapping.clock);
92
93
  invariant(now >= reservation.claim.claimedAtMillis);
93
94
  return {
@@ -110,7 +111,7 @@ const credential = Effect.fn("oauthConnected.signInCredential")(function* (mappi
110
111
  [c.moduleId]: context.moduleId,
111
112
  [c.credentialId]: input.credentialId,
112
113
  [c.subjectId]: found.nativeId,
113
- [c.identityKey]: oauthIdentityKey(input.identity),
114
+ [c.identityKey]: yield* oauthIdentityKey(input.identity),
114
115
  [c.credentialRevision]: input.credentialRevision
115
116
  }), c.activeCondition);
116
117
  const login = yield* owner.read(c.table, loginWhere, { limit: 1 });
@@ -153,11 +154,11 @@ const slot = Effect.fn("oauthConnected.signInSlot")(function* (mapping, moduleId
153
154
  });
154
155
  /** Orders belong to one client registration. Moving a profile to another client
155
156
  * requires a newer profile generation; retired clients cannot replace it later. */
156
- const canReplace = (reservation, previous) => {
157
+ const canReplace = Effect.fnUntraced(function* (reservation, previous) {
157
158
  const generation = reservation.configuration.profile.generation;
158
159
  const oldGeneration = previous.configuration.profile.generation;
159
- return clientKey(reservation.configuration) === clientKey(previous.configuration) ? generation >= oldGeneration && orderNumber(reservation.order) > orderNumber(previous.exchangeOrder) : generation > oldGeneration;
160
- };
160
+ return (yield* clientKey(reservation.configuration)) === (yield* clientKey(previous.configuration)) ? generation >= oldGeneration && orderNumber(reservation.order) > orderNumber(previous.exchangeOrder) : generation > oldGeneration;
161
+ });
161
162
  const inspectSignIn = Effect.fn("oauthConnected.inspectSignIn")(function* (mapping, input) {
162
163
  const found = yield* credential(mapping, input.reservation, input.credential);
163
164
  if (found === void 0) return { _tag: "Rejected" };
@@ -171,7 +172,7 @@ const inspectSignIn = Effect.fn("oauthConnected.inspectSignIn")(function* (mappi
171
172
  const previous = yield* slot(mapping, r.claim.flow.context.moduleId, found.nativeId, tuple.key, r.configuration.profile.key);
172
173
  const held = yield* exact(mapping, r);
173
174
  if (held === void 0) return { _tag: "Rejected" };
174
- const quarantine = !held.active || co.blocked || orderNumber(r.order) <= co.cutoff || previous?.row[mapping.grant.refreshWork] === "Unresolved" || previous !== void 0 && !canReplace(r, previous.context);
175
+ const quarantine = !held.active || co.blocked || orderNumber(r.order) <= co.cutoff || previous?.row[mapping.grant.refreshWork] === "Unresolved" || previous !== void 0 && !(yield* canReplace(r, previous.context));
175
176
  return snapshotOAuthSync(M.OAuthSignInAccessInspection, {
176
177
  _tag: quarantine ? "Quarantine" : "Target",
177
178
  grantId: previous?.context.grantId ?? input.grantId,
@@ -210,7 +211,7 @@ const settleSignIn = Effect.fn("oauthConnected.settleSignIn")(function* (mapping
210
211
  const held = yield* exact(mapping, r);
211
212
  if (held === void 0) return { _tag: "Rejected" };
212
213
  invariant(token.exchangeOrder === r.order && validMetadata(token, held.now) && token.metadata.obtainedAtMillis >= r.claim.claimedAtMillis);
213
- const target = out.previous === void 0 ? previous === void 0 : previous !== void 0 && sameTarget(out.previous, previous.context) && sameIdentity(previous.context.identity, token.identity) && previous.row[mapping.grant.refreshWork] !== "Unresolved" && canReplace(r, previous.context);
214
+ const target = out.previous === void 0 ? previous === void 0 : previous !== void 0 && sameTarget(out.previous, previous.context) && sameIdentity(previous.context.identity, token.identity) && previous.row[mapping.grant.refreshWork] !== "Unresolved" && (yield* canReplace(r, previous.context));
214
215
  const previousSafe = yield* noFormerOwner(mapping, tuple.key, cl.id, native);
215
216
  if (!owned || !previousSafe) {
216
217
  yield* owner.update(f.table, held.key, {