@yielded/auth-persistence 0.1.0-beta.17 → 0.1.0-beta.19

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 (85) hide show
  1. package/README.md +5 -2
  2. package/dist/Adapter.d.mts +2 -2
  3. package/dist/Adapter.mjs +2 -2
  4. package/dist/internal/configuration.d.mts +5 -4
  5. package/dist/internal/configuration.mjs.map +1 -1
  6. package/dist/internal/crypto.mjs +12 -0
  7. package/dist/internal/crypto.mjs.map +1 -0
  8. package/dist/internal/email-kernel.d.mts +7 -7
  9. package/dist/internal/passkey/admission.mjs +19 -15
  10. package/dist/internal/passkey/admission.mjs.map +1 -1
  11. package/dist/internal/passkey/credentials.mjs +4 -4
  12. package/dist/internal/passkey/credentials.mjs.map +1 -1
  13. package/dist/internal/passkey/enrollment.mjs +6 -6
  14. package/dist/internal/passkey/enrollment.mjs.map +1 -1
  15. package/dist/internal/passkey/flow.mjs +7 -7
  16. package/dist/internal/passkey/flow.mjs.map +1 -1
  17. package/dist/internal/passkey/management.mjs +2 -2
  18. package/dist/internal/passkey/management.mjs.map +1 -1
  19. package/dist/internal/passkey/registration-ceremony.mjs +2 -2
  20. package/dist/internal/passkey/registration-ceremony.mjs.map +1 -1
  21. package/dist/internal/passkey/registration-custody.mjs +1 -1
  22. package/dist/internal/passkey/registration-custody.mjs.map +1 -1
  23. package/dist/internal/passkey/registration-write.mjs +12 -12
  24. package/dist/internal/passkey/registration-write.mjs.map +1 -1
  25. package/dist/internal/passkey/state.d.mts +1 -1
  26. package/dist/internal/passkey/state.mjs +8 -9
  27. package/dist/internal/passkey/state.mjs.map +1 -1
  28. package/dist/internal/passkey/target.d.mts +1 -1
  29. package/dist/internal/passkey/target.mjs.map +1 -1
  30. package/dist/internal/passkey/write-state.mjs +13 -13
  31. package/dist/internal/passkey/write-state.mjs.map +1 -1
  32. package/dist/internal/passkey/write-target.mjs.map +1 -1
  33. package/dist/internal/passkey-kernel.d.mts +705 -249
  34. package/dist/internal/passkeys.mjs +32 -14
  35. package/dist/internal/passkeys.mjs.map +1 -1
  36. package/dist/internal/password-kernel.d.mts +6 -6
  37. package/dist/internal/password-kernel.mjs +1 -1
  38. package/dist/internal/password-kernel.mjs.map +1 -1
  39. package/dist/internal/persistence.d.mts +2 -2
  40. package/dist/internal/persistence.mjs +18 -9
  41. package/dist/internal/persistence.mjs.map +1 -1
  42. package/dist/internal/phone-kernel.d.mts +7 -7
  43. package/dist/internal/phone-kernel.mjs +14 -14
  44. package/dist/internal/phone-kernel.mjs.map +1 -1
  45. package/dist/internal/registration.mjs +8 -7
  46. package/dist/internal/registration.mjs.map +1 -1
  47. package/dist/internal/session-kernel.mjs +2 -1
  48. package/dist/internal/session-kernel.mjs.map +1 -1
  49. package/dist/internal/sql-query.mjs +1 -1
  50. package/dist/internal/sql-query.mjs.map +1 -1
  51. package/dist/internal/storage-mapping.d.mts +5 -4
  52. package/dist/internal/storage-mapping.mjs +16 -13
  53. package/dist/internal/storage-mapping.mjs.map +1 -1
  54. package/dist/internal/storage-validation.d.mts +13 -3
  55. package/dist/internal/storage-validation.mjs +128 -68
  56. package/dist/internal/storage-validation.mjs.map +1 -1
  57. package/dist/internal/transaction-execution-kernel.d.mts +4 -4
  58. package/dist/internal/transaction-execution-kernel.mjs +7 -5
  59. package/dist/internal/transaction-execution-kernel.mjs.map +1 -1
  60. package/package.json +1 -1
  61. package/src/Adapter.ts +7 -1
  62. package/src/internal/configuration.ts +5 -3
  63. package/src/internal/crypto.ts +15 -0
  64. package/src/internal/passkey/admission.ts +22 -15
  65. package/src/internal/passkey/credentials.ts +4 -4
  66. package/src/internal/passkey/enrollment.ts +7 -7
  67. package/src/internal/passkey/flow.ts +8 -8
  68. package/src/internal/passkey/management.ts +7 -2
  69. package/src/internal/passkey/registration-ceremony.ts +2 -2
  70. package/src/internal/passkey/registration-custody.ts +1 -1
  71. package/src/internal/passkey/registration-write.ts +12 -12
  72. package/src/internal/passkey/state.ts +10 -13
  73. package/src/internal/passkey/target.ts +16 -8
  74. package/src/internal/passkey/write-state.ts +10 -14
  75. package/src/internal/passkey/write-target.ts +11 -3
  76. package/src/internal/passkeys.ts +121 -70
  77. package/src/internal/password-kernel.ts +2 -2
  78. package/src/internal/persistence.ts +30 -13
  79. package/src/internal/phone-kernel.ts +26 -17
  80. package/src/internal/registration.ts +10 -8
  81. package/src/internal/session-kernel.ts +3 -2
  82. package/src/internal/sql-query.ts +3 -2
  83. package/src/internal/storage-mapping.ts +21 -13
  84. package/src/internal/storage-validation.ts +219 -139
  85. package/src/internal/transaction-execution-kernel.ts +30 -11
@@ -1,4 +1,5 @@
1
1
  import { PersistenceConfigurationError } from "./configuration.mjs";
2
+ import { randomId } from "./crypto.mjs";
2
3
  import { PersistenceMappingError } from "./mapping-error.mjs";
3
4
  import { requireStandalone } from "./standalone.mjs";
4
5
  import { NativeDatabase, makeTransactionKernel } from "./transaction-kernel.mjs";
@@ -11,10 +12,9 @@ import { CurrentPhoneTransaction, makePhoneKernel } from "./phone-kernel.mjs";
11
12
  import { makeRegistrationAuthority } from "./registration.mjs";
12
13
  import { CurrentSessionSql, makeSessionKernel } from "./session-kernel.mjs";
13
14
  import { makeMappings } from "./storage-mapping.mjs";
14
- import { validateStorage } from "./storage-validation.mjs";
15
+ import { validateStorageBatch, withStorageValidation } from "./storage-validation.mjs";
15
16
  import { Context, Effect, Layer, Schema } from "effect";
16
17
  import { SqlClient } from "effect/sql";
17
- import { digest, randomId } from "@yielded/auth-crypto";
18
18
  import { LifecycleHooks } from "@yielded/auth/Hooks";
19
19
  import { AuthenticationAuthority, SessionUnavailable } from "@yielded/auth/Sessions";
20
20
  import { hooksLayer } from "@yielded/auth/Persistence";
@@ -87,7 +87,8 @@ const createPersistence = (backend) => {
87
87
  ]) if (description.columns[key] === void 0) throw configError(`Missing subject column ${key}`);
88
88
  if (subject.activeValue === void 0) throw configError("An explicit active subject value is required");
89
89
  if (idColumn === void 0 || idColumn.type === "boolean") throw configError("Subject ID must map a text or integer column");
90
- const prefix = options.prefix ?? `auth_${digest(auth.namespace).slice(0, 12).replaceAll("-", "_")}`;
90
+ const prefix = options.prefix;
91
+ if (managed && (prefix === void 0 || !/^[A-Za-z_][A-Za-z0-9_]{0,100}$/.test(prefix))) throw configError("Managed persistence requires an explicit SQL table prefix");
91
92
  const schema = { ...options.tables };
92
93
  for (const role of roles) if (schema[role] === void 0 && managed) {
93
94
  const definition = tableDefinition(role, `${prefix}_${role}`, idColumn.type);
@@ -144,16 +145,24 @@ const createPersistence = (backend) => {
144
145
  if (auth.sessionMode !== "stateful") return yield* configError("The composed layer currently requires stateful sessions");
145
146
  if (features.some((feature) => feature === void 0 || "lifecycle" in feature && feature.lifecycle || feature.kind === "email" && !feature.addresses)) return yield* configError("Use explicit services for strategies without composed persistence support");
146
147
  if (storage.namespace !== auth.namespace) return yield* configError("Persistence configuration belongs to a different Auth definition");
148
+ const validations = [];
147
149
  for (const role of roles) {
148
150
  const table = storage.schema[role];
149
151
  if (table === void 0) return yield* configError(`Missing ${role} table`);
150
152
  const description = backend.describe(table);
151
153
  const columns = description.columns;
152
154
  for (const name of Object.keys(storageTables[role].columns)) if (columns[name] === void 0) return yield* configError(`Missing ${role}.${name} column`);
153
- yield* validateStorage(dialect, description, storageTables[role].unique);
155
+ validations.push({
156
+ table: description,
157
+ required: storageTables[role].unique
158
+ });
154
159
  }
155
- yield* validateStorage(dialect, backend.describe(storage.subjects.table), [[storage.subjects.id]]);
156
- const mappings = makeMappings(storage);
160
+ validations.push({
161
+ table: backend.describe(storage.subjects.table),
162
+ required: [[storage.subjects.id]]
163
+ });
164
+ yield* validateStorageBatch(dialect, validations);
165
+ const mappings = yield* makeMappings(storage);
157
166
  const standalone = (error) => requireStandalone(error, client.transactionService);
158
167
  const native = database;
159
168
  const options = {
@@ -184,7 +193,7 @@ const createPersistence = (backend) => {
184
193
  locking: dialect === "pg",
185
194
  standaloneGuard: standalone(() => PasswordUnavailable.make({})),
186
195
  insertIfAbsent: (query) => query.onConflictDoNothing(),
187
- proof: proofConfiguration
196
+ ...proofConfiguration === void 0 ? {} : { proof: proofConfiguration }
188
197
  }).pipe(Effect.provideService(CurrentPasswordSql, native), Effect.provideService(NativeDatabase, native));
189
198
  context = Context.add(context, PasswordPersistence, persistence);
190
199
  }
@@ -199,7 +208,7 @@ const createPersistence = (backend) => {
199
208
  mode: "interactive",
200
209
  locking: dialect === "pg",
201
210
  standaloneGuard: standalone(() => EmailUnavailable.make({})),
202
- proof: proofConfiguration
211
+ ...proofConfiguration === void 0 ? {} : { proof: proofConfiguration }
203
212
  }).pipe(Effect.provideService(CurrentEmailSql, native), Effect.provideService(NativeDatabase, native)));
204
213
  if (phone) {
205
214
  const { column, eq } = backend.operations;
@@ -274,7 +283,7 @@ const createPersistence = (backend) => {
274
283
  context = Context.merge(context, yield* services.pipe(Effect.provideService(NativeDatabase, native), Effect.provideService(CurrentProofSql, native)));
275
284
  }
276
285
  return context;
277
- }).pipe(Effect.mapError((error) => Schema.is(PersistenceConfigurationError)(error) ? error : configError("Cannot acquire SQL persistence")))).pipe(Layer.provide(hooksLayer)),
286
+ }).pipe(withStorageValidation, Effect.mapError((error) => Schema.is(PersistenceConfigurationError)(error) ? error : configError("Cannot acquire SQL persistence")))).pipe(Layer.provide(hooksLayer)),
278
287
  managed: (options) => layout(options, true),
279
288
  map: (options) => layout(options, false)
280
289
  };
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.mjs","names":[],"sources":["../../src/internal/persistence.ts"],"sourcesContent":["import { digest, randomId } from \"@yielded/auth-crypto\";\nimport { EmailAddressPersistence, EmailUnavailable } from \"@yielded/auth/Email\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { PasskeyConfig } from \"@yielded/auth/Passkey\";\nimport { PasswordPersistence, PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { hooksLayer } from \"@yielded/auth/Persistence\";\nimport { PhoneAdmission, PhoneSignInTargets, PhoneOtpUnavailable } from \"@yielded/auth/PhoneOtp\";\nimport { ProofPersistence, ProofUnavailable } from \"@yielded/auth/Proofs\";\nimport { AuthenticationAuthority, SessionUnavailable } from \"@yielded/auth/Sessions\";\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport {\n PersistenceConfigurationError,\n type ClaimsCodec,\n type ConfigId,\n type Definition,\n type PersistenceApi,\n type Ports,\n type Roles,\n type Provisioning,\n type ProvisioningRequirement,\n type StorageLayout,\n type SubjectMapping,\n type SubjectOptions,\n type PasskeyFeature,\n type PasskeyRequirement,\n type MappingInput,\n} from \"./configuration\";\nimport { makeEmailKernel, CurrentEmailSql, type EmailSqlDatabase } from \"./email-kernel\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport {\n makePasswordKernel,\n CurrentPasswordSql,\n type PasswordSqlDatabase,\n} from \"./password-kernel\";\nimport { makePhoneKernel, CurrentPhoneTransaction } from \"./phone-kernel\";\nimport {\n makeProofKernel,\n CurrentProofSql,\n type ProofSqlDatabase,\n type ProofSqlQuery,\n} from \"./proof-kernel\";\nimport type { QueryOperations } from \"./query-operations\";\nimport { makeRegistrationAuthority } from \"./registration\";\nimport { makeSessionKernel, CurrentSessionSql, type SessionSqlDatabase } from \"./session-kernel\";\nimport { requireStandalone } from \"./standalone\";\nimport { makeMappings } from \"./storage-mapping\";\nimport {\n tableDefinition,\n storageTables,\n type StorageRole,\n type StorageTable,\n} from \"./storage-tables\";\nimport { validateStorage } from \"./storage-validation\";\nimport { makeTransactionExecutionKernel } from \"./transaction-execution-kernel\";\nimport {\n makeTransactionKernel,\n NativeDatabase,\n type TransactionNativeDatabase,\n} from \"./transaction-kernel\";\n\nexport interface Backend<T extends object, R> {\n readonly makeTable: (definition: StorageTable) => T;\n readonly describe: (table: T) => StorageTable;\n readonly acquire: Effect.Effect<object, PersistenceConfigurationError, R | SqlClient.SqlClient>;\n readonly operations: QueryOperations;\n readonly passkeys: (input: {\n readonly storage: MappingInput;\n readonly namespace: string;\n readonly dialect: \"pg\" | \"sqlite\";\n readonly features: ReadonlyArray<PasskeyFeature>;\n readonly passwordModules: ReadonlyArray<string>;\n }) => Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n PasskeyConfig | LifecycleHooks | SqlClient.SqlClient | NativeDatabase | CurrentProofSql\n >;\n}\n\nconst configError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappingError = (cause: unknown) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause });\n\nconst timestampKeys = new Set([\n \"verifiedAt\",\n \"createdAt\",\n \"lastIssueAt\",\n \"issuedAt\",\n \"expiresAt\",\n \"absoluteExpiresAt\",\n \"retentionUntil\",\n \"claimDeadline\",\n \"retryAt\",\n \"admittedAt\",\n \"deadline\",\n \"occurredAt\",\n \"dedupUntil\",\n]);\n\nexport const createPersistence = <T extends object, R>(\n backend: Backend<T, R>,\n): PersistenceApi<T, R> => {\n const proofKernel = makeProofKernel(backend.operations);\n const passwordKernel = makePasswordKernel(backend.operations, proofKernel);\n const emailKernel = makeEmailKernel(backend.operations, proofKernel);\n const sessionKernel = makeSessionKernel(backend.operations);\n const transactionKernel = makeTransactionKernel(backend.operations);\n const executionKernel = makeTransactionExecutionKernel(transactionKernel);\n const phoneKernel = makePhoneKernel(backend.operations, transactionKernel);\n\n const make = <C extends ClaimsCodec, const Id extends string, const A extends Definition<C, Id>>(\n auth: A & Definition<C, Id>,\n ) => {\n const features = Object.values(auth.strategies).map((strategy) => strategy.persistence);\n const phone = features.some((feature) => feature?.kind === \"phone\");\n const password = features.some((feature) => feature?.kind === \"password\");\n\n const passkeys = features.filter(\n (feature): feature is PasskeyFeature => feature?.kind === \"passkey\",\n );\n\n const management = features.some(\n (feature) => feature?.kind === \"password\" && feature.management,\n );\n\n const email = features.some((feature) => feature?.kind === \"email\" && feature.addresses);\n const proofs = phone || management || email;\n\n const roles: StorageRole[] = [\"identifiers\", \"credentials\", \"sessions\", \"sessionFlows\"];\n\n if (password)\n roles.push(\n \"passwords\",\n \"passwordAttempts\",\n \"passwordScopes\",\n \"passwordCharges\",\n \"passwordCommands\",\n );\n if (management) roles.push(\"passwordRegistrations\");\n if (email) roles.push(\"emailCredentials\", \"emailCommands\");\n if (phone) roles.push(\"phoneState\");\n if (passkeys.length > 0)\n roles.push(\n \"passkeyCredentials\",\n \"passkeyOwnership\",\n \"passkeyHandles\",\n \"passkeyModules\",\n \"passkeyFlows\",\n \"passkeyAdmissions\",\n \"passkeyCharges\",\n );\n if (passkeys.some((feature) => feature.management)) roles.push(\"passkeyCommands\");\n if (proofs)\n roles.push(\n \"proofRequests\",\n \"proofSeries\",\n \"proofGenerations\",\n \"proofContinuations\",\n \"proofScopes\",\n \"proofAbuse\",\n \"proofFailures\",\n \"proofCommands\",\n );\n\n const ConfigKey = Context.Service<\n ConfigId<A[\"namespace\"]>,\n StorageLayout<T, Roles<C, Id, A>>\n >()(`@yielded/auth-persistence/${auth.namespace}/Config`);\n\n const Config = Object.assign(ConfigKey, {\n layer: (value: StorageLayout<T, Roles<C, Id, A>>) => Layer.succeed(ConfigKey, value),\n });\n\n const ProvisioningKey = Context.Service<ProvisioningRequirement<A>, Provisioning<A>>()(\n `@yielded/auth-persistence/${auth.namespace}/Provisioning`,\n );\n\n const layout = <N, Instant>(\n options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<StorageRole, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n },\n managed: boolean,\n ): StorageLayout<T, Roles<C, Id, A>> => {\n const subject = options.subjects;\n\n if (passkeys.length > 0 && options.timestamps !== undefined)\n throw configError(\n \"Composed passkey storage uses integer milliseconds; use an explicit passkey adapter for a custom timestamp representation\",\n );\n const description = backend.describe(subject.table);\n const idColumn = description.columns[subject.id];\n\n for (const key of [subject.id, subject.status, subject.securityRevision]) {\n if (description.columns[key] === undefined)\n throw configError(`Missing subject column ${key}`);\n }\n if (subject.activeValue === undefined)\n throw configError(\"An explicit active subject value is required\");\n\n if (idColumn === undefined || idColumn.type === \"boolean\")\n throw configError(\"Subject ID must map a text or integer column\");\n\n const prefix =\n options.prefix ?? `auth_${digest(auth.namespace).slice(0, 12).replaceAll(\"-\", \"_\")}`;\n\n const schema: Partial<Record<StorageRole, T>> = { ...options.tables };\n\n for (const role of roles) {\n if (schema[role] === undefined && managed) {\n const definition = tableDefinition(role, `${prefix}_${role}`, idColumn.type);\n\n const adjusted =\n options.timestamps === undefined\n ? definition\n : {\n ...definition,\n columns: Object.fromEntries(\n Object.entries(definition.columns).map(([key, column]) => [\n key,\n timestampKeys.has(key)\n ? { ...column, type: options.timestamps?.type ?? column.type }\n : column,\n ]),\n ),\n };\n\n schema[role] = backend.makeTable(adjusted);\n }\n }\n for (const role of roles) {\n if (schema[role] === undefined) throw configError(`Missing ${role} table`);\n }\n const instantCodec = options.timestamps?.codec;\n\n const decodeInstant =\n instantCodec === undefined\n ? Schema.decodeUnknownEffect(Schema.Int)\n : Schema.decodeUnknownEffect(instantCodec);\n\n const decodeInstantSync =\n instantCodec === undefined\n ? Schema.decodeUnknownSync(Schema.Int)\n : Schema.decodeUnknownSync(instantCodec);\n\n const subjects: SubjectMapping = {\n table: subject.table,\n id: subject.id,\n status: subject.status,\n securityRevision: subject.securityRevision,\n activeValue: subject.activeValue,\n requirements: subject.requirements,\n actionRequirements: subject.actionRequirements ?? subject.requirements,\n toSubject: (id) =>\n Schema.decodeUnknownEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toNative: (id) =>\n Schema.encodeEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toSubjectSync: Schema.decodeUnknownSync(subject.idCodec),\n toNativeSync: Schema.encodeSync(subject.idCodec),\n };\n\n return Object.freeze({\n namespace: auth.namespace,\n schema: Object.freeze(schema) as Readonly<Record<Roles<C, Id, A>, T>>,\n tables: schema,\n subjects,\n encodeInstant:\n instantCodec === undefined ? (millis: number) => millis : Schema.encodeSync(instantCodec),\n decodeInstant: (value: unknown) => decodeInstant(value).pipe(Effect.mapError(mappingError)),\n decodeInstantSync,\n });\n };\n\n const services = Layer.effectContext(\n Effect.gen(function* () {\n const storage = yield* ConfigKey;\n const hooks = yield* LifecycleHooks;\n const client = yield* SqlClient.SqlClient;\n const database = yield* backend.acquire;\n\n const dialect = client.onDialectOrElse({\n pg: () => \"pg\" as const,\n sqlite: () => \"sqlite\" as const,\n orElse: () => undefined,\n });\n\n if (dialect === undefined)\n return yield* configError(\"Use an explicit adapter for this SQL dialect\");\n if (auth.sessionMode !== \"stateful\")\n return yield* configError(\"The composed layer currently requires stateful sessions\");\n if (\n features.some(\n (feature) =>\n feature === undefined ||\n (\"lifecycle\" in feature && feature.lifecycle) ||\n (feature.kind === \"email\" && !feature.addresses),\n )\n )\n return yield* configError(\n \"Use explicit services for strategies without composed persistence support\",\n );\n if (storage.namespace !== auth.namespace)\n return yield* configError(\n \"Persistence configuration belongs to a different Auth definition\",\n );\n for (const role of roles) {\n const table = (storage.schema as Partial<Record<StorageRole, T>>)[role];\n\n if (table === undefined) return yield* configError(`Missing ${role} table`);\n const description = backend.describe(table);\n const columns = description.columns;\n\n for (const name of Object.keys(storageTables[role].columns)) {\n if (columns[name] === undefined)\n return yield* configError(`Missing ${role}.${name} column`);\n }\n yield* validateStorage(dialect, description, storageTables[role].unique);\n }\n yield* validateStorage(dialect, backend.describe(storage.subjects.table as T), [\n [storage.subjects.id],\n ]);\n const mappings = makeMappings(storage);\n\n const standalone = <E>(error: () => E) =>\n requireStandalone(error, client.transactionService);\n\n // Backend validation owns the foreign query-builder shape, never the decoded rows.\n const native = database as ProofSqlDatabase &\n PasswordSqlDatabase &\n EmailSqlDatabase &\n SessionSqlDatabase &\n TransactionNativeDatabase;\n\n const options = {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => SessionUnavailable.make({})),\n };\n\n const sessionMapping = mappings.sessions(auth.claims);\n\n const sessionServices = yield* sessionKernel\n .makeSqlStatefulSessions(sessionMapping, options)\n .pipe(\n Effect.provideService(CurrentSessionSql, native),\n Effect.provideService(NativeDatabase, native),\n );\n\n const authority = yield* sessionKernel\n .makeSqlAuthenticationAuthority<C[\"Type\"]>(\n { ...mappings.authority(), isConstraintConflict: () => false },\n options,\n )\n .pipe(\n Effect.provideService(CurrentSessionSql, native),\n Effect.provideService(NativeDatabase, native),\n );\n\n let context: Context.Context<never> = Context.make(AuthenticationAuthority, authority).pipe(\n Context.add(\n auth.sessions.StatefulSessionPersistence,\n sessionServices.statefulSessionPersistence,\n ),\n Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository),\n );\n\n const proofConfiguration = proofs\n ? {\n mapping: mappings.proofs(),\n configuration: {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => ProofUnavailable.make({})),\n insertIfAbsent: (query: ProofSqlQuery) => query.onConflictDoNothing(),\n },\n }\n : undefined;\n\n if (proofConfiguration !== undefined) {\n context = Context.add(\n context,\n ProofPersistence,\n yield* proofKernel\n .makeSqlProofPersistence(proofConfiguration.mapping, proofConfiguration.configuration)\n .pipe(\n Effect.provideService(CurrentProofSql, native),\n Effect.provideService(NativeDatabase, native),\n ),\n );\n }\n\n if (password) {\n const persistence = yield* passwordKernel\n .makeSqlPasswordPersistence(mappings.passwords(), {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => PasswordUnavailable.make({})),\n insertIfAbsent: (query) => query.onConflictDoNothing(),\n proof: proofConfiguration,\n })\n .pipe(\n Effect.provideService(CurrentPasswordSql, native),\n Effect.provideService(NativeDatabase, native),\n );\n\n context = Context.add(context, PasswordPersistence, persistence);\n }\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n\n if (key === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n const registration = yield* makeRegistrationAuthority(\n mappings,\n backend.operations,\n standalone(() => PasswordUnavailable.make({})),\n ProvisioningKey,\n name,\n ).pipe(Effect.provideService(CurrentPasswordSql, native));\n\n context = Context.add(context, key, registration);\n }\n if (email) {\n context = Context.add(\n context,\n EmailAddressPersistence,\n yield* emailKernel\n .makeSqlEmailAddressPersistence(mappings.emails(), {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => EmailUnavailable.make({})),\n proof: proofConfiguration,\n })\n .pipe(\n Effect.provideService(CurrentEmailSql, native),\n Effect.provideService(NativeDatabase, native),\n ),\n );\n }\n if (phone) {\n const { column, eq } = backend.operations;\n\n const mapping = (moduleId: string) => ({\n moduleId,\n subject: {\n table: storage.subjects.table,\n id: storage.subjects.id,\n securityRevision: storage.subjects.securityRevision,\n activeCondition: eq(\n column(storage.subjects.table, storage.subjects.status),\n storage.subjects.activeValue,\n ),\n },\n subjectIds: {\n toNative: storage.subjects.toNativeSync,\n toSubject: storage.subjects.toSubjectSync,\n },\n identifier: {\n table: mappings.table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n verifiedAt: \"verifiedAt\",\n activeCondition: eq(column(mappings.table(\"identifiers\"), \"active\"), true),\n },\n credential: {\n table: mappings.table(\"credentials\"),\n id: \"credentialId\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n activeCondition: eq(column(mappings.table(\"credentials\"), \"active\"), true),\n },\n state: {\n table: mappings.table(\"phoneState\"),\n scope: \"scope\",\n state: \"state\",\n version: \"version\",\n encodeInsert: (row: object) => row,\n },\n admission: {\n windowMillis: 60_000,\n networkRequests: 10,\n networkAttempts: 100,\n maximumMessages: 10,\n requestRetentionMillis: 86_400_000,\n },\n engineNowMillis: backend.operations\n .sql`${dialect === \"pg\" ? backend.operations.sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)` : backend.operations.sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`}`,\n encodeInstant: storage.encodeInstant,\n });\n\n const execution = yield* executionKernel\n .makeTransactionExecution(\n CurrentPhoneTransaction,\n {\n mode: \"interactive\",\n dialect,\n locking: dialect === \"pg\",\n standaloneGuard: () => standalone(() => PhoneOtpUnavailable.make({})),\n },\n () => PhoneOtpUnavailable.make({}),\n randomId,\n )\n .pipe(Effect.provideService(NativeDatabase, native));\n\n const run = <Value, E, Requirements>(\n work: Effect.Effect<Value, E, Requirements>,\n mutation = true,\n ) =>\n execution.admit.pipe(\n Effect.andThen(execution.run(work, mutation)),\n Effect.provideService(LifecycleHooks, hooks),\n );\n\n const allowed = (moduleId: string) =>\n features.some((feature) => feature?.kind === \"phone\" && feature.moduleId === moduleId);\n\n const admission = PhoneAdmission.of({\n admit: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.admitPhone(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n cleanup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.cleanupPhoneAdmission(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n const targets = PhoneSignInTargets.of({\n lookup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.lookupPhone(mapping(request.moduleId), request), false)\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n context = context.pipe(\n Context.add(PhoneAdmission, admission),\n Context.add(PhoneSignInTargets, targets),\n );\n }\n\n if (passkeys.length > 0) {\n // Auth capability metadata determines whether PasskeyConfig is required.\n const services = backend.passkeys({\n storage,\n namespace: auth.namespace,\n dialect,\n features: passkeys,\n passwordModules: features.flatMap((feature) =>\n feature?.kind === \"password\" ? [feature.moduleId] : [],\n ),\n }) as Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n | PasskeyRequirement<A>\n | LifecycleHooks\n | SqlClient.SqlClient\n | NativeDatabase\n | CurrentProofSql\n >;\n\n context = Context.merge(\n context,\n yield* services.pipe(\n Effect.provideService(NativeDatabase, native),\n Effect.provideService(CurrentProofSql, native),\n ),\n );\n }\n\n // The checked capability metadata above determines exactly these service keys.\n return context as Context.Context<Ports<C, Id, A>>;\n }).pipe(\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : configError(\"Cannot acquire SQL persistence\"),\n ),\n ),\n ).pipe(Layer.provide(hooksLayer));\n\n return {\n Config,\n Provisioning: ProvisioningKey,\n layer: services,\n managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, true),\n map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Partial<Record<StorageRole, T>>;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, false),\n };\n };\n\n return { make };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"persistence.mjs","names":[],"sources":["../../src/internal/persistence.ts"],"sourcesContent":["import { EmailAddressPersistence, EmailUnavailable } from \"@yielded/auth/Email\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport type { PasskeyConfig } from \"@yielded/auth/Passkey\";\nimport { PasswordPersistence, PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { hooksLayer } from \"@yielded/auth/Persistence\";\nimport { PhoneAdmission, PhoneSignInTargets, PhoneOtpUnavailable } from \"@yielded/auth/PhoneOtp\";\nimport { ProofPersistence, ProofUnavailable } from \"@yielded/auth/Proofs\";\nimport { AuthenticationAuthority, SessionUnavailable } from \"@yielded/auth/Sessions\";\nimport { Context, type Crypto, Effect, Layer, Schema } from \"effect\";\nimport { SqlClient } from \"effect/sql\";\n\nimport {\n PersistenceConfigurationError,\n type ClaimsCodec,\n type ConfigId,\n type Definition,\n type PersistenceApi,\n type Ports,\n type Roles,\n type Provisioning,\n type ProvisioningRequirement,\n type StorageLayout,\n type SubjectMapping,\n type SubjectOptions,\n type PasskeyFeature,\n type PasskeyRequirement,\n type MappingInput,\n} from \"./configuration\";\nimport { randomId } from \"./crypto\";\nimport { makeEmailKernel, CurrentEmailSql, type EmailSqlDatabase } from \"./email-kernel\";\nimport { PersistenceMappingError } from \"./mapping-error\";\nimport {\n makePasswordKernel,\n CurrentPasswordSql,\n type PasswordSqlDatabase,\n} from \"./password-kernel\";\nimport { makePhoneKernel, CurrentPhoneTransaction } from \"./phone-kernel\";\nimport {\n makeProofKernel,\n CurrentProofSql,\n type ProofSqlDatabase,\n type ProofSqlQuery,\n} from \"./proof-kernel\";\nimport type { QueryOperations } from \"./query-operations\";\nimport { makeRegistrationAuthority } from \"./registration\";\nimport { makeSessionKernel, CurrentSessionSql, type SessionSqlDatabase } from \"./session-kernel\";\nimport { requireStandalone } from \"./standalone\";\nimport { makeMappings } from \"./storage-mapping\";\nimport {\n tableDefinition,\n storageTables,\n type StorageRole,\n type StorageTable,\n} from \"./storage-tables\";\nimport {\n validateStorageBatch,\n withStorageValidation,\n type StorageValidation,\n} from \"./storage-validation\";\nimport { makeTransactionExecutionKernel } from \"./transaction-execution-kernel\";\nimport {\n makeTransactionKernel,\n NativeDatabase,\n type TransactionNativeDatabase,\n} from \"./transaction-kernel\";\n\nexport interface Backend<T extends object, R> {\n readonly makeTable: (definition: StorageTable) => T;\n readonly describe: (table: T) => StorageTable;\n readonly acquire: Effect.Effect<object, PersistenceConfigurationError, R | SqlClient.SqlClient>;\n readonly operations: QueryOperations;\n readonly passkeys: (input: {\n readonly storage: MappingInput;\n readonly namespace: string;\n readonly dialect: \"pg\" | \"sqlite\";\n readonly features: ReadonlyArray<PasskeyFeature>;\n readonly passwordModules: ReadonlyArray<string>;\n }) => Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n | PasskeyConfig\n | LifecycleHooks\n | SqlClient.SqlClient\n | NativeDatabase\n | CurrentProofSql\n | Crypto.Crypto\n >;\n}\n\nconst configError = (reason: string) => PersistenceConfigurationError.make({ reason });\n\nconst mappingError = (cause: unknown) =>\n PersistenceMappingError.make({ operation: \"mapping\", cause });\n\nconst timestampKeys = new Set([\n \"verifiedAt\",\n \"createdAt\",\n \"lastIssueAt\",\n \"issuedAt\",\n \"expiresAt\",\n \"absoluteExpiresAt\",\n \"retentionUntil\",\n \"claimDeadline\",\n \"retryAt\",\n \"admittedAt\",\n \"deadline\",\n \"occurredAt\",\n \"dedupUntil\",\n]);\n\nexport const createPersistence = <T extends object, R>(\n backend: Backend<T, R>,\n): PersistenceApi<T, R> => {\n const proofKernel = makeProofKernel(backend.operations);\n const passwordKernel = makePasswordKernel(backend.operations, proofKernel);\n const emailKernel = makeEmailKernel(backend.operations, proofKernel);\n const sessionKernel = makeSessionKernel(backend.operations);\n const transactionKernel = makeTransactionKernel(backend.operations);\n const executionKernel = makeTransactionExecutionKernel(transactionKernel);\n const phoneKernel = makePhoneKernel(backend.operations, transactionKernel);\n\n const make = <C extends ClaimsCodec, const Id extends string, const A extends Definition<C, Id>>(\n auth: A & Definition<C, Id>,\n ) => {\n const features = Object.values(auth.strategies).map((strategy) => strategy.persistence);\n const phone = features.some((feature) => feature?.kind === \"phone\");\n const password = features.some((feature) => feature?.kind === \"password\");\n\n const passkeys = features.filter(\n (feature): feature is PasskeyFeature => feature?.kind === \"passkey\",\n );\n\n const management = features.some(\n (feature) => feature?.kind === \"password\" && feature.management,\n );\n\n const email = features.some((feature) => feature?.kind === \"email\" && feature.addresses);\n const proofs = phone || management || email;\n\n const roles: StorageRole[] = [\"identifiers\", \"credentials\", \"sessions\", \"sessionFlows\"];\n\n if (password)\n roles.push(\n \"passwords\",\n \"passwordAttempts\",\n \"passwordScopes\",\n \"passwordCharges\",\n \"passwordCommands\",\n );\n if (management) roles.push(\"passwordRegistrations\");\n if (email) roles.push(\"emailCredentials\", \"emailCommands\");\n if (phone) roles.push(\"phoneState\");\n if (passkeys.length > 0)\n roles.push(\n \"passkeyCredentials\",\n \"passkeyOwnership\",\n \"passkeyHandles\",\n \"passkeyModules\",\n \"passkeyFlows\",\n \"passkeyAdmissions\",\n \"passkeyCharges\",\n );\n if (passkeys.some((feature) => feature.management)) roles.push(\"passkeyCommands\");\n if (proofs)\n roles.push(\n \"proofRequests\",\n \"proofSeries\",\n \"proofGenerations\",\n \"proofContinuations\",\n \"proofScopes\",\n \"proofAbuse\",\n \"proofFailures\",\n \"proofCommands\",\n );\n\n const ConfigKey = Context.Service<\n ConfigId<A[\"namespace\"]>,\n StorageLayout<T, Roles<C, Id, A>>\n >()(`@yielded/auth-persistence/${auth.namespace}/Config`);\n\n const Config = Object.assign(ConfigKey, {\n layer: (value: StorageLayout<T, Roles<C, Id, A>>) => Layer.succeed(ConfigKey, value),\n });\n\n const ProvisioningKey = Context.Service<ProvisioningRequirement<A>, Provisioning<A>>()(\n `@yielded/auth-persistence/${auth.namespace}/Provisioning`,\n );\n\n const layout = <N, Instant>(\n options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<StorageRole, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n },\n managed: boolean,\n ): StorageLayout<T, Roles<C, Id, A>> => {\n const subject = options.subjects;\n\n if (passkeys.length > 0 && options.timestamps !== undefined)\n throw configError(\n \"Composed passkey storage uses integer milliseconds; use an explicit passkey adapter for a custom timestamp representation\",\n );\n const description = backend.describe(subject.table);\n const idColumn = description.columns[subject.id];\n\n for (const key of [subject.id, subject.status, subject.securityRevision]) {\n if (description.columns[key] === undefined)\n throw configError(`Missing subject column ${key}`);\n }\n if (subject.activeValue === undefined)\n throw configError(\"An explicit active subject value is required\");\n\n if (idColumn === undefined || idColumn.type === \"boolean\")\n throw configError(\"Subject ID must map a text or integer column\");\n\n const prefix = options.prefix;\n\n if (managed && (prefix === undefined || !/^[A-Za-z_][A-Za-z0-9_]{0,100}$/.test(prefix)))\n throw configError(\"Managed persistence requires an explicit SQL table prefix\");\n\n const schema: Partial<Record<StorageRole, T>> = { ...options.tables };\n\n for (const role of roles) {\n if (schema[role] === undefined && managed) {\n const definition = tableDefinition(role, `${prefix}_${role}`, idColumn.type);\n\n const adjusted =\n options.timestamps === undefined\n ? definition\n : {\n ...definition,\n columns: Object.fromEntries(\n Object.entries(definition.columns).map(([key, column]) => [\n key,\n timestampKeys.has(key)\n ? { ...column, type: options.timestamps?.type ?? column.type }\n : column,\n ]),\n ),\n };\n\n schema[role] = backend.makeTable(adjusted);\n }\n }\n for (const role of roles) {\n if (schema[role] === undefined) throw configError(`Missing ${role} table`);\n }\n const instantCodec = options.timestamps?.codec;\n\n const decodeInstant =\n instantCodec === undefined\n ? Schema.decodeUnknownEffect(Schema.Int)\n : Schema.decodeUnknownEffect(instantCodec);\n\n const decodeInstantSync =\n instantCodec === undefined\n ? Schema.decodeUnknownSync(Schema.Int)\n : Schema.decodeUnknownSync(instantCodec);\n\n const subjects: SubjectMapping = {\n table: subject.table,\n id: subject.id,\n status: subject.status,\n securityRevision: subject.securityRevision,\n activeValue: subject.activeValue,\n requirements: subject.requirements,\n actionRequirements: subject.actionRequirements ?? subject.requirements,\n toSubject: (id) =>\n Schema.decodeUnknownEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toNative: (id) =>\n Schema.encodeEffect(subject.idCodec)(id).pipe(Effect.mapError(mappingError)),\n toSubjectSync: Schema.decodeUnknownSync(subject.idCodec),\n toNativeSync: Schema.encodeSync(subject.idCodec),\n };\n\n return Object.freeze({\n namespace: auth.namespace,\n schema: Object.freeze(schema) as Readonly<Record<Roles<C, Id, A>, T>>,\n tables: schema,\n subjects,\n encodeInstant:\n instantCodec === undefined ? (millis: number) => millis : Schema.encodeSync(instantCodec),\n decodeInstant: (value: unknown) => decodeInstant(value).pipe(Effect.mapError(mappingError)),\n decodeInstantSync,\n });\n };\n\n const services = Layer.effectContext(\n Effect.gen(function* () {\n const storage = yield* ConfigKey;\n const hooks = yield* LifecycleHooks;\n const client = yield* SqlClient.SqlClient;\n const database = yield* backend.acquire;\n\n const dialect = client.onDialectOrElse({\n pg: () => \"pg\" as const,\n sqlite: () => \"sqlite\" as const,\n orElse: () => undefined,\n });\n\n if (dialect === undefined)\n return yield* configError(\"Use an explicit adapter for this SQL dialect\");\n if (auth.sessionMode !== \"stateful\")\n return yield* configError(\"The composed layer currently requires stateful sessions\");\n if (\n features.some(\n (feature) =>\n feature === undefined ||\n (\"lifecycle\" in feature && feature.lifecycle) ||\n (feature.kind === \"email\" && !feature.addresses),\n )\n )\n return yield* configError(\n \"Use explicit services for strategies without composed persistence support\",\n );\n if (storage.namespace !== auth.namespace)\n return yield* configError(\n \"Persistence configuration belongs to a different Auth definition\",\n );\n const validations: StorageValidation[] = [];\n\n for (const role of roles) {\n const table = (storage.schema as Partial<Record<StorageRole, T>>)[role];\n\n if (table === undefined) return yield* configError(`Missing ${role} table`);\n const description = backend.describe(table);\n const columns = description.columns;\n\n for (const name of Object.keys(storageTables[role].columns)) {\n if (columns[name] === undefined)\n return yield* configError(`Missing ${role}.${name} column`);\n }\n validations.push({ table: description, required: storageTables[role].unique });\n }\n validations.push({\n table: backend.describe(storage.subjects.table as T),\n required: [[storage.subjects.id]],\n });\n yield* validateStorageBatch(dialect, validations);\n const mappings = yield* makeMappings(storage);\n\n const standalone = <E>(error: () => E) =>\n requireStandalone(error, client.transactionService);\n\n // Backend validation owns the foreign query-builder shape, never the decoded rows.\n const native = database as ProofSqlDatabase &\n PasswordSqlDatabase &\n EmailSqlDatabase &\n SessionSqlDatabase &\n TransactionNativeDatabase;\n\n const options = {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => SessionUnavailable.make({})),\n };\n\n const sessionMapping = mappings.sessions(auth.claims);\n\n const sessionServices = yield* sessionKernel\n .makeSqlStatefulSessions(sessionMapping, options)\n .pipe(\n Effect.provideService(CurrentSessionSql, native),\n Effect.provideService(NativeDatabase, native),\n );\n\n const authority = yield* sessionKernel\n .makeSqlAuthenticationAuthority<C[\"Type\"]>(\n { ...mappings.authority(), isConstraintConflict: () => false },\n options,\n )\n .pipe(\n Effect.provideService(CurrentSessionSql, native),\n Effect.provideService(NativeDatabase, native),\n );\n\n let context: Context.Context<never> = Context.make(AuthenticationAuthority, authority).pipe(\n Context.add(\n auth.sessions.StatefulSessionPersistence,\n sessionServices.statefulSessionPersistence,\n ),\n Context.add(auth.sessions.SessionRepository, sessionServices.sessionRepository),\n );\n\n const proofConfiguration = proofs\n ? {\n mapping: mappings.proofs(),\n configuration: {\n mode: \"interactive\" as const,\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => ProofUnavailable.make({})),\n insertIfAbsent: (query: ProofSqlQuery) => query.onConflictDoNothing(),\n },\n }\n : undefined;\n\n if (proofConfiguration !== undefined) {\n context = Context.add(\n context,\n ProofPersistence,\n yield* proofKernel\n .makeSqlProofPersistence(proofConfiguration.mapping, proofConfiguration.configuration)\n .pipe(\n Effect.provideService(CurrentProofSql, native),\n Effect.provideService(NativeDatabase, native),\n ),\n );\n }\n\n if (password) {\n const persistence = yield* passwordKernel\n .makeSqlPasswordPersistence(mappings.passwords(), {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => PasswordUnavailable.make({})),\n insertIfAbsent: (query) => query.onConflictDoNothing(),\n ...(proofConfiguration === undefined ? {} : { proof: proofConfiguration }),\n })\n .pipe(\n Effect.provideService(CurrentPasswordSql, native),\n Effect.provideService(NativeDatabase, native),\n );\n\n context = Context.add(context, PasswordPersistence, persistence);\n }\n for (const [name, strategy] of Object.entries(auth.strategies)) {\n if (strategy.persistence?.kind !== \"password\" || !strategy.persistence.management)\n continue;\n const key = strategy.RegistrationAuthority;\n\n if (key === undefined)\n return yield* configError(`Missing subject provisioning for ${name}`);\n\n const registration = yield* makeRegistrationAuthority(\n mappings,\n backend.operations,\n standalone(() => PasswordUnavailable.make({})),\n ProvisioningKey,\n name,\n ).pipe(Effect.provideService(CurrentPasswordSql, native));\n\n context = Context.add(context, key, registration);\n }\n if (email) {\n context = Context.add(\n context,\n EmailAddressPersistence,\n yield* emailKernel\n .makeSqlEmailAddressPersistence(mappings.emails(), {\n mode: \"interactive\",\n locking: dialect === \"pg\",\n standaloneGuard: standalone(() => EmailUnavailable.make({})),\n ...(proofConfiguration === undefined ? {} : { proof: proofConfiguration }),\n })\n .pipe(\n Effect.provideService(CurrentEmailSql, native),\n Effect.provideService(NativeDatabase, native),\n ),\n );\n }\n if (phone) {\n const { column, eq } = backend.operations;\n\n const mapping = (moduleId: string) => ({\n moduleId,\n subject: {\n table: storage.subjects.table,\n id: storage.subjects.id,\n securityRevision: storage.subjects.securityRevision,\n activeCondition: eq(\n column(storage.subjects.table, storage.subjects.status),\n storage.subjects.activeValue,\n ),\n },\n subjectIds: {\n toNative: storage.subjects.toNativeSync,\n toSubject: storage.subjects.toSubjectSync,\n },\n identifier: {\n table: mappings.table(\"identifiers\"),\n namespace: \"namespace\",\n value: \"value\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n verifiedAt: \"verifiedAt\",\n activeCondition: eq(column(mappings.table(\"identifiers\"), \"active\"), true),\n },\n credential: {\n table: mappings.table(\"credentials\"),\n id: \"credentialId\",\n subjectId: \"subjectId\",\n revision: \"revision\",\n activeCondition: eq(column(mappings.table(\"credentials\"), \"active\"), true),\n },\n state: {\n table: mappings.table(\"phoneState\"),\n scope: \"scope\",\n state: \"state\",\n version: \"version\",\n encodeInsert: (row: object) => row,\n },\n admission: {\n windowMillis: 60_000,\n networkRequests: 10,\n networkAttempts: 100,\n maximumMessages: 10,\n requestRetentionMillis: 86_400_000,\n },\n engineNowMillis: backend.operations\n .sql`${dialect === \"pg\" ? backend.operations.sql`cast(extract(epoch from clock_timestamp()) * 1000 as bigint)` : backend.operations.sql`cast(round((julianday('now') - 2440587.5) * 86400000) as integer)`}`,\n encodeInstant: storage.encodeInstant,\n });\n\n const execution = yield* executionKernel\n .makeTransactionExecution(\n CurrentPhoneTransaction,\n {\n mode: \"interactive\",\n dialect,\n locking: dialect === \"pg\",\n standaloneGuard: () => standalone(() => PhoneOtpUnavailable.make({})),\n },\n () => PhoneOtpUnavailable.make({}),\n randomId,\n )\n .pipe(Effect.provideService(NativeDatabase, native));\n\n const run = <Value, E, Requirements>(\n work: Effect.Effect<Value, E, Requirements>,\n mutation = true,\n ) =>\n execution.admit.pipe(\n Effect.andThen(execution.run(work, mutation)),\n Effect.provideService(LifecycleHooks, hooks),\n );\n\n const allowed = (moduleId: string) =>\n features.some((feature) => feature?.kind === \"phone\" && feature.moduleId === moduleId);\n\n const admission = PhoneAdmission.of({\n admit: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.admitPhone(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n cleanup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.cleanupPhoneAdmission(mapping(request.moduleId), request))\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n const targets = PhoneSignInTargets.of({\n lookup: (request) =>\n allowed(request.moduleId)\n ? run(phoneKernel.lookupPhone(mapping(request.moduleId), request), false)\n : Effect.fail(PhoneOtpUnavailable.make({})),\n });\n\n context = context.pipe(\n Context.add(PhoneAdmission, admission),\n Context.add(PhoneSignInTargets, targets),\n );\n }\n\n if (passkeys.length > 0) {\n // Auth capability metadata determines whether PasskeyConfig is required.\n const services = backend.passkeys({\n storage,\n namespace: auth.namespace,\n dialect,\n features: passkeys,\n passwordModules: features.flatMap((feature) =>\n feature?.kind === \"password\" ? [feature.moduleId] : [],\n ),\n }) as Effect.Effect<\n Context.Context<never>,\n PersistenceConfigurationError,\n | PasskeyRequirement<A>\n | Crypto.Crypto\n | LifecycleHooks\n | SqlClient.SqlClient\n | NativeDatabase\n | CurrentProofSql\n >;\n\n context = Context.merge(\n context,\n yield* services.pipe(\n Effect.provideService(NativeDatabase, native),\n Effect.provideService(CurrentProofSql, native),\n ),\n );\n }\n\n // The checked capability metadata above determines exactly these service keys.\n return context as Context.Context<Ports<C, Id, A>>;\n }).pipe(\n withStorageValidation,\n Effect.mapError((error) =>\n Schema.is(PersistenceConfigurationError)(error)\n ? error\n : configError(\"Cannot acquire SQL persistence\"),\n ),\n ),\n ).pipe(Layer.provide(hooksLayer));\n\n return {\n Config,\n Provisioning: ProvisioningKey,\n layer: services,\n managed: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables?: Partial<Record<Roles<C, Id, A>, T>>;\n readonly prefix?: string;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, true),\n map: <N, Instant = number>(options: {\n readonly subjects: SubjectOptions<T, N>;\n readonly tables: Partial<Record<StorageRole, T>>;\n readonly timestamps?: {\n readonly type: \"text\" | \"integer\";\n readonly codec: Schema.Codec<number, Instant>;\n };\n }) => layout(options, false),\n };\n };\n\n return { make };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyFA,MAAM,eAAe,WAAmB,8BAA8B,KAAK,EAAE,OAAO,CAAC;AAErF,MAAM,gBAAgB,UACpB,wBAAwB,KAAK;CAAE,WAAW;CAAW;AAAM,CAAC;AAE9D,MAAM,gCAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAa,qBACX,YACyB;CACzB,MAAM,cAAc,gBAAgB,QAAQ,UAAU;CACtD,MAAM,iBAAiB,mBAAmB,QAAQ,YAAY,WAAW;CACzE,MAAM,cAAc,gBAAgB,QAAQ,YAAY,WAAW;CACnE,MAAM,gBAAgB,kBAAkB,QAAQ,UAAU;CAC1D,MAAM,oBAAoB,sBAAsB,QAAQ,UAAU;CAClE,MAAM,kBAAkB,+BAA+B,iBAAiB;CACxE,MAAM,cAAc,gBAAgB,QAAQ,YAAY,iBAAiB;CAEzE,MAAM,QACJ,SACG;EACH,MAAM,WAAW,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,KAAK,aAAa,SAAS,WAAW;EACtF,MAAM,QAAQ,SAAS,MAAM,YAAY,SAAS,SAAS,OAAO;EAClE,MAAM,WAAW,SAAS,MAAM,YAAY,SAAS,SAAS,UAAU;EAExE,MAAM,WAAW,SAAS,QACvB,YAAuC,SAAS,SAAS,SAC5D;EAEA,MAAM,aAAa,SAAS,MACzB,YAAY,SAAS,SAAS,cAAc,QAAQ,UACvD;EAEA,MAAM,QAAQ,SAAS,MAAM,YAAY,SAAS,SAAS,WAAW,QAAQ,SAAS;EACvF,MAAM,SAAS,SAAS,cAAc;EAEtC,MAAM,QAAuB;GAAC;GAAe;GAAe;GAAY;EAAc;EAEtF,IAAI,UACF,MAAM,KACJ,aACA,oBACA,kBACA,mBACA,kBACF;EACF,IAAI,YAAY,MAAM,KAAK,uBAAuB;EAClD,IAAI,OAAO,MAAM,KAAK,oBAAoB,eAAe;EACzD,IAAI,OAAO,MAAM,KAAK,YAAY;EAClC,IAAI,SAAS,SAAS,GACpB,MAAM,KACJ,sBACA,oBACA,kBACA,kBACA,gBACA,qBACA,gBACF;EACF,IAAI,SAAS,MAAM,YAAY,QAAQ,UAAU,GAAG,MAAM,KAAK,iBAAiB;EAChF,IAAI,QACF,MAAM,KACJ,iBACA,eACA,oBACA,sBACA,eACA,cACA,iBACA,eACF;EAEF,MAAM,YAAY,QAAQ,QAGxB,CAAC,CAAC,6BAA6B,KAAK,UAAU,QAAQ;EAExD,MAAM,SAAS,OAAO,OAAO,WAAW,EACtC,QAAQ,UAA6C,MAAM,QAAQ,WAAW,KAAK,EACrF,CAAC;EAED,MAAM,kBAAkB,QAAQ,QAAqD,CAAC,CACpF,6BAA6B,KAAK,UAAU,cAC9C;EAEA,MAAM,UACJ,SASA,YACsC;GACtC,MAAM,UAAU,QAAQ;GAExB,IAAI,SAAS,SAAS,KAAK,QAAQ,eAAe,KAAA,GAChD,MAAM,YACJ,2HACF;GACF,MAAM,cAAc,QAAQ,SAAS,QAAQ,KAAK;GAClD,MAAM,WAAW,YAAY,QAAQ,QAAQ;GAE7C,KAAK,MAAM,OAAO;IAAC,QAAQ;IAAI,QAAQ;IAAQ,QAAQ;GAAgB,GACrE,IAAI,YAAY,QAAQ,SAAS,KAAA,GAC/B,MAAM,YAAY,0BAA0B,KAAK;GAErD,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,MAAM,YAAY,8CAA8C;GAElE,IAAI,aAAa,KAAA,KAAa,SAAS,SAAS,WAC9C,MAAM,YAAY,8CAA8C;GAElE,MAAM,SAAS,QAAQ;GAEvB,IAAI,YAAY,WAAW,KAAA,KAAa,CAAC,iCAAiC,KAAK,MAAM,IACnF,MAAM,YAAY,2DAA2D;GAE/E,MAAM,SAA0C,EAAE,GAAG,QAAQ,OAAO;GAEpE,KAAK,MAAM,QAAQ,OACjB,IAAI,OAAO,UAAU,KAAA,KAAa,SAAS;IACzC,MAAM,aAAa,gBAAgB,MAAM,GAAG,OAAO,GAAG,QAAQ,SAAS,IAAI;IAE3E,MAAM,WACJ,QAAQ,eAAe,KAAA,IACnB,aACA;KACE,GAAG;KACH,SAAS,OAAO,YACd,OAAO,QAAQ,WAAW,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,YAAY,CACxD,KACA,cAAc,IAAI,GAAG,IACjB;MAAE,GAAG;MAAQ,MAAM,QAAQ,YAAY,QAAQ,OAAO;KAAK,IAC3D,MACN,CAAC,CACH;IACF;IAEN,OAAO,QAAQ,QAAQ,UAAU,QAAQ;GAC3C;GAEF,KAAK,MAAM,QAAQ,OACjB,IAAI,OAAO,UAAU,KAAA,GAAW,MAAM,YAAY,WAAW,KAAK,OAAO;GAE3E,MAAM,eAAe,QAAQ,YAAY;GAEzC,MAAM,gBACJ,iBAAiB,KAAA,IACb,OAAO,oBAAoB,OAAO,GAAG,IACrC,OAAO,oBAAoB,YAAY;GAE7C,MAAM,oBACJ,iBAAiB,KAAA,IACb,OAAO,kBAAkB,OAAO,GAAG,IACnC,OAAO,kBAAkB,YAAY;GAE3C,MAAM,WAA2B;IAC/B,OAAO,QAAQ;IACf,IAAI,QAAQ;IACZ,QAAQ,QAAQ;IAChB,kBAAkB,QAAQ;IAC1B,aAAa,QAAQ;IACrB,cAAc,QAAQ;IACtB,oBAAoB,QAAQ,sBAAsB,QAAQ;IAC1D,YAAY,OACV,OAAO,oBAAoB,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,SAAS,YAAY,CAAC;IACpF,WAAW,OACT,OAAO,aAAa,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,SAAS,YAAY,CAAC;IAC7E,eAAe,OAAO,kBAAkB,QAAQ,OAAO;IACvD,cAAc,OAAO,WAAW,QAAQ,OAAO;GACjD;GAEA,OAAO,OAAO,OAAO;IACnB,WAAW,KAAK;IAChB,QAAQ,OAAO,OAAO,MAAM;IAC5B,QAAQ;IACR;IACA,eACE,iBAAiB,KAAA,KAAa,WAAmB,SAAS,OAAO,WAAW,YAAY;IAC1F,gBAAgB,UAAmB,cAAc,KAAK,CAAC,CAAC,KAAK,OAAO,SAAS,YAAY,CAAC;IAC1F;GACF,CAAC;EACH;EAgUA,OAAO;GACL;GACA,cAAc;GACd,OAjUe,MAAM,cACrB,OAAO,IAAI,aAAa;IACtB,MAAM,UAAU,OAAO;IACvB,MAAM,QAAQ,OAAO;IACrB,MAAM,SAAS,OAAO,UAAU;IAChC,MAAM,WAAW,OAAO,QAAQ;IAEhC,MAAM,UAAU,OAAO,gBAAgB;KACrC,UAAU;KACV,cAAc;KACd,cAAc,KAAA;IAChB,CAAC;IAED,IAAI,YAAY,KAAA,GACd,OAAO,OAAO,YAAY,8CAA8C;IAC1E,IAAI,KAAK,gBAAgB,YACvB,OAAO,OAAO,YAAY,yDAAyD;IACrF,IACE,SAAS,MACN,YACC,YAAY,KAAA,KACX,eAAe,WAAW,QAAQ,aAClC,QAAQ,SAAS,WAAW,CAAC,QAAQ,SAC1C,GAEA,OAAO,OAAO,YACZ,2EACF;IACF,IAAI,QAAQ,cAAc,KAAK,WAC7B,OAAO,OAAO,YACZ,kEACF;IACF,MAAM,cAAmC,CAAC;IAE1C,KAAK,MAAM,QAAQ,OAAO;KACxB,MAAM,QAAS,QAAQ,OAA2C;KAElE,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,YAAY,WAAW,KAAK,OAAO;KAC1E,MAAM,cAAc,QAAQ,SAAS,KAAK;KAC1C,MAAM,UAAU,YAAY;KAE5B,KAAK,MAAM,QAAQ,OAAO,KAAK,cAAc,KAAK,CAAC,OAAO,GACxD,IAAI,QAAQ,UAAU,KAAA,GACpB,OAAO,OAAO,YAAY,WAAW,KAAK,GAAG,KAAK,QAAQ;KAE9D,YAAY,KAAK;MAAE,OAAO;MAAa,UAAU,cAAc,KAAK,CAAC;KAAO,CAAC;IAC/E;IACA,YAAY,KAAK;KACf,OAAO,QAAQ,SAAS,QAAQ,SAAS,KAAU;KACnD,UAAU,CAAC,CAAC,QAAQ,SAAS,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,qBAAqB,SAAS,WAAW;IAChD,MAAM,WAAW,OAAO,aAAa,OAAO;IAE5C,MAAM,cAAiB,UACrB,kBAAkB,OAAO,OAAO,kBAAkB;IAGpD,MAAM,SAAS;IAMf,MAAM,UAAU;KACd,MAAM;KACN,SAAS,YAAY;KACrB,iBAAiB,iBAAiB,mBAAmB,KAAK,CAAC,CAAC,CAAC;IAC/D;IAEA,MAAM,iBAAiB,SAAS,SAAS,KAAK,MAAM;IAEpD,MAAM,kBAAkB,OAAO,cAC5B,wBAAwB,gBAAgB,OAAO,CAAC,CAChD,KACC,OAAO,eAAe,mBAAmB,MAAM,GAC/C,OAAO,eAAe,gBAAgB,MAAM,CAC9C;IAEF,MAAM,YAAY,OAAO,cACtB,+BACC;KAAE,GAAG,SAAS,UAAU;KAAG,4BAA4B;IAAM,GAC7D,OACF,CAAC,CACA,KACC,OAAO,eAAe,mBAAmB,MAAM,GAC/C,OAAO,eAAe,gBAAgB,MAAM,CAC9C;IAEF,IAAI,UAAkC,QAAQ,KAAK,yBAAyB,SAAS,CAAC,CAAC,KACrF,QAAQ,IACN,KAAK,SAAS,4BACd,gBAAgB,0BAClB,GACA,QAAQ,IAAI,KAAK,SAAS,mBAAmB,gBAAgB,iBAAiB,CAChF;IAEA,MAAM,qBAAqB,SACvB;KACE,SAAS,SAAS,OAAO;KACzB,eAAe;MACb,MAAM;MACN,SAAS,YAAY;MACrB,iBAAiB,iBAAiB,iBAAiB,KAAK,CAAC,CAAC,CAAC;MAC3D,iBAAiB,UAAyB,MAAM,oBAAoB;KACtE;IACF,IACA,KAAA;IAEJ,IAAI,uBAAuB,KAAA,GACzB,UAAU,QAAQ,IAChB,SACA,kBACA,OAAO,YACJ,wBAAwB,mBAAmB,SAAS,mBAAmB,aAAa,CAAC,CACrF,KACC,OAAO,eAAe,iBAAiB,MAAM,GAC7C,OAAO,eAAe,gBAAgB,MAAM,CAC9C,CACJ;IAGF,IAAI,UAAU;KACZ,MAAM,cAAc,OAAO,eACxB,2BAA2B,SAAS,UAAU,GAAG;MAChD,MAAM;MACN,SAAS,YAAY;MACrB,iBAAiB,iBAAiB,oBAAoB,KAAK,CAAC,CAAC,CAAC;MAC9D,iBAAiB,UAAU,MAAM,oBAAoB;MACrD,GAAI,uBAAuB,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,mBAAmB;KAC1E,CAAC,CAAC,CACD,KACC,OAAO,eAAe,oBAAoB,MAAM,GAChD,OAAO,eAAe,gBAAgB,MAAM,CAC9C;KAEF,UAAU,QAAQ,IAAI,SAAS,qBAAqB,WAAW;IACjE;IACA,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,KAAK,UAAU,GAAG;KAC9D,IAAI,SAAS,aAAa,SAAS,cAAc,CAAC,SAAS,YAAY,YACrE;KACF,MAAM,MAAM,SAAS;KAErB,IAAI,QAAQ,KAAA,GACV,OAAO,OAAO,YAAY,oCAAoC,MAAM;KAEtE,MAAM,eAAe,OAAO,0BAC1B,UACA,QAAQ,YACR,iBAAiB,oBAAoB,KAAK,CAAC,CAAC,CAAC,GAC7C,iBACA,IACF,CAAC,CAAC,KAAK,OAAO,eAAe,oBAAoB,MAAM,CAAC;KAExD,UAAU,QAAQ,IAAI,SAAS,KAAK,YAAY;IAClD;IACA,IAAI,OACF,UAAU,QAAQ,IAChB,SACA,yBACA,OAAO,YACJ,+BAA+B,SAAS,OAAO,GAAG;KACjD,MAAM;KACN,SAAS,YAAY;KACrB,iBAAiB,iBAAiB,iBAAiB,KAAK,CAAC,CAAC,CAAC;KAC3D,GAAI,uBAAuB,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,mBAAmB;IAC1E,CAAC,CAAC,CACD,KACC,OAAO,eAAe,iBAAiB,MAAM,GAC7C,OAAO,eAAe,gBAAgB,MAAM,CAC9C,CACJ;IAEF,IAAI,OAAO;KACT,MAAM,EAAE,QAAQ,OAAO,QAAQ;KAE/B,MAAM,WAAW,cAAsB;MACrC;MACA,SAAS;OACP,OAAO,QAAQ,SAAS;OACxB,IAAI,QAAQ,SAAS;OACrB,kBAAkB,QAAQ,SAAS;OACnC,iBAAiB,GACf,OAAO,QAAQ,SAAS,OAAO,QAAQ,SAAS,MAAM,GACtD,QAAQ,SAAS,WACnB;MACF;MACA,YAAY;OACV,UAAU,QAAQ,SAAS;OAC3B,WAAW,QAAQ,SAAS;MAC9B;MACA,YAAY;OACV,OAAO,SAAS,MAAM,aAAa;OACnC,WAAW;OACX,OAAO;OACP,WAAW;OACX,UAAU;OACV,YAAY;OACZ,iBAAiB,GAAG,OAAO,SAAS,MAAM,aAAa,GAAG,QAAQ,GAAG,IAAI;MAC3E;MACA,YAAY;OACV,OAAO,SAAS,MAAM,aAAa;OACnC,IAAI;OACJ,WAAW;OACX,UAAU;OACV,iBAAiB,GAAG,OAAO,SAAS,MAAM,aAAa,GAAG,QAAQ,GAAG,IAAI;MAC3E;MACA,OAAO;OACL,OAAO,SAAS,MAAM,YAAY;OAClC,OAAO;OACP,OAAO;OACP,SAAS;OACT,eAAe,QAAgB;MACjC;MACA,WAAW;OACT,cAAc;OACd,iBAAiB;OACjB,iBAAiB;OACjB,iBAAiB;OACjB,wBAAwB;MAC1B;MACA,iBAAiB,QAAQ,WACtB,GAAG,GAAG,YAAY,OAAO,QAAQ,WAAW,GAAG,iEAAiE,QAAQ,WAAW,GAAG;MACzI,eAAe,QAAQ;KACzB;KAEA,MAAM,YAAY,OAAO,gBACtB,yBACC,yBACA;MACE,MAAM;MACN;MACA,SAAS,YAAY;MACrB,uBAAuB,iBAAiB,oBAAoB,KAAK,CAAC,CAAC,CAAC;KACtE,SACM,oBAAoB,KAAK,CAAC,CAAC,GACjC,QACF,CAAC,CACA,KAAK,OAAO,eAAe,gBAAgB,MAAM,CAAC;KAErD,MAAM,OACJ,MACA,WAAW,SAEX,UAAU,MAAM,KACd,OAAO,QAAQ,UAAU,IAAI,MAAM,QAAQ,CAAC,GAC5C,OAAO,eAAe,gBAAgB,KAAK,CAC7C;KAEF,MAAM,WAAW,aACf,SAAS,MAAM,YAAY,SAAS,SAAS,WAAW,QAAQ,aAAa,QAAQ;KAEvF,MAAM,YAAY,eAAe,GAAG;MAClC,QAAQ,YACN,QAAQ,QAAQ,QAAQ,IACpB,IAAI,YAAY,WAAW,QAAQ,QAAQ,QAAQ,GAAG,OAAO,CAAC,IAC9D,OAAO,KAAK,oBAAoB,KAAK,CAAC,CAAC,CAAC;MAC9C,UAAU,YACR,QAAQ,QAAQ,QAAQ,IACpB,IAAI,YAAY,sBAAsB,QAAQ,QAAQ,QAAQ,GAAG,OAAO,CAAC,IACzE,OAAO,KAAK,oBAAoB,KAAK,CAAC,CAAC,CAAC;KAChD,CAAC;KAED,MAAM,UAAU,mBAAmB,GAAG,EACpC,SAAS,YACP,QAAQ,QAAQ,QAAQ,IACpB,IAAI,YAAY,YAAY,QAAQ,QAAQ,QAAQ,GAAG,OAAO,GAAG,KAAK,IACtE,OAAO,KAAK,oBAAoB,KAAK,CAAC,CAAC,CAAC,EAChD,CAAC;KAED,UAAU,QAAQ,KAChB,QAAQ,IAAI,gBAAgB,SAAS,GACrC,QAAQ,IAAI,oBAAoB,OAAO,CACzC;IACF;IAEA,IAAI,SAAS,SAAS,GAAG;KAEvB,MAAM,WAAW,QAAQ,SAAS;MAChC;MACA,WAAW,KAAK;MAChB;MACA,UAAU;MACV,iBAAiB,SAAS,SAAS,YACjC,SAAS,SAAS,aAAa,CAAC,QAAQ,QAAQ,IAAI,CAAC,CACvD;KACF,CAAC;KAWD,UAAU,QAAQ,MAChB,SACA,OAAO,SAAS,KACd,OAAO,eAAe,gBAAgB,MAAM,GAC5C,OAAO,eAAe,iBAAiB,MAAM,CAC/C,CACF;IACF;IAGA,OAAO;GACT,CAAC,CAAC,CAAC,KACD,uBACA,OAAO,UAAU,UACf,OAAO,GAAG,6BAA6B,CAAC,CAAC,KAAK,IAC1C,QACA,YAAY,gCAAgC,CAClD,CACF,CACF,CAAC,CAAC,KAAK,MAAM,QAAQ,UAAU,CAKf;GACd,UAA+B,YAQzB,OAAO,SAAS,IAAI;GAC1B,MAA2B,YAOrB,OAAO,SAAS,KAAK;EAC7B;CACF;CAEA,OAAO,EAAE,KAAK;AAChB"}
@@ -77,7 +77,7 @@ export declare const makePhoneKernel: <Fragment extends SqlFragment = SqlFragmen
77
77
  subject: Observation | null;
78
78
  subjectRow: Row | undefined;
79
79
  targetIdentifier: Observation;
80
- }, PhoneOtpUnavailable, CurrentPhoneTransaction>;
80
+ }, PhoneOtpUnavailable | import("effect/PlatformError").PlatformError, import("effect/Crypto").Crypto | CurrentPhoneTransaction>;
81
81
  lookupPhone: (mapping: any, input: {
82
82
  readonly moduleId: string;
83
83
  readonly phoneNumber: any;
@@ -111,7 +111,7 @@ export declare const makePhoneKernel: <Fragment extends SqlFragment = SqlFragmen
111
111
  readonly revision: string & import("effect/Brand").Brand<"effect-auth/SecurityRevision">;
112
112
  }[];
113
113
  };
114
- }>, PhoneOtpUnavailable, CurrentPhoneTransaction>;
114
+ }>, PhoneOtpUnavailable | import("effect/PlatformError").PlatformError, import("effect/Crypto").Crypto | CurrentPhoneTransaction>;
115
115
  admitPhone: (mapping: any, input: {
116
116
  readonly moduleId: string;
117
117
  readonly action: "request" | "attempt";
@@ -119,13 +119,13 @@ export declare const makePhoneKernel: <Fragment extends SqlFragment = SqlFragmen
119
119
  readonly fingerprint: string;
120
120
  readonly networkKey: string;
121
121
  readonly replayLifetimeMillis: number;
122
- }) => Effect.Effect<boolean, PhoneOtpUnavailable, CurrentPhoneTransaction>;
122
+ }) => Effect.Effect<boolean, PhoneOtpUnavailable | import("effect/PlatformError").PlatformError, import("effect/Crypto").Crypto | CurrentPhoneTransaction>;
123
123
  preparePhoneMutation: (mapping: any, input: PhoneMutation) => Effect.Effect<{
124
124
  decision: {
125
125
  readonly _tag: "Rejected";
126
126
  };
127
- mutate?: undefined;
128
- appliedCondition?: undefined;
127
+ mutate?: never;
128
+ appliedCondition?: never;
129
129
  } | {
130
130
  decision: {
131
131
  readonly _tag: "Accepted";
@@ -146,9 +146,9 @@ export declare const makePhoneKernel: <Fragment extends SqlFragment = SqlFragmen
146
146
  };
147
147
  };
148
148
  };
149
- mutate: Effect.Effect<boolean, PhoneOtpUnavailable, CurrentPhoneTransaction>;
149
+ mutate: Effect.Effect<boolean, PhoneOtpUnavailable | import("effect/PlatformError").PlatformError, import("effect/Crypto").Crypto | CurrentPhoneTransaction>;
150
150
  appliedCondition: Fragment;
151
- }, PhoneOtpUnavailable, CurrentPhoneTransaction>;
151
+ }, PhoneOtpUnavailable | import("effect/PlatformError").PlatformError, import("effect/Crypto").Crypto | CurrentPhoneTransaction>;
152
152
  cleanupPhoneAdmission: (mapping: any, input: {
153
153
  readonly moduleId: string;
154
154
  readonly limit: number;
@@ -1,5 +1,5 @@
1
+ import { digest, randomId } from "./crypto.mjs";
1
2
  import { Context, Effect, Option, Schema } from "effect";
2
- import { digest, randomId } from "@yielded/auth-crypto";
3
3
  import { AuthenticationRequirement, SecurityRevision } from "@yielded/auth/Sessions";
4
4
  import { PhoneCommandId, PhoneCredentialSnapshot, PhoneCustody, PhoneLifecycleAction, PhoneLifecyclePolicy, PhoneLifecycleTarget, PhoneOtpUnavailable } from "@yielded/auth/PhoneOtp";
5
5
  //#region src/internal/phone-kernel.ts
@@ -59,7 +59,7 @@ const makePhoneKernel = (operations, transactions) => {
59
59
  moduleId: mapping.moduleId,
60
60
  record: value
61
61
  }),
62
- [mapping.state.version]: randomId()
62
+ [mapping.state.version]: yield* randomId
63
63
  };
64
64
  if (observed.rows.length === 0) observed.rows = (yield* owner.insert(mapping.state.table, {
65
65
  ...copiedRow(mapping.state.encodeInsert({
@@ -73,7 +73,7 @@ const makePhoneKernel = (operations, transactions) => {
73
73
  else yield* owner.update(mapping.state.table, { [mapping.state.scope]: key }, values);
74
74
  });
75
75
  const custodyRead = Effect.fn("PhoneNative.custodyRead")(function* (mapping, phoneNumber) {
76
- const key = scope(mapping.moduleId, "custody", phoneNumber), observation = yield* stateRead(mapping, key);
76
+ const key = yield* scope(mapping.moduleId, "custody", phoneNumber), observation = yield* stateRead(mapping, key);
77
77
  const custody = observation.rows.length === 0 ? null : readStored(mapping, observation.rows[0][mapping.state.state], PhoneCustody);
78
78
  invariant(custody === null || custody.phoneNumber === phoneNumber);
79
79
  return {
@@ -158,17 +158,17 @@ const makePhoneKernel = (operations, transactions) => {
158
158
  admitPhone: Effect.fn("PhoneNative.admit")(function* (mapping, input) {
159
159
  invariant(input.moduleId === mapping.moduleId && Number.isSafeInteger(input.replayLifetimeMillis) && input.replayLifetimeMillis >= 0 && input.networkKey.length > 0 && input.networkKey.length <= 1024 && input.requestId.length > 0 && input.requestId.length <= 256);
160
160
  const owner = yield* CurrentPhoneTransaction, now = yield* owner.now(mapping), policy = mapping.admission;
161
- const key = scope(mapping.moduleId, "admission", input.action + "/" + input.requestId), receipt = yield* stateRead(mapping, key);
161
+ const key = yield* scope(mapping.moduleId, "admission", input.action + "/" + input.requestId), receipt = yield* stateRead(mapping, key);
162
162
  if (receipt.rows.length !== 0) {
163
163
  const saved = readStored(mapping, receipt.rows[0][mapping.state.state], AdmissionReceipt);
164
164
  if (saved.expiresAtMillis > now) owner.postconditions.push(sql`${mapping.engineNowMillis} < ${saved.expiresAtMillis}`);
165
- return saved.fingerprint === input.fingerprint && saved.network === digest(input.networkKey) && saved.accepted === true && saved.expiresAtMillis > now;
165
+ return saved.fingerprint === input.fingerprint && saved.network === (yield* digest(input.networkKey)) && saved.accepted === true && saved.expiresAtMillis > now;
166
166
  }
167
167
  const window = Math.floor(now / policy.windowMillis), entries = [{
168
- key: scope(mapping.moduleId, "network", input.action + "/" + digest(input.networkKey)),
168
+ key: yield* scope(mapping.moduleId, "network", input.action + "/" + (yield* digest(input.networkKey))),
169
169
  limit: input.action === "request" ? policy.networkRequests : policy.networkAttempts
170
170
  }, ...input.action === "request" ? [{
171
- key: scope(mapping.moduleId, "messages", "global"),
171
+ key: yield* scope(mapping.moduleId, "messages", "global"),
172
172
  limit: policy.maximumMessages
173
173
  }] : []].sort((a, b) => a.key.localeCompare(b.key));
174
174
  const updates = [];
@@ -189,7 +189,7 @@ const makePhoneKernel = (operations, transactions) => {
189
189
  }, update.observed);
190
190
  yield* stateWrite(mapping, key, {
191
191
  fingerprint: input.fingerprint,
192
- network: digest(input.networkKey),
192
+ network: yield* digest(input.networkKey),
193
193
  accepted,
194
194
  expiresAtMillis: now + Math.min(policy.requestRetentionMillis, input.replayLifetimeMillis)
195
195
  }, receipt);
@@ -210,7 +210,7 @@ const makePhoneKernel = (operations, transactions) => {
210
210
  if (input.completion.input.moduleId !== `${mapping.moduleId}/lifecycle` || input.completion.input.purpose !== "phone-lifecycle" || binding.identifier.namespace !== "phone" || binding.identifier.value !== input.target.phoneNumber) return { decision: rejected };
211
211
  if (input.action === "register" ? binding._tag !== "Identifier" : binding._tag === "Identifier" || binding.revision.subjectId !== input.target.revision?.subjectId || binding.revision.securityRevision !== input.target.revision?.securityRevision) return { decision: rejected };
212
212
  if (input.action === "verify" && binding._tag !== "Subject" || input.action === "change" && binding._tag !== "IdentifierChange") return { decision: rejected };
213
- const commandKey = scope(mapping.moduleId, "command", input.commandId), command = yield* stateRead(mapping, commandKey);
213
+ const commandKey = yield* scope(mapping.moduleId, "command", input.commandId), command = yield* stateRead(mapping, commandKey);
214
214
  if (command.rows.length !== 0) return { decision: rejected };
215
215
  const now = yield* owner.now(mapping), guards = [];
216
216
  const credentialGuards = [];
@@ -250,7 +250,7 @@ const makePhoneKernel = (operations, transactions) => {
250
250
  guards.push(sql`${mapping.engineNowMillis} >= ${at} and ${mapping.engineNowMillis} < ${at + age}`);
251
251
  }
252
252
  }
253
- const subjectId = input.action === "register" ? mapping.subjectIds.toSubject(mapping.subjectIds.allocate()) : captured.target.revision.subjectId, nativeId = mapping.subjectIds.toNative(subjectId), securityRevision = SecurityRevision.make(randomId()), credentialRevision = SecurityRevision.make(randomId()), custodyRevision = SecurityRevision.make(randomId()), credentialId = captured.target.custody?.credentialId ?? randomId();
253
+ const subjectId = input.action === "register" ? mapping.subjectIds.toSubject(mapping.subjectIds.allocate()) : captured.target.revision.subjectId, nativeId = mapping.subjectIds.toNative(subjectId), securityRevision = SecurityRevision.make(yield* randomId), credentialRevision = SecurityRevision.make(yield* randomId), custodyRevision = SecurityRevision.make(yield* randomId), credentialId = captured.target.custody?.credentialId ?? (yield* randomId);
254
254
  invariant(mapping.subjectIds.toSubject(nativeId) === subjectId);
255
255
  const custody = {
256
256
  phoneNumber: input.target.phoneNumber,
@@ -307,20 +307,20 @@ const makePhoneKernel = (operations, transactions) => {
307
307
  [i.value]: old.phoneNumber
308
308
  }, {
309
309
  [i.status]: i.encodeStatus(false),
310
- [i.revision]: randomId()
310
+ [i.revision]: yield* randomId
311
311
  });
312
312
  yield* owner.update(c.table, {
313
313
  [c.id]: old.credentialId,
314
314
  [c.subjectId]: nativeId
315
315
  }, {
316
316
  [c.status]: c.encodeStatus(false),
317
- [c.revision]: randomId()
317
+ [c.revision]: yield* randomId
318
318
  });
319
319
  yield* stateWrite(mapping, captured.source.key, {
320
320
  ...old,
321
321
  state: "retired",
322
- custodyRevision: SecurityRevision.make(randomId()),
323
- credentialRevision: SecurityRevision.make(randomId())
322
+ custodyRevision: SecurityRevision.make(yield* randomId),
323
+ credentialRevision: SecurityRevision.make(yield* randomId)
324
324
  }, captured.source.observation);
325
325
  }
326
326
  if (captured.targetIdentifier.rows.length === 0) {