{"version":3,"file":"registration.mjs","names":[],"sources":["../../src/internal/registration.ts"],"sourcesContent":["import type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { PasswordUnavailable } from \"@yielded/auth/Password\";\nimport { reportPersistenceFailure } from \"@yielded/auth/Persistence\";\nimport { SecurityRevision } from \"@yielded/auth/Sessions\";\nimport * as Cause from \"effect/Cause\";\nimport type * as Context from \"effect/Context\";\nimport * as Digest from \"effect/crypto/Digest\";\nimport * as SecureRandom from \"effect/crypto/SecureRandom\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport * as SqlClient from \"effect/sql/SqlClient\";\n\nimport { PersistenceConfigurationError, type SubjectProvisioning } from \"./configuration\";\nimport { randomId } from \"./crypto\";\nimport type { AnyPasswordPersistenceMapping } from \"./models/password-model\";\nimport type { NativeSqlTables } from \"./native-sql-table\";\nimport {\n  makeNativePasswordRegistrationStore,\n  PasswordIdentifierTaken,\n} from \"./password-registration-native\";\nimport type { PasswordRegistrationAuthority } from \"./registration-contract\";\nimport { makeSqlCommitExecutor, CurrentSqlCommit, SqlBatchCommit } from \"./sql-commit\";\n\nconst SubjectValues = Schema.Record(Schema.String, Schema.Unknown);\n\n/** Application provisioning and the unverified identifier/password binding share\n * one physical owner. Identifier uniqueness arbitrates registration; correlation\n * request IDs never become a retained credential-issuance receipt. */\nexport const makeRegistrationAuthority = Effect.fnUntraced(function* <R>(\n  tables: NativeSqlTables,\n  mapping: AnyPasswordPersistenceMapping,\n  provisioning: Context.Key<R, object>,\n  strategy: string,\n): Effect.fn.Return<\n  PasswordRegistrationAuthority<unknown>,\n  PersistenceConfigurationError,\n  | LifecycleHooks\n  | SqlClient.SqlClient\n  | (SecureRandom.SecureRandom | Digest.Digest)\n  | SqlBatchCommit\n  | R\n> {\n  const sql = (yield* SqlClient.SqlClient).withoutTransforms();\n  const crypto = yield* SecureRandom.SecureRandom;\n  const digests = yield* Digest.Digest;\n  const executor = yield* makeSqlCommitExecutor(() => PasswordUnavailable.make({}));\n  const parent = yield* Effect.serviceOption(CurrentSqlCommit);\n  const batch = yield* SqlBatchCommit;\n  const store = yield* makeNativePasswordRegistrationStore(tables, mapping, batch !== undefined);\n  // The strategy has already decoded its registration Schema. Only its callback\n  // signature is erased by the heterogeneous strategy service map.\n  const creators = (yield* provisioning) as Readonly<Record<string, SubjectProvisioning<unknown>>>;\n  const createSubject = creators[strategy];\n\n  if (createSubject === undefined)\n    return yield* PersistenceConfigurationError.make({\n      reason: `Missing subject provisioning for ${strategy}`,\n    });\n  if (batch !== undefined && typeof createSubject === \"function\")\n    return yield* PersistenceConfigurationError.make({\n      reason: `D1 subject provisioning for ${strategy} requires { values }; return the new subject row instead of inserting it`,\n    });\n  const s = mapping.subject;\n  const subject = tables(s.table);\n  const lock = sql.onDialectOrElse({ sqlite: () => sql``, orElse: () => sql`for update` });\n\n  const run = <A, E, R2>(work: Effect.Effect<A, E, R2>, suppressed: Effect.Effect<A, E, R2>) =>\n    batch !== undefined\n      ? executor.batch(work).pipe(Effect.provideService(SqlBatchCommit, batch))\n      : Option.isSome(parent)\n        ? executor.run(work)\n        : executor\n            .operation(\n              reportPersistenceFailure(\n                work,\n                (error) =>\n                  Schema.is(PasswordIdentifierTaken)(error) ||\n                  Schema.is(PasswordUnavailable)(error),\n                { markReported: true },\n              ).pipe(\n                Effect.catchCause((cause) =>\n                  Effect.failCause(\n                    Cause.map(cause, (error) =>\n                      Schema.is(PasswordIdentifierTaken)(error)\n                        ? error\n                        : PasswordUnavailable.make({}),\n                    ),\n                  ),\n                ),\n              ),\n            )\n            .pipe(\n              (effect) =>\n                Effect.catchCauseIf(\n                  effect,\n                  (cause) =>\n                    cause.reasons.length > 0 &&\n                    cause.reasons.every(\n                      (reason) =>\n                        Cause.isFailReason(reason) &&\n                        Schema.is(PasswordIdentifierTaken)(reason.error),\n                    ),\n                  () => executor.run(suppressed, \"statement\"),\n                ),\n              Effect.catchCause((cause) =>\n                Effect.failCause(Cause.map(cause, () => PasswordUnavailable.make({}))),\n              ),\n            );\n\n  return {\n    register: (input, project) =>\n      executor.read(store.available(input.identifier)).pipe(\n        Effect.flatMap((existing) =>\n          existing.length !== 0\n            ? executor.run(store.prepare({ _tag: \"Suppressed\" }, project), \"statement\")\n            : run(\n                Effect.gen(function* () {\n                  const provisioningInput = {\n                    requestId: input.requestId,\n                    identifier: input.identifier,\n                    registration: input.registration,\n                  };\n\n                  const row = yield* (function* () {\n                    if (typeof createSubject !== \"function\")\n                      return yield* createSubject\n                        .values(provisioningInput)\n                        .pipe(Effect.flatMap(Schema.decodeEffect(SubjectValues)));\n                    const subjectId = yield* createSubject(provisioningInput);\n                    const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n                    const rows =\n                      yield* sql`select ${subject.fields(\"registration_subject_\")} from ${subject.name} where ${subject.column(s.id)} = ${subject.value(s.id, nativeId)} limit 2 ${lock}`;\n\n                    if (rows.length !== 1) return yield* PasswordUnavailable.make({});\n\n                    return subject.decode(rows[0]!, \"registration_subject_\");\n                  })();\n\n                  if (!s.isActiveStatus(row[s.status])) return yield* PasswordUnavailable.make({});\n                  const subjectId = yield* mapping.subjectId.toSubject(row[s.id]);\n\n                  const securityRevision = yield* Schema.decodeUnknownEffect(SecurityRevision)(\n                    row[s.securityRevision],\n                  );\n\n                  if (typeof createSubject !== \"function\")\n                    yield* store.stage(sql`${subject.insert(row)}`);\n\n                  const identifierRevision = SecurityRevision.make(yield* randomId);\n                  const credentialId = yield* randomId;\n                  const credentialRevision = SecurityRevision.make(yield* randomId);\n                  const verifierVersion = SecurityRevision.make(yield* randomId);\n\n                  yield* store.bind({\n                    ...input,\n                    subjectId,\n                    securityRevision,\n                    identifierRevision,\n                    credentialId,\n                    credentialRevision,\n                    verifierVersion,\n                  });\n\n                  return yield* store.prepare({ _tag: \"Created\", subjectId }, project);\n                }).pipe(\n                  Effect.provideService(SecureRandom.SecureRandom, crypto),\n                  Effect.provideService(Digest.Digest, digests),\n                ),\n                store.prepare({ _tag: \"Suppressed\" }, project),\n              ),\n        ),\n      ),\n  };\n});\n"],"mappings":"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"}