@yielded/auth-persistence 0.1.0-beta.31 → 0.1.0-beta.32

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 (113) hide show
  1. package/README.md +9 -2
  2. package/dist/Adapter.mjs +8 -8
  3. package/dist/OAuthPersistence.mjs +10 -5
  4. package/dist/OAuthPersistence.mjs.map +1 -1
  5. package/dist/internal/configuration.d.mts +31 -5
  6. package/dist/internal/configuration.mjs.map +1 -1
  7. package/dist/internal/email-native.mjs +10 -2
  8. package/dist/internal/email-native.mjs.map +1 -1
  9. package/dist/internal/email-policy.mjs +3 -2
  10. package/dist/internal/email-policy.mjs.map +1 -1
  11. package/dist/internal/models/oauth-model.d.mts +4 -2
  12. package/dist/internal/models/oauth-model.mjs.map +1 -1
  13. package/dist/internal/oauth/native-accounts.d.mts +1 -1
  14. package/dist/internal/oauth/native-accounts.mjs +6 -6
  15. package/dist/internal/oauth/native-accounts.mjs.map +1 -1
  16. package/dist/internal/oauth/native-connected.d.mts +1 -1
  17. package/dist/internal/oauth/native-connected.mjs +1 -1
  18. package/dist/internal/oauth/native-registration.mjs +19 -8
  19. package/dist/internal/oauth/native-registration.mjs.map +1 -1
  20. package/dist/internal/oauth/native-sign-in.d.mts +1 -1
  21. package/dist/internal/oauth/native-sign-in.mjs +1 -1
  22. package/dist/internal/oauth/native-state.mjs +21 -11
  23. package/dist/internal/oauth/native-state.mjs.map +1 -1
  24. package/dist/internal/oauth/state.d.mts +1 -1
  25. package/dist/internal/oauth/state.mjs +1 -1
  26. package/dist/internal/oauth-managed.mjs +182 -0
  27. package/dist/internal/oauth-managed.mjs.map +1 -0
  28. package/dist/internal/passkey-managed.mjs +1 -1
  29. package/dist/internal/passkey-native-registration.mjs +1 -1
  30. package/dist/internal/passkey-native-state.mjs +33 -23
  31. package/dist/internal/passkey-native-state.mjs.map +1 -1
  32. package/dist/internal/passkey-native-write.mjs +3 -3
  33. package/dist/internal/passkey-native-write.mjs.map +1 -1
  34. package/dist/internal/passkey-native.d.mts +15 -7
  35. package/dist/internal/passkey-native.mjs +2 -1
  36. package/dist/internal/passkey-native.mjs.map +1 -1
  37. package/dist/internal/passkey-policy.mjs +9 -7
  38. package/dist/internal/passkey-policy.mjs.map +1 -1
  39. package/dist/internal/password-native.mjs +9 -6
  40. package/dist/internal/password-native.mjs.map +1 -1
  41. package/dist/internal/password-policy.mjs +7 -6
  42. package/dist/internal/password-policy.mjs.map +1 -1
  43. package/dist/internal/persistence.mjs +96 -37
  44. package/dist/internal/persistence.mjs.map +1 -1
  45. package/dist/internal/phone-native.mjs +1 -1
  46. package/dist/internal/phone-native.mjs.map +1 -1
  47. package/dist/internal/session-native-authority.mjs +6 -5
  48. package/dist/internal/session-native-authority.mjs.map +1 -1
  49. package/dist/internal/session-native-login.d.mts +2 -2
  50. package/dist/internal/session-native-login.mjs +2 -1
  51. package/dist/internal/session-native-login.mjs.map +1 -1
  52. package/dist/internal/session-native-pending-read.mjs +26 -20
  53. package/dist/internal/session-native-pending-read.mjs.map +1 -1
  54. package/dist/internal/session-native-record.mjs +6 -4
  55. package/dist/internal/session-native-record.mjs.map +1 -1
  56. package/dist/internal/session-native-state.mjs +3 -0
  57. package/dist/internal/session-native-state.mjs.map +1 -1
  58. package/dist/internal/session-native-stateful.d.mts +2 -2
  59. package/dist/internal/session-native-stateful.mjs +65 -37
  60. package/dist/internal/session-native-stateful.mjs.map +1 -1
  61. package/dist/internal/session-native-step-up.d.mts +2 -2
  62. package/dist/internal/session-native-step-up.mjs +14 -18
  63. package/dist/internal/session-native-step-up.mjs.map +1 -1
  64. package/dist/internal/session-native-validity.mjs +3 -1
  65. package/dist/internal/session-native-validity.mjs.map +1 -1
  66. package/dist/internal/sql-authority.mjs +5 -1
  67. package/dist/internal/sql-authority.mjs.map +1 -1
  68. package/dist/internal/sql-storage-validation.mjs +2 -1
  69. package/dist/internal/sql-storage-validation.mjs.map +1 -1
  70. package/dist/internal/sql-table.d.mts +1 -0
  71. package/dist/internal/sql-table.mjs.map +1 -1
  72. package/dist/internal/step-up-state.mjs +19 -6
  73. package/dist/internal/step-up-state.mjs.map +1 -1
  74. package/dist/internal/storage-mapping.mjs +1 -1
  75. package/dist/internal/storage-tables.d.mts +237 -0
  76. package/dist/internal/storage-tables.mjs +68 -0
  77. package/dist/internal/storage-tables.mjs.map +1 -1
  78. package/dist/internal/storage-validation.d.mts +3 -1
  79. package/dist/internal/storage-validation.mjs +70 -17
  80. package/dist/internal/storage-validation.mjs.map +1 -1
  81. package/dist/internal/totp-native.mjs +1 -1
  82. package/package.json +1 -1
  83. package/src/OAuthPersistence.ts +7 -2
  84. package/src/internal/configuration.ts +46 -7
  85. package/src/internal/email-native.ts +16 -6
  86. package/src/internal/email-policy.ts +12 -3
  87. package/src/internal/models/oauth-model.ts +7 -1
  88. package/src/internal/oauth/native-accounts.ts +3 -3
  89. package/src/internal/oauth/native-registration.ts +17 -6
  90. package/src/internal/oauth/native-state.ts +38 -18
  91. package/src/internal/oauth-managed.ts +277 -0
  92. package/src/internal/passkey-native-state.ts +59 -52
  93. package/src/internal/passkey-native-write.ts +2 -2
  94. package/src/internal/passkey-native.ts +4 -2
  95. package/src/internal/passkey-policy.ts +13 -9
  96. package/src/internal/password-native.ts +17 -9
  97. package/src/internal/password-policy.ts +16 -8
  98. package/src/internal/persistence.ts +216 -70
  99. package/src/internal/phone-native.ts +1 -1
  100. package/src/internal/session-native-authority.ts +23 -7
  101. package/src/internal/session-native-login.ts +6 -3
  102. package/src/internal/session-native-pending-read.ts +46 -33
  103. package/src/internal/session-native-record.ts +6 -4
  104. package/src/internal/session-native-state.ts +3 -0
  105. package/src/internal/session-native-stateful.ts +144 -51
  106. package/src/internal/session-native-step-up.ts +27 -23
  107. package/src/internal/session-native-validity.ts +3 -1
  108. package/src/internal/sql-authority.ts +5 -1
  109. package/src/internal/sql-storage-validation.ts +53 -46
  110. package/src/internal/sql-table.ts +1 -0
  111. package/src/internal/step-up-state.ts +43 -6
  112. package/src/internal/storage-tables.ts +76 -0
  113. package/src/internal/storage-validation.ts +127 -27
package/README.md CHANGED
@@ -28,8 +28,15 @@ Applications own subject provisioning, policy, claims, delivery, and their datab
28
28
  connection and migration runner.
29
29
 
30
30
  The composed Layer covers password sign-in and management, email address verification
31
- and changes, phone sign-in, and passkey sign-in and management with stateful sessions
32
- on PostgreSQL and SQLite. Adapter authors use typed table mappings or
31
+ and changes, phone sign-in, passkey sign-in and management, OAuth sign-in with optional
32
+ retained access, and connected accounts with stateful sessions on PostgreSQL and SQLite.
33
+ OAuth-only definitions also support stateless sessions without a session table; identity
34
+ authority and OAuth flows remain durable. Other stateless combinations and state-assisted
35
+ sessions require explicit persistence services.
36
+ OAuth registration and login linking/unlinking still use explicit `OAuthPersistence`
37
+ mappings. Applications provision login identities and supply OAuth action evidence,
38
+ use authorization, provider configuration, and encryption keys.
39
+ Adapter authors use typed table mappings or
33
40
  `NativeSqlTables` through `/Adapter`. Use the explicit coordinators when auth and
34
41
  application writes must share one commit; independent transaction owners are not atomic.
35
42
  See [persistence examples](../../docs/src/content/docs/reference/adapters.md#runnable-examples) for all
package/dist/Adapter.mjs CHANGED
@@ -5,10 +5,17 @@ import { requireStandalone } from "./internal/standalone.mjs";
5
5
  import { SqlBatchCommit, SqlNativeCommit, captureSqlBatchStatements, makeSqlCommitExecutor } from "./internal/sql-commit.mjs";
6
6
  import { makeNativeProofServices } from "./internal/proof-native.mjs";
7
7
  import { makeNativeEmailAddressServices, makeNativeEmailSignInServices } from "./internal/email-native.mjs";
8
+ import { requiredOAuthConnectedConstraints, requiredOAuthConnectedRevocationConstraints } from "./internal/models/oauth-connected-model.mjs";
9
+ import { oauthCleanupTable, oauthEligibilityTable, oauthRegistrationGuardTable, requiredOAuthRegistrationConstraints, requiredOAuthSignInConstraints } from "./internal/models/oauth-model.mjs";
10
+ import { validateStorage, validateStorageBatch, withStorageValidation } from "./internal/storage-validation.mjs";
11
+ import { captureOAuthMapping } from "./internal/oauth/state.mjs";
12
+ import { makeNativeOAuthSignInServices } from "./internal/oauth/native-sign-in.mjs";
13
+ import { makeNativeOAuthConnectedServices } from "./internal/oauth/native-connected.mjs";
14
+ import { makeNativeOAuthRevocationServices } from "./internal/oauth/native-revocations.mjs";
15
+ import { storageTables } from "./internal/storage-tables.mjs";
8
16
  import { passkeyCredentialsLayer, passkeyPersistenceLayer, requiredPasskeyCredentialConstraints, requiredPasskeyPersistenceConstraints } from "./internal/models/passkey-model.mjs";
9
17
  import { makeBatchPasskeyServices, makeNativePasskeyCredentialServices, makeNativePasskeyServices } from "./internal/passkey-native.mjs";
10
18
  import { makePasskeyNativeManagement } from "./internal/passkey-native-write.mjs";
11
- import { storageTables } from "./internal/storage-tables.mjs";
12
19
  import { makeNativePasswordServices } from "./internal/password-native.mjs";
13
20
  import { requiredPhoneConstraints } from "./internal/models/phone-model.mjs";
14
21
  import { makeNativePhoneServices } from "./internal/phone-native.mjs";
@@ -22,18 +29,11 @@ import { requiredEmailAddressConstraints, requiredEmailRegistrationConstraints,
22
29
  import { requiredPasswordConstraints, requiredPasswordRegistrationConstraints } from "./internal/models/password-model.mjs";
23
30
  import { requiredProofConstraints } from "./internal/models/proof-model.mjs";
24
31
  import { makeMappings } from "./internal/storage-mapping.mjs";
25
- import { validateStorage, validateStorageBatch, withStorageValidation } from "./internal/storage-validation.mjs";
26
32
  import { createPersistence } from "./internal/persistence.mjs";
27
33
  import { makeOAuthProxyPersistence } from "./internal/oauth-proxy.mjs";
28
- import { oauthCleanupTable, oauthEligibilityTable, oauthRegistrationGuardTable, requiredOAuthRegistrationConstraints, requiredOAuthSignInConstraints } from "./internal/models/oauth-model.mjs";
29
- import { captureOAuthMapping } from "./internal/oauth/state.mjs";
30
- import { makeNativeOAuthSignInServices } from "./internal/oauth/native-sign-in.mjs";
31
34
  import { makeNativeOAuthAccountsServices } from "./internal/oauth/native-accounts.mjs";
32
- import { makeNativeOAuthConnectedServices } from "./internal/oauth/native-connected.mjs";
33
35
  import { makeNativeOAuthRegistrationIntentServices, makeNativeOAuthRegistrationServices } from "./internal/oauth/native-registration.mjs";
34
- import { makeNativeOAuthRevocationServices } from "./internal/oauth/native-revocations.mjs";
35
36
  import { storageKeyPlans } from "./internal/storage-plans.mjs";
36
- import { requiredOAuthConnectedConstraints, requiredOAuthConnectedRevocationConstraints } from "./internal/models/oauth-connected-model.mjs";
37
37
  import { oauthAccountsPersistenceLayer, oauthConnectedPersistenceLayer, oauthConnectedRevocationsLayer, oauthRegistrationAuthorityLayer, oauthRegistrationIntentsLayer, oauthSignInPersistenceLayer } from "./internal/oauth/native-layers.mjs";
38
38
  import { passkeyInvalidationMutation } from "./internal/models/passkey-write-model.mjs";
39
39
  import { requiredPendingAuthenticationConstraints, requiredSessionConstraints, requiredSignedValidityConstraints, requiredStatefulPendingConstraints } from "./internal/models/session-model.mjs";
@@ -5,22 +5,24 @@ import { SqlExpression, and, eq, sql } from "./internal/sql-expression.mjs";
5
5
  import { makeNativeSqlTables } from "./internal/native-sql-table.mjs";
6
6
  import { requireStandalone } from "./internal/standalone.mjs";
7
7
  import { makeSqlCommitExecutor } from "./internal/sql-commit.mjs";
8
+ import { requiredOAuthConnectedConstraints, requiredOAuthConnectedRevocationConstraints } from "./internal/models/oauth-connected-model.mjs";
8
9
  import { requiredOAuthRegistrationConstraints, requiredOAuthSignInConstraints } from "./internal/models/oauth-model.mjs";
10
+ import { withStorageValidation } from "./internal/storage-validation.mjs";
9
11
  import { captureOAuthMapping } from "./internal/oauth/state.mjs";
10
12
  import { makeNativeOAuthSignInServices } from "./internal/oauth/native-sign-in.mjs";
11
- import { makeNativeOAuthAccountsServices } from "./internal/oauth/native-accounts.mjs";
12
13
  import { makeNativeOAuthConnectedServices } from "./internal/oauth/native-connected.mjs";
13
- import { makeNativeOAuthRegistrationIntentServices, makeNativeOAuthRegistrationServices } from "./internal/oauth/native-registration.mjs";
14
14
  import { makeNativeOAuthRevocationServices } from "./internal/oauth/native-revocations.mjs";
15
+ import { makeNativeOAuthAccountsServices } from "./internal/oauth/native-accounts.mjs";
16
+ import { makeNativeOAuthRegistrationIntentServices, makeNativeOAuthRegistrationServices } from "./internal/oauth/native-registration.mjs";
15
17
  import { validateSqlStorage } from "./internal/sql-storage-validation.mjs";
16
18
  import { oauthCleanupTable, oauthEligibilityTable, oauthRegistrationGuardTable } from "./internal/sql-oauth-model.mjs";
17
- import { requiredOAuthConnectedConstraints, requiredOAuthConnectedRevocationConstraints } from "./internal/models/oauth-connected-model.mjs";
18
19
  import { oauthAccountsPersistenceLayer, oauthConnectedPersistenceLayer, oauthConnectedRevocationsLayer, oauthRegistrationAuthorityLayer, oauthRegistrationIntentsLayer, oauthSignInPersistenceLayer } from "./internal/oauth/native-layers.mjs";
19
20
  import { makeAuthenticationAuthorityServices } from "./internal/sql-authority.mjs";
20
21
  import { Effect, Predicate, Schema } from "effect";
21
22
  import { SqlClient } from "effect/sql";
22
23
  import { hasCommitScope } from "@yielded/auth/Hooks";
23
24
  import { OAuthAccountsPersistence, OAuthConnectedPersistence, OAuthConnectedRevocations, OAuthRegistrationIntents, OAuthSignInPersistence, OAuthUnavailable } from "@yielded/auth/OAuth";
25
+ import { reportAuthDiagnostic } from "@yielded/auth/Persistence";
24
26
  //#region src/OAuthPersistence.ts
25
27
  /** Direct PostgreSQL and SQLite owners for upstream OAuth. Provider exchange stays outside these transactions. */
26
28
  var OAuthPersistence_exports = /* @__PURE__ */ __exportAll({
@@ -74,7 +76,10 @@ const acquire = Effect.gen(function* () {
74
76
  pg: () => true,
75
77
  sqlite: () => true,
76
78
  orElse: () => false
77
- }) || Predicate.hasProperty(client, "~@effect/sql-d1/D1Client")) return yield* PersistenceConfigurationError.make({ reason: "OAuth persistence requires PostgreSQL or SQLite with interactive transactions" });
79
+ }) || Predicate.hasProperty(client, "~@effect/sql-d1/D1Client")) {
80
+ yield* reportAuthDiagnostic("persistence-validation", "configuration");
81
+ return yield* PersistenceConfigurationError.make({ reason: "OAuth persistence requires PostgreSQL or SQLite with interactive transactions" });
82
+ }
78
83
  return {
79
84
  client,
80
85
  tables: makeNativeSqlTables(client)
@@ -85,7 +90,7 @@ const using = (original, make) => Effect.gen(function* () {
85
90
  const mapping = captureOAuthMapping(original);
86
91
  yield* validateSqlStorage(mapping).pipe(Effect.mapError(() => OAuthUnavailable.make({})));
87
92
  return yield* make(target.tables, mapping);
88
- });
93
+ }).pipe(withStorageValidation);
89
94
  const coordinate = (make, body) => Effect.gen(function* () {
90
95
  const { client } = yield* acquire;
91
96
  if (yield* hasCommitScope) return yield* OAuthUnavailable.make({});
@@ -1 +1 @@
1
- {"version":3,"file":"OAuthPersistence.mjs","names":[],"sources":["../src/OAuthPersistence.ts"],"sourcesContent":["/** Direct PostgreSQL and SQLite owners for upstream OAuth. Provider exchange stays outside these transactions. */\nimport { hasCommitScope, type LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n OAuthAccountsPersistence,\n OAuthSignInPersistence,\n OAuthRegistrationIntents,\n OAuthConnectedPersistence,\n OAuthConnectedRevocations,\n OAuthUnavailable,\n} from \"@yielded/auth/OAuth\";\nimport { type Context, type Crypto, Effect, Predicate, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport { PersistenceConfigurationError } from \"./internal/configuration\";\nimport { makeNativeSqlTables } from \"./internal/native-sql-table\";\nimport {\n makeNativeOAuthAccountsServices,\n type OAuthNativeAccountsMapping,\n} from \"./internal/oauth/native-accounts\";\nimport { makeNativeOAuthConnectedServices } from \"./internal/oauth/native-connected\";\nimport type { OAuthNativeConnectedMapping } from \"./internal/oauth/native-connected-state\";\nimport {\n makeNativeOAuthRegistrationIntentServices,\n makeNativeOAuthRegistrationServices,\n type OAuthNativeRegistrationIntentMapping,\n type OAuthNativeRegistrationMapping,\n} from \"./internal/oauth/native-registration\";\nimport {\n makeNativeOAuthRevocationServices,\n type OAuthNativeRevocationMapping,\n} from \"./internal/oauth/native-revocations\";\nimport { makeNativeOAuthSignInServices } from \"./internal/oauth/native-sign-in\";\nimport { type OAuthNativeReadMapping } from \"./internal/oauth/native-state\";\nimport { captureOAuthMapping } from \"./internal/oauth/state\";\nimport { makeSqlCommitExecutor } from \"./internal/sql-commit\";\nimport { sql, SqlExpression } from \"./internal/sql-expression\";\nimport type {\n OAuthConnectedMapping,\n OAuthConnectedRevocationMapping,\n} from \"./internal/sql-oauth-connected-model\";\nimport type {\n OAuthAccountsMapping,\n OAuthSignInMapping,\n OAuthRegistrationIntentMapping,\n OAuthRegistrationMapping,\n OAuthRegistrationAuthority,\n} from \"./internal/sql-oauth-model\";\nimport { validateSqlStorage } from \"./internal/sql-storage-validation\";\nimport { Table } from \"./internal/sql-table\";\nimport { requireStandalone } from \"./internal/standalone\";\nimport type { StorageTable } from \"./internal/storage-tables\";\nexport * from \"./internal/sql-oauth-model\";\nexport * from \"./internal/sql-oauth-connected-model\";\nexport * from \"./internal/oauth/native-layers\";\nexport { sql, and, eq } from \"./internal/sql-expression\";\nexport { makeAuthenticationAuthorityServices } from \"./internal/sql-authority\";\n\nexport const table = (definition: StorageTable) =>\n new Table(definition.name, definition.columns, definition.unique, definition.schema);\n\nexport const clock = {\n encodeInstant: Schema.encodeSync(Schema.Int),\n decodeInstant: Schema.decodeUnknownSync(Schema.Int),\n engineNowMillis: new SqlExpression((client) =>\n client.onDialectOrElse({\n pg: () => client`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)`,\n orElse: () => client`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`,\n }),\n ),\n toMillis: (expression: SqlExpression) => expression,\n fromMillis: (expression: SqlExpression) => expression,\n};\n\nconst acquire = Effect.gen(function* () {\n const client = yield* SqlClient.SqlClient;\n\n if (\n !client.onDialectOrElse({ pg: () => true, sqlite: () => true, orElse: () => false }) ||\n Predicate.hasProperty(client, \"~@effect/sql-d1/D1Client\")\n )\n return yield* PersistenceConfigurationError.make({\n reason: \"OAuth persistence requires PostgreSQL or SQLite with interactive transactions\",\n });\n\n return { client, tables: makeNativeSqlTables(client) };\n});\n\nconst using = <M, A, E, R>(\n original: M,\n make: (tables: ReturnType<typeof makeNativeSqlTables>, mapping: M) => Effect.Effect<A, E, R>,\n) =>\n Effect.gen(function* () {\n const target = yield* acquire;\n const mapping = captureOAuthMapping(original);\n\n yield* validateSqlStorage(mapping).pipe(Effect.mapError(() => OAuthUnavailable.make({})));\n\n return yield* make(target.tables, mapping);\n });\n\nconst coordinate = <S, A, E, R, ES, RS>(\n make: Effect.Effect<S, ES, RS>,\n body: (services: S) => Effect.Effect<A, E, R>,\n) =>\n Effect.gen(function* () {\n const { client } = yield* acquire;\n\n if (yield* hasCommitScope) return yield* OAuthUnavailable.make({});\n yield* requireStandalone(() => OAuthUnavailable.make({}), client.transactionService);\n const executor = yield* makeSqlCommitExecutor(() => OAuthUnavailable.make({}));\n\n return yield* executor.coordinate(\n Effect.flatMap(make.pipe(Effect.mapError(() => OAuthUnavailable.make({}))), body),\n );\n });\n\nexport const makeOAuthSignInServices = <N>(\n mapping: OAuthSignInMapping<Table, Table, Table, Table, Table, N>,\n): Effect.Effect<\n { readonly oauthSignInPersistence: OAuthSignInPersistence[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthSignInServices(tables, value as unknown as OAuthNativeReadMapping),\n );\n\nexport const coordinateOAuthSignIn = <N, A, E, R>(\n options: { readonly mapping: OAuthSignInMapping<Table, Table, Table, Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthSignInPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthSignInServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthSignInPersistence, services.oauthSignInPersistence),\n );\n\nexport const makeOAuthAccountsServices = <N>(\n mapping: OAuthAccountsMapping<Table, Table, Table, Table, Table, N>,\n): Effect.Effect<\n { readonly oauthAccountsPersistence: OAuthAccountsPersistence[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthAccountsServices(tables, value as unknown as OAuthNativeAccountsMapping),\n );\n\nexport const coordinateOAuthAccounts = <N, A, E, R>(\n options: { readonly mapping: OAuthAccountsMapping<Table, Table, Table, Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthAccountsPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthAccountsServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthAccountsPersistence, services.oauthAccountsPersistence),\n );\n\nexport const makeOAuthRegistrationIntentServices = <N>(\n mapping: OAuthRegistrationIntentMapping<Table, Table, N>,\n): Effect.Effect<\n { readonly oauthRegistrationIntents: OAuthRegistrationIntents[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthRegistrationIntentServices(\n tables,\n value as unknown as OAuthNativeRegistrationIntentMapping,\n ),\n );\n\nexport const coordinateOAuthRegistrationIntents = <N, A, E, R>(\n options: { readonly mapping: OAuthRegistrationIntentMapping<Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthRegistrationIntents> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthRegistrationIntentServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthRegistrationIntents, services.oauthRegistrationIntents),\n );\n\nexport const makeOAuthConnectedServices = <N>(\n mapping: OAuthConnectedMapping<Table, Table, Table, Table, Table, N, Table>,\n): Effect.Effect<\n { readonly oauthConnectedPersistence: OAuthConnectedPersistence[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthConnectedServices(tables, value as unknown as OAuthNativeConnectedMapping),\n );\n\nexport const coordinateOAuthConnected = <N, A, E, R>(\n options: { readonly mapping: OAuthConnectedMapping<Table, Table, Table, Table, Table, N, Table> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthConnectedPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthConnectedServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthConnectedPersistence, services.oauthConnectedPersistence),\n );\n\nexport const makeOAuthConnectedRevocationServices = <N>(\n mapping: OAuthConnectedRevocationMapping<Table, Table, Table, N>,\n): Effect.Effect<\n { readonly oauthConnectedRevocations: OAuthConnectedRevocations[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthRevocationServices(tables, value as unknown as OAuthNativeRevocationMapping),\n );\n\nexport const coordinateOAuthConnectedRevocations = <N, A, E, R>(\n options: { readonly mapping: OAuthConnectedRevocationMapping<Table, Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthConnectedRevocations> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthConnectedRevocationServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthConnectedRevocations, services.oauthConnectedRevocations),\n );\n\nexport const makeOAuthRegistrationServices = <Registration, N>(\n mapping: OAuthRegistrationMapping<Registration, Table, Table, Table, Table, Table, N>,\n): Effect.Effect<\n { readonly registrationAuthority: OAuthRegistrationAuthority<Registration> },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthRegistrationServices(\n tables,\n value as unknown as OAuthNativeRegistrationMapping<Registration>,\n ),\n );\n\nexport const coordinateOAuthRegistration = <Id, Registration, N, A, E, R>(\n options: {\n readonly mapping: OAuthRegistrationMapping<\n NoInfer<Registration>,\n Table,\n Table,\n Table,\n Table,\n Table,\n N\n >;\n readonly target: Context.Key<Id, OAuthRegistrationAuthority<Registration>>;\n },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, Id> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthRegistrationServices(options.mapping), (services) =>\n Effect.provideService(body, options.target, services.registrationAuthority),\n );\n\nexport const oauthConnectedOwnershipReferences = <N>(\n mapping: OAuthConnectedMapping<Table, Table, Table, Table, Table, N, Table>,\n) => ({\n connectedReference: (input: { readonly identityKey: string; readonly subjectId: N }) => {\n const g = mapping.grant;\n const grant = sql`exists(select 1 from ${g.table} where ${g.table.columns[g.identityKey]} = ${input.identityKey} and ${g.table.columns[g.subjectId]} = ${input.subjectId})`;\n\n if (mapping.revocation.mode === \"unsupported\") return grant;\n const j = mapping.revocation.job;\n\n return sql`(${grant}) or exists(select 1 from ${j.table} where ${j.table.columns[j.identityKey]} = ${input.identityKey} and ${j.table.columns[j.subjectId]} = ${input.subjectId})`;\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"OAuthPersistence.mjs","names":[],"sources":["../src/OAuthPersistence.ts"],"sourcesContent":["/** Direct PostgreSQL and SQLite owners for upstream OAuth. Provider exchange stays outside these transactions. */\nimport { hasCommitScope, type LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n OAuthAccountsPersistence,\n OAuthSignInPersistence,\n OAuthRegistrationIntents,\n OAuthConnectedPersistence,\n OAuthConnectedRevocations,\n OAuthUnavailable,\n} from \"@yielded/auth/OAuth\";\nimport { reportAuthDiagnostic } from \"@yielded/auth/Persistence\";\nimport { type Context, type Crypto, Effect, Predicate, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport { PersistenceConfigurationError } from \"./internal/configuration\";\nimport { makeNativeSqlTables } from \"./internal/native-sql-table\";\nimport {\n makeNativeOAuthAccountsServices,\n type OAuthNativeAccountsMapping,\n} from \"./internal/oauth/native-accounts\";\nimport { makeNativeOAuthConnectedServices } from \"./internal/oauth/native-connected\";\nimport type { OAuthNativeConnectedMapping } from \"./internal/oauth/native-connected-state\";\nimport {\n makeNativeOAuthRegistrationIntentServices,\n makeNativeOAuthRegistrationServices,\n type OAuthNativeRegistrationIntentMapping,\n type OAuthNativeRegistrationMapping,\n} from \"./internal/oauth/native-registration\";\nimport {\n makeNativeOAuthRevocationServices,\n type OAuthNativeRevocationMapping,\n} from \"./internal/oauth/native-revocations\";\nimport { makeNativeOAuthSignInServices } from \"./internal/oauth/native-sign-in\";\nimport { type OAuthNativeReadMapping } from \"./internal/oauth/native-state\";\nimport { captureOAuthMapping } from \"./internal/oauth/state\";\nimport { makeSqlCommitExecutor } from \"./internal/sql-commit\";\nimport { sql, SqlExpression } from \"./internal/sql-expression\";\nimport type {\n OAuthConnectedMapping,\n OAuthConnectedRevocationMapping,\n} from \"./internal/sql-oauth-connected-model\";\nimport type {\n OAuthAccountsMapping,\n OAuthSignInMapping,\n OAuthRegistrationIntentMapping,\n OAuthRegistrationMapping,\n OAuthRegistrationAuthority,\n} from \"./internal/sql-oauth-model\";\nimport { validateSqlStorage } from \"./internal/sql-storage-validation\";\nimport { Table } from \"./internal/sql-table\";\nimport { requireStandalone } from \"./internal/standalone\";\nimport type { StorageTable } from \"./internal/storage-tables\";\nimport { withStorageValidation } from \"./internal/storage-validation\";\nexport * from \"./internal/sql-oauth-model\";\nexport * from \"./internal/sql-oauth-connected-model\";\nexport * from \"./internal/oauth/native-layers\";\nexport { sql, and, eq } from \"./internal/sql-expression\";\nexport { makeAuthenticationAuthorityServices } from \"./internal/sql-authority\";\n\nexport const table = (definition: StorageTable) =>\n new Table(definition.name, definition.columns, definition.unique, definition.schema);\n\nexport const clock = {\n encodeInstant: Schema.encodeSync(Schema.Int),\n decodeInstant: Schema.decodeUnknownSync(Schema.Int),\n engineNowMillis: new SqlExpression((client) =>\n client.onDialectOrElse({\n pg: () => client`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)`,\n orElse: () => client`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`,\n }),\n ),\n toMillis: (expression: SqlExpression) => expression,\n fromMillis: (expression: SqlExpression) => expression,\n};\n\nconst acquire = Effect.gen(function* () {\n const client = yield* SqlClient.SqlClient;\n\n if (\n !client.onDialectOrElse({ pg: () => true, sqlite: () => true, orElse: () => false }) ||\n Predicate.hasProperty(client, \"~@effect/sql-d1/D1Client\")\n ) {\n yield* reportAuthDiagnostic(\"persistence-validation\", \"configuration\");\n\n return yield* PersistenceConfigurationError.make({\n reason: \"OAuth persistence requires PostgreSQL or SQLite with interactive transactions\",\n });\n }\n\n return { client, tables: makeNativeSqlTables(client) };\n});\n\nconst using = <M, A, E, R>(\n original: M,\n make: (tables: ReturnType<typeof makeNativeSqlTables>, mapping: M) => Effect.Effect<A, E, R>,\n) =>\n Effect.gen(function* () {\n const target = yield* acquire;\n const mapping = captureOAuthMapping(original);\n\n yield* validateSqlStorage(mapping).pipe(Effect.mapError(() => OAuthUnavailable.make({})));\n\n return yield* make(target.tables, mapping);\n }).pipe(withStorageValidation);\n\nconst coordinate = <S, A, E, R, ES, RS>(\n make: Effect.Effect<S, ES, RS>,\n body: (services: S) => Effect.Effect<A, E, R>,\n) =>\n Effect.gen(function* () {\n const { client } = yield* acquire;\n\n if (yield* hasCommitScope) return yield* OAuthUnavailable.make({});\n yield* requireStandalone(() => OAuthUnavailable.make({}), client.transactionService);\n const executor = yield* makeSqlCommitExecutor(() => OAuthUnavailable.make({}));\n\n return yield* executor.coordinate(\n Effect.flatMap(make.pipe(Effect.mapError(() => OAuthUnavailable.make({}))), body),\n );\n });\n\nexport const makeOAuthSignInServices = <N>(\n mapping: OAuthSignInMapping<Table, Table, Table, Table, Table, N>,\n): Effect.Effect<\n { readonly oauthSignInPersistence: OAuthSignInPersistence[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthSignInServices(tables, value as unknown as OAuthNativeReadMapping),\n );\n\nexport const coordinateOAuthSignIn = <N, A, E, R>(\n options: { readonly mapping: OAuthSignInMapping<Table, Table, Table, Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthSignInPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthSignInServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthSignInPersistence, services.oauthSignInPersistence),\n );\n\nexport const makeOAuthAccountsServices = <N>(\n mapping: OAuthAccountsMapping<Table, Table, Table, Table, Table, N>,\n): Effect.Effect<\n { readonly oauthAccountsPersistence: OAuthAccountsPersistence[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthAccountsServices(tables, value as unknown as OAuthNativeAccountsMapping),\n );\n\nexport const coordinateOAuthAccounts = <N, A, E, R>(\n options: { readonly mapping: OAuthAccountsMapping<Table, Table, Table, Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthAccountsPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthAccountsServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthAccountsPersistence, services.oauthAccountsPersistence),\n );\n\nexport const makeOAuthRegistrationIntentServices = <N>(\n mapping: OAuthRegistrationIntentMapping<Table, Table, N>,\n): Effect.Effect<\n { readonly oauthRegistrationIntents: OAuthRegistrationIntents[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthRegistrationIntentServices(\n tables,\n value as unknown as OAuthNativeRegistrationIntentMapping,\n ),\n );\n\nexport const coordinateOAuthRegistrationIntents = <N, A, E, R>(\n options: { readonly mapping: OAuthRegistrationIntentMapping<Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthRegistrationIntents> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthRegistrationIntentServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthRegistrationIntents, services.oauthRegistrationIntents),\n );\n\nexport const makeOAuthConnectedServices = <N>(\n mapping: OAuthConnectedMapping<Table, Table, Table, Table, Table, N, Table>,\n): Effect.Effect<\n { readonly oauthConnectedPersistence: OAuthConnectedPersistence[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthConnectedServices(tables, value as unknown as OAuthNativeConnectedMapping),\n );\n\nexport const coordinateOAuthConnected = <N, A, E, R>(\n options: { readonly mapping: OAuthConnectedMapping<Table, Table, Table, Table, Table, N, Table> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthConnectedPersistence> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthConnectedServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthConnectedPersistence, services.oauthConnectedPersistence),\n );\n\nexport const makeOAuthConnectedRevocationServices = <N>(\n mapping: OAuthConnectedRevocationMapping<Table, Table, Table, N>,\n): Effect.Effect<\n { readonly oauthConnectedRevocations: OAuthConnectedRevocations[\"Service\"] },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthRevocationServices(tables, value as unknown as OAuthNativeRevocationMapping),\n );\n\nexport const coordinateOAuthConnectedRevocations = <N, A, E, R>(\n options: { readonly mapping: OAuthConnectedRevocationMapping<Table, Table, Table, N> },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, OAuthConnectedRevocations> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthConnectedRevocationServices(options.mapping), (services) =>\n Effect.provideService(body, OAuthConnectedRevocations, services.oauthConnectedRevocations),\n );\n\nexport const makeOAuthRegistrationServices = <Registration, N>(\n mapping: OAuthRegistrationMapping<Registration, Table, Table, Table, Table, Table, N>,\n): Effect.Effect<\n { readonly registrationAuthority: OAuthRegistrationAuthority<Registration> },\n OAuthUnavailable | PersistenceConfigurationError,\n Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n using(mapping, (tables, value) =>\n makeNativeOAuthRegistrationServices(\n tables,\n value as unknown as OAuthNativeRegistrationMapping<Registration>,\n ),\n );\n\nexport const coordinateOAuthRegistration = <Id, Registration, N, A, E, R>(\n options: {\n readonly mapping: OAuthRegistrationMapping<\n NoInfer<Registration>,\n Table,\n Table,\n Table,\n Table,\n Table,\n N\n >;\n readonly target: Context.Key<Id, OAuthRegistrationAuthority<Registration>>;\n },\n body: Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | OAuthUnavailable | PersistenceConfigurationError,\n Exclude<R, Id> | Crypto.Crypto | LifecycleHooks | SqlClient.SqlClient\n> =>\n coordinate(makeOAuthRegistrationServices(options.mapping), (services) =>\n Effect.provideService(body, options.target, services.registrationAuthority),\n );\n\nexport const oauthConnectedOwnershipReferences = <N>(\n mapping: OAuthConnectedMapping<Table, Table, Table, Table, Table, N, Table>,\n) => ({\n connectedReference: (input: { readonly identityKey: string; readonly subjectId: N }) => {\n const g = mapping.grant;\n const grant = sql`exists(select 1 from ${g.table} where ${g.table.columns[g.identityKey]} = ${input.identityKey} and ${g.table.columns[g.subjectId]} = ${input.subjectId})`;\n\n if (mapping.revocation.mode === \"unsupported\") return grant;\n const j = mapping.revocation.job;\n\n return sql`(${grant}) or exists(select 1 from ${j.table} where ${j.table.columns[j.identityKey]} = ${input.identityKey} and ${j.table.columns[j.subjectId]} = ${input.subjectId})`;\n },\n});\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { StorageRole } from "./storage-tables.mjs";
3
3
  import { Context, Crypto, Effect, Layer, Schema } from "effect";
4
4
  import { SqlClient } from "effect/sql";
5
5
  import { EmailAction, EmailAddressPersistence } from "@yielded/auth/Email";
6
+ import { OAuthConnectedPersistence, OAuthConnectedPolicy, OAuthConnectedRevocations, OAuthSignInPersistence } from "@yielded/auth/OAuth";
6
7
  import { PasskeyActionChallenge, PasskeyConfig, PasskeyConfigurationError, PasskeyCredentials, PasskeyManagementPersistence, PasskeyManagementPolicy, PasskeyMethodPolicy, PasskeyPersistence } from "@yielded/auth/Passkey";
7
8
  import { PasswordAction, PasswordPersistence, PasswordUnavailable } from "@yielded/auth/Password";
8
9
  import { PhoneSignInTargets } from "@yielded/auth/PhoneOtp";
@@ -23,9 +24,16 @@ export interface PasskeyFeature {
23
24
  readonly management?: boolean;
24
25
  readonly managementPolicy?: PasskeyManagementPolicy;
25
26
  }
27
+ export interface OAuthFeature {
28
+ readonly kind: "oauth";
29
+ readonly moduleId: string;
30
+ readonly signIn: boolean;
31
+ readonly connected?: OAuthConnectedPolicy;
32
+ }
26
33
  export interface Strategy {
27
34
  readonly strategy: object;
28
- readonly persistence?: PasskeyFeature | {
35
+ /** Absent metadata leaves the strategy's persistence services application-supplied. */
36
+ readonly persistence?: PasskeyFeature | OAuthFeature | {
29
37
  readonly kind: "password" | "phone" | "email";
30
38
  readonly moduleId: string;
31
39
  readonly lifecycle?: boolean;
@@ -44,7 +52,7 @@ export interface Definition<C extends ClaimsCodec, Id extends string> {
44
52
  type KeyId<T> = T extends Context.Key<infer Id, infer _Service> ? Id : never;
45
53
  type Enabled<A extends {
46
54
  readonly strategies: Readonly<Record<string, Strategy>>;
47
- }, Kind extends "password" | "phone" | "email" | "passkey"> = Extract<A["strategies"][keyof A["strategies"]], {
55
+ }, Kind extends "password" | "phone" | "email" | "passkey" | "oauth"> = Extract<A["strategies"][keyof A["strategies"]], {
48
56
  persistence: {
49
57
  kind: Kind;
50
58
  };
@@ -66,6 +74,20 @@ type ManagedPasskey<A extends {
66
74
  type PasskeyRequirement$1<A extends {
67
75
  readonly strategies: Readonly<Record<string, Strategy>>;
68
76
  }> = Enabled<A, "passkey"> extends never ? never : PasskeyConfig;
77
+ type OAuthSignIn<A extends {
78
+ readonly strategies: Readonly<Record<string, Strategy>>;
79
+ }> = Extract<Enabled<A, "oauth">, {
80
+ persistence: {
81
+ signIn: true;
82
+ };
83
+ }>;
84
+ type OAuthConnected<A extends {
85
+ readonly strategies: Readonly<Record<string, Strategy>>;
86
+ }> = Extract<Enabled<A, "oauth">, {
87
+ persistence: {
88
+ connected: OAuthConnectedPolicy;
89
+ };
90
+ }>;
69
91
  type RegistrationKey<S> = S extends {
70
92
  readonly RegistrationAuthority: infer K;
71
93
  } ? K : never;
@@ -107,8 +129,8 @@ type ProofRoles = "proofs";
107
129
  type UsesProofs<A extends {
108
130
  readonly strategies: Readonly<Record<string, Strategy>>;
109
131
  }> = Enabled<A, "phone"> | Enabled<A, "email"> | ManagedPassword<A>;
110
- export type Ports<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = AuthenticationAuthority | KeyId<A["sessions"]["StatefulSessionPersistence"]> | KeyId<A["sessions"]["SessionRepository"]> | KeyId<A["sessions"]["PendingAuthentication"]> | KeyId<A["sessions"]["SessionStepUpPersistence"]> | KeyId<A["sessions"]["SessionCleanup"]> | (Enabled<A, "password"> extends never ? never : PasswordPersistence) | KeyId<RegistrationKey<ManagedPassword<A>>> | (Enabled<A, "passkey"> extends never ? never : PasskeyPersistence | PasskeyCredentials) | (ManagedPasskey<A> extends never ? never : PasskeyManagementPersistence) | (Enabled<A, "email"> extends never ? never : EmailAddressPersistence) | (UsesProofs<A> extends never ? never : ProofPersistence) | (Enabled<A, "phone"> extends never ? never : PhoneSignInTargets);
111
- export type Roles<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = "identifiers" | "credentials" | "sessions" | "pending" | (Enabled<A, "password"> extends never ? never : "passwords") | (Enabled<A, "email"> extends never ? never : "emailCredentials") | (Enabled<A, "passkey"> extends never ? never : "passkeyCredentials" | "passkeyFlows") | (UsesProofs<A> extends never ? never : ProofRoles);
132
+ export type Ports<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = AuthenticationAuthority | ("stateful" extends A["sessionMode"] ? KeyId<A["sessions"]["StatefulSessionPersistence"]> | KeyId<A["sessions"]["SessionRepository"]> : never) | KeyId<A["sessions"]["PendingAuthentication"]> | KeyId<A["sessions"]["SessionStepUpPersistence"]> | KeyId<A["sessions"]["SessionCleanup"]> | (Enabled<A, "password"> extends never ? never : PasswordPersistence) | KeyId<RegistrationKey<ManagedPassword<A>>> | (Enabled<A, "passkey"> extends never ? never : PasskeyPersistence | PasskeyCredentials) | (ManagedPasskey<A> extends never ? never : PasskeyManagementPersistence) | (Enabled<A, "email"> extends never ? never : EmailAddressPersistence) | (UsesProofs<A> extends never ? never : ProofPersistence) | (Enabled<A, "phone"> extends never ? never : PhoneSignInTargets) | (OAuthSignIn<A> extends never ? never : OAuthSignInPersistence) | (OAuthConnected<A> extends never ? never : OAuthConnectedPersistence | OAuthConnectedRevocations);
133
+ export type Roles<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> = "identifiers" | "credentials" | ("stateful" extends A["sessionMode"] ? "sessions" : never) | "pending" | (Enabled<A, "password"> extends never ? never : "passwords") | (Enabled<A, "email"> extends never ? never : "emailCredentials") | (Enabled<A, "passkey"> extends never ? never : "passkeyCredentials" | "passkeyFlows") | (UsesProofs<A> extends never ? never : ProofRoles) | (Enabled<A, "oauth"> extends never ? never : "oauthIdentities" | "oauthCredentials") | (OAuthSignIn<A> extends never ? never : "oauthSignInFlows") | (OAuthConnected<A> extends never ? never : "oauthConnectedFlows" | "oauthConnectedGrants" | "oauthConnectedRevocations");
112
134
  export interface SubjectOptions<T extends object, NativeId> {
113
135
  readonly table: T;
114
136
  readonly id: string;
@@ -163,9 +185,13 @@ export interface BoundPersistence<T extends object, R, C extends ClaimsCodec, Id
163
185
  * or perform external side effects while preparing a subject.
164
186
  */
165
187
  readonly Provisioning: Context.Service<ProvisioningRequirement<A>, Provisioning<A>>;
166
- /** Capture dependencies at acquisition; validate SQL metadata and configure storage
188
+ /** Stateful sessions and OAuth-only stateless sessions are supported. Other session
189
+ * configurations fail acquisition with PersistenceConfigurationError.
190
+ * Capture dependencies at acquisition; validate SQL metadata and configure storage
167
191
  * once on the first service operation. Initialization failures become that port's
168
192
  * unavailable error. Failure or interruption remains cached until layer reacquisition.
193
+ * Managed OAuth metadata/token-use authorizations bind policyRevision to the subject's
194
+ * securityRevision; changes to application authorization policy must advance it.
169
195
  */
170
196
  readonly layer: Layer.Layer<Ports<C, Id, A>, PersistenceConfigurationError, Crypto.Crypto | ConfigId<A["namespace"]> | ProvisioningRequirement<A> | PasskeyRequirement$1<A> | SqlClient.SqlClient | R>;
171
197
  readonly managed: <N, Instant = number>(options: {
@@ -1 +1 @@
1
- {"version":3,"file":"configuration.mjs","names":[],"sources":["../../src/internal/configuration.ts"],"sourcesContent":["import type { EmailAction, EmailAddressPersistence } from \"@yielded/auth/Email\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport type {\n PasskeyActionChallenge,\n PasskeyConfig,\n PasskeyCredentials,\n PasskeyManagementPersistence,\n PasskeyManagementPolicy,\n PasskeyMethodPolicy,\n PasskeyPersistence,\n PasskeyConfigurationError,\n} from \"@yielded/auth/Passkey\";\nimport type {\n PasswordAction,\n PasswordPersistence,\n PasswordUnavailable,\n} from \"@yielded/auth/Password\";\nimport type { PhoneSignInTargets } from \"@yielded/auth/PhoneOtp\";\nimport type { ProofPersistence } from \"@yielded/auth/Proofs\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport type {\n AuthenticationAuthority,\n AuthenticationRequirement,\n make as makeSessions,\n} from \"@yielded/auth/Sessions\";\nimport { type Context, type Crypto, type Effect, type Layer, Schema } from \"effect\";\nimport type { SqlClient } from \"effect/sql\";\n\nimport type { PersistenceMappingError } from \"./mapping-error\";\nimport type { StorageRole } from \"./storage-tables\";\n\nexport class PersistenceConfigurationError extends Schema.TaggedError<PersistenceConfigurationError>()(\n \"PersistenceConfigurationError\",\n { reason: Schema.String },\n) {}\n\nexport type ClaimsCodec = Schema.Codec<unknown, unknown, never, never>;\n\nexport interface PasskeyFeature {\n readonly kind: \"passkey\";\n readonly moduleId: string;\n readonly policy: Effect.Effect<PasskeyMethodPolicy, PasskeyConfigurationError, PasskeyConfig>;\n readonly management?: boolean;\n readonly managementPolicy?: PasskeyManagementPolicy;\n}\n\nexport interface Strategy {\n readonly strategy: object;\n readonly persistence?:\n | PasskeyFeature\n | {\n readonly kind: \"password\" | \"phone\" | \"email\";\n readonly moduleId: string;\n readonly lifecycle?: boolean;\n readonly management?: boolean;\n readonly addresses?: boolean;\n };\n readonly RegistrationAuthority?: Context.Key<unknown, unknown>;\n}\n\nexport interface Definition<C extends ClaimsCodec, Id extends string> {\n readonly namespace: string;\n readonly claims: C;\n readonly sessionMode?: string | undefined;\n readonly sessions: ReturnType<typeof makeSessions<C, Id>>;\n readonly strategies: Readonly<Record<string, Strategy>>;\n}\n\ntype KeyId<T> = T extends Context.Key<infer Id, infer _Service> ? Id : never;\ntype Enabled<\n A extends { readonly strategies: Readonly<Record<string, Strategy>> },\n Kind extends \"password\" | \"phone\" | \"email\" | \"passkey\",\n> = Extract<A[\"strategies\"][keyof A[\"strategies\"]], { persistence: { kind: Kind } }>;\n\ntype ManagedPassword<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> =\n Extract<Enabled<A, \"password\">, { persistence: { management: true } }>;\n\ntype ManagedPasskey<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> =\n Extract<Enabled<A, \"passkey\">, { persistence: { management: true } }>;\n\nexport type PasskeyRequirement<\n A extends { readonly strategies: Readonly<Record<string, Strategy>> },\n> = Enabled<A, \"passkey\"> extends never ? never : PasskeyConfig;\n\ntype RegistrationKey<S> = S extends { readonly RegistrationAuthority: infer K } ? K : never;\ntype Registration<S> =\n RegistrationKey<S> extends Context.Key<infer _Id, infer Service>\n ? Service extends { readonly register: (input: infer Input, ...args: never[]) => unknown }\n ? Input extends { readonly registration: infer Value }\n ? Value\n : never\n : never\n : never;\n\nexport interface ProvisioningId<Id extends string> {\n readonly authNamespace: Id;\n readonly service: \"PersistenceProvisioning\";\n}\n\nexport interface SubjectProvisioningInput<Registration> {\n readonly requestId: string;\n readonly identifier: LoginIdentifier;\n readonly registration: Registration;\n}\n\n/** Return application subject values for insertion by the auth commit owner.\n * Include the allocated native ID, active status, and initial security revision.\n * Preparing values may allocate IDs, but must not write to the database or perform\n * external side effects. Interactive drivers also accept an existing insert callback.\n */\nexport type SubjectProvisioning<Registration> =\n | {\n readonly values: (\n input: SubjectProvisioningInput<Registration>,\n ) => Effect.Effect<Readonly<Record<string, unknown>>, PasswordUnavailable>;\n }\n | ((\n input: SubjectProvisioningInput<Registration>,\n ) => Effect.Effect<SubjectId, PasswordUnavailable>);\n\nexport type Provisioning<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> = {\n readonly [\n K in keyof A[\"strategies\"] as A[\"strategies\"][K] extends {\n persistence: { kind: \"password\"; management: true };\n }\n ? K\n : never\n ]: SubjectProvisioning<Registration<A[\"strategies\"][K]>>;\n};\n\nexport type ProvisioningRequirement<\n A extends { readonly namespace: string; readonly strategies: Readonly<Record<string, Strategy>> },\n> = ManagedPassword<A> extends never ? never : ProvisioningId<A[\"namespace\"]>;\n\ntype ProofRoles = \"proofs\";\n\ntype UsesProofs<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> =\n | Enabled<A, \"phone\">\n | Enabled<A, \"email\">\n | ManagedPassword<A>;\n\nexport type Ports<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> =\n | AuthenticationAuthority\n | KeyId<A[\"sessions\"][\"StatefulSessionPersistence\"]>\n | KeyId<A[\"sessions\"][\"SessionRepository\"]>\n | KeyId<A[\"sessions\"][\"PendingAuthentication\"]>\n | KeyId<A[\"sessions\"][\"SessionStepUpPersistence\"]>\n | KeyId<A[\"sessions\"][\"SessionCleanup\"]>\n | (Enabled<A, \"password\"> extends never ? never : PasswordPersistence)\n | KeyId<RegistrationKey<ManagedPassword<A>>>\n | (Enabled<A, \"passkey\"> extends never ? never : PasskeyPersistence | PasskeyCredentials)\n | (ManagedPasskey<A> extends never ? never : PasskeyManagementPersistence)\n | (Enabled<A, \"email\"> extends never ? never : EmailAddressPersistence)\n | (UsesProofs<A> extends never ? never : ProofPersistence)\n | (Enabled<A, \"phone\"> extends never ? never : PhoneSignInTargets);\n\nexport type Roles<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> =\n | \"identifiers\"\n | \"credentials\"\n | \"sessions\"\n | \"pending\"\n | (Enabled<A, \"password\"> extends never ? never : \"passwords\")\n | (Enabled<A, \"email\"> extends never ? never : \"emailCredentials\")\n | (Enabled<A, \"passkey\"> extends never ? never : \"passkeyCredentials\" | \"passkeyFlows\")\n | (UsesProofs<A> extends never ? never : ProofRoles);\n\nexport interface SubjectOptions<T extends object, NativeId> {\n readonly table: T;\n readonly id: string;\n readonly status: string;\n readonly activeValue: unknown;\n readonly securityRevision: string;\n readonly idCodec: Schema.Codec<SubjectId, NativeId>;\n readonly requirements: (\n row: Readonly<Record<string, unknown>>,\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n /** Defaults to sign-in requirements. Recovery can have a distinct application policy. */\n readonly actionRequirements?: (\n row: Readonly<Record<string, unknown>>,\n action: PasswordAction | EmailAction | PasskeyActionChallenge[\"action\"],\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n}\n\n/** Codecs at the application-owned subject and timestamp boundary. */\nexport interface SubjectMapping {\n readonly table: object;\n readonly id: string;\n readonly status: string;\n readonly securityRevision: string;\n readonly activeValue: unknown;\n readonly requirements: SubjectOptions<object, unknown>[\"requirements\"];\n readonly actionRequirements: NonNullable<SubjectOptions<object, unknown>[\"actionRequirements\"]>;\n readonly toSubject: (value: unknown) => Effect.Effect<SubjectId, PersistenceMappingError>;\n readonly toNative: (value: SubjectId) => Effect.Effect<unknown, PersistenceMappingError>;\n readonly toSubjectSync: (value: unknown) => SubjectId;\n readonly toNativeSync: (value: SubjectId) => unknown;\n}\n\nexport interface MappingInput {\n readonly tables: Partial<Record<StorageRole, object>>;\n readonly subjects: SubjectMapping;\n readonly encodeInstant: (millis: number) => unknown;\n readonly decodeInstant: (value: unknown) => Effect.Effect<number, PersistenceMappingError>;\n readonly decodeInstantSync: (value: unknown) => number;\n}\n\nexport interface StorageLayout<\n T extends object,\n Role extends StorageRole = StorageRole,\n> extends MappingInput {\n readonly namespace: string;\n readonly schema: Readonly<Record<Role, T>>;\n}\n\nexport interface ConfigId<Id extends string> {\n readonly authNamespace: Id;\n readonly service: \"PersistenceConfig\";\n}\n\nexport interface TimestampOptions<Instant> {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n}\n\nexport interface BoundPersistence<\n T extends object,\n R,\n C extends ClaimsCodec,\n Id extends string,\n A extends Definition<C, Id>,\n> {\n readonly Config: Context.Service<ConfigId<A[\"namespace\"]>, StorageLayout<T, Roles<C, Id, A>>> & {\n readonly layer: (\n value: StorageLayout<T, Roles<C, Id, A>>,\n ) => Layer.Layer<ConfigId<A[\"namespace\"]>>;\n };\n /** Supply subject values through `{ values }` on every driver, including D1.\n * Interactive drivers also accept callbacks that insert through the owning\n * SqlClient and return the new subject ID. Never open an independent transaction\n * or perform external side effects while preparing a subject.\n */\n readonly Provisioning: Context.Service<ProvisioningRequirement<A>, Provisioning<A>>;\n /** Capture dependencies at acquisition; validate SQL metadata and configure storage\n * once on the first service operation. Initialization failures become that port's\n * unavailable error. Failure or interruption remains cached until layer reacquisition.\n */\n readonly layer: Layer.Layer<\n Ports<C, Id, A>,\n PersistenceConfigurationError,\n | Crypto.Crypto\n | ConfigId<A[\"namespace\"]>\n | ProvisioningRequirement<A>\n | PasskeyRequirement<A>\n | SqlClient.SqlClient\n | R\n >;\n readonly managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n /** Stable SQL identifier prefix; reuse the deployed prefix for existing tables. */\n readonly prefix: string;\n readonly timestamps?: TimestampOptions<Instant>;\n }) => StorageLayout<T, Roles<C, Id, A>>;\n readonly map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Readonly<Record<Roles<C, Id, A>, T>>;\n readonly timestamps?: TimestampOptions<Instant>;\n }) => StorageLayout<T, Roles<C, Id, A>>;\n}\n\n/** Shared configuration shape. The backend chooses table types and service requirements. */\nexport interface PersistenceApi<T extends object, R = never> {\n readonly make: <\n C extends ClaimsCodec,\n const Id extends string,\n const A extends Definition<C, Id>,\n >(\n auth: A & Definition<C, Id>,\n ) => BoundPersistence<T, R, C, Id, A>;\n}\n"],"mappings":";;AA+BA,IAAa,gCAAb,cAAmD,OAAO,YAA2C,CAAC,CACpG,iCACA,EAAE,QAAQ,OAAO,OAAO,CAC1B,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"configuration.mjs","names":[],"sources":["../../src/internal/configuration.ts"],"sourcesContent":["import type { EmailAction, EmailAddressPersistence } from \"@yielded/auth/Email\";\nimport type { LoginIdentifier } from \"@yielded/auth/Identity\";\nimport type {\n OAuthConnectedPersistence,\n OAuthConnectedPolicy,\n OAuthConnectedRevocations,\n OAuthSignInPersistence,\n} from \"@yielded/auth/OAuth\";\nimport type {\n PasskeyActionChallenge,\n PasskeyConfig,\n PasskeyCredentials,\n PasskeyManagementPersistence,\n PasskeyManagementPolicy,\n PasskeyMethodPolicy,\n PasskeyPersistence,\n PasskeyConfigurationError,\n} from \"@yielded/auth/Passkey\";\nimport type {\n PasswordAction,\n PasswordPersistence,\n PasswordUnavailable,\n} from \"@yielded/auth/Password\";\nimport type { PhoneSignInTargets } from \"@yielded/auth/PhoneOtp\";\nimport type { ProofPersistence } from \"@yielded/auth/Proofs\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\nimport type {\n AuthenticationAuthority,\n AuthenticationRequirement,\n make as makeSessions,\n} from \"@yielded/auth/Sessions\";\nimport { type Context, type Crypto, type Effect, type Layer, Schema } from \"effect\";\nimport type { SqlClient } from \"effect/sql\";\n\nimport type { PersistenceMappingError } from \"./mapping-error\";\nimport type { StorageRole } from \"./storage-tables\";\n\nexport class PersistenceConfigurationError extends Schema.TaggedError<PersistenceConfigurationError>()(\n \"PersistenceConfigurationError\",\n { reason: Schema.String },\n) {}\n\nexport type ClaimsCodec = Schema.Codec<unknown, unknown, never, never>;\n\nexport interface PasskeyFeature {\n readonly kind: \"passkey\";\n readonly moduleId: string;\n readonly policy: Effect.Effect<PasskeyMethodPolicy, PasskeyConfigurationError, PasskeyConfig>;\n readonly management?: boolean;\n readonly managementPolicy?: PasskeyManagementPolicy;\n}\n\nexport interface OAuthFeature {\n readonly kind: \"oauth\";\n readonly moduleId: string;\n readonly signIn: boolean;\n readonly connected?: OAuthConnectedPolicy;\n}\n\nexport interface Strategy {\n readonly strategy: object;\n /** Absent metadata leaves the strategy's persistence services application-supplied. */\n readonly persistence?:\n | PasskeyFeature\n | OAuthFeature\n | {\n readonly kind: \"password\" | \"phone\" | \"email\";\n readonly moduleId: string;\n readonly lifecycle?: boolean;\n readonly management?: boolean;\n readonly addresses?: boolean;\n };\n readonly RegistrationAuthority?: Context.Key<unknown, unknown>;\n}\n\nexport interface Definition<C extends ClaimsCodec, Id extends string> {\n readonly namespace: string;\n readonly claims: C;\n readonly sessionMode?: string | undefined;\n readonly sessions: ReturnType<typeof makeSessions<C, Id>>;\n readonly strategies: Readonly<Record<string, Strategy>>;\n}\n\ntype KeyId<T> = T extends Context.Key<infer Id, infer _Service> ? Id : never;\ntype Enabled<\n A extends { readonly strategies: Readonly<Record<string, Strategy>> },\n Kind extends \"password\" | \"phone\" | \"email\" | \"passkey\" | \"oauth\",\n> = Extract<A[\"strategies\"][keyof A[\"strategies\"]], { persistence: { kind: Kind } }>;\n\ntype ManagedPassword<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> =\n Extract<Enabled<A, \"password\">, { persistence: { management: true } }>;\n\ntype ManagedPasskey<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> =\n Extract<Enabled<A, \"passkey\">, { persistence: { management: true } }>;\n\nexport type PasskeyRequirement<\n A extends { readonly strategies: Readonly<Record<string, Strategy>> },\n> = Enabled<A, \"passkey\"> extends never ? never : PasskeyConfig;\n\ntype OAuthSignIn<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> = Extract<\n Enabled<A, \"oauth\">,\n { persistence: { signIn: true } }\n>;\n\ntype OAuthConnected<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> =\n Extract<Enabled<A, \"oauth\">, { persistence: { connected: OAuthConnectedPolicy } }>;\n\ntype RegistrationKey<S> = S extends { readonly RegistrationAuthority: infer K } ? K : never;\ntype Registration<S> =\n RegistrationKey<S> extends Context.Key<infer _Id, infer Service>\n ? Service extends { readonly register: (input: infer Input, ...args: never[]) => unknown }\n ? Input extends { readonly registration: infer Value }\n ? Value\n : never\n : never\n : never;\n\nexport interface ProvisioningId<Id extends string> {\n readonly authNamespace: Id;\n readonly service: \"PersistenceProvisioning\";\n}\n\nexport interface SubjectProvisioningInput<Registration> {\n readonly requestId: string;\n readonly identifier: LoginIdentifier;\n readonly registration: Registration;\n}\n\n/** Return application subject values for insertion by the auth commit owner.\n * Include the allocated native ID, active status, and initial security revision.\n * Preparing values may allocate IDs, but must not write to the database or perform\n * external side effects. Interactive drivers also accept an existing insert callback.\n */\nexport type SubjectProvisioning<Registration> =\n | {\n readonly values: (\n input: SubjectProvisioningInput<Registration>,\n ) => Effect.Effect<Readonly<Record<string, unknown>>, PasswordUnavailable>;\n }\n | ((\n input: SubjectProvisioningInput<Registration>,\n ) => Effect.Effect<SubjectId, PasswordUnavailable>);\n\nexport type Provisioning<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> = {\n readonly [\n K in keyof A[\"strategies\"] as A[\"strategies\"][K] extends {\n persistence: { kind: \"password\"; management: true };\n }\n ? K\n : never\n ]: SubjectProvisioning<Registration<A[\"strategies\"][K]>>;\n};\n\nexport type ProvisioningRequirement<\n A extends { readonly namespace: string; readonly strategies: Readonly<Record<string, Strategy>> },\n> = ManagedPassword<A> extends never ? never : ProvisioningId<A[\"namespace\"]>;\n\ntype ProofRoles = \"proofs\";\n\ntype UsesProofs<A extends { readonly strategies: Readonly<Record<string, Strategy>> }> =\n | Enabled<A, \"phone\">\n | Enabled<A, \"email\">\n | ManagedPassword<A>;\n\nexport type Ports<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> =\n | AuthenticationAuthority\n | (\"stateful\" extends A[\"sessionMode\"]\n ?\n | KeyId<A[\"sessions\"][\"StatefulSessionPersistence\"]>\n | KeyId<A[\"sessions\"][\"SessionRepository\"]>\n : never)\n | KeyId<A[\"sessions\"][\"PendingAuthentication\"]>\n | KeyId<A[\"sessions\"][\"SessionStepUpPersistence\"]>\n | KeyId<A[\"sessions\"][\"SessionCleanup\"]>\n | (Enabled<A, \"password\"> extends never ? never : PasswordPersistence)\n | KeyId<RegistrationKey<ManagedPassword<A>>>\n | (Enabled<A, \"passkey\"> extends never ? never : PasskeyPersistence | PasskeyCredentials)\n | (ManagedPasskey<A> extends never ? never : PasskeyManagementPersistence)\n | (Enabled<A, \"email\"> extends never ? never : EmailAddressPersistence)\n | (UsesProofs<A> extends never ? never : ProofPersistence)\n | (Enabled<A, \"phone\"> extends never ? never : PhoneSignInTargets)\n | (OAuthSignIn<A> extends never ? never : OAuthSignInPersistence)\n | (OAuthConnected<A> extends never\n ? never\n : OAuthConnectedPersistence | OAuthConnectedRevocations);\n\nexport type Roles<C extends ClaimsCodec, Id extends string, A extends Definition<C, Id>> =\n | \"identifiers\"\n | \"credentials\"\n | (\"stateful\" extends A[\"sessionMode\"] ? \"sessions\" : never)\n | \"pending\"\n | (Enabled<A, \"password\"> extends never ? never : \"passwords\")\n | (Enabled<A, \"email\"> extends never ? never : \"emailCredentials\")\n | (Enabled<A, \"passkey\"> extends never ? never : \"passkeyCredentials\" | \"passkeyFlows\")\n | (UsesProofs<A> extends never ? never : ProofRoles)\n | (Enabled<A, \"oauth\"> extends never ? never : \"oauthIdentities\" | \"oauthCredentials\")\n | (OAuthSignIn<A> extends never ? never : \"oauthSignInFlows\")\n | (OAuthConnected<A> extends never\n ? never\n : \"oauthConnectedFlows\" | \"oauthConnectedGrants\" | \"oauthConnectedRevocations\");\n\nexport interface SubjectOptions<T extends object, NativeId> {\n readonly table: T;\n readonly id: string;\n readonly status: string;\n readonly activeValue: unknown;\n readonly securityRevision: string;\n readonly idCodec: Schema.Codec<SubjectId, NativeId>;\n readonly requirements: (\n row: Readonly<Record<string, unknown>>,\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n /** Defaults to sign-in requirements. Recovery can have a distinct application policy. */\n readonly actionRequirements?: (\n row: Readonly<Record<string, unknown>>,\n action: PasswordAction | EmailAction | PasskeyActionChallenge[\"action\"],\n ) => Effect.Effect<AuthenticationRequirement, PersistenceMappingError>;\n}\n\n/** Codecs at the application-owned subject and timestamp boundary. */\nexport interface SubjectMapping {\n readonly table: object;\n readonly id: string;\n readonly status: string;\n readonly securityRevision: string;\n readonly activeValue: unknown;\n readonly requirements: SubjectOptions<object, unknown>[\"requirements\"];\n readonly actionRequirements: NonNullable<SubjectOptions<object, unknown>[\"actionRequirements\"]>;\n readonly toSubject: (value: unknown) => Effect.Effect<SubjectId, PersistenceMappingError>;\n readonly toNative: (value: SubjectId) => Effect.Effect<unknown, PersistenceMappingError>;\n readonly toSubjectSync: (value: unknown) => SubjectId;\n readonly toNativeSync: (value: SubjectId) => unknown;\n}\n\nexport interface MappingInput {\n readonly tables: Partial<Record<StorageRole, object>>;\n readonly subjects: SubjectMapping;\n readonly encodeInstant: (millis: number) => unknown;\n readonly decodeInstant: (value: unknown) => Effect.Effect<number, PersistenceMappingError>;\n readonly decodeInstantSync: (value: unknown) => number;\n}\n\nexport interface StorageLayout<\n T extends object,\n Role extends StorageRole = StorageRole,\n> extends MappingInput {\n readonly namespace: string;\n readonly schema: Readonly<Record<Role, T>>;\n}\n\nexport interface ConfigId<Id extends string> {\n readonly authNamespace: Id;\n readonly service: \"PersistenceConfig\";\n}\n\nexport interface TimestampOptions<Instant> {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n}\n\nexport interface BoundPersistence<\n T extends object,\n R,\n C extends ClaimsCodec,\n Id extends string,\n A extends Definition<C, Id>,\n> {\n readonly Config: Context.Service<ConfigId<A[\"namespace\"]>, StorageLayout<T, Roles<C, Id, A>>> & {\n readonly layer: (\n value: StorageLayout<T, Roles<C, Id, A>>,\n ) => Layer.Layer<ConfigId<A[\"namespace\"]>>;\n };\n /** Supply subject values through `{ values }` on every driver, including D1.\n * Interactive drivers also accept callbacks that insert through the owning\n * SqlClient and return the new subject ID. Never open an independent transaction\n * or perform external side effects while preparing a subject.\n */\n readonly Provisioning: Context.Service<ProvisioningRequirement<A>, Provisioning<A>>;\n /** Stateful sessions and OAuth-only stateless sessions are supported. Other session\n * configurations fail acquisition with PersistenceConfigurationError.\n * Capture dependencies at acquisition; validate SQL metadata and configure storage\n * once on the first service operation. Initialization failures become that port's\n * unavailable error. Failure or interruption remains cached until layer reacquisition.\n * Managed OAuth metadata/token-use authorizations bind policyRevision to the subject's\n * securityRevision; changes to application authorization policy must advance it.\n */\n readonly layer: Layer.Layer<\n Ports<C, Id, A>,\n PersistenceConfigurationError,\n | Crypto.Crypto\n | ConfigId<A[\"namespace\"]>\n | ProvisioningRequirement<A>\n | PasskeyRequirement<A>\n | SqlClient.SqlClient\n | R\n >;\n readonly managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n /** Stable SQL identifier prefix; reuse the deployed prefix for existing tables. */\n readonly prefix: string;\n readonly timestamps?: TimestampOptions<Instant>;\n }) => StorageLayout<T, Roles<C, Id, A>>;\n readonly map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Readonly<Record<Roles<C, Id, A>, T>>;\n readonly timestamps?: TimestampOptions<Instant>;\n }) => StorageLayout<T, Roles<C, Id, A>>;\n}\n\n/** Shared configuration shape. The backend chooses table types and service requirements. */\nexport interface PersistenceApi<T extends object, R = never> {\n readonly make: <\n C extends ClaimsCodec,\n const Id extends string,\n const A extends Definition<C, Id>,\n >(\n auth: A & Definition<C, Id>,\n ) => BoundPersistence<T, R, C, Id, A>;\n}\n"],"mappings":";;AAqCA,IAAa,gCAAb,cAAmD,OAAO,YAA2C,CAAC,CACpG,iCACA,EAAE,QAAQ,OAAO,OAAO,CAC1B,CAAC,CAAC,CAAC"}
@@ -97,7 +97,15 @@ const makeNativeEmailAddressServices = Effect.fnUntraced(function* (tables, mapp
97
97
  requirement: Effect.succeed(requirement)
98
98
  }, current.now))) return yield* prepare("rejected", project);
99
99
  const requirements = [input.authorization.requirement, requirement];
100
- const deadline = [...new Set(input.authorization.evidence.proofs.flatMap((proof) => requirements.map((r) => DateTime.toEpochMillis(proof.verifiedAt) + r.maximumAgeMillis)))].filter((time) => time > current.now).sort((a, b) => a - b).find((time) => requirements.some((r) => !passwordEvidenceSatisfiedAt(input.authorization.evidence, r, time)));
100
+ const boundaries = [...new Set(input.authorization.evidence.proofs.flatMap((proof) => requirements.map((r) => DateTime.toEpochMillis(proof.verifiedAt) + r.maximumAgeMillis)))].filter((time) => time > current.now).sort((a, b) => a - b);
101
+ let deadline;
102
+ for (const time of boundaries) {
103
+ for (const requirement of requirements) if (!(yield* passwordEvidenceSatisfiedAt(input.authorization.evidence, requirement, time))) {
104
+ deadline = time;
105
+ break;
106
+ }
107
+ if (deadline !== void 0) break;
108
+ }
101
109
  ensureEmail(deadline !== void 0);
102
110
  const freshness = sql`${now} >= ${current.now} and ${now} < ${deadline}`;
103
111
  const factorCondition = (revision) => sql.and([sql`(select count(*) from ${authority.name} where ${id(authority, a.subjectId, native)} and ${activeAuthority}) = ${revision.credentials.length}`, ...revision.credentials.map((f) => sql`exists(select 1 from ${authority.name} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, f.credentialId)} and ${exact(authority, a.revision, f.revision)} and ${activeAuthority})`)]);
@@ -224,7 +232,7 @@ const makeNativeEmailAddressServices = Effect.fnUntraced(function* (tables, mapp
224
232
  });
225
233
  ensureEmail(final !== void 0 && sameEmailRevision(final.revision, revision) && final.now >= current.now && final.now < deadline && final.targetSnapshot !== void 0 && final.targetSnapshot.credentialId === targetCredentialId && final.targetSnapshot.credentialRevision === targetCredentialRevision && final.targetSnapshot.identifierRevision === targetIdentifierRevision && (yield* mapping.decodeInstant(final.targetIdentifier[i.verifiedAt])) === current.now);
226
234
  const policy = yield* s.decodeActionRequirement(final.subject, action);
227
- ensureEmail(passwordEvidenceSatisfiedAt(input.authorization.evidence, policy, final.now));
235
+ ensureEmail(yield* passwordEvidenceSatisfiedAt(input.authorization.evidence, policy, final.now));
228
236
  if (source !== void 0) ensureEmail(final.sourceIdentifier !== void 0 && final.sourceCredential !== void 0 && final.sourceAuthority !== void 0 && (yield* mapping.subjectId.toSubject(final.sourceAuthority[a.subjectId])) === revision.subjectId && final.sourceAuthority[a.credentialId] === source.credentialId && final.sourceAuthority[a.revision] === sourceCredentialRevision && !a.isActiveStatus(final.sourceAuthority[a.status]) && (yield* mapping.subjectId.toSubject(final.sourceIdentifier[i.subjectId])) === revision.subjectId && final.sourceIdentifier[i.bindingRevision] === sourceIdentifierRevision && !i.isCurrent(final.sourceIdentifier) && final.sourceCredential[c.credentialRevision] === sourceCredentialRevision && !c.isActiveStatus(final.sourceCredential[c.status]));
229
237
  }).pipe(Effect.mapError((cause) => PersistenceMappingError.make({
230
238
  operation: "decode",
@@ -1 +1 @@
1
- {"version":3,"file":"email-native.mjs","names":["unavailable"],"sources":["../../src/internal/email-native.ts"],"sourcesContent":["import * as E from \"@yielded/auth/Email\";\nimport { CurrentCommitJournal, type LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { ProofRedemptionInput } from \"@yielded/auth/Proofs\";\nimport type { AuthenticationRevision } from \"@yielded/auth/Sessions\";\nimport { SecurityRevision } from \"@yielded/auth/Sessions\";\nimport { Crypto, DateTime, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport { sqlBatchAssertion } from \"./d1-planning\";\nimport {\n makeNativeEmailReader,\n emailUnavailable as unavailable,\n ensureEmail as ensure,\n} from \"./email-native-state\";\nimport {\n allocateEmailValue,\n allocateEmailSecurityRevision,\n snapshotEmailMutation,\n validateEmailMutation,\n sameEmailRevision,\n} from \"./email-policy\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyEmailAddressMapping, AnyEmailSignInMapping } from \"./models/email-model\";\nimport type { AnyProofPersistenceMapping } from \"./models/proof-model\";\nimport type { NativeSqlTables, SqlTable } from \"./native-sql-table\";\nimport { passwordEvidenceSatisfiedAt } from \"./password-policy\";\nimport { makeNativeProofStore } from \"./proof-native\";\nimport { exactSqlText, executeSqlChange } from \"./sql-change\";\nimport {\n appendSqlBatchStatement,\n makeSqlCommitExecutor,\n registerSqlBatchPostcondition,\n registerSqlCommitReceipt,\n registerSqlPostcondition,\n SqlBatchCommit,\n} from \"./sql-commit\";\n\nexport const makeNativeEmailSignInServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyEmailSignInMapping,\n): Effect.fn.Return<\n { readonly emailSignInTargets: E.EmailSignInTargets[\"Service\"] },\n never,\n SqlClient | LifecycleHooks\n> {\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const reader = yield* makeNativeEmailReader(tables, mapping);\n\n return {\n emailSignInTargets: E.EmailSignInTargets.of({\n lookup: (input) => executor.read(reader.lookup(input)),\n }),\n };\n});\n\nexport const makeNativeEmailAddressServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyEmailAddressMapping,\n proofs?: AnyProofPersistenceMapping,\n): Effect.fn.Return<\n { readonly emailAddressPersistence: E.EmailAddressPersistence[\"Service\"] },\n never,\n SqlClient | LifecycleHooks | Crypto.Crypto | SqlBatchCommit\n> {\n const batch = yield* SqlBatchCommit;\n\n const sql = (yield* SqlClient).withoutTransforms(),\n executor = yield* makeSqlCommitExecutor(unavailable),\n crypto = yield* Crypto.Crypto;\n\n const now = tables.expression(mapping.clock.engineNowMillis);\n const reader = yield* makeNativeEmailReader(tables, mapping, now);\n\n const s = mapping.subject,\n i = mapping.identifier,\n c = mapping.credential,\n a = mapping.authorityCredential;\n\n const subject = tables(s.table),\n identifier = tables(i.table),\n credential = tables(c.table),\n authority = tables(a.table);\n\n const exact = (t: SqlTable, key: string, value: unknown) =>\n exactSqlText(sql, t.column(key), t.value(key, value));\n\n const id = (t: SqlTable, key: string, value: unknown) =>\n sql`${t.column(key)} = ${t.value(key, value)}`;\n\n const identifierKey = (value: { readonly namespace: string; readonly value: string }) =>\n sql.and([\n exact(identifier, i.namespace, value.namespace),\n exact(identifier, i.value, value.value),\n ]);\n\n const activeSubject = id(subject, s.status, s.activeStatusValue),\n activeCredential = id(credential, c.status, c.activeStatusValue),\n activeAuthority = id(authority, a.status, a.activeStatusValue);\n\n const lock = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });\n const mode = \"interactive\";\n\n const run = <A, X, R>(work: Effect.Effect<A, X, R>) =>\n batch === undefined\n ? executor.run(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n : executor\n .batch(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n .pipe(Effect.provideService(SqlBatchCommit, batch));\n\n const stage = Effect.fnUntraced(function* (statement: Fragment) {\n if (batch === undefined) ensure((yield* executeSqlChange(sql, statement)) === 1);\n else {\n yield* appendSqlBatchStatement(sql`${statement}`);\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));\n }\n });\n\n const prepare = <A>(\n decision: E.EmailAddressDecision,\n project: E.PrepareEmailCommit<E.EmailAddressDecision, A>,\n ) =>\n Effect.gen(function* () {\n const receipt = project(decision, yield* CurrentCommitJournal);\n\n yield* registerSqlCommitReceipt(receipt);\n\n return receipt;\n });\n\n const target = Effect.fnUntraced(function* (\n input: Parameters<E.EmailAddressPersistence[\"Service\"][\"target\"]>[0],\n sourceIdentifier?: { readonly namespace: string; readonly value: string },\n ) {\n const state = yield* reader.read({\n moduleId: input.moduleId,\n subjectId: input.subjectId,\n identifier: input.target,\n ...(input.sourceCredentialId === undefined\n ? {}\n : { sourceCredentialId: input.sourceCredentialId }),\n ...(sourceIdentifier === undefined ? {} : { sourceIdentifier }),\n single: mapping.addressCardinality === \"single\",\n });\n\n if (state === undefined) return undefined;\n\n const owned =\n state.targetIdentifier !== undefined &&\n (yield* mapping.subjectId.toSubject(state.targetIdentifier[i.subjectId])) === input.subjectId;\n\n const mutable =\n owned &&\n mapping.identifier.isMutableTarget(state.targetIdentifier!) &&\n (state.targetCredential === undefined ||\n (!c.isActiveStatus(state.targetCredential[c.status]) &&\n (yield* mapping.subjectId.toSubject(state.targetCredential[c.subjectId])) ===\n input.subjectId));\n\n const source = state.sourceSnapshot;\n\n const eligible =\n (state.targetIdentifier === undefined ? state.targetCredential === undefined : mutable) &&\n (input.sourceCredentialId === undefined || source !== undefined) &&\n (source === undefined ||\n source.identifier.namespace !== input.target.namespace ||\n source.identifier.value !== input.target.value) &&\n !state.cardinalityConflict;\n\n const captured: E.EmailAddressTarget = {\n revision: state.revision,\n eligible,\n ...(source === undefined ? {} : { source }),\n ...(mutable\n ? {\n targetIdentifierRevision: yield* Schema.decodeUnknownEffect(SecurityRevision)(\n state.targetIdentifier![i.bindingRevision],\n ),\n }\n : {}),\n };\n\n return { ...state, target: captured };\n });\n\n const mutate = <A>(\n original: E.EmailAddressMutation,\n action: E.EmailAction,\n project: E.PrepareEmailCommit<E.EmailAddressDecision, A>,\n ) =>\n run(\n Effect.gen(function* () {\n const input = yield* snapshotEmailMutation(original);\n\n const redemption = yield* Schema.decodeEffect(Schema.toCodecIso(ProofRedemptionInput))(\n yield* Schema.encodeEffect(Schema.toCodecIso(ProofRedemptionInput))(\n original.redemption.input,\n ),\n );\n\n const native = yield* mapping.subjectId.toNative(input.captured.revision.subjectId);\n\n const locked =\n yield* sql`select ${subject.fields(\"email_locked_\")} from ${subject.name} where ${id(subject, s.id, native)} limit 2 ${batch === undefined ? lock : sql``}`;\n\n if (locked.length !== 1) return yield* prepare(\"rejected\", project);\n ensure(\n (yield* mapping.subjectId.toSubject(\n subject.decode(locked[0]!, \"email_locked_\")[s.id],\n )) === input.captured.revision.subjectId,\n );\n\n const current = yield* target(\n {\n moduleId: input.moduleId,\n subjectId: input.captured.revision.subjectId,\n target: input.target,\n ...(input.captured.source === undefined\n ? {}\n : { sourceCredentialId: input.captured.source.credentialId }),\n },\n input.captured.source?.identifier,\n );\n\n if (current === undefined || proofs === undefined)\n return yield* prepare(\"rejected\", project);\n const requirement = yield* s.decodeActionRequirement(current.subject, action);\n\n if (\n !(yield* validateEmailMutation(\n mapping,\n { ...input, redemption: { input: redemption, prepare: original.redemption.prepare } },\n action,\n { target: current.target, requirement: Effect.succeed(requirement) },\n current.now,\n ))\n )\n return yield* prepare(\"rejected\", project);\n const requirements = [input.authorization.requirement, requirement];\n\n const boundaries = [\n ...new Set(\n input.authorization.evidence.proofs.flatMap((proof) =>\n requirements.map(\n (r) => DateTime.toEpochMillis(proof.verifiedAt) + r.maximumAgeMillis,\n ),\n ),\n ),\n ]\n .filter((time) => time > current.now)\n .sort((a, b) => a - b);\n\n const deadline = boundaries.find((time) =>\n requirements.some(\n (r) => !passwordEvidenceSatisfiedAt(input.authorization.evidence, r, time),\n ),\n );\n\n ensure(deadline !== undefined);\n const freshness = sql`${now} >= ${current.now} and ${now} < ${deadline}`;\n\n const factorCondition = (revision: AuthenticationRevision) =>\n sql.and([\n sql`(select count(*) from ${authority.name} where ${id(authority, a.subjectId, native)} and ${activeAuthority}) = ${revision.credentials.length}`,\n ...revision.credentials.map(\n (f) =>\n sql`exists(select 1 from ${authority.name} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, f.credentialId)} and ${exact(authority, a.revision, f.revision)} and ${activeAuthority})`,\n ),\n ]);\n\n if (batch !== undefined) {\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql.and([\n sql`exists(select 1 from ${subject.name} where ${id(subject, s.id, native)} and ${exact(subject, s.securityRevision, current.revision.securityRevision)} and ${activeSubject})`,\n factorCondition(current.revision),\n freshness,\n ]),\n ),\n );\n if (current.targetIdentifier !== undefined) {\n ensure(i.d1MutableTargetCondition !== undefined);\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${tables.expression(i.d1MutableTargetCondition({ identifier: input.target, nativeSubjectId: native }))})`,\n ),\n );\n }\n if (current.target.source !== undefined) {\n ensure(i.d1CurrentCondition !== undefined);\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(current.target.source.identifier)} and ${id(identifier, i.subjectId, native)} and ${tables.expression(i.d1CurrentCondition({ identifier: current.target.source.identifier, nativeSubjectId: native, bindingRevision: current.target.source.identifierRevision }))})`,\n ),\n );\n }\n }\n\n const proof = yield* makeNativeProofStore(tables, proofs, batch !== undefined),\n redeemed = yield* proof.redeemLocked(redemption);\n\n yield* registerSqlCommitReceipt(\n original.redemption.prepare(\n redeemed.decision,\n yield* CurrentCommitJournal,\n (value) => value,\n ),\n );\n if (redeemed.decision !== \"redeemed\") return yield* prepare(\"rejected\", project);\n\n const allocate = () =>\n allocateEmailValue(mode, mapping.allocateRevision, mapping.allocateRevisionSync);\n\n const targetIdentifierRevision = yield* allocate(),\n targetCredentialRevision = yield* allocate(),\n sourceIdentifierRevision = yield* allocate(),\n sourceCredentialRevision = yield* allocate();\n\n const confirms =\n action === \"verify-address\" && current.target.targetIdentifierRevision !== undefined;\n\n const nextSecurityRevision = confirms\n ? current.revision.securityRevision\n : yield* allocateEmailSecurityRevision(mapping, mode, current.revision.securityRevision);\n\n ensure(confirms || nextSecurityRevision !== current.revision.securityRevision);\n\n const targetCredentialId =\n current.targetCredential === undefined\n ? yield* allocateEmailValue(\n mode,\n mapping.allocateCredentialId,\n mapping.allocateCredentialIdSync,\n )\n : yield* Schema.decodeUnknownEffect(Schema.String)(\n current.targetCredential[c.credentialId],\n );\n\n const source = current.target.source;\n\n if (action === \"change-address\") {\n ensure(source !== undefined);\n yield* stage(\n sql`${identifier.update(i.encodeRetirement({ source: source.identifier, bindingRevision: sourceIdentifierRevision }))} where ${identifierKey(source.identifier)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, source.identifierRevision)}`,\n );\n yield* stage(\n sql`${credential.update(c.encodeRetirement({ source: source.identifier, credentialRevision: sourceCredentialRevision }))} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, source.credentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, source.credentialRevision)} and ${activeCredential}`,\n );\n yield* stage(\n sql`${authority.update(a.encodeRetirement(sourceCredentialRevision))} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, source.credentialId)} and ${exact(authority, a.revision, source.credentialRevision)} and ${activeAuthority}`,\n );\n }\n if (current.targetIdentifier === undefined)\n yield* stage(\n identifier.insert(\n i.encodeVerifiedInsert({\n identifier: input.target,\n subjectId: native,\n verifiedAtMillis: current.now,\n bindingRevision: targetIdentifierRevision,\n }),\n ),\n );\n else\n yield* stage(\n sql`${identifier.update(i.encodeVerification({ verifiedAtMillis: current.now, bindingRevision: targetIdentifierRevision }))} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, current.targetIdentifier[i.bindingRevision])} and ${identifier.column(i.verifiedAt)} is null`,\n );\n if (current.targetCredential === undefined) {\n yield* stage(\n credential.insert(\n c.encodeVerifiedInsert({\n moduleId: input.moduleId,\n subjectId: native,\n credentialId: targetCredentialId,\n identifier: input.target,\n credentialRevision: targetCredentialRevision,\n }),\n ),\n );\n yield* stage(\n authority.insert(\n a.encodeInsert({\n subjectId: native,\n credentialId: targetCredentialId,\n revision: targetCredentialRevision,\n }),\n ),\n );\n } else {\n const old = current.targetCredential[c.credentialRevision];\n\n yield* stage(\n sql`${credential.update(c.encodeActivation({ identifier: input.target, credentialRevision: targetCredentialRevision }))} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, targetCredentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, old)}`,\n );\n yield* stage(\n sql`${authority.update(a.encodeActivation(targetCredentialRevision))} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, targetCredentialId)} and ${exact(authority, a.revision, old)}`,\n );\n }\n if (!confirms)\n yield* stage(\n sql`${subject.update({ [s.securityRevision]: nextSecurityRevision })} where ${id(subject, s.id, native)} and ${exact(subject, s.securityRevision, current.revision.securityRevision)} and ${activeSubject} and ${freshness}`,\n );\n\n const revision: AuthenticationRevision = {\n subjectId: current.revision.subjectId,\n securityRevision: nextSecurityRevision,\n credentials: [\n ...current.revision.credentials.filter(\n (f) =>\n f.credentialId !== targetCredentialId && f.credentialId !== source?.credentialId,\n ),\n { credentialId: targetCredentialId, revision: targetCredentialRevision },\n ].sort((a, b) => a.credentialId.localeCompare(b.credentialId)),\n };\n\n if (batch !== undefined) {\n ensure(i.d1CurrentCondition !== undefined);\n\n const conditions = [\n redeemed.validUntil,\n freshness,\n factorCondition(revision),\n sql`exists(select 1 from ${subject.name} where ${id(subject, s.id, native)} and ${exact(subject, s.securityRevision, nextSecurityRevision)} and ${activeSubject})`,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${tables.expression(i.d1CurrentCondition({ identifier: input.target, nativeSubjectId: native, bindingRevision: targetIdentifierRevision }))})`,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, targetIdentifierRevision)} and ${id(identifier, i.verifiedAt, mapping.clock.encodeInstant(current.now))})`,\n sql`exists(select 1 from ${credential.name} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, targetCredentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, targetCredentialRevision)} and ${exact(credential, c.identifierNamespace, input.target.namespace)} and ${exact(credential, c.identifierValue, input.target.value)} and ${activeCredential})`,\n ];\n\n if (source !== undefined)\n conditions.push(\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(source.identifier)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, sourceIdentifierRevision)} and not (${tables.expression(i.d1CurrentCondition({ identifier: source.identifier, nativeSubjectId: native, bindingRevision: sourceIdentifierRevision }))}))`,\n sql`exists(select 1 from ${credential.name} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, source.credentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, sourceCredentialRevision)} and not (${activeCredential}))`,\n sql`exists(select 1 from ${authority.name} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, source.credentialId)} and ${exact(authority, a.revision, sourceCredentialRevision)} and not (${activeAuthority}))`,\n );\n yield* registerSqlBatchPostcondition({\n name: \"email-address-authority\",\n statement: sqlBatchAssertion(sql, sql.and(conditions)),\n });\n } else\n yield* registerSqlPostcondition({\n name: \"email-address-authority\",\n check: Effect.gen(function* () {\n const final = yield* reader.read({\n validity: redeemed.validUntil,\n moduleId: input.moduleId,\n subjectId: revision.subjectId,\n identifier: input.target,\n ...(source === undefined\n ? {}\n : {\n sourceCredentialId: source.credentialId,\n sourceIdentifier: source.identifier,\n }),\n });\n\n ensure(\n final !== undefined &&\n sameEmailRevision(final.revision, revision) &&\n final.now >= current.now &&\n final.now < deadline &&\n final.targetSnapshot !== undefined &&\n final.targetSnapshot.credentialId === targetCredentialId &&\n final.targetSnapshot.credentialRevision === targetCredentialRevision &&\n final.targetSnapshot.identifierRevision === targetIdentifierRevision &&\n (yield* mapping.decodeInstant(final.targetIdentifier![i.verifiedAt])) ===\n current.now,\n );\n const policy = yield* s.decodeActionRequirement(final.subject, action);\n\n ensure(passwordEvidenceSatisfiedAt(input.authorization.evidence, policy, final.now));\n if (source !== undefined)\n ensure(\n final.sourceIdentifier !== undefined &&\n final.sourceCredential !== undefined &&\n final.sourceAuthority !== undefined &&\n (yield* mapping.subjectId.toSubject(final.sourceAuthority[a.subjectId])) ===\n revision.subjectId &&\n final.sourceAuthority[a.credentialId] === source.credentialId &&\n final.sourceAuthority[a.revision] === sourceCredentialRevision &&\n !a.isActiveStatus(final.sourceAuthority[a.status]) &&\n (yield* mapping.subjectId.toSubject(final.sourceIdentifier[i.subjectId])) ===\n revision.subjectId &&\n final.sourceIdentifier[i.bindingRevision] === sourceIdentifierRevision &&\n !i.isCurrent(final.sourceIdentifier) &&\n final.sourceCredential[c.credentialRevision] === sourceCredentialRevision &&\n !c.isActiveStatus(final.sourceCredential[c.status]),\n );\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"decode\", cause }),\n ),\n ),\n });\n\n return yield* prepare(\"changed\", project);\n }),\n );\n\n return {\n emailAddressPersistence: E.EmailAddressPersistence.of({\n target: (input) =>\n executor.read(\n Effect.flatMap(target(input), (value) =>\n value === undefined ? Effect.fail(unavailable()) : Effect.succeed(value.target),\n ),\n ),\n verifyWithProof: (input, project) => mutate(input, \"verify-address\", project),\n changeWithProof: (input, project) => mutate(input, \"change-address\", project),\n }),\n };\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"email-native.mjs","names":["unavailable"],"sources":["../../src/internal/email-native.ts"],"sourcesContent":["import * as E from \"@yielded/auth/Email\";\nimport { CurrentCommitJournal, type LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { ProofRedemptionInput } from \"@yielded/auth/Proofs\";\nimport type { AuthenticationRevision } from \"@yielded/auth/Sessions\";\nimport { SecurityRevision } from \"@yielded/auth/Sessions\";\nimport { Crypto, DateTime, Effect, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\nimport type { Fragment } from \"effect/sql/Statement\";\n\nimport { sqlBatchAssertion } from \"./d1-planning\";\nimport {\n makeNativeEmailReader,\n emailUnavailable as unavailable,\n ensureEmail as ensure,\n} from \"./email-native-state\";\nimport {\n allocateEmailValue,\n allocateEmailSecurityRevision,\n snapshotEmailMutation,\n validateEmailMutation,\n sameEmailRevision,\n} from \"./email-policy\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport type { AnyEmailAddressMapping, AnyEmailSignInMapping } from \"./models/email-model\";\nimport type { AnyProofPersistenceMapping } from \"./models/proof-model\";\nimport type { NativeSqlTables, SqlTable } from \"./native-sql-table\";\nimport { passwordEvidenceSatisfiedAt } from \"./password-policy\";\nimport { makeNativeProofStore } from \"./proof-native\";\nimport { exactSqlText, executeSqlChange } from \"./sql-change\";\nimport {\n appendSqlBatchStatement,\n makeSqlCommitExecutor,\n registerSqlBatchPostcondition,\n registerSqlCommitReceipt,\n registerSqlPostcondition,\n SqlBatchCommit,\n} from \"./sql-commit\";\n\nexport const makeNativeEmailSignInServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyEmailSignInMapping,\n): Effect.fn.Return<\n { readonly emailSignInTargets: E.EmailSignInTargets[\"Service\"] },\n never,\n SqlClient | LifecycleHooks\n> {\n const executor = yield* makeSqlCommitExecutor(unavailable);\n const reader = yield* makeNativeEmailReader(tables, mapping);\n\n return {\n emailSignInTargets: E.EmailSignInTargets.of({\n lookup: (input) => executor.read(reader.lookup(input)),\n }),\n };\n});\n\nexport const makeNativeEmailAddressServices = Effect.fnUntraced(function* (\n tables: NativeSqlTables,\n mapping: AnyEmailAddressMapping,\n proofs?: AnyProofPersistenceMapping,\n): Effect.fn.Return<\n { readonly emailAddressPersistence: E.EmailAddressPersistence[\"Service\"] },\n never,\n SqlClient | LifecycleHooks | Crypto.Crypto | SqlBatchCommit\n> {\n const batch = yield* SqlBatchCommit;\n\n const sql = (yield* SqlClient).withoutTransforms(),\n executor = yield* makeSqlCommitExecutor(unavailable),\n crypto = yield* Crypto.Crypto;\n\n const now = tables.expression(mapping.clock.engineNowMillis);\n const reader = yield* makeNativeEmailReader(tables, mapping, now);\n\n const s = mapping.subject,\n i = mapping.identifier,\n c = mapping.credential,\n a = mapping.authorityCredential;\n\n const subject = tables(s.table),\n identifier = tables(i.table),\n credential = tables(c.table),\n authority = tables(a.table);\n\n const exact = (t: SqlTable, key: string, value: unknown) =>\n exactSqlText(sql, t.column(key), t.value(key, value));\n\n const id = (t: SqlTable, key: string, value: unknown) =>\n sql`${t.column(key)} = ${t.value(key, value)}`;\n\n const identifierKey = (value: { readonly namespace: string; readonly value: string }) =>\n sql.and([\n exact(identifier, i.namespace, value.namespace),\n exact(identifier, i.value, value.value),\n ]);\n\n const activeSubject = id(subject, s.status, s.activeStatusValue),\n activeCredential = id(credential, c.status, c.activeStatusValue),\n activeAuthority = id(authority, a.status, a.activeStatusValue);\n\n const lock = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });\n const mode = \"interactive\";\n\n const run = <A, X, R>(work: Effect.Effect<A, X, R>) =>\n batch === undefined\n ? executor.run(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n : executor\n .batch(work.pipe(Effect.provideService(Crypto.Crypto, crypto)))\n .pipe(Effect.provideService(SqlBatchCommit, batch));\n\n const stage = Effect.fnUntraced(function* (statement: Fragment) {\n if (batch === undefined) ensure((yield* executeSqlChange(sql, statement)) === 1);\n else {\n yield* appendSqlBatchStatement(sql`${statement}`);\n yield* appendSqlBatchStatement(sqlBatchAssertion(sql, sql`changes() = 1`));\n }\n });\n\n const prepare = <A>(\n decision: E.EmailAddressDecision,\n project: E.PrepareEmailCommit<E.EmailAddressDecision, A>,\n ) =>\n Effect.gen(function* () {\n const receipt = project(decision, yield* CurrentCommitJournal);\n\n yield* registerSqlCommitReceipt(receipt);\n\n return receipt;\n });\n\n const target = Effect.fnUntraced(function* (\n input: Parameters<E.EmailAddressPersistence[\"Service\"][\"target\"]>[0],\n sourceIdentifier?: { readonly namespace: string; readonly value: string },\n ) {\n const state = yield* reader.read({\n moduleId: input.moduleId,\n subjectId: input.subjectId,\n identifier: input.target,\n ...(input.sourceCredentialId === undefined\n ? {}\n : { sourceCredentialId: input.sourceCredentialId }),\n ...(sourceIdentifier === undefined ? {} : { sourceIdentifier }),\n single: mapping.addressCardinality === \"single\",\n });\n\n if (state === undefined) return undefined;\n\n const owned =\n state.targetIdentifier !== undefined &&\n (yield* mapping.subjectId.toSubject(state.targetIdentifier[i.subjectId])) === input.subjectId;\n\n const mutable =\n owned &&\n mapping.identifier.isMutableTarget(state.targetIdentifier!) &&\n (state.targetCredential === undefined ||\n (!c.isActiveStatus(state.targetCredential[c.status]) &&\n (yield* mapping.subjectId.toSubject(state.targetCredential[c.subjectId])) ===\n input.subjectId));\n\n const source = state.sourceSnapshot;\n\n const eligible =\n (state.targetIdentifier === undefined ? state.targetCredential === undefined : mutable) &&\n (input.sourceCredentialId === undefined || source !== undefined) &&\n (source === undefined ||\n source.identifier.namespace !== input.target.namespace ||\n source.identifier.value !== input.target.value) &&\n !state.cardinalityConflict;\n\n const captured: E.EmailAddressTarget = {\n revision: state.revision,\n eligible,\n ...(source === undefined ? {} : { source }),\n ...(mutable\n ? {\n targetIdentifierRevision: yield* Schema.decodeUnknownEffect(SecurityRevision)(\n state.targetIdentifier![i.bindingRevision],\n ),\n }\n : {}),\n };\n\n return { ...state, target: captured };\n });\n\n const mutate = <A>(\n original: E.EmailAddressMutation,\n action: E.EmailAction,\n project: E.PrepareEmailCommit<E.EmailAddressDecision, A>,\n ) =>\n run(\n Effect.gen(function* () {\n const input = yield* snapshotEmailMutation(original);\n\n const redemption = yield* Schema.decodeEffect(Schema.toCodecIso(ProofRedemptionInput))(\n yield* Schema.encodeEffect(Schema.toCodecIso(ProofRedemptionInput))(\n original.redemption.input,\n ),\n );\n\n const native = yield* mapping.subjectId.toNative(input.captured.revision.subjectId);\n\n const locked =\n yield* sql`select ${subject.fields(\"email_locked_\")} from ${subject.name} where ${id(subject, s.id, native)} limit 2 ${batch === undefined ? lock : sql``}`;\n\n if (locked.length !== 1) return yield* prepare(\"rejected\", project);\n ensure(\n (yield* mapping.subjectId.toSubject(\n subject.decode(locked[0]!, \"email_locked_\")[s.id],\n )) === input.captured.revision.subjectId,\n );\n\n const current = yield* target(\n {\n moduleId: input.moduleId,\n subjectId: input.captured.revision.subjectId,\n target: input.target,\n ...(input.captured.source === undefined\n ? {}\n : { sourceCredentialId: input.captured.source.credentialId }),\n },\n input.captured.source?.identifier,\n );\n\n if (current === undefined || proofs === undefined)\n return yield* prepare(\"rejected\", project);\n const requirement = yield* s.decodeActionRequirement(current.subject, action);\n\n if (\n !(yield* validateEmailMutation(\n mapping,\n { ...input, redemption: { input: redemption, prepare: original.redemption.prepare } },\n action,\n { target: current.target, requirement: Effect.succeed(requirement) },\n current.now,\n ))\n )\n return yield* prepare(\"rejected\", project);\n const requirements = [input.authorization.requirement, requirement];\n\n const boundaries = [\n ...new Set(\n input.authorization.evidence.proofs.flatMap((proof) =>\n requirements.map(\n (r) => DateTime.toEpochMillis(proof.verifiedAt) + r.maximumAgeMillis,\n ),\n ),\n ),\n ]\n .filter((time) => time > current.now)\n .sort((a, b) => a - b);\n\n let deadline: number | undefined;\n\n for (const time of boundaries) {\n for (const requirement of requirements) {\n if (\n !(yield* passwordEvidenceSatisfiedAt(input.authorization.evidence, requirement, time))\n ) {\n deadline = time;\n break;\n }\n }\n if (deadline !== undefined) break;\n }\n\n ensure(deadline !== undefined);\n const freshness = sql`${now} >= ${current.now} and ${now} < ${deadline}`;\n\n const factorCondition = (revision: AuthenticationRevision) =>\n sql.and([\n sql`(select count(*) from ${authority.name} where ${id(authority, a.subjectId, native)} and ${activeAuthority}) = ${revision.credentials.length}`,\n ...revision.credentials.map(\n (f) =>\n sql`exists(select 1 from ${authority.name} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, f.credentialId)} and ${exact(authority, a.revision, f.revision)} and ${activeAuthority})`,\n ),\n ]);\n\n if (batch !== undefined) {\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql.and([\n sql`exists(select 1 from ${subject.name} where ${id(subject, s.id, native)} and ${exact(subject, s.securityRevision, current.revision.securityRevision)} and ${activeSubject})`,\n factorCondition(current.revision),\n freshness,\n ]),\n ),\n );\n if (current.targetIdentifier !== undefined) {\n ensure(i.d1MutableTargetCondition !== undefined);\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${tables.expression(i.d1MutableTargetCondition({ identifier: input.target, nativeSubjectId: native }))})`,\n ),\n );\n }\n if (current.target.source !== undefined) {\n ensure(i.d1CurrentCondition !== undefined);\n yield* appendSqlBatchStatement(\n sqlBatchAssertion(\n sql,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(current.target.source.identifier)} and ${id(identifier, i.subjectId, native)} and ${tables.expression(i.d1CurrentCondition({ identifier: current.target.source.identifier, nativeSubjectId: native, bindingRevision: current.target.source.identifierRevision }))})`,\n ),\n );\n }\n }\n\n const proof = yield* makeNativeProofStore(tables, proofs, batch !== undefined),\n redeemed = yield* proof.redeemLocked(redemption);\n\n yield* registerSqlCommitReceipt(\n original.redemption.prepare(\n redeemed.decision,\n yield* CurrentCommitJournal,\n (value) => value,\n ),\n );\n if (redeemed.decision !== \"redeemed\") return yield* prepare(\"rejected\", project);\n\n const allocate = () =>\n allocateEmailValue(mode, mapping.allocateRevision, mapping.allocateRevisionSync);\n\n const targetIdentifierRevision = yield* allocate(),\n targetCredentialRevision = yield* allocate(),\n sourceIdentifierRevision = yield* allocate(),\n sourceCredentialRevision = yield* allocate();\n\n const confirms =\n action === \"verify-address\" && current.target.targetIdentifierRevision !== undefined;\n\n const nextSecurityRevision = confirms\n ? current.revision.securityRevision\n : yield* allocateEmailSecurityRevision(mapping, mode, current.revision.securityRevision);\n\n ensure(confirms || nextSecurityRevision !== current.revision.securityRevision);\n\n const targetCredentialId =\n current.targetCredential === undefined\n ? yield* allocateEmailValue(\n mode,\n mapping.allocateCredentialId,\n mapping.allocateCredentialIdSync,\n )\n : yield* Schema.decodeUnknownEffect(Schema.String)(\n current.targetCredential[c.credentialId],\n );\n\n const source = current.target.source;\n\n if (action === \"change-address\") {\n ensure(source !== undefined);\n yield* stage(\n sql`${identifier.update(i.encodeRetirement({ source: source.identifier, bindingRevision: sourceIdentifierRevision }))} where ${identifierKey(source.identifier)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, source.identifierRevision)}`,\n );\n yield* stage(\n sql`${credential.update(c.encodeRetirement({ source: source.identifier, credentialRevision: sourceCredentialRevision }))} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, source.credentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, source.credentialRevision)} and ${activeCredential}`,\n );\n yield* stage(\n sql`${authority.update(a.encodeRetirement(sourceCredentialRevision))} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, source.credentialId)} and ${exact(authority, a.revision, source.credentialRevision)} and ${activeAuthority}`,\n );\n }\n if (current.targetIdentifier === undefined)\n yield* stage(\n identifier.insert(\n i.encodeVerifiedInsert({\n identifier: input.target,\n subjectId: native,\n verifiedAtMillis: current.now,\n bindingRevision: targetIdentifierRevision,\n }),\n ),\n );\n else\n yield* stage(\n sql`${identifier.update(i.encodeVerification({ verifiedAtMillis: current.now, bindingRevision: targetIdentifierRevision }))} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, current.targetIdentifier[i.bindingRevision])} and ${identifier.column(i.verifiedAt)} is null`,\n );\n if (current.targetCredential === undefined) {\n yield* stage(\n credential.insert(\n c.encodeVerifiedInsert({\n moduleId: input.moduleId,\n subjectId: native,\n credentialId: targetCredentialId,\n identifier: input.target,\n credentialRevision: targetCredentialRevision,\n }),\n ),\n );\n yield* stage(\n authority.insert(\n a.encodeInsert({\n subjectId: native,\n credentialId: targetCredentialId,\n revision: targetCredentialRevision,\n }),\n ),\n );\n } else {\n const old = current.targetCredential[c.credentialRevision];\n\n yield* stage(\n sql`${credential.update(c.encodeActivation({ identifier: input.target, credentialRevision: targetCredentialRevision }))} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, targetCredentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, old)}`,\n );\n yield* stage(\n sql`${authority.update(a.encodeActivation(targetCredentialRevision))} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, targetCredentialId)} and ${exact(authority, a.revision, old)}`,\n );\n }\n if (!confirms)\n yield* stage(\n sql`${subject.update({ [s.securityRevision]: nextSecurityRevision })} where ${id(subject, s.id, native)} and ${exact(subject, s.securityRevision, current.revision.securityRevision)} and ${activeSubject} and ${freshness}`,\n );\n\n const revision: AuthenticationRevision = {\n subjectId: current.revision.subjectId,\n securityRevision: nextSecurityRevision,\n credentials: [\n ...current.revision.credentials.filter(\n (f) =>\n f.credentialId !== targetCredentialId && f.credentialId !== source?.credentialId,\n ),\n { credentialId: targetCredentialId, revision: targetCredentialRevision },\n ].sort((a, b) => a.credentialId.localeCompare(b.credentialId)),\n };\n\n if (batch !== undefined) {\n ensure(i.d1CurrentCondition !== undefined);\n\n const conditions = [\n redeemed.validUntil,\n freshness,\n factorCondition(revision),\n sql`exists(select 1 from ${subject.name} where ${id(subject, s.id, native)} and ${exact(subject, s.securityRevision, nextSecurityRevision)} and ${activeSubject})`,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${tables.expression(i.d1CurrentCondition({ identifier: input.target, nativeSubjectId: native, bindingRevision: targetIdentifierRevision }))})`,\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(input.target)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, targetIdentifierRevision)} and ${id(identifier, i.verifiedAt, mapping.clock.encodeInstant(current.now))})`,\n sql`exists(select 1 from ${credential.name} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, targetCredentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, targetCredentialRevision)} and ${exact(credential, c.identifierNamespace, input.target.namespace)} and ${exact(credential, c.identifierValue, input.target.value)} and ${activeCredential})`,\n ];\n\n if (source !== undefined)\n conditions.push(\n sql`exists(select 1 from ${identifier.name} where ${identifierKey(source.identifier)} and ${id(identifier, i.subjectId, native)} and ${exact(identifier, i.bindingRevision, sourceIdentifierRevision)} and not (${tables.expression(i.d1CurrentCondition({ identifier: source.identifier, nativeSubjectId: native, bindingRevision: sourceIdentifierRevision }))}))`,\n sql`exists(select 1 from ${credential.name} where ${exact(credential, c.moduleId, input.moduleId)} and ${exact(credential, c.credentialId, source.credentialId)} and ${id(credential, c.subjectId, native)} and ${exact(credential, c.credentialRevision, sourceCredentialRevision)} and not (${activeCredential}))`,\n sql`exists(select 1 from ${authority.name} where ${id(authority, a.subjectId, native)} and ${exact(authority, a.credentialId, source.credentialId)} and ${exact(authority, a.revision, sourceCredentialRevision)} and not (${activeAuthority}))`,\n );\n yield* registerSqlBatchPostcondition({\n name: \"email-address-authority\",\n statement: sqlBatchAssertion(sql, sql.and(conditions)),\n });\n } else\n yield* registerSqlPostcondition({\n name: \"email-address-authority\",\n check: Effect.gen(function* () {\n const final = yield* reader.read({\n validity: redeemed.validUntil,\n moduleId: input.moduleId,\n subjectId: revision.subjectId,\n identifier: input.target,\n ...(source === undefined\n ? {}\n : {\n sourceCredentialId: source.credentialId,\n sourceIdentifier: source.identifier,\n }),\n });\n\n ensure(\n final !== undefined &&\n sameEmailRevision(final.revision, revision) &&\n final.now >= current.now &&\n final.now < deadline &&\n final.targetSnapshot !== undefined &&\n final.targetSnapshot.credentialId === targetCredentialId &&\n final.targetSnapshot.credentialRevision === targetCredentialRevision &&\n final.targetSnapshot.identifierRevision === targetIdentifierRevision &&\n (yield* mapping.decodeInstant(final.targetIdentifier![i.verifiedAt])) ===\n current.now,\n );\n const policy = yield* s.decodeActionRequirement(final.subject, action);\n\n ensure(\n yield* passwordEvidenceSatisfiedAt(input.authorization.evidence, policy, final.now),\n );\n if (source !== undefined)\n ensure(\n final.sourceIdentifier !== undefined &&\n final.sourceCredential !== undefined &&\n final.sourceAuthority !== undefined &&\n (yield* mapping.subjectId.toSubject(final.sourceAuthority[a.subjectId])) ===\n revision.subjectId &&\n final.sourceAuthority[a.credentialId] === source.credentialId &&\n final.sourceAuthority[a.revision] === sourceCredentialRevision &&\n !a.isActiveStatus(final.sourceAuthority[a.status]) &&\n (yield* mapping.subjectId.toSubject(final.sourceIdentifier[i.subjectId])) ===\n revision.subjectId &&\n final.sourceIdentifier[i.bindingRevision] === sourceIdentifierRevision &&\n !i.isCurrent(final.sourceIdentifier) &&\n final.sourceCredential[c.credentialRevision] === sourceCredentialRevision &&\n !c.isActiveStatus(final.sourceCredential[c.status]),\n );\n }).pipe(\n Effect.mapError((cause) =>\n PersistenceMappingError.make({ operation: \"decode\", cause }),\n ),\n ),\n });\n\n return yield* prepare(\"changed\", project);\n }),\n );\n\n return {\n emailAddressPersistence: E.EmailAddressPersistence.of({\n target: (input) =>\n executor.read(\n Effect.flatMap(target(input), (value) =>\n value === undefined ? Effect.fail(unavailable()) : Effect.succeed(value.target),\n ),\n ),\n verifyWithProof: (input, project) => mutate(input, \"verify-address\", project),\n changeWithProof: (input, project) => mutate(input, \"change-address\", project),\n }),\n };\n});\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { PersistenceMappingError } from "./mapping-error.mjs";
2
2
  import { passwordEvidenceSatisfiedAt } from "./password-policy.mjs";
3
- import { Effect } from "effect";
3
+ import { DateTime, Effect } from "effect";
4
4
  import { EmailUnavailable, snapshotEmailCredential, snapshotEmailRequirement, snapshotEmailRevision } from "@yielded/auth/Email";
5
5
  import { snapshotAuthenticationEvidence } from "@yielded/auth/Sessions";
6
6
  //#region src/internal/email-policy.ts
@@ -49,7 +49,8 @@ const validateEmailMutation = Effect.fn("EmailAddressPersistence.validateAuthori
49
49
  if (!input.captured.eligible || !emailRedemptionMatches(input, action) || input.authorization.challenge.moduleId !== input.moduleId || input.authorization.challenge.action !== action || input.authorization.challenge.commandId !== input.commandId || !sameIdentifier(input.authorization.challenge.target, input.target) || input.authorization.challenge.sourceCredentialId !== input.captured.source?.credentialId || !sameEmailRevision(input.authorization.challenge.revision, input.captured.revision) || input.authorization.challenge.targetIdentifierRevision !== input.captured.targetIdentifierRevision || input.authorization.evidence.flowId !== input.commandId || input.authorization.evidence.bindingDigest !== input.authorization.challenge.bindingDigest || !sameEmailRevision(input.authorization.evidence.revision, input.captured.revision) || action === "verify-address" && input.captured.source !== void 0 || action === "change-address" && input.captured.source === void 0 || confirmsExisting !== (input.invalidation === void 0) || input.invalidation?.existingSessions === "immediate" && policy.sessionInvalidation !== "same-authority-immediate") return false;
50
50
  if (current === void 0 || !current.target.eligible || !sameEmailRevision(current.target.revision, input.captured.revision) || current.target.targetIdentifierRevision !== input.captured.targetIdentifierRevision || input.captured.source !== void 0 && (current.target.source === void 0 || current.target.source.identifierRevision !== input.captured.source.identifierRevision || current.target.source.credentialRevision !== input.captured.source.credentialRevision || !sameIdentifier(current.target.source.identifier, input.captured.source.identifier))) return false;
51
51
  const currentRequirement = yield* current.requirement;
52
- return passwordEvidenceSatisfiedAt(input.authorization.evidence, input.authorization.requirement, now) && passwordEvidenceSatisfiedAt(input.authorization.evidence, currentRequirement, now);
52
+ if (input.authorization.evidence.proofs.some((proof) => DateTime.toEpochMillis(proof.verifiedAt) > now)) return false;
53
+ return (yield* passwordEvidenceSatisfiedAt(input.authorization.evidence, input.authorization.requirement, now)) && (yield* passwordEvidenceSatisfiedAt(input.authorization.evidence, currentRequirement, now));
53
54
  });
54
55
  const allocateEmailValue = (mode, asynchronous, synchronous) => {
55
56
  if (mode === "synchronous") return synchronous === void 0 ? Effect.fail(unavailable()) : Effect.try({