@yielded/auth-persistence-drizzle 0.1.0-beta.0 → 0.1.0-beta.12
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.
- package/README.md +6 -1
- package/dist/D1.d.mts +155 -40
- package/dist/D1.mjs +10 -6
- package/dist/D1.mjs.map +1 -1
- package/dist/Libsql.d.mts +251 -129
- package/dist/Libsql.mjs +20 -21
- package/dist/Libsql.mjs.map +1 -1
- package/dist/Mysql2.d.mts +208 -56
- package/dist/Mysql2.mjs +13 -8
- package/dist/Mysql2.mjs.map +1 -1
- package/dist/Pglite.d.mts +209 -57
- package/dist/Pglite.mjs +13 -9
- package/dist/Pglite.mjs.map +1 -1
- package/dist/Postgres.d.mts +207 -55
- package/dist/Postgres.mjs +13 -9
- package/dist/Postgres.mjs.map +1 -1
- package/dist/SqliteBun.d.mts +249 -126
- package/dist/SqliteBun.mjs +20 -18
- package/dist/SqliteBun.mjs.map +1 -1
- package/dist/SqliteDo.d.mts +248 -158
- package/dist/SqliteDo.mjs +26 -44
- package/dist/SqliteDo.mjs.map +1 -1
- package/dist/SqliteNode.d.mts +247 -124
- package/dist/SqliteNode.mjs +20 -18
- package/dist/SqliteNode.mjs.map +1 -1
- package/dist/SqliteWasm.d.mts +251 -128
- package/dist/SqliteWasm.mjs +20 -18
- package/dist/SqliteWasm.mjs.map +1 -1
- package/dist/drizzle/D1BatchStatements.d.mts +1 -1
- package/dist/drizzle/D1BatchStatements.mjs.map +1 -1
- package/dist/drizzle/d1-database.d.mts +11 -0
- package/dist/drizzle/d1-database.mjs +8 -0
- package/dist/drizzle/d1-database.mjs.map +1 -0
- package/dist/drizzle/d1-emails.d.mts +8 -7
- package/dist/drizzle/d1-emails.mjs +7 -4
- package/dist/drizzle/d1-emails.mjs.map +1 -1
- package/dist/drizzle/d1-generated-statement.mjs.map +1 -1
- package/dist/drizzle/d1-identity.mjs +12 -9
- package/dist/drizzle/d1-identity.mjs.map +1 -1
- package/dist/drizzle/d1-oauth.d.mts +41 -10
- package/dist/drizzle/d1-oauth.mjs +8 -5
- package/dist/drizzle/d1-oauth.mjs.map +1 -1
- package/dist/drizzle/d1-passkey.d.mts +3 -14
- package/dist/drizzle/d1-passkey.mjs +2 -1
- package/dist/drizzle/d1-passkey.mjs.map +1 -1
- package/dist/drizzle/d1-password-prepared.d.mts +4 -3
- package/dist/drizzle/d1-password-prepared.mjs +3 -1
- package/dist/drizzle/d1-password-prepared.mjs.map +1 -1
- package/dist/drizzle/d1-passwords.d.mts +7 -6
- package/dist/drizzle/d1-passwords.mjs +5 -2
- package/dist/drizzle/d1-passwords.mjs.map +1 -1
- package/dist/drizzle/d1-phone.d.mts +3 -4
- package/dist/drizzle/d1-phone.mjs +2 -1
- package/dist/drizzle/d1-phone.mjs.map +1 -1
- package/dist/drizzle/d1-planning.d.mts +1 -1
- package/dist/drizzle/d1-proofs.d.mts +5 -4
- package/dist/drizzle/d1-proofs.mjs +3 -1
- package/dist/drizzle/d1-proofs.mjs.map +1 -1
- package/dist/drizzle/d1-sessions.d.mts +14 -13
- package/dist/drizzle/d1-sessions.mjs +15 -9
- package/dist/drizzle/d1-sessions.mjs.map +1 -1
- package/dist/drizzle/d1-totp.d.mts +3 -4
- package/dist/drizzle/d1-totp.mjs +2 -1
- package/dist/drizzle/d1-totp.mjs.map +1 -1
- package/dist/drizzle/email-registration.d.mts +1 -1
- package/dist/drizzle/email-registration.mjs +2 -1
- package/dist/drizzle/email-registration.mjs.map +1 -1
- package/dist/drizzle/email-target.d.mts +8 -7
- package/dist/drizzle/email-target.mjs +10 -10
- package/dist/drizzle/email-target.mjs.map +1 -1
- package/dist/drizzle/model.d.mts +2 -126
- package/dist/drizzle/model.mjs +2 -21
- package/dist/drizzle/model.mjs.map +1 -1
- package/dist/drizzle/mysql-database.d.mts +8 -0
- package/dist/drizzle/mysql-database.mjs +8 -0
- package/dist/drizzle/mysql-database.mjs.map +1 -0
- package/dist/drizzle/mysql-emails.d.mts +8 -7
- package/dist/drizzle/mysql-emails.mjs +12 -8
- package/dist/drizzle/mysql-emails.mjs.map +1 -1
- package/dist/drizzle/mysql-identity.mjs +12 -9
- package/dist/drizzle/mysql-identity.mjs.map +1 -1
- package/dist/drizzle/mysql-password-prepared.d.mts +4 -3
- package/dist/drizzle/mysql-password-prepared.mjs +6 -2
- package/dist/drizzle/mysql-password-prepared.mjs.map +1 -1
- package/dist/drizzle/mysql-passwords.d.mts +7 -5
- package/dist/drizzle/mysql-passwords.mjs +11 -7
- package/dist/drizzle/mysql-passwords.mjs.map +1 -1
- package/dist/drizzle/mysql-proofs.d.mts +4 -3
- package/dist/drizzle/mysql-proofs.mjs +8 -4
- package/dist/drizzle/mysql-proofs.mjs.map +1 -1
- package/dist/drizzle/mysql-sessions.d.mts +12 -11
- package/dist/drizzle/mysql-sessions.mjs +16 -12
- package/dist/drizzle/mysql-sessions.mjs.map +1 -1
- package/dist/drizzle/native-database.mjs +10 -0
- package/dist/drizzle/native-database.mjs.map +1 -0
- package/dist/drizzle/oauth-accounts.mjs +1 -1
- package/dist/drizzle/oauth-connected-access.mjs +14 -12
- package/dist/drizzle/oauth-connected-access.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-custody.mjs +2 -2
- package/dist/drizzle/oauth-connected-drivers.mjs +11 -6
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-flow.mjs +2 -2
- package/dist/drizzle/oauth-connected-input.mjs +14 -1
- package/dist/drizzle/oauth-connected-input.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-maintenance.mjs +1 -1
- package/dist/drizzle/oauth-connected-management.mjs +2 -2
- package/dist/drizzle/oauth-connected-model.d.mts +17 -3
- package/dist/drizzle/oauth-connected-model.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-settlement.mjs +51 -41
- package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-sign-in.mjs +263 -0
- package/dist/drizzle/oauth-connected-sign-in.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-state.d.mts +110 -2
- package/dist/drizzle/oauth-connected-state.mjs +9 -4
- package/dist/drizzle/oauth-connected-state.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-target.d.mts +142 -15
- package/dist/drizzle/oauth-connected-target.mjs +9 -6
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -1
- package/dist/drizzle/oauth-drivers.mjs +9 -7
- package/dist/drizzle/oauth-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-flow.d.mts +1 -1
- package/dist/drizzle/oauth-flow.mjs +1 -1
- package/dist/drizzle/oauth-input.mjs +1 -1
- package/dist/drizzle/oauth-model.d.mts +1 -1
- package/dist/drizzle/oauth-owner.d.mts +1 -1
- package/dist/drizzle/oauth-registration.d.mts +2 -2
- package/dist/drizzle/oauth-registration.mjs +1 -1
- package/dist/drizzle/oauth-state.mjs +5 -4
- package/dist/drizzle/oauth-state.mjs.map +1 -1
- package/dist/drizzle/oauth-target.d.mts +14 -13
- package/dist/drizzle/oauth-target.mjs +14 -13
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/passkey-drivers.mjs +8 -6
- package/dist/drizzle/passkey-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-drivers.mjs +5 -3
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-target.d.mts +1 -1
- package/dist/drizzle/password-prepared-sql.mjs +2 -1
- package/dist/drizzle/password-prepared-sql.mjs.map +1 -1
- package/dist/drizzle/password-prepared-state.mjs +1 -1
- package/dist/drizzle/password-prepared-target.d.mts +4 -3
- package/dist/drizzle/password-prepared-target.mjs +4 -3
- package/dist/drizzle/password-prepared-target.mjs.map +1 -1
- package/dist/drizzle/password-registration.mjs +2 -1
- package/dist/drizzle/password-registration.mjs.map +1 -1
- package/dist/drizzle/password-target.d.mts +6 -5
- package/dist/drizzle/password-target.mjs +8 -8
- package/dist/drizzle/password-target.mjs.map +1 -1
- package/dist/drizzle/pg-database.d.mts +9 -0
- package/dist/drizzle/pg-database.mjs +8 -0
- package/dist/drizzle/pg-database.mjs.map +1 -0
- package/dist/drizzle/pg-emails.d.mts +8 -7
- package/dist/drizzle/pg-emails.mjs +12 -8
- package/dist/drizzle/pg-emails.mjs.map +1 -1
- package/dist/drizzle/pg-identity.mjs +92 -0
- package/dist/drizzle/pg-identity.mjs.map +1 -0
- package/dist/drizzle/pg-password-prepared.d.mts +4 -3
- package/dist/drizzle/pg-password-prepared.mjs +6 -2
- package/dist/drizzle/pg-password-prepared.mjs.map +1 -1
- package/dist/drizzle/pg-passwords.d.mts +7 -5
- package/dist/drizzle/pg-passwords.mjs +11 -7
- package/dist/drizzle/pg-passwords.mjs.map +1 -1
- package/dist/drizzle/pg-proofs.d.mts +4 -3
- package/dist/drizzle/pg-proofs.mjs +8 -4
- package/dist/drizzle/pg-proofs.mjs.map +1 -1
- package/dist/drizzle/pg-sessions.d.mts +12 -11
- package/dist/drizzle/pg-sessions.mjs +16 -12
- package/dist/drizzle/pg-sessions.mjs.map +1 -1
- package/dist/drizzle/phone-model.d.mts +1 -1
- package/dist/drizzle/phone-target.d.mts +5 -4
- package/dist/drizzle/phone-target.mjs +12 -11
- package/dist/drizzle/phone-target.mjs.map +1 -1
- package/dist/drizzle/proof-target.d.mts +4 -3
- package/dist/drizzle/proof-target.mjs +5 -5
- package/dist/drizzle/proof-target.mjs.map +1 -1
- package/dist/drizzle/session-sql.d.mts +1 -0
- package/dist/drizzle/session-target.d.mts +11 -9
- package/dist/drizzle/session-target.mjs +11 -11
- package/dist/drizzle/session-target.mjs.map +1 -1
- package/dist/drizzle/sqlite-emails.mjs +9 -5
- package/dist/drizzle/sqlite-emails.mjs.map +1 -1
- package/dist/drizzle/sqlite-identity.mjs +14 -11
- package/dist/drizzle/sqlite-identity.mjs.map +1 -1
- package/dist/drizzle/sqlite-password-prepared.mjs +7 -3
- package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -1
- package/dist/drizzle/sqlite-passwords.mjs +10 -6
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -1
- package/dist/drizzle/sqlite-proofs.mjs +7 -3
- package/dist/drizzle/sqlite-proofs.mjs.map +1 -1
- package/dist/drizzle/sqlite-sessions.mjs +16 -12
- package/dist/drizzle/sqlite-sessions.mjs.map +1 -1
- package/dist/drizzle/standalone-guard.d.mts +2 -0
- package/dist/drizzle/standalone-guard.mjs +8 -4
- package/dist/drizzle/standalone-guard.mjs.map +1 -1
- package/dist/drizzle/totp-model.d.mts +1 -1
- package/dist/drizzle/totp-target.d.mts +5 -4
- package/dist/drizzle/totp-target.mjs +31 -28
- package/dist/drizzle/totp-target.mjs.map +1 -1
- package/dist/drizzle/transaction-mysql.mjs +1 -1
- package/dist/drizzle/transaction-mysql.mjs.map +1 -1
- package/dist/index.d.mts +2 -4
- package/dist/index.mjs +2 -4
- package/dist/internal/drizzle-postgres.mjs.map +1 -1
- package/dist/internal/drizzle-sqlite.mjs.map +1 -1
- package/package.json +1 -1
- package/src/D1.ts +37 -26
- package/src/Libsql.ts +45 -61
- package/src/Mysql2.ts +39 -35
- package/src/Pglite.ts +48 -30
- package/src/Postgres.ts +48 -30
- package/src/SqliteBun.ts +59 -68
- package/src/SqliteDo.ts +61 -274
- package/src/SqliteNode.ts +56 -66
- package/src/SqliteWasm.ts +56 -66
- package/src/drizzle/D1BatchStatements.ts +1 -1
- package/src/drizzle/d1-database.ts +10 -0
- package/src/drizzle/d1-emails.ts +86 -88
- package/src/drizzle/d1-generated-statement.ts +1 -1
- package/src/drizzle/d1-identity.ts +17 -20
- package/src/drizzle/d1-oauth.ts +19 -8
- package/src/drizzle/d1-passkey.ts +5 -1
- package/src/drizzle/d1-password-prepared.ts +40 -42
- package/src/drizzle/d1-passwords.ts +76 -80
- package/src/drizzle/d1-phone.ts +5 -1
- package/src/drizzle/d1-proofs.ts +31 -34
- package/src/drizzle/d1-sessions.ts +53 -40
- package/src/drizzle/d1-totp.ts +5 -1
- package/src/drizzle/email-registration.ts +6 -2
- package/src/drizzle/email-target.ts +18 -20
- package/src/drizzle/model.ts +1 -208
- package/src/drizzle/mysql-database.ts +8 -0
- package/src/drizzle/mysql-emails.ts +29 -17
- package/src/drizzle/mysql-identity.ts +18 -21
- package/src/drizzle/mysql-password-prepared.ts +11 -9
- package/src/drizzle/mysql-passwords.ts +22 -10
- package/src/drizzle/mysql-proofs.ts +17 -6
- package/src/drizzle/mysql-sessions.ts +41 -18
- package/src/drizzle/native-database.ts +22 -0
- package/src/drizzle/oauth-connected-access.ts +8 -1
- package/src/drizzle/oauth-connected-drivers.ts +21 -6
- package/src/drizzle/oauth-connected-input.ts +13 -0
- package/src/drizzle/oauth-connected-model.ts +17 -0
- package/src/drizzle/oauth-connected-settlement.ts +65 -42
- package/src/drizzle/oauth-connected-sign-in.ts +438 -0
- package/src/drizzle/oauth-connected-state.ts +19 -7
- package/src/drizzle/oauth-connected-target.ts +26 -18
- package/src/drizzle/oauth-drivers.ts +26 -10
- package/src/drizzle/oauth-state.ts +5 -4
- package/src/drizzle/oauth-target.ts +31 -43
- package/src/drizzle/passkey-drivers.ts +21 -13
- package/src/drizzle/passkey-write-drivers.ts +11 -6
- package/src/drizzle/password-prepared-sql.ts +2 -4
- package/src/drizzle/password-prepared-target.ts +10 -7
- package/src/drizzle/password-registration.ts +7 -8
- package/src/drizzle/password-target.ts +20 -19
- package/src/drizzle/pg-database.ts +10 -0
- package/src/drizzle/pg-emails.ts +29 -17
- package/src/drizzle/pg-identity.ts +297 -0
- package/src/drizzle/pg-password-prepared.ts +11 -9
- package/src/drizzle/pg-passwords.ts +22 -10
- package/src/drizzle/pg-proofs.ts +17 -6
- package/src/drizzle/pg-sessions.ts +41 -18
- package/src/drizzle/phone-target.ts +23 -18
- package/src/drizzle/proof-target.ts +10 -13
- package/src/drizzle/session-target.ts +33 -51
- package/src/drizzle/sqlite-emails.ts +31 -14
- package/src/drizzle/sqlite-identity.ts +22 -42
- package/src/drizzle/sqlite-password-prepared.ts +24 -10
- package/src/drizzle/sqlite-passwords.ts +30 -16
- package/src/drizzle/sqlite-proofs.ts +29 -6
- package/src/drizzle/sqlite-sessions.ts +50 -24
- package/src/drizzle/standalone-guard.ts +19 -7
- package/src/drizzle/totp-target.ts +62 -61
- package/src/drizzle/transaction-mysql.ts +1 -1
- package/src/index.ts +0 -24
- package/src/internal/drizzle-postgres.ts +1 -1
- package/src/internal/drizzle-sqlite.ts +1 -1
- package/dist/drizzle/d1-identity.d.mts +0 -30
- package/dist/drizzle/mysql-identity.d.mts +0 -21
- package/dist/drizzle/mysql.d.mts +0 -69
- package/dist/drizzle/mysql.mjs +0 -218
- package/dist/drizzle/mysql.mjs.map +0 -1
- package/dist/drizzle/pg.d.mts +0 -80
- package/dist/drizzle/pg.mjs +0 -289
- package/dist/drizzle/pg.mjs.map +0 -1
- package/dist/drizzle/sqlite.d.mts +0 -77
- package/dist/drizzle/sqlite.mjs +0 -217
- package/dist/drizzle/sqlite.mjs.map +0 -1
- package/src/drizzle/mysql.ts +0 -687
- package/src/drizzle/pg.ts +0 -984
- package/src/drizzle/sqlite.ts +0 -705
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.mjs","names":[],"sources":["../../src/drizzle/model.ts"],"sourcesContent":["import { requireStandalone } from \"@yielded/auth-persistence/Adapter\";\nimport { AuthStore } from \"@yielded/auth/AuthStore\";\nimport { AuthStoreError } from \"@yielded/auth/Errors\";\nimport {\n ExternalIdentityMutation,\n SubjectProvisioner,\n type SubjectProvisioningInput,\n type ExternalIdentity,\n type LoginIdentifier,\n} from \"@yielded/auth/Identity\";\nimport { OAuthStateStore, type OAuthState } from \"@yielded/auth/OAuth\";\nimport {\n type ConsumeChallenge,\n type NewChallenge,\n type NewRegistration,\n type PendingRegistration,\n} from \"@yielded/auth/Schema\";\nimport {\n getTableColumns,\n type AnyColumn,\n type InferInsertModel,\n type InferSelectModel,\n type Table,\n} from \"drizzle-orm\";\nimport { Context, DateTime, Effect, Layer } from \"effect\";\nimport type * as SqlClient from \"effect/unstable/sql/SqlClient\";\n\nexport type CommitMode = \"interactive\" | \"synchronous\" | \"batch\";\n\n/**\n * Ordinary error-channel consumes must own their commit. Coordinated callers\n * use the decision methods inside their outer transaction and translate only\n * after that owner commits.\n */\nexport interface SqlClientTransactionDatabase {\n readonly $client: Pick<SqlClient.SqlClient, \"transactionService\">;\n}\n\nexport const requireStandaloneConsume = (\n database: SqlClientTransactionDatabase,\n): Effect.Effect<void, AuthStoreError> =>\n requireStandalone(\n () =>\n AuthStoreError.make({\n message: \"Use the decision consume API inside an outer database transaction\",\n }),\n database.$client,\n );\n\nexport type { ChallengeConsumeDecision } from \"@yielded/auth/Persistence\";\nexport type { ConsumeDecision } from \"@yielded/auth/AuthStore\";\n\nexport {\n PersistenceMappingError,\n isMappedConstraintConflict,\n} from \"@yielded/auth-persistence/Adapter\";\n\nimport type { PersistenceMappingError, SubjectIdCodec } from \"@yielded/auth-persistence/Adapter\";\n\nexport interface InstantCodec<NativeInstant> {\n readonly encode: (instant: DateTime.Utc) => NativeInstant;\n readonly decode: (native: NativeInstant) => Effect.Effect<DateTime.Utc, PersistenceMappingError>;\n}\n\nexport interface RequiredAuthStoreConstraints {\n readonly series: \"unique(namespace,value,purpose)\";\n readonly challengeDigest: \"unique(tokenDigest)\";\n readonly registrationDigest: \"unique(tokenDigest)\";\n}\n\nexport interface RequiredOAuthStateConstraints {\n readonly oauthStateDigest: \"unique(stateDigest)\";\n}\n\nexport interface RequiredAuthConstraints\n extends RequiredAuthStoreConstraints, RequiredOAuthStateConstraints {}\n\nexport const requiredAuthConstraints: RequiredAuthConstraints = {\n series: \"unique(namespace,value,purpose)\",\n challengeDigest: \"unique(tokenDigest)\",\n registrationDigest: \"unique(tokenDigest)\",\n oauthStateDigest: \"unique(stateDigest)\",\n};\n\nexport const requiredAuthStoreConstraints: RequiredAuthStoreConstraints = {\n series: \"unique(namespace,value,purpose)\",\n challengeDigest: \"unique(tokenDigest)\",\n registrationDigest: \"unique(tokenDigest)\",\n};\n\nexport const requiredOAuthStateConstraints: RequiredOAuthStateConstraints = {\n oauthStateDigest: \"unique(stateDigest)\",\n};\n\ntype ColumnKey<T extends Table> = Extract<keyof T[\"_\"][\"columns\"], string>;\n\nexport interface ChallengeRecord {\n readonly challenge: NewChallenge;\n readonly namespace: string;\n readonly failedAttempts: number;\n readonly consumed: boolean;\n}\n\nexport interface ChallengeColumns<T extends Table> {\n readonly challengeId: ColumnKey<T>;\n readonly tokenDigest: ColumnKey<T>;\n readonly namespace: ColumnKey<T>;\n readonly value: ColumnKey<T>;\n readonly purpose: ColumnKey<T>;\n readonly otpKeyId: ColumnKey<T>;\n readonly otpDigest: ColumnKey<T>;\n readonly issuedAt: ColumnKey<T>;\n readonly expiresAt: ColumnKey<T>;\n readonly attemptLimit: ColumnKey<T>;\n readonly failedAttempts: ColumnKey<T>;\n readonly consumed: ColumnKey<T>;\n}\n\n/**\n * Inputs are immutable server-created issuances. Replacements must advance\n * issuedAt; equal or older issuances fail even after consumption or expiry.\n * Instant encoding must preserve this ordering. Retain the series row as an\n * issuance watermark until every previously accepted issuance has expired;\n * current-row expiry alone is insufficient if historical lifetimes were longer.\n */\nexport interface ChallengeTableMapping<T extends Table> {\n readonly table: T;\n readonly columns: ChallengeColumns<T>;\n readonly identifierNamespace: string;\n readonly encodeInstant: (instant: DateTime.Utc) => unknown;\n readonly encodeInsert: (\n input: NewChallenge,\n state: {\n readonly namespace: string;\n readonly failedAttempts: number;\n readonly consumed: false;\n },\n ) => InferInsertModel<T>;\n readonly encodeUpdate: (\n input: NewChallenge,\n state: {\n readonly namespace: string;\n readonly failedAttempts: unknown;\n readonly consumed: false;\n },\n ) => Readonly<Record<string, unknown>>;\n readonly decode: (\n row: InferSelectModel<T>,\n ) => Effect.Effect<ChallengeRecord, PersistenceMappingError>;\n}\n\nexport interface RegistrationRecord {\n readonly registration: PendingRegistration;\n readonly consumed: boolean;\n}\n\nexport interface RegistrationColumns<T extends Table> {\n readonly registrationId: ColumnKey<T>;\n readonly tokenDigest: ColumnKey<T>;\n readonly expiresAt: ColumnKey<T>;\n readonly consumed: ColumnKey<T>;\n}\n\nexport interface RegistrationTableMapping<T extends Table> {\n readonly table: T;\n readonly columns: RegistrationColumns<T>;\n readonly encodeInstant: (instant: DateTime.Utc) => unknown;\n readonly encodeInsert: (input: NewRegistration, consumed: false) => InferInsertModel<T>;\n readonly decode: (\n row: InferSelectModel<T>,\n ) => Effect.Effect<RegistrationRecord, PersistenceMappingError>;\n}\n\nexport interface OAuthStateColumns<T extends Table> {\n readonly stateDigest: ColumnKey<T>;\n readonly expiresAt: ColumnKey<T>;\n readonly consumed: ColumnKey<T>;\n}\n\nexport interface OAuthStateTableMapping<T extends Table> {\n readonly table: T;\n readonly columns: OAuthStateColumns<T>;\n readonly encodeInstant: (instant: DateTime.Utc) => unknown;\n readonly encodeInsert: (state: OAuthState, consumed: false) => InferInsertModel<T>;\n readonly decode: (\n row: InferSelectModel<T>,\n ) => Effect.Effect<\n { readonly state: OAuthState; readonly consumed: boolean },\n PersistenceMappingError\n >;\n}\n\nexport interface AuthStoreTables<Challenge extends Table, Registration extends Table> {\n readonly constraints: RequiredAuthStoreConstraints;\n readonly challenge: ChallengeTableMapping<Challenge>;\n readonly registration: RegistrationTableMapping<Registration>;\n}\n\nexport interface OAuthStateTables<State extends Table> {\n readonly constraints: RequiredOAuthStateConstraints;\n readonly oauthState: OAuthStateTableMapping<State>;\n}\n\nexport interface AuthTables<\n Challenge extends Table,\n Registration extends Table,\n State extends Table,\n> {\n readonly constraints: RequiredAuthConstraints;\n readonly challenge: ChallengeTableMapping<Challenge>;\n readonly registration: RegistrationTableMapping<Registration>;\n readonly oauthState: OAuthStateTableMapping<State>;\n}\n\nexport interface RequiredIdentityConstraints {\n readonly identifier: \"unique(namespace,value)\";\n readonly externalIdentity: \"unique(provider,issuer,subject)\";\n readonly provisioningRequest: \"unique(requestId)\";\n readonly provisioningSubject: \"notNull(provisioningRequest.subjectId)\";\n}\n\nexport interface RequiredSubjectProvisioningConstraints {\n readonly identifier: \"unique(namespace,value)\";\n readonly provisioningRequest: \"unique(requestId)\";\n readonly provisioningSubject: \"notNull(provisioningRequest.subjectId)\";\n}\n\nexport interface RequiredExternalIdentityConstraints {\n readonly externalIdentity: \"unique(provider,issuer,subject)\";\n}\n\nexport const requiredIdentityConstraints: RequiredIdentityConstraints = {\n identifier: \"unique(namespace,value)\",\n externalIdentity: \"unique(provider,issuer,subject)\",\n provisioningRequest: \"unique(requestId)\",\n provisioningSubject: \"notNull(provisioningRequest.subjectId)\",\n};\n\nexport const requiredSubjectProvisioningConstraints: RequiredSubjectProvisioningConstraints = {\n identifier: \"unique(namespace,value)\",\n provisioningRequest: \"unique(requestId)\",\n provisioningSubject: \"notNull(provisioningRequest.subjectId)\",\n};\n\nexport const requiredExternalIdentityConstraints: RequiredExternalIdentityConstraints = {\n externalIdentity: \"unique(provider,issuer,subject)\",\n};\n\nexport type { SubjectIdCodec } from \"@yielded/auth-persistence/Adapter\";\n\nexport interface SubjectProvisioningTables<\n Subject extends Table,\n Identifier extends Table,\n Request extends Table,\n NativeId,\n> {\n readonly constraints: RequiredSubjectProvisioningConstraints;\n readonly subject: {\n readonly table: Subject;\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly encodeInsert: (\n input: SubjectProvisioningInput,\n allocatedId: NativeId | undefined,\n ) => InferInsertModel<Subject>;\n readonly allocateId?: Effect.Effect<NativeId, PersistenceMappingError>;\n /** Required instead of allocateId when a synchronous-only DO transaction preallocates IDs. */\n readonly allocateIdSync?: () => NativeId;\n /** Decodes MySQL `$returningId()` for an autoincrement/runtime-default key. */\n readonly decodeGeneratedId?: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeId, PersistenceMappingError>;\n };\n readonly identifier: {\n readonly table: Identifier;\n readonly namespace: ColumnKey<Identifier>;\n readonly value: ColumnKey<Identifier>;\n readonly subjectId: ColumnKey<Identifier>;\n readonly encodeInsert: (\n identifier: LoginIdentifier,\n subjectId: NativeId,\n verifiedAt: DateTime.Utc | undefined,\n ) => InferInsertModel<Identifier>;\n };\n readonly provisioningRequest: {\n readonly table: Request;\n readonly requestId: ColumnKey<Request>;\n readonly fingerprint: ColumnKey<Request>;\n readonly subjectId: ColumnKey<Request>;\n readonly encodeInsert: (\n requestId: string,\n fingerprint: string,\n subjectId: NativeId,\n ) => InferInsertModel<Request>;\n };\n readonly subjectId: SubjectIdCodec<NativeId>;\n /** Narrows only database constraint failures; every other cause is unavailable. */\n readonly isConstraintConflict: (cause: unknown) => boolean;\n}\n\nexport interface ExternalIdentityTables<Subject extends Table, External extends Table, NativeId> {\n readonly constraints: RequiredExternalIdentityConstraints;\n readonly subject: {\n readonly table: Subject;\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n };\n readonly externalIdentity: {\n readonly table: External;\n readonly provider: ColumnKey<External>;\n readonly issuer: ColumnKey<External>;\n readonly subject: ColumnKey<External>;\n readonly subjectId: ColumnKey<External>;\n readonly encodeInsert: (\n identity: ExternalIdentity,\n subjectId: NativeId,\n ) => InferInsertModel<External>;\n };\n readonly subjectId: SubjectIdCodec<NativeId>;\n readonly isConstraintConflict: (cause: unknown) => boolean;\n}\n\nexport interface IdentityTables<\n Subject extends Table,\n Identifier extends Table,\n External extends Table,\n Request extends Table,\n NativeId,\n> {\n readonly constraints: RequiredIdentityConstraints;\n readonly subject: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>[\"subject\"];\n readonly identifier: SubjectProvisioningTables<\n Subject,\n Identifier,\n Request,\n NativeId\n >[\"identifier\"];\n readonly externalIdentity: ExternalIdentityTables<\n Subject,\n External,\n NativeId\n >[\"externalIdentity\"];\n readonly provisioningRequest: SubjectProvisioningTables<\n Subject,\n Identifier,\n Request,\n NativeId\n >[\"provisioningRequest\"];\n readonly subjectId: SubjectIdCodec<NativeId>;\n readonly isConstraintConflict: (cause: unknown) => boolean;\n}\n\n/** Extra encoders used by D1's ordered batch when the subject id is database-generated. */\nexport interface D1SubjectProvisioningMapping<\n Subject extends Table,\n Identifier extends Table,\n Request extends Table,\n NativeId,\n> extends SubjectProvisioningTables<Subject, Identifier, Request, NativeId> {\n readonly d1: {\n readonly requestInsertWithoutSubject: (\n requestId: string,\n fingerprint: string,\n ) => Partial<InferInsertModel<Request>>;\n readonly identifierInsertWithoutSubject: (\n identifier: LoginIdentifier,\n verifiedAt: DateTime.Utc | undefined,\n ) => Partial<InferInsertModel<Identifier>>;\n /** Unshadowed hidden-rowid alias; omit for WITHOUT ROWID or preallocated IDs. */\n readonly generatedRowIdAlias?: \"rowid\" | \"_rowid_\" | \"oid\";\n };\n}\n\nexport interface D1ExternalIdentityMapping<\n Subject extends Table,\n External extends Table,\n NativeId,\n> extends ExternalIdentityTables<Subject, External, NativeId> {\n readonly d1: {\n readonly activeStatusValue: unknown;\n };\n}\n\nexport interface D1GeneratedIdentityMapping<\n Subject extends Table,\n Identifier extends Table,\n External extends Table,\n Request extends Table,\n NativeId,\n> extends IdentityTables<Subject, Identifier, External, Request, NativeId> {\n readonly d1: D1SubjectProvisioningMapping<Subject, Identifier, Request, NativeId>[\"d1\"] &\n D1ExternalIdentityMapping<Subject, External, NativeId>[\"d1\"];\n}\n\nexport const provisioningFingerprint = (input: SubjectProvisioningInput): string =>\n // oxlint-disable-next-line no-restricted-properties -- stable internal provisioning fingerprint, never external JSON.\n JSON.stringify(\n input.identifier === undefined\n ? [\"v1\", null]\n : [\n \"v1\",\n input.identifier.namespace,\n input.identifier.value,\n input.verifiedAt === undefined ? null : DateTime.toEpochMillis(input.verifiedAt),\n ],\n );\n\n/**\n * Drizzle wraps Effect SQL failures before adapters observe them. Give the\n * consumer classifier each semantic wrapper in the short `cause`/`reason`\n * chain without exposing query text or bound parameters through public errors.\n */\n\nexport const column = <T extends Table>(table: T, key: ColumnKey<T>): AnyColumn =>\n getTableColumns(table)[key] as AnyColumn;\n\nexport const updateValues = <T extends Table>(\n entries: ReadonlyArray<readonly [ColumnKey<T>, unknown]>,\n): Partial<InferInsertModel<T>> => Object.fromEntries(entries) as Partial<InferInsertModel<T>>;\n\nexport type ChallengeInput = ConsumeChallenge;\n\n/** Acquire an application database in Effect and expose the auth stores as one layer. */\nexport const authServicesLayer = <E, R>(\n acquire: Effect.Effect<\n {\n readonly authStore: AuthStore[\"Service\"];\n readonly oauthStateStore: OAuthStateStore[\"Service\"];\n },\n E,\n R\n >,\n) =>\n Layer.effectContext(\n Effect.map(acquire, ({ authStore, oauthStateStore }) =>\n Context.make(AuthStore, authStore).pipe(Context.add(OAuthStateStore, oauthStateStore)),\n ),\n );\n\n/** Acquire an application database in Effect and expose the identity services as one layer. */\nexport const identityServicesLayer = <E, R>(\n acquire: Effect.Effect<\n {\n readonly subjectProvisioner: SubjectProvisioner[\"Service\"];\n readonly externalIdentityMutation: ExternalIdentityMutation[\"Service\"];\n },\n E,\n R\n >,\n) =>\n Layer.effectContext(\n Effect.map(acquire, ({ subjectProvisioner, externalIdentityMutation }) =>\n Context.make(SubjectProvisioner, subjectProvisioner).pipe(\n Context.add(ExternalIdentityMutation, externalIdentityMutation),\n ),\n ),\n );\n"],"mappings":";;;;;;;;;AAsCA,MAAa,4BACX,aAEA,wBAEI,eAAe,KAAK,EAClB,SAAS,oEACX,CAAC,GACH,SAAS,OACX;AA8BF,MAAa,0BAAmD;CAC9D,QAAQ;CACR,iBAAiB;CACjB,oBAAoB;CACpB,kBAAkB;AACpB;AAEA,MAAa,+BAA6D;CACxE,QAAQ;CACR,iBAAiB;CACjB,oBAAoB;AACtB;AAEA,MAAa,gCAA+D,EAC1E,kBAAkB,sBACpB;AA2IA,MAAa,8BAA2D;CACtE,YAAY;CACZ,kBAAkB;CAClB,qBAAqB;CACrB,qBAAqB;AACvB;AAEA,MAAa,yCAAiF;CAC5F,YAAY;CACZ,qBAAqB;CACrB,qBAAqB;AACvB;AAEA,MAAa,sCAA2E,EACtF,kBAAkB,kCACpB;AAsJA,MAAa,2BAA2B,UAEtC,KAAK,UACH,MAAM,eAAe,KAAA,IACjB,CAAC,MAAM,IAAI,IACX;CACE;CACA,MAAM,WAAW;CACjB,MAAM,WAAW;CACjB,MAAM,eAAe,KAAA,IAAY,OAAO,SAAS,cAAc,MAAM,UAAU;AACjF,CACN;;;;;;AAQF,MAAa,UAA2B,OAAU,QAChD,gBAAgB,KAAK,CAAC,CAAC;AAEzB,MAAa,gBACX,YACiC,OAAO,YAAY,OAAO;;AAK7D,MAAa,qBACX,YASA,MAAM,cACJ,OAAO,IAAI,UAAU,EAAE,WAAW,sBAChC,QAAQ,KAAK,WAAW,SAAS,CAAC,CAAC,KAAK,QAAQ,IAAI,iBAAiB,eAAe,CAAC,CACvF,CACF;;AAGF,MAAa,yBACX,YASA,MAAM,cACJ,OAAO,IAAI,UAAU,EAAE,oBAAoB,+BACzC,QAAQ,KAAK,oBAAoB,kBAAkB,CAAC,CAAC,KACnD,QAAQ,IAAI,0BAA0B,wBAAwB,CAChE,CACF,CACF"}
|
|
1
|
+
{"version":3,"file":"model.mjs","names":[],"sources":["../../src/drizzle/model.ts"],"sourcesContent":["import {\n ExternalIdentityMutation,\n SubjectProvisioner,\n type SubjectProvisioningInput,\n type ExternalIdentity,\n type LoginIdentifier,\n} from \"@yielded/auth/Identity\";\nimport { getTableColumns, type AnyColumn, type InferInsertModel, type Table } from \"drizzle-orm\";\nimport { Context, DateTime, Effect, Layer } from \"effect\";\n\nexport type CommitMode = \"interactive\" | \"synchronous\" | \"batch\";\n\nexport {\n PersistenceMappingError,\n isMappedConstraintConflict,\n} from \"@yielded/auth-persistence/Adapter\";\n\nimport type { PersistenceMappingError, SubjectIdCodec } from \"@yielded/auth-persistence/Adapter\";\n\nexport interface InstantCodec<NativeInstant> {\n readonly encode: (instant: DateTime.Utc) => NativeInstant;\n readonly decode: (native: NativeInstant) => Effect.Effect<DateTime.Utc, PersistenceMappingError>;\n}\n\ntype ColumnKey<T extends Table> = Extract<keyof T[\"_\"][\"columns\"], string>;\n\nexport interface RequiredIdentityConstraints {\n readonly identifier: \"unique(namespace,value)\";\n readonly externalIdentity: \"unique(provider,issuer,subject)\";\n readonly provisioningRequest: \"unique(requestId)\";\n readonly provisioningSubject: \"notNull(provisioningRequest.subjectId)\";\n}\n\nexport interface RequiredSubjectProvisioningConstraints {\n readonly identifier: \"unique(namespace,value)\";\n readonly provisioningRequest: \"unique(requestId)\";\n readonly provisioningSubject: \"notNull(provisioningRequest.subjectId)\";\n}\n\nexport interface RequiredExternalIdentityConstraints {\n readonly externalIdentity: \"unique(provider,issuer,subject)\";\n}\n\nexport const requiredIdentityConstraints: RequiredIdentityConstraints = {\n identifier: \"unique(namespace,value)\",\n externalIdentity: \"unique(provider,issuer,subject)\",\n provisioningRequest: \"unique(requestId)\",\n provisioningSubject: \"notNull(provisioningRequest.subjectId)\",\n};\n\nexport const requiredSubjectProvisioningConstraints: RequiredSubjectProvisioningConstraints = {\n identifier: \"unique(namespace,value)\",\n provisioningRequest: \"unique(requestId)\",\n provisioningSubject: \"notNull(provisioningRequest.subjectId)\",\n};\n\nexport const requiredExternalIdentityConstraints: RequiredExternalIdentityConstraints = {\n externalIdentity: \"unique(provider,issuer,subject)\",\n};\n\nexport type { SubjectIdCodec } from \"@yielded/auth-persistence/Adapter\";\n\nexport interface SubjectProvisioningTables<\n Subject extends Table,\n Identifier extends Table,\n Request extends Table,\n NativeId,\n> {\n readonly constraints: RequiredSubjectProvisioningConstraints;\n readonly subject: {\n readonly table: Subject;\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n readonly encodeInsert: (\n input: SubjectProvisioningInput,\n allocatedId: NativeId | undefined,\n ) => InferInsertModel<Subject>;\n readonly allocateId?: Effect.Effect<NativeId, PersistenceMappingError>;\n /** Required instead of allocateId when a synchronous-only DO transaction preallocates IDs. */\n readonly allocateIdSync?: () => NativeId;\n /** Decodes MySQL `$returningId()` for an autoincrement/runtime-default key. */\n readonly decodeGeneratedId?: (\n rows: ReadonlyArray<unknown>,\n ) => Effect.Effect<NativeId, PersistenceMappingError>;\n };\n readonly identifier: {\n readonly table: Identifier;\n readonly namespace: ColumnKey<Identifier>;\n readonly value: ColumnKey<Identifier>;\n readonly subjectId: ColumnKey<Identifier>;\n readonly encodeInsert: (\n identifier: LoginIdentifier,\n subjectId: NativeId,\n verifiedAt: DateTime.Utc | undefined,\n ) => InferInsertModel<Identifier>;\n };\n readonly provisioningRequest: {\n readonly table: Request;\n readonly requestId: ColumnKey<Request>;\n readonly fingerprint: ColumnKey<Request>;\n readonly subjectId: ColumnKey<Request>;\n readonly encodeInsert: (\n requestId: string,\n fingerprint: string,\n subjectId: NativeId,\n ) => InferInsertModel<Request>;\n };\n readonly subjectId: SubjectIdCodec<NativeId>;\n /** Narrows only database constraint failures; every other cause is unavailable. */\n readonly isConstraintConflict: (cause: unknown) => boolean;\n}\n\nexport interface ExternalIdentityTables<Subject extends Table, External extends Table, NativeId> {\n readonly constraints: RequiredExternalIdentityConstraints;\n readonly subject: {\n readonly table: Subject;\n readonly id: ColumnKey<Subject>;\n readonly status: ColumnKey<Subject>;\n readonly isActiveStatus: (value: unknown) => boolean;\n };\n readonly externalIdentity: {\n readonly table: External;\n readonly provider: ColumnKey<External>;\n readonly issuer: ColumnKey<External>;\n readonly subject: ColumnKey<External>;\n readonly subjectId: ColumnKey<External>;\n readonly encodeInsert: (\n identity: ExternalIdentity,\n subjectId: NativeId,\n ) => InferInsertModel<External>;\n };\n readonly subjectId: SubjectIdCodec<NativeId>;\n readonly isConstraintConflict: (cause: unknown) => boolean;\n}\n\nexport interface IdentityTables<\n Subject extends Table,\n Identifier extends Table,\n External extends Table,\n Request extends Table,\n NativeId,\n> {\n readonly constraints: RequiredIdentityConstraints;\n readonly subject: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>[\"subject\"];\n readonly identifier: SubjectProvisioningTables<\n Subject,\n Identifier,\n Request,\n NativeId\n >[\"identifier\"];\n readonly externalIdentity: ExternalIdentityTables<\n Subject,\n External,\n NativeId\n >[\"externalIdentity\"];\n readonly provisioningRequest: SubjectProvisioningTables<\n Subject,\n Identifier,\n Request,\n NativeId\n >[\"provisioningRequest\"];\n readonly subjectId: SubjectIdCodec<NativeId>;\n readonly isConstraintConflict: (cause: unknown) => boolean;\n}\n\n/** Extra encoders used by D1's ordered batch when the subject id is database-generated. */\nexport interface D1SubjectProvisioningMapping<\n Subject extends Table,\n Identifier extends Table,\n Request extends Table,\n NativeId,\n> extends SubjectProvisioningTables<Subject, Identifier, Request, NativeId> {\n readonly d1: {\n readonly requestInsertWithoutSubject: (\n requestId: string,\n fingerprint: string,\n ) => Partial<InferInsertModel<Request>>;\n readonly identifierInsertWithoutSubject: (\n identifier: LoginIdentifier,\n verifiedAt: DateTime.Utc | undefined,\n ) => Partial<InferInsertModel<Identifier>>;\n /** Unshadowed hidden-rowid alias; omit for WITHOUT ROWID or preallocated IDs. */\n readonly generatedRowIdAlias?: \"rowid\" | \"_rowid_\" | \"oid\";\n };\n}\n\nexport interface D1ExternalIdentityMapping<\n Subject extends Table,\n External extends Table,\n NativeId,\n> extends ExternalIdentityTables<Subject, External, NativeId> {\n readonly d1: {\n readonly activeStatusValue: unknown;\n };\n}\n\nexport interface D1GeneratedIdentityMapping<\n Subject extends Table,\n Identifier extends Table,\n External extends Table,\n Request extends Table,\n NativeId,\n> extends IdentityTables<Subject, Identifier, External, Request, NativeId> {\n readonly d1: D1SubjectProvisioningMapping<Subject, Identifier, Request, NativeId>[\"d1\"] &\n D1ExternalIdentityMapping<Subject, External, NativeId>[\"d1\"];\n}\n\nexport const provisioningFingerprint = (input: SubjectProvisioningInput): string =>\n // oxlint-disable-next-line no-restricted-properties -- stable internal provisioning fingerprint, never external JSON.\n JSON.stringify(\n input.identifier === undefined\n ? [\"v1\", null]\n : [\n \"v1\",\n input.identifier.namespace,\n input.identifier.value,\n input.verifiedAt === undefined ? null : DateTime.toEpochMillis(input.verifiedAt),\n ],\n );\n\n/**\n * Drizzle wraps Effect SQL failures before adapters observe them. Give the\n * consumer classifier each semantic wrapper in the short `cause`/`reason`\n * chain without exposing query text or bound parameters through public errors.\n */\n\nexport const column = <T extends Table>(table: T, key: ColumnKey<T>): AnyColumn =>\n getTableColumns(table)[key] as AnyColumn;\n\nexport const updateValues = <T extends Table>(\n entries: ReadonlyArray<readonly [ColumnKey<T>, unknown]>,\n): Partial<InferInsertModel<T>> => Object.fromEntries(entries) as Partial<InferInsertModel<T>>;\n\n/** Acquire an application database in Effect and expose the identity services as one layer. */\nexport const identityServicesLayer = <E, R>(\n acquire: Effect.Effect<\n {\n readonly subjectProvisioner: SubjectProvisioner[\"Service\"];\n readonly externalIdentityMutation: ExternalIdentityMutation[\"Service\"];\n },\n E,\n R\n >,\n) =>\n Layer.effectContext(\n Effect.map(acquire, ({ subjectProvisioner, externalIdentityMutation }) =>\n Context.make(SubjectProvisioner, subjectProvisioner).pipe(\n Context.add(ExternalIdentityMutation, externalIdentityMutation),\n ),\n ),\n );\n"],"mappings":";;;;;AA2CA,MAAa,8BAA2D;CACtE,YAAY;CACZ,kBAAkB;CAClB,qBAAqB;CACrB,qBAAqB;AACvB;AAEA,MAAa,yCAAiF;CAC5F,YAAY;CACZ,qBAAqB;CACrB,qBAAqB;AACvB;AAEA,MAAa,sCAA2E,EACtF,kBAAkB,kCACpB;AAsJA,MAAa,2BAA2B,UAEtC,KAAK,UACH,MAAM,eAAe,KAAA,IACjB,CAAC,MAAM,IAAI,IACX;CACE;CACA,MAAM,WAAW;CACjB,MAAM,WAAW;CACjB,MAAM,eAAe,KAAA,IAAY,OAAO,SAAS,cAAc,MAAM,UAAU;AACjF,CACN;;;;;;AAQF,MAAa,UAA2B,OAAU,QAChD,gBAAgB,KAAK,CAAC,CAAC;AAEzB,MAAa,gBACX,YACiC,OAAO,YAAY,OAAO;;AAG7D,MAAa,yBACX,YASA,MAAM,cACJ,OAAO,IAAI,UAAU,EAAE,oBAAoB,+BACzC,QAAQ,KAAK,oBAAoB,kBAAkB,CAAC,CAAC,KACnD,QAAQ,IAAI,0BAA0B,wBAAwB,CAChE,CACF,CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
|
|
3
|
+
//#region src/drizzle/mysql-database.d.ts
|
|
4
|
+
declare const Database_base: Context.ServiceClass<Database, "effect-auth/persistence-drizzle/Mysql2/Database", EffectMysql2Database<import("drizzle-orm").TablesRelationalConfig>>;
|
|
5
|
+
/** Application-owned MySQL database used to construct persistence services. */
|
|
6
|
+
export declare class Database extends Database_base {}
|
|
7
|
+
//#endregion
|
|
8
|
+
//# sourceMappingURL=mysql-database.d.mts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
//#region src/drizzle/mysql-database.ts
|
|
3
|
+
/** Application-owned MySQL database used to construct persistence services. */
|
|
4
|
+
var Database = class extends Context.Service()("effect-auth/persistence-drizzle/Mysql2/Database") {};
|
|
5
|
+
//#endregion
|
|
6
|
+
export { Database };
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=mysql-database.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mysql-database.mjs","names":[],"sources":["../../src/drizzle/mysql-database.ts"],"sourcesContent":["import type { AnyRelations } from \"drizzle-orm\";\nimport type { EffectMysql2Database } from \"drizzle-orm/effect-mysql2\";\nimport { Context } from \"effect\";\n\n/** Application-owned MySQL database used to construct persistence services. */\nexport class Database extends Context.Service<Database, EffectMysql2Database<AnyRelations>>()(\n \"effect-auth/persistence-drizzle/Mysql2/Database\",\n) {}\n"],"mappings":";;;AAKA,IAAa,WAAb,cAA8B,QAAQ,QAAsD,CAAC,CAC3F,iDACF,CAAC,CAAC,CAAC"}
|
|
@@ -2,26 +2,27 @@ import { EmailAddressMapping, EmailRegistrationMapping, EmailSignInMapping } fro
|
|
|
2
2
|
import { ProofPersistenceMapping } from "./proof-model.mjs";
|
|
3
3
|
import { EmailRegistrationAuthority } from "./email-registration.mjs";
|
|
4
4
|
import { SuppliedService } from "./SuppliedService.mjs";
|
|
5
|
+
import { Database as Database$1 } from "./mysql-database.mjs";
|
|
5
6
|
import { AnyRelations } from "drizzle-orm";
|
|
6
7
|
import { Effect } from "effect";
|
|
7
8
|
import { HookConfigurationError, LifecycleHooks } from "@yielded/auth/Hooks";
|
|
8
9
|
import { EmailAddressPersistence, EmailUnavailable } from "@yielded/auth/Email";
|
|
9
10
|
import { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
|
|
10
|
-
import { SqlError } from "effect/
|
|
11
|
+
import { SqlError } from "effect/sql/SqlError";
|
|
11
12
|
import { AnyMySqlTable } from "drizzle-orm/mysql-core";
|
|
12
13
|
//#region src/drizzle/mysql-emails.d.ts
|
|
13
14
|
type Database = EffectMysql2Database<AnyRelations>;
|
|
14
15
|
type TransactionOf<D extends Database> = Parameters<Parameters<D["transaction"]>[0]>[0];
|
|
15
16
|
type ProofMapping = ProofPersistenceMapping<any, any, any, any, any, any, any, any, any, any, any, any>;
|
|
16
|
-
export declare const makeMysqlEmailSignInServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, NativeId>(
|
|
17
|
+
export declare const makeMysqlEmailSignInServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, NativeId>(mapping: EmailSignInMapping<S, I, C, NativeId>) => Effect.Effect<{
|
|
17
18
|
emailSignInTargets: {
|
|
18
19
|
readonly lookup: (input: {
|
|
19
20
|
readonly moduleId: string;
|
|
20
21
|
readonly identifier: import("@yielded/auth/Identity").LoginIdentifier;
|
|
21
22
|
}) => Effect.Effect<import("effect/Option").Option<import("@yielded/auth/Email").EmailCredentialSnapshot>, EmailUnavailable>;
|
|
22
23
|
};
|
|
23
|
-
}, never,
|
|
24
|
-
export declare const makeMysqlEmailAddressServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, M extends AnyMySqlTable, NativeId>(
|
|
24
|
+
}, never, Database$1>;
|
|
25
|
+
export declare const makeMysqlEmailAddressServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, M extends AnyMySqlTable, NativeId>(mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>, proofMapping: ProofMapping) => Effect.Effect<{
|
|
25
26
|
emailAddressPersistence: {
|
|
26
27
|
readonly target: (input: {
|
|
27
28
|
readonly moduleId: string;
|
|
@@ -40,7 +41,7 @@ export declare const makeMysqlEmailAddressServices: <S extends AnyMySqlTable, I
|
|
|
40
41
|
readonly hasMore: boolean;
|
|
41
42
|
}, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, EmailUnavailable>;
|
|
42
43
|
};
|
|
43
|
-
}, never, LifecycleHooks>;
|
|
44
|
+
}, never, Database$1 | LifecycleHooks>;
|
|
44
45
|
export declare function coordinateMysqlEmailAddress<D extends Database, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, M extends AnyMySqlTable, NativeId, Out, E, R, DatabaseError, DatabaseRequirements>(acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>, options: {
|
|
45
46
|
readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;
|
|
46
47
|
readonly proofMapping: ProofMapping;
|
|
@@ -51,9 +52,9 @@ export declare function coordinateMysqlEmailAddress<D extends Database, S extend
|
|
|
51
52
|
readonly proofMapping: ProofMapping;
|
|
52
53
|
readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;
|
|
53
54
|
}, body: Effect.Effect<Out, E, R>): Effect.Effect<Out, E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError, Exclude<R, EmailAddressPersistence | TxId> | LifecycleHooks | DatabaseRequirements>;
|
|
54
|
-
export declare const makeMysqlEmailRegistrationServices: <Registration, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, Rq extends AnyMySqlTable, NativeId>(
|
|
55
|
+
export declare const makeMysqlEmailRegistrationServices: <Registration, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, Rq extends AnyMySqlTable, NativeId>(mapping: EmailRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>, proofMapping: ProofMapping) => Effect.Effect<{
|
|
55
56
|
registrationAuthority: EmailRegistrationAuthority<Registration>;
|
|
56
|
-
}, never, LifecycleHooks>;
|
|
57
|
+
}, never, Database$1 | LifecycleHooks>;
|
|
57
58
|
export declare function coordinateMysqlEmailRegistration<TargetId, Registration, D extends Database, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, Rq extends AnyMySqlTable, NativeId, Out, E, R, DatabaseError, DatabaseRequirements>(acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>, options: {
|
|
58
59
|
readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;
|
|
59
60
|
readonly proofMapping: ProofMapping;
|
|
@@ -1,32 +1,36 @@
|
|
|
1
|
+
import { acquireTransactionService, transactionService } from "./standalone-guard.mjs";
|
|
2
|
+
import { CurrentEmailSql } from "./email-sql.mjs";
|
|
1
3
|
import { coordinateTargetEmailAddress, coordinateTargetEmailRegistration, makeTargetEmailAddressServices, makeTargetEmailRegistrationServices, makeTargetEmailSignInServices, sqlClientEmailStandaloneGuard } from "./email-target.mjs";
|
|
2
4
|
import { sqlClientProofStandaloneGuard } from "./proof-target.mjs";
|
|
5
|
+
import { nativeDatabase } from "./native-database.mjs";
|
|
6
|
+
import { Database } from "./mysql-database.mjs";
|
|
3
7
|
import { Context, Effect } from "effect";
|
|
4
8
|
import { EmailAddressPersistence } from "@yielded/auth/Email";
|
|
5
9
|
//#region src/drizzle/mysql-emails.ts
|
|
6
|
-
const configuration = (
|
|
10
|
+
const configuration = (service) => ({
|
|
7
11
|
mode: "interactive",
|
|
8
12
|
locking: true,
|
|
9
|
-
standaloneGuard: sqlClientEmailStandaloneGuard(
|
|
13
|
+
standaloneGuard: sqlClientEmailStandaloneGuard(service),
|
|
10
14
|
generatedSubjectRows: (query) => query.$returningId(),
|
|
11
15
|
proof: {
|
|
12
16
|
mode: "interactive",
|
|
13
17
|
locking: true,
|
|
14
|
-
standaloneGuard: sqlClientProofStandaloneGuard(
|
|
18
|
+
standaloneGuard: sqlClientProofStandaloneGuard(service),
|
|
15
19
|
insertIfAbsent: (query, selfKey, selfValue) => query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } })
|
|
16
20
|
}
|
|
17
21
|
});
|
|
18
|
-
const makeMysqlEmailSignInServices = (
|
|
19
|
-
const makeMysqlEmailAddressServices = (
|
|
22
|
+
const makeMysqlEmailSignInServices = (mapping) => Effect.flatMap(Effect.map(acquireTransactionService(Database), configuration), (configuration) => makeTargetEmailSignInServices(mapping, configuration)).pipe(Effect.provideServiceEffect(CurrentEmailSql, nativeDatabase(Database)));
|
|
23
|
+
const makeMysqlEmailAddressServices = (mapping, proofMapping) => Effect.flatMap(Effect.map(acquireTransactionService(Database), configuration), (configuration) => makeTargetEmailAddressServices(mapping, proofMapping, configuration)).pipe(Effect.provideServiceEffect(CurrentEmailSql, nativeDatabase(Database)));
|
|
20
24
|
function coordinateMysqlEmailAddress(acquire, options, body) {
|
|
21
|
-
return Effect.flatMap(acquire, (database) => coordinateTargetEmailAddress(database, options.mapping, options.proofMapping, configuration(database), (transaction, services) => {
|
|
25
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetEmailAddress(database, options.mapping, options.proofMapping, configuration(transactionService(database)), (transaction, services) => {
|
|
22
26
|
const provided = Context.make(EmailAddressPersistence, services.emailAddressPersistence);
|
|
23
27
|
const work = Effect.provideContext(body, provided);
|
|
24
28
|
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
25
29
|
}));
|
|
26
30
|
}
|
|
27
|
-
const makeMysqlEmailRegistrationServices = (
|
|
31
|
+
const makeMysqlEmailRegistrationServices = (mapping, proofMapping) => Effect.flatMap(Effect.map(acquireTransactionService(Database), configuration), (configuration) => makeTargetEmailRegistrationServices(mapping, proofMapping, configuration)).pipe(Effect.provideServiceEffect(CurrentEmailSql, nativeDatabase(Database)));
|
|
28
32
|
function coordinateMysqlEmailRegistration(acquire, options, body) {
|
|
29
|
-
return Effect.flatMap(acquire, (database) => coordinateTargetEmailRegistration(database, options.mapping, options.proofMapping, configuration(database), (transaction, services) => {
|
|
33
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetEmailRegistration(database, options.mapping, options.proofMapping, configuration(transactionService(database)), (transaction, services) => {
|
|
30
34
|
const provided = Context.make(options.target, services.registrationAuthority);
|
|
31
35
|
const work = Effect.provideContext(body, provided);
|
|
32
36
|
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql-emails.mjs","names":[],"sources":["../../src/drizzle/mysql-emails.ts"],"sourcesContent":["import { EmailAddressPersistence, type EmailUnavailable } from \"@yielded/auth/Email\";\nimport type { LifecycleHooks, HookConfigurationError } from \"@yielded/auth/Hooks\";\n/* oxlint-disable no-explicit-any -- proof mapping tables are independently typed by the proof owner; this driver forwards them unchanged to the shared target. */\nimport type { AnyRelations } from \"drizzle-orm\";\nimport type { EffectMysql2Database } from \"drizzle-orm/effect-mysql2\";\nimport type { AnyMySqlTable } from \"drizzle-orm/mysql-core\";\nimport { Effect, Context } from \"effect\";\nimport type { SqlError } from \"effect/unstable/sql/SqlError\";\n\nimport type {\n EmailAddressMapping,\n EmailRegistrationMapping,\n EmailSignInMapping,\n} from \"./email-model\";\nimport type { EmailRegistrationAuthority } from \"./email-registration\";\nimport type { EmailSqlQuery } from \"./email-sql\";\nimport {\n coordinateTargetEmailAddress,\n coordinateTargetEmailRegistration,\n makeTargetEmailAddressServices,\n makeTargetEmailRegistrationServices,\n makeTargetEmailSignInServices,\n sqlClientEmailStandaloneGuard,\n} from \"./email-target\";\nimport type { ProofPersistenceMapping } from \"./proof-model\";\nimport type { ProofSqlQuery } from \"./proof-sql\";\nimport { sqlClientProofStandaloneGuard } from \"./proof-target\";\nimport type { SuppliedService } from \"./SuppliedService\";\n\ntype Database = EffectMysql2Database<AnyRelations>;\ntype TransactionOf<D extends Database> = Parameters<Parameters<D[\"transaction\"]>[0]>[0];\ntype ProofMapping = ProofPersistenceMapping<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>;\n\nconst configuration = (database: Database) => ({\n mode: \"interactive\" as const,\n locking: true,\n standaloneGuard: sqlClientEmailStandaloneGuard(database),\n generatedSubjectRows: (query: EmailSqlQuery) => query.$returningId(),\n proof: {\n mode: \"interactive\" as const,\n locking: true,\n standaloneGuard: sqlClientProofStandaloneGuard(database),\n insertIfAbsent: (query: ProofSqlQuery, selfKey: string, selfValue: unknown) =>\n query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } }),\n },\n});\n\nexport const makeMysqlEmailSignInServices = <\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n NativeId,\n>(\n database: Database,\n mapping: EmailSignInMapping<S, I, C, NativeId>,\n) => makeTargetEmailSignInServices(database, mapping, configuration(database));\n\nexport const makeMysqlEmailAddressServices = <\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n>(\n database: Database,\n mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>,\n proofMapping: ProofMapping,\n) => makeTargetEmailAddressServices(database, mapping, proofMapping, configuration(database));\n\nexport function coordinateMysqlEmailAddress<\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly transaction?: never;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, EmailAddressPersistence> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailAddress<\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, EmailAddressPersistence | TxId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailAddress<\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, EmailAddressPersistence> | LifecycleHooks | DatabaseRequirements\n> {\n return Effect.flatMap(acquire, (database) =>\n coordinateTargetEmailAddress<TransactionOf<D>, Out, E, Exclude<R, EmailAddressPersistence>>(\n database,\n options.mapping,\n options.proofMapping,\n configuration(database),\n (\n transaction: TransactionOf<D>,\n services: { readonly emailAddressPersistence: EmailAddressPersistence[\"Service\"] },\n ) => {\n const provided = Context.make(EmailAddressPersistence, services.emailAddressPersistence);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n}\n\nexport const makeMysqlEmailRegistrationServices = <\n Registration,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n>(\n database: Database,\n mapping: EmailRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>,\n proofMapping: ProofMapping,\n) =>\n makeTargetEmailRegistrationServices<Registration>(\n database,\n mapping,\n proofMapping,\n configuration(database),\n );\n\nexport function coordinateMysqlEmailRegistration<\n TargetId,\n Registration,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;\n readonly transaction?: never;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailRegistration<\n TargetId,\n Registration,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId | TxId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailRegistration<\n TargetId,\n Registration,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements\n> {\n return Effect.flatMap(acquire, (database) =>\n coordinateTargetEmailRegistration<Registration, TransactionOf<D>, Out, E, Exclude<R, TargetId>>(\n database,\n options.mapping,\n options.proofMapping,\n configuration(database),\n (\n transaction: TransactionOf<D>,\n services: { readonly registrationAuthority: EmailRegistrationAuthority<Registration> },\n ) => {\n const provided = Context.make(options.target, services.registrationAuthority);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n}\n"],"mappings":";;;;;AA8CA,MAAM,iBAAiB,cAAwB;CAC7C,MAAM;CACN,SAAS;CACT,iBAAiB,8BAA8B,QAAQ;CACvD,uBAAuB,UAAyB,MAAM,aAAa;CACnE,OAAO;EACL,MAAM;EACN,SAAS;EACT,iBAAiB,8BAA8B,QAAQ;EACvD,iBAAiB,OAAsB,SAAiB,cACtD,MAAM,qBAAqB,EAAE,KAAK,GAAG,UAAU,UAAU,EAAE,CAAC;CAChE;AACF;AAEA,MAAa,gCAMX,UACA,YACG,8BAA8B,UAAU,SAAS,cAAc,QAAQ,CAAC;AAE7E,MAAa,iCAQX,UACA,SACA,iBACG,+BAA+B,UAAU,SAAS,cAAc,cAAc,QAAQ,CAAC;AA0D5F,SAAgB,4BAgBd,SACA,SAKA,MAKA;CACA,OAAO,OAAO,QAAQ,UAAU,aAC9B,6BACE,UACA,QAAQ,SACR,QAAQ,cACR,cAAc,QAAQ,IAEpB,aACA,aACG;EACH,MAAM,WAAW,QAAQ,KAAK,yBAAyB,SAAS,uBAAuB;EACvF,MAAM,OAAO,OAAO,eAAe,MAAM,QAAQ;EAEjD,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;CAC1F,CACF,CACF;AACF;AAEA,MAAa,sCASX,UACA,SACA,iBAEA,oCACE,UACA,SACA,cACA,cAAc,QAAQ,CACxB;AAgEF,SAAgB,iCAkBd,SACA,SAMA,MAKA;CACA,OAAO,OAAO,QAAQ,UAAU,aAC9B,kCACE,UACA,QAAQ,SACR,QAAQ,cACR,cAAc,QAAQ,IAEpB,aACA,aACG;EACH,MAAM,WAAW,QAAQ,KAAK,QAAQ,QAAQ,SAAS,qBAAqB;EAC5E,MAAM,OAAO,OAAO,eAAe,MAAM,QAAQ;EAEjD,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;CAC1F,CACF,CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"mysql-emails.mjs","names":["DatabaseService"],"sources":["../../src/drizzle/mysql-emails.ts"],"sourcesContent":["import { EmailAddressPersistence, type EmailUnavailable } from \"@yielded/auth/Email\";\nimport type { LifecycleHooks, HookConfigurationError } from \"@yielded/auth/Hooks\";\n/* oxlint-disable no-explicit-any -- proof mapping tables are independently typed by the proof owner; this driver forwards them unchanged to the shared target. */\nimport type { AnyRelations } from \"drizzle-orm\";\nimport type { EffectMysql2Database } from \"drizzle-orm/effect-mysql2\";\nimport type { AnyMySqlTable } from \"drizzle-orm/mysql-core\";\nimport { Effect, Context } from \"effect\";\nimport type { SqlError } from \"effect/sql/SqlError\";\n\nimport type {\n EmailAddressMapping,\n EmailRegistrationMapping,\n EmailSignInMapping,\n} from \"./email-model\";\nimport type { EmailRegistrationAuthority } from \"./email-registration\";\nimport { CurrentEmailSql } from \"./email-sql\";\nimport type { EmailSqlQuery } from \"./email-sql\";\nimport {\n coordinateTargetEmailAddress,\n coordinateTargetEmailRegistration,\n makeTargetEmailAddressServices,\n makeTargetEmailRegistrationServices,\n makeTargetEmailSignInServices,\n sqlClientEmailStandaloneGuard,\n} from \"./email-target\";\nimport { Database as DatabaseService } from \"./mysql-database\";\nimport { nativeDatabase } from \"./native-database\";\nimport type { ProofPersistenceMapping } from \"./proof-model\";\nimport type { ProofSqlQuery } from \"./proof-sql\";\nimport { sqlClientProofStandaloneGuard } from \"./proof-target\";\nimport {\n type TransactionService,\n acquireTransactionService,\n transactionService,\n} from \"./standalone-guard\";\nimport type { SuppliedService } from \"./SuppliedService\";\n\ntype Database = EffectMysql2Database<AnyRelations>;\ntype TransactionOf<D extends Database> = Parameters<Parameters<D[\"transaction\"]>[0]>[0];\ntype ProofMapping = ProofPersistenceMapping<\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>;\n\nconst configuration = (service: TransactionService | undefined) => ({\n mode: \"interactive\" as const,\n locking: true,\n standaloneGuard: sqlClientEmailStandaloneGuard(service),\n generatedSubjectRows: (query: EmailSqlQuery) => query.$returningId(),\n proof: {\n mode: \"interactive\" as const,\n locking: true,\n standaloneGuard: sqlClientProofStandaloneGuard(service),\n insertIfAbsent: (query: ProofSqlQuery, selfKey: string, selfValue: unknown) =>\n query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } }),\n },\n});\n\nexport const makeMysqlEmailSignInServices = <\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n NativeId,\n>(\n mapping: EmailSignInMapping<S, I, C, NativeId>,\n) =>\n Effect.flatMap(\n Effect.map(acquireTransactionService(DatabaseService), configuration),\n (configuration) => makeTargetEmailSignInServices(mapping, configuration),\n ).pipe(Effect.provideServiceEffect(CurrentEmailSql, nativeDatabase(DatabaseService)));\n\nexport const makeMysqlEmailAddressServices = <\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n>(\n mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>,\n proofMapping: ProofMapping,\n) =>\n Effect.flatMap(\n Effect.map(acquireTransactionService(DatabaseService), configuration),\n (configuration) => makeTargetEmailAddressServices(mapping, proofMapping, configuration),\n ).pipe(Effect.provideServiceEffect(CurrentEmailSql, nativeDatabase(DatabaseService)));\n\nexport function coordinateMysqlEmailAddress<\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly transaction?: never;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, EmailAddressPersistence> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailAddress<\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, EmailAddressPersistence | TxId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailAddress<\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n M extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, EmailAddressPersistence> | LifecycleHooks | DatabaseRequirements\n> {\n return Effect.flatMap(acquire, (database) =>\n coordinateTargetEmailAddress<TransactionOf<D>, Out, E, Exclude<R, EmailAddressPersistence>>(\n database,\n options.mapping,\n options.proofMapping,\n configuration(transactionService(database)),\n (\n transaction: TransactionOf<D>,\n services: { readonly emailAddressPersistence: EmailAddressPersistence[\"Service\"] },\n ) => {\n const provided = Context.make(EmailAddressPersistence, services.emailAddressPersistence);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n}\n\nexport const makeMysqlEmailRegistrationServices = <\n Registration,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n>(\n mapping: EmailRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>,\n proofMapping: ProofMapping,\n) =>\n Effect.flatMap(\n Effect.map(acquireTransactionService(DatabaseService), configuration),\n (configuration) =>\n makeTargetEmailRegistrationServices<Registration>(mapping, proofMapping, configuration),\n ).pipe(Effect.provideServiceEffect(CurrentEmailSql, nativeDatabase(DatabaseService)));\n\nexport function coordinateMysqlEmailRegistration<\n TargetId,\n Registration,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;\n readonly transaction?: never;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailRegistration<\n TargetId,\n Registration,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId | TxId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMysqlEmailRegistration<\n TargetId,\n Registration,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n Rq extends AnyMySqlTable,\n NativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;\n readonly proofMapping: ProofMapping;\n readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements\n> {\n return Effect.flatMap(acquire, (database) =>\n coordinateTargetEmailRegistration<Registration, TransactionOf<D>, Out, E, Exclude<R, TargetId>>(\n database,\n options.mapping,\n options.proofMapping,\n configuration(transactionService(database)),\n (\n transaction: TransactionOf<D>,\n services: { readonly registrationAuthority: EmailRegistrationAuthority<Registration> },\n ) => {\n const provided = Context.make(options.target, services.registrationAuthority);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n}\n"],"mappings":";;;;;;;;;AAsDA,MAAM,iBAAiB,aAA6C;CAClE,MAAM;CACN,SAAS;CACT,iBAAiB,8BAA8B,OAAO;CACtD,uBAAuB,UAAyB,MAAM,aAAa;CACnE,OAAO;EACL,MAAM;EACN,SAAS;EACT,iBAAiB,8BAA8B,OAAO;EACtD,iBAAiB,OAAsB,SAAiB,cACtD,MAAM,qBAAqB,EAAE,KAAK,GAAG,UAAU,UAAU,EAAE,CAAC;CAChE;AACF;AAEA,MAAa,gCAMX,YAEA,OAAO,QACL,OAAO,IAAI,0BAA0BA,QAAe,GAAG,aAAa,IACnE,kBAAkB,8BAA8B,SAAS,aAAa,CACzE,CAAC,CAAC,KAAK,OAAO,qBAAqB,iBAAiB,eAAeA,QAAe,CAAC,CAAC;AAEtF,MAAa,iCAQX,SACA,iBAEA,OAAO,QACL,OAAO,IAAI,0BAA0BA,QAAe,GAAG,aAAa,IACnE,kBAAkB,+BAA+B,SAAS,cAAc,aAAa,CACxF,CAAC,CAAC,KAAK,OAAO,qBAAqB,iBAAiB,eAAeA,QAAe,CAAC,CAAC;AA0DtF,SAAgB,4BAgBd,SACA,SAKA,MAKA;CACA,OAAO,OAAO,QAAQ,UAAU,aAC9B,6BACE,UACA,QAAQ,SACR,QAAQ,cACR,cAAc,mBAAmB,QAAQ,CAAC,IAExC,aACA,aACG;EACH,MAAM,WAAW,QAAQ,KAAK,yBAAyB,SAAS,uBAAuB;EACvF,MAAM,OAAO,OAAO,eAAe,MAAM,QAAQ;EAEjD,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;CAC1F,CACF,CACF;AACF;AAEA,MAAa,sCASX,SACA,iBAEA,OAAO,QACL,OAAO,IAAI,0BAA0BA,QAAe,GAAG,aAAa,IACnE,kBACC,oCAAkD,SAAS,cAAc,aAAa,CAC1F,CAAC,CAAC,KAAK,OAAO,qBAAqB,iBAAiB,eAAeA,QAAe,CAAC,CAAC;AAgEtF,SAAgB,iCAkBd,SACA,SAMA,MAKA;CACA,OAAO,OAAO,QAAQ,UAAU,aAC9B,kCACE,UACA,QAAQ,SACR,QAAQ,cACR,cAAc,mBAAmB,QAAQ,CAAC,IAExC,aACA,aACG;EACH,MAAM,WAAW,QAAQ,KAAK,QAAQ,QAAQ,SAAS,qBAAqB;EAC5E,MAAM,OAAO,OAAO,eAAe,MAAM,QAAQ;EAEjD,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;CAC1F,CACF,CACF;AACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PersistenceMappingError, column, isMappedConstraintConflict, provisioningFingerprint } from "./model.mjs";
|
|
2
|
+
import { Database } from "./mysql-database.mjs";
|
|
2
3
|
import { ExternalIdentityMutation, IdentityConflict, IdentityUnavailable, SubjectProvisioned, SubjectProvisioner } from "@yielded/auth/Identity";
|
|
3
4
|
import { and, eq } from "drizzle-orm";
|
|
4
5
|
import { Cause, Effect, Schema } from "effect";
|
|
@@ -7,8 +8,8 @@ import { reportPersistenceFailure } from "@yielded/auth/Persistence";
|
|
|
7
8
|
const unavailable = () => IdentityUnavailable.make();
|
|
8
9
|
const isIdentityFailure = Schema.is(Schema.Union([IdentityConflict, IdentityUnavailable]));
|
|
9
10
|
const mapUnavailable = (effect) => reportPersistenceFailure(effect, isIdentityFailure).pipe(Effect.catchCause((cause) => Effect.failCause(Cause.map(cause, (error) => isIdentityFailure(error) ? error : unavailable()))));
|
|
10
|
-
const makeMysqlSubjectProvisioningServices = (
|
|
11
|
-
const db =
|
|
11
|
+
const makeMysqlSubjectProvisioningServices = Effect.fnUntraced(function* (mapping) {
|
|
12
|
+
const db = yield* Database;
|
|
12
13
|
const requestTable = mapping.provisioningRequest.table;
|
|
13
14
|
const requestIdColumn = column(requestTable, mapping.provisioningRequest.requestId);
|
|
14
15
|
const requestFingerprintColumn = column(requestTable, mapping.provisioningRequest.fingerprint);
|
|
@@ -57,9 +58,9 @@ const makeMysqlSubjectProvisioningServices = (database, mapping) => {
|
|
|
57
58
|
return SubjectProvisioned.make({ subjectId });
|
|
58
59
|
}, mapUnavailable);
|
|
59
60
|
return { subjectProvisioner: SubjectProvisioner.of({ provision }) };
|
|
60
|
-
};
|
|
61
|
-
const makeMysqlExternalIdentityServices = (
|
|
62
|
-
const db =
|
|
61
|
+
});
|
|
62
|
+
const makeMysqlExternalIdentityServices = Effect.fnUntraced(function* (mapping) {
|
|
63
|
+
const db = yield* Database;
|
|
63
64
|
const externalTable = mapping.externalIdentity.table;
|
|
64
65
|
const externalProviderColumn = column(externalTable, mapping.externalIdentity.provider);
|
|
65
66
|
const externalIssuerColumn = column(externalTable, mapping.externalIdentity.issuer);
|
|
@@ -82,10 +83,12 @@ const makeMysqlExternalIdentityServices = (database, mapping) => {
|
|
|
82
83
|
})))._tag === "conflict") return yield* IdentityConflict.make();
|
|
83
84
|
}, mapUnavailable);
|
|
84
85
|
return { externalIdentityMutation: ExternalIdentityMutation.of({ bind }) };
|
|
85
|
-
};
|
|
86
|
-
const makeMysqlIdentityServices = (
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
});
|
|
87
|
+
const makeMysqlIdentityServices = Effect.fnUntraced(function* (mapping) {
|
|
88
|
+
return {
|
|
89
|
+
...yield* makeMysqlSubjectProvisioningServices(mapping),
|
|
90
|
+
...yield* makeMysqlExternalIdentityServices(mapping)
|
|
91
|
+
};
|
|
89
92
|
});
|
|
90
93
|
//#endregion
|
|
91
94
|
export { makeMysqlExternalIdentityServices, makeMysqlIdentityServices, makeMysqlSubjectProvisioningServices };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql-identity.mjs","names":[],"sources":["../../src/drizzle/mysql-identity.ts"],"sourcesContent":["import {\n ExternalIdentityMutation,\n type ExternalIdentity,\n IdentityConflict,\n IdentityUnavailable,\n SubjectProvisioned,\n SubjectProvisioner,\n type SubjectProvisioningInput,\n} from \"@yielded/auth/Identity\";\nimport { reportPersistenceFailure } from \"@yielded/auth/Persistence\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\n/* oxlint-disable no-explicit-any -- Drizzle generic query types are narrowed at this technology boundary. */\nimport { and, eq, type AnyRelations } from \"drizzle-orm\";\nimport type { EffectMysql2Database } from \"drizzle-orm/effect-mysql2\";\nimport type { AnyMySqlTable, MySqlColumn } from \"drizzle-orm/mysql-core\";\nimport { Cause, Effect, Schema } from \"effect\";\n\nimport {\n column,\n isMappedConstraintConflict,\n PersistenceMappingError,\n provisioningFingerprint,\n type ExternalIdentityTables,\n type IdentityTables,\n type SubjectProvisioningTables,\n} from \"./model\";\n\ntype Database = EffectMysql2Database<AnyRelations>;\ntype RuntimeDatabase = EffectMysql2Database<any>;\nconst unavailable = () => IdentityUnavailable.make();\nconst isIdentityFailure = Schema.is(Schema.Union([IdentityConflict, IdentityUnavailable]));\n\nconst mapUnavailable = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n reportPersistenceFailure(effect, isIdentityFailure).pipe(\n Effect.catchCause((cause) =>\n Effect.failCause(\n Cause.map(cause, (error) => (isIdentityFailure(error) ? error : unavailable())),\n ),\n ),\n );\n\nexport const makeMysqlSubjectProvisioningServices = <\n Subject extends AnyMySqlTable,\n Identifier extends AnyMySqlTable,\n Request extends AnyMySqlTable,\n NativeId,\n>(\n database: Database,\n mapping: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>,\n) => {\n const db = database as RuntimeDatabase;\n const requestTable = mapping.provisioningRequest.table;\n\n const requestIdColumn = column(\n requestTable,\n mapping.provisioningRequest.requestId,\n ) as MySqlColumn;\n\n const requestFingerprintColumn = column(\n requestTable,\n mapping.provisioningRequest.fingerprint,\n ) as MySqlColumn;\n\n const requestSubjectColumn = column(\n requestTable,\n mapping.provisioningRequest.subjectId,\n ) as MySqlColumn;\n\n const identifierTable = mapping.identifier.table;\n\n const identifierNamespaceColumn = column(\n identifierTable,\n mapping.identifier.namespace,\n ) as MySqlColumn;\n\n const identifierValueColumn = column(identifierTable, mapping.identifier.value) as MySqlColumn;\n\n const findReceipt = Effect.fn(\"DrizzleMysqlIdentity.findReceipt\")(function* (requestId: string) {\n const rows = yield* db\n .select({ fingerprint: requestFingerprintColumn, subjectId: requestSubjectColumn })\n .from(requestTable as any)\n .where(eq(requestIdColumn, requestId))\n .limit(1);\n\n return rows[0];\n });\n\n const provision = Effect.fn(\"DrizzleMysqlIdentity.provision\")(function* (\n input: SubjectProvisioningInput,\n ) {\n const fingerprint = provisioningFingerprint(input);\n const existing = yield* findReceipt(input.requestId);\n\n if (existing !== undefined) {\n if (existing.fingerprint !== fingerprint) return yield* IdentityConflict.make();\n const subjectId = yield* mapping.subjectId.toSubject(existing.subjectId as NativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }\n\n const attempt = db.transaction((tx) =>\n Effect.gen(function* () {\n const allocated =\n mapping.subject.allocateId === undefined\n ? mapping.subject.allocateIdSync?.()\n : yield* mapping.subject.allocateId;\n\n const insert = tx\n .insert(mapping.subject.table as any)\n .values(mapping.subject.encodeInsert(input, allocated) as any);\n\n let nativeId = allocated;\n\n if (nativeId === undefined) {\n if (mapping.subject.decodeGeneratedId === undefined)\n return yield* PersistenceMappingError.make({\n operation: \"provisionSubject.generatedId\",\n cause: new Error(\"MySQL generated IDs require decodeGeneratedId\"),\n });\n const ids = yield* insert.$returningId();\n\n nativeId = yield* mapping.subject.decodeGeneratedId(ids as ReadonlyArray<unknown>);\n } else {\n yield* insert;\n }\n if (input.identifier !== undefined)\n yield* tx\n .insert(identifierTable as any)\n .values(\n mapping.identifier.encodeInsert(input.identifier, nativeId, input.verifiedAt) as any,\n );\n yield* tx\n .insert(requestTable as any)\n .values(\n mapping.provisioningRequest.encodeInsert(input.requestId, fingerprint, nativeId) as any,\n );\n\n return nativeId;\n }),\n );\n\n const nativeId = yield* attempt.pipe(\n Effect.catchCause(\n (\n cause,\n ): Effect.Effect<\n NativeId,\n | Effect.Error<typeof attempt>\n | Effect.Error<ReturnType<typeof findReceipt>>\n | IdentityConflict\n > => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return findReceipt(input.requestId).pipe(\n Effect.flatMap((receipt) => {\n if (receipt !== undefined && receipt.fingerprint === fingerprint)\n return Effect.succeed(receipt.subjectId as NativeId);\n if (input.identifier === undefined) return IdentityConflict.make();\n\n return db\n .select({\n subjectId: column(identifierTable, mapping.identifier.subjectId) as MySqlColumn,\n })\n .from(identifierTable as any)\n .where(\n and(\n eq(identifierNamespaceColumn, input.identifier.namespace),\n eq(identifierValueColumn, input.identifier.value),\n ),\n )\n .limit(1)\n .pipe(Effect.flatMap(() => IdentityConflict.make()));\n }),\n );\n },\n ),\n );\n\n const subjectId = yield* mapping.subjectId.toSubject(nativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }, mapUnavailable);\n\n return { subjectProvisioner: SubjectProvisioner.of({ provision }) } as const;\n};\n\nexport const makeMysqlExternalIdentityServices = <\n Subject extends AnyMySqlTable,\n External extends AnyMySqlTable,\n NativeId,\n>(\n database: Database,\n mapping: ExternalIdentityTables<Subject, External, NativeId>,\n) => {\n const db = database as RuntimeDatabase;\n const externalTable = mapping.externalIdentity.table;\n\n const externalProviderColumn = column(\n externalTable,\n mapping.externalIdentity.provider,\n ) as MySqlColumn;\n\n const externalIssuerColumn = column(\n externalTable,\n mapping.externalIdentity.issuer,\n ) as MySqlColumn;\n\n const externalSubjectColumn = column(\n externalTable,\n mapping.externalIdentity.subject,\n ) as MySqlColumn;\n\n const externalSubjectIdColumn = column(\n externalTable,\n mapping.externalIdentity.subjectId,\n ) as MySqlColumn;\n\n const subjectIdColumn = column(mapping.subject.table, mapping.subject.id) as MySqlColumn;\n const subjectStatusColumn = column(mapping.subject.table, mapping.subject.status) as MySqlColumn;\n\n const bind = Effect.fn(\"DrizzleMysqlIdentity.bindExternalIdentity\")(function* (\n subjectId: SubjectId,\n identity: ExternalIdentity,\n ) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const decision = yield* db\n .transaction((tx) =>\n Effect.gen(function* () {\n const subjects = yield* tx\n .select({ status: subjectStatusColumn })\n .from(mapping.subject.table as any)\n .where(eq(subjectIdColumn, nativeId))\n .for(\"update\")\n .limit(1);\n\n if (subjects[0] === undefined || !mapping.subject.isActiveStatus(subjects[0].status))\n return { _tag: \"conflict\" } as const;\n\n const links = yield* tx\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .for(\"update\")\n .limit(1);\n\n if (links[0] !== undefined)\n return mapping.subjectId.equals(links[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const);\n yield* tx\n .insert(externalTable as any)\n .values(mapping.externalIdentity.encodeInsert(identity, nativeId) as any);\n\n return { _tag: \"bound\" } as const;\n }),\n )\n .pipe(\n Effect.catchCause((cause) => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return db\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .limit(1)\n .pipe(\n Effect.map((rows) =>\n rows[0] !== undefined &&\n mapping.subjectId.equals(rows[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const),\n ),\n );\n }),\n );\n\n if (decision._tag === \"conflict\") return yield* IdentityConflict.make();\n }, mapUnavailable);\n\n return { externalIdentityMutation: ExternalIdentityMutation.of({ bind }) } as const;\n};\n\nexport const makeMysqlIdentityServices = <\n Subject extends AnyMySqlTable,\n Identifier extends AnyMySqlTable,\n External extends AnyMySqlTable,\n Request extends AnyMySqlTable,\n NativeId,\n>(\n database: Database,\n mapping: IdentityTables<Subject, Identifier, External, Request, NativeId>,\n) => ({\n ...makeMysqlSubjectProvisioningServices(database, mapping),\n ...makeMysqlExternalIdentityServices(database, mapping),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mysql-identity.mjs","names":["DatabaseService"],"sources":["../../src/drizzle/mysql-identity.ts"],"sourcesContent":["import {\n ExternalIdentityMutation,\n type ExternalIdentity,\n IdentityConflict,\n IdentityUnavailable,\n SubjectProvisioned,\n SubjectProvisioner,\n type SubjectProvisioningInput,\n} from \"@yielded/auth/Identity\";\nimport { reportPersistenceFailure } from \"@yielded/auth/Persistence\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\n/* oxlint-disable no-explicit-any -- Drizzle generic query types are narrowed at this technology boundary. */\nimport { and, eq } from \"drizzle-orm\";\nimport type { EffectMysql2Database } from \"drizzle-orm/effect-mysql2\";\nimport type { AnyMySqlTable, MySqlColumn } from \"drizzle-orm/mysql-core\";\nimport { Cause, Effect, Schema } from \"effect\";\n\nimport {\n column,\n isMappedConstraintConflict,\n PersistenceMappingError,\n provisioningFingerprint,\n type ExternalIdentityTables,\n type IdentityTables,\n type SubjectProvisioningTables,\n} from \"./model\";\nimport { Database as DatabaseService } from \"./mysql-database\";\n\ntype RuntimeDatabase = EffectMysql2Database<any>;\nconst unavailable = () => IdentityUnavailable.make();\nconst isIdentityFailure = Schema.is(Schema.Union([IdentityConflict, IdentityUnavailable]));\n\nconst mapUnavailable = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n reportPersistenceFailure(effect, isIdentityFailure).pipe(\n Effect.catchCause((cause) =>\n Effect.failCause(\n Cause.map(cause, (error) => (isIdentityFailure(error) ? error : unavailable())),\n ),\n ),\n );\n\nexport const makeMysqlSubjectProvisioningServices = Effect.fnUntraced(function* <\n Subject extends AnyMySqlTable,\n Identifier extends AnyMySqlTable,\n Request extends AnyMySqlTable,\n NativeId,\n>(mapping: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>) {\n const database = yield* DatabaseService;\n\n const db = database as RuntimeDatabase;\n const requestTable = mapping.provisioningRequest.table;\n\n const requestIdColumn = column(\n requestTable,\n mapping.provisioningRequest.requestId,\n ) as MySqlColumn;\n\n const requestFingerprintColumn = column(\n requestTable,\n mapping.provisioningRequest.fingerprint,\n ) as MySqlColumn;\n\n const requestSubjectColumn = column(\n requestTable,\n mapping.provisioningRequest.subjectId,\n ) as MySqlColumn;\n\n const identifierTable = mapping.identifier.table;\n\n const identifierNamespaceColumn = column(\n identifierTable,\n mapping.identifier.namespace,\n ) as MySqlColumn;\n\n const identifierValueColumn = column(identifierTable, mapping.identifier.value) as MySqlColumn;\n\n const findReceipt = Effect.fn(\"DrizzleMysqlIdentity.findReceipt\")(function* (requestId: string) {\n const rows = yield* db\n .select({ fingerprint: requestFingerprintColumn, subjectId: requestSubjectColumn })\n .from(requestTable as any)\n .where(eq(requestIdColumn, requestId))\n .limit(1);\n\n return rows[0];\n });\n\n const provision = Effect.fn(\"DrizzleMysqlIdentity.provision\")(function* (\n input: SubjectProvisioningInput,\n ) {\n const fingerprint = provisioningFingerprint(input);\n const existing = yield* findReceipt(input.requestId);\n\n if (existing !== undefined) {\n if (existing.fingerprint !== fingerprint) return yield* IdentityConflict.make();\n const subjectId = yield* mapping.subjectId.toSubject(existing.subjectId as NativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }\n\n const attempt = db.transaction((tx) =>\n Effect.gen(function* () {\n const allocated =\n mapping.subject.allocateId === undefined\n ? mapping.subject.allocateIdSync?.()\n : yield* mapping.subject.allocateId;\n\n const insert = tx\n .insert(mapping.subject.table as any)\n .values(mapping.subject.encodeInsert(input, allocated) as any);\n\n let nativeId = allocated;\n\n if (nativeId === undefined) {\n if (mapping.subject.decodeGeneratedId === undefined)\n return yield* PersistenceMappingError.make({\n operation: \"provisionSubject.generatedId\",\n cause: new Error(\"MySQL generated IDs require decodeGeneratedId\"),\n });\n const ids = yield* insert.$returningId();\n\n nativeId = yield* mapping.subject.decodeGeneratedId(ids as ReadonlyArray<unknown>);\n } else {\n yield* insert;\n }\n if (input.identifier !== undefined)\n yield* tx\n .insert(identifierTable as any)\n .values(\n mapping.identifier.encodeInsert(input.identifier, nativeId, input.verifiedAt) as any,\n );\n yield* tx\n .insert(requestTable as any)\n .values(\n mapping.provisioningRequest.encodeInsert(input.requestId, fingerprint, nativeId) as any,\n );\n\n return nativeId;\n }),\n );\n\n const nativeId = yield* attempt.pipe(\n Effect.catchCause(\n (\n cause,\n ): Effect.Effect<\n NativeId,\n | Effect.Error<typeof attempt>\n | Effect.Error<ReturnType<typeof findReceipt>>\n | IdentityConflict\n > => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return findReceipt(input.requestId).pipe(\n Effect.flatMap((receipt) => {\n if (receipt !== undefined && receipt.fingerprint === fingerprint)\n return Effect.succeed(receipt.subjectId as NativeId);\n if (input.identifier === undefined) return IdentityConflict.make();\n\n return db\n .select({\n subjectId: column(identifierTable, mapping.identifier.subjectId) as MySqlColumn,\n })\n .from(identifierTable as any)\n .where(\n and(\n eq(identifierNamespaceColumn, input.identifier.namespace),\n eq(identifierValueColumn, input.identifier.value),\n ),\n )\n .limit(1)\n .pipe(Effect.flatMap(() => IdentityConflict.make()));\n }),\n );\n },\n ),\n );\n\n const subjectId = yield* mapping.subjectId.toSubject(nativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }, mapUnavailable);\n\n return { subjectProvisioner: SubjectProvisioner.of({ provision }) } as const;\n});\n\nexport const makeMysqlExternalIdentityServices = Effect.fnUntraced(function* <\n Subject extends AnyMySqlTable,\n External extends AnyMySqlTable,\n NativeId,\n>(mapping: ExternalIdentityTables<Subject, External, NativeId>) {\n const database = yield* DatabaseService;\n\n const db = database as RuntimeDatabase;\n const externalTable = mapping.externalIdentity.table;\n\n const externalProviderColumn = column(\n externalTable,\n mapping.externalIdentity.provider,\n ) as MySqlColumn;\n\n const externalIssuerColumn = column(\n externalTable,\n mapping.externalIdentity.issuer,\n ) as MySqlColumn;\n\n const externalSubjectColumn = column(\n externalTable,\n mapping.externalIdentity.subject,\n ) as MySqlColumn;\n\n const externalSubjectIdColumn = column(\n externalTable,\n mapping.externalIdentity.subjectId,\n ) as MySqlColumn;\n\n const subjectIdColumn = column(mapping.subject.table, mapping.subject.id) as MySqlColumn;\n const subjectStatusColumn = column(mapping.subject.table, mapping.subject.status) as MySqlColumn;\n\n const bind = Effect.fn(\"DrizzleMysqlIdentity.bindExternalIdentity\")(function* (\n subjectId: SubjectId,\n identity: ExternalIdentity,\n ) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const decision = yield* db\n .transaction((tx) =>\n Effect.gen(function* () {\n const subjects = yield* tx\n .select({ status: subjectStatusColumn })\n .from(mapping.subject.table as any)\n .where(eq(subjectIdColumn, nativeId))\n .for(\"update\")\n .limit(1);\n\n if (subjects[0] === undefined || !mapping.subject.isActiveStatus(subjects[0].status))\n return { _tag: \"conflict\" } as const;\n\n const links = yield* tx\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .for(\"update\")\n .limit(1);\n\n if (links[0] !== undefined)\n return mapping.subjectId.equals(links[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const);\n yield* tx\n .insert(externalTable as any)\n .values(mapping.externalIdentity.encodeInsert(identity, nativeId) as any);\n\n return { _tag: \"bound\" } as const;\n }),\n )\n .pipe(\n Effect.catchCause((cause) => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return db\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .limit(1)\n .pipe(\n Effect.map((rows) =>\n rows[0] !== undefined &&\n mapping.subjectId.equals(rows[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const),\n ),\n );\n }),\n );\n\n if (decision._tag === \"conflict\") return yield* IdentityConflict.make();\n }, mapUnavailable);\n\n return { externalIdentityMutation: ExternalIdentityMutation.of({ bind }) } as const;\n});\n\nexport const makeMysqlIdentityServices = Effect.fnUntraced(function* <\n Subject extends AnyMySqlTable,\n Identifier extends AnyMySqlTable,\n External extends AnyMySqlTable,\n Request extends AnyMySqlTable,\n NativeId,\n>(mapping: IdentityTables<Subject, Identifier, External, Request, NativeId>) {\n return {\n ...(yield* makeMysqlSubjectProvisioningServices(mapping)),\n ...(yield* makeMysqlExternalIdentityServices(mapping)),\n };\n});\n"],"mappings":"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"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { PasswordPreparedPersistenceMapping, PasswordPreparedProofMapping } from "./password-prepared-model.mjs";
|
|
2
2
|
import { SuppliedService } from "./SuppliedService.mjs";
|
|
3
|
+
import { Database as Database$1 } from "./mysql-database.mjs";
|
|
3
4
|
import { AnyRelations } from "drizzle-orm";
|
|
4
5
|
import { Effect } from "effect";
|
|
5
6
|
import { HookConfigurationError, LifecycleHooks } from "@yielded/auth/Hooks";
|
|
6
7
|
import { PasswordPreparedPersistence, PasswordUnavailable } from "@yielded/auth/Password";
|
|
7
8
|
import { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
|
|
8
|
-
import { SqlError } from "effect/
|
|
9
|
+
import { SqlError } from "effect/sql/SqlError";
|
|
9
10
|
import { AnyMySqlTable } from "drizzle-orm/mysql-core";
|
|
10
11
|
//#region src/drizzle/mysql-password-prepared.d.ts
|
|
11
12
|
type Database = EffectMysql2Database<AnyRelations>;
|
|
12
13
|
type TransactionOf<D extends Database> = Parameters<Parameters<D["transaction"]>[0]>[0];
|
|
13
|
-
export declare const makeMySqlPasswordPreparedPersistenceServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, A extends AnyMySqlTable, RS extends AnyMySqlTable, CE extends AnyMySqlTable, M extends AnyMySqlTable, T extends AnyMySqlTable, B extends AnyMySqlTable, NativeId, PS extends AnyMySqlTable = AnyMySqlTable, PC extends AnyMySqlTable = AnyMySqlTable, PM extends AnyMySqlTable = AnyMySqlTable, PSub extends AnyMySqlTable = AnyMySqlTable, PI extends AnyMySqlTable = AnyMySqlTable, PCr extends AnyMySqlTable = AnyMySqlTable, PNativeId = unknown>(
|
|
14
|
+
export declare const makeMySqlPasswordPreparedPersistenceServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, A extends AnyMySqlTable, RS extends AnyMySqlTable, CE extends AnyMySqlTable, M extends AnyMySqlTable, T extends AnyMySqlTable, B extends AnyMySqlTable, NativeId, PS extends AnyMySqlTable = AnyMySqlTable, PC extends AnyMySqlTable = AnyMySqlTable, PM extends AnyMySqlTable = AnyMySqlTable, PSub extends AnyMySqlTable = AnyMySqlTable, PI extends AnyMySqlTable = AnyMySqlTable, PCr extends AnyMySqlTable = AnyMySqlTable, PNativeId = unknown>(mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, A, RS, CE, M, T, B, NativeId>, proofMapping?: PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>) => Effect.Effect<{
|
|
14
15
|
passwordPreparedPersistence: PasswordPreparedPersistence;
|
|
15
|
-
}, never, LifecycleHooks>;
|
|
16
|
+
}, never, Database$1 | LifecycleHooks>;
|
|
16
17
|
export declare function coordinateMySqlPasswordPreparedPersistence<TargetId, D extends Database, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, A extends AnyMySqlTable, RS extends AnyMySqlTable, CE extends AnyMySqlTable, M extends AnyMySqlTable, T extends AnyMySqlTable, B extends AnyMySqlTable, NativeId, PS extends AnyMySqlTable, PC extends AnyMySqlTable, PM extends AnyMySqlTable, PSub extends AnyMySqlTable, PI extends AnyMySqlTable, PCr extends AnyMySqlTable, PNativeId, Out, E, R, DatabaseError, DatabaseRequirements>(acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>, options: {
|
|
17
18
|
readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, A, RS, CE, M, T, B, NativeId>;
|
|
18
19
|
readonly proofMapping?: PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId> | undefined;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { acquireTransactionService, transactionService } from "./standalone-guard.mjs";
|
|
2
|
+
import { CurrentPasswordSql } from "./password-sql.mjs";
|
|
1
3
|
import { coordinateTargetPasswordPreparedPersistence, makeTargetPasswordPreparedPersistenceServices } from "./password-prepared-target.mjs";
|
|
4
|
+
import { nativeDatabase } from "./native-database.mjs";
|
|
5
|
+
import { Database } from "./mysql-database.mjs";
|
|
2
6
|
import { mysqlPasswordConfiguration as configuration } from "./mysql-passwords.mjs";
|
|
3
7
|
import { Context, Effect } from "effect";
|
|
4
8
|
//#region src/drizzle/mysql-password-prepared.ts
|
|
5
|
-
const makeMySqlPasswordPreparedPersistenceServices = (
|
|
9
|
+
const makeMySqlPasswordPreparedPersistenceServices = (mapping, proofMapping) => Effect.flatMap(Effect.map(acquireTransactionService(Database), configuration), (configuration) => makeTargetPasswordPreparedPersistenceServices(mapping, configuration, proofMapping)).pipe(Effect.provideServiceEffect(CurrentPasswordSql, nativeDatabase(Database)));
|
|
6
10
|
function coordinateMySqlPasswordPreparedPersistence(acquire, options, body) {
|
|
7
|
-
return Effect.flatMap(acquire, (database) => coordinateTargetPasswordPreparedPersistence(database, options.mapping, configuration(database), options.proofMapping, (transaction, services) => {
|
|
11
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetPasswordPreparedPersistence(database, options.mapping, configuration(transactionService(database)), options.proofMapping, (transaction, services) => {
|
|
8
12
|
const provided = Context.make(options.target, services.passwordPreparedPersistence);
|
|
9
13
|
const work = Effect.provideContext(body, provided);
|
|
10
14
|
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql-password-prepared.mjs","names":[],"sources":["../../src/drizzle/mysql-password-prepared.ts"],"sourcesContent":["import type { LifecycleHooks, HookConfigurationError } from \"@yielded/auth/Hooks\";\nimport type { PasswordUnavailable, PasswordPreparedPersistence } from \"@yielded/auth/Password\";\nimport type { AnyRelations } from \"drizzle-orm\";\nimport type { EffectMysql2Database } from \"drizzle-orm/effect-mysql2\";\nimport type { AnyMySqlTable } from \"drizzle-orm/mysql-core\";\nimport { Effect, Context } from \"effect\";\nimport type { SqlError } from \"effect/
|
|
1
|
+
{"version":3,"file":"mysql-password-prepared.mjs","names":["DatabaseService"],"sources":["../../src/drizzle/mysql-password-prepared.ts"],"sourcesContent":["import type { LifecycleHooks, HookConfigurationError } from \"@yielded/auth/Hooks\";\nimport type { PasswordUnavailable, PasswordPreparedPersistence } from \"@yielded/auth/Password\";\nimport type { AnyRelations } from \"drizzle-orm\";\nimport type { EffectMysql2Database } from \"drizzle-orm/effect-mysql2\";\nimport type { AnyMySqlTable } from \"drizzle-orm/mysql-core\";\nimport { Effect, Context } from \"effect\";\nimport type { SqlError } from \"effect/sql/SqlError\";\n\nimport { Database as DatabaseService } from \"./mysql-database\";\nimport { mysqlPasswordConfiguration as configuration } from \"./mysql-passwords\";\nimport { nativeDatabase } from \"./native-database\";\nimport type {\n PasswordPreparedPersistenceMapping,\n PasswordPreparedProofMapping,\n} from \"./password-prepared-model\";\nimport {\n makeTargetPasswordPreparedPersistenceServices,\n coordinateTargetPasswordPreparedPersistence,\n} from \"./password-prepared-target\";\nimport { CurrentPasswordSql } from \"./password-sql\";\nimport { acquireTransactionService, transactionService } from \"./standalone-guard\";\nimport type { SuppliedService } from \"./SuppliedService\";\ntype Database = EffectMysql2Database<AnyRelations>;\ntype TransactionOf<D extends Database> = Parameters<Parameters<D[\"transaction\"]>[0]>[0];\n\nexport const makeMySqlPasswordPreparedPersistenceServices = <\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n A extends AnyMySqlTable,\n RS extends AnyMySqlTable,\n CE extends AnyMySqlTable,\n M extends AnyMySqlTable,\n T extends AnyMySqlTable,\n B extends AnyMySqlTable,\n NativeId,\n PS extends AnyMySqlTable = AnyMySqlTable,\n PC extends AnyMySqlTable = AnyMySqlTable,\n PM extends AnyMySqlTable = AnyMySqlTable,\n PSub extends AnyMySqlTable = AnyMySqlTable,\n PI extends AnyMySqlTable = AnyMySqlTable,\n PCr extends AnyMySqlTable = AnyMySqlTable,\n PNativeId = unknown,\n>(\n mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, A, RS, CE, M, T, B, NativeId>,\n proofMapping?: PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>,\n) =>\n Effect.flatMap(\n Effect.map(acquireTransactionService(DatabaseService), configuration),\n (configuration) =>\n makeTargetPasswordPreparedPersistenceServices(mapping, configuration, proofMapping),\n ).pipe(Effect.provideServiceEffect(CurrentPasswordSql, nativeDatabase(DatabaseService)));\n\nexport function coordinateMySqlPasswordPreparedPersistence<\n TargetId,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n A extends AnyMySqlTable,\n RS extends AnyMySqlTable,\n CE extends AnyMySqlTable,\n M extends AnyMySqlTable,\n T extends AnyMySqlTable,\n B extends AnyMySqlTable,\n NativeId,\n PS extends AnyMySqlTable,\n PC extends AnyMySqlTable,\n PM extends AnyMySqlTable,\n PSub extends AnyMySqlTable,\n PI extends AnyMySqlTable,\n PCr extends AnyMySqlTable,\n PNativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, A, RS, CE, M, T, B, NativeId>;\n readonly proofMapping?:\n | PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>\n | undefined;\n readonly target: SuppliedService<TargetId, PasswordPreparedPersistence>;\n readonly transaction?: never;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | PasswordUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMySqlPasswordPreparedPersistence<\n TargetId,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n A extends AnyMySqlTable,\n RS extends AnyMySqlTable,\n CE extends AnyMySqlTable,\n M extends AnyMySqlTable,\n T extends AnyMySqlTable,\n B extends AnyMySqlTable,\n NativeId,\n PS extends AnyMySqlTable,\n PC extends AnyMySqlTable,\n PM extends AnyMySqlTable,\n PSub extends AnyMySqlTable,\n PI extends AnyMySqlTable,\n PCr extends AnyMySqlTable,\n PNativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, A, RS, CE, M, T, B, NativeId>;\n readonly proofMapping?:\n | PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>\n | undefined;\n readonly target: SuppliedService<TargetId, PasswordPreparedPersistence>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | PasswordUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId | TxId> | LifecycleHooks | DatabaseRequirements\n>;\n\nexport function coordinateMySqlPasswordPreparedPersistence<\n TargetId,\n D extends Database,\n S extends AnyMySqlTable,\n I extends AnyMySqlTable,\n C extends AnyMySqlTable,\n AC extends AnyMySqlTable,\n A extends AnyMySqlTable,\n RS extends AnyMySqlTable,\n CE extends AnyMySqlTable,\n M extends AnyMySqlTable,\n T extends AnyMySqlTable,\n B extends AnyMySqlTable,\n NativeId,\n PS extends AnyMySqlTable,\n PC extends AnyMySqlTable,\n PM extends AnyMySqlTable,\n PSub extends AnyMySqlTable,\n PI extends AnyMySqlTable,\n PCr extends AnyMySqlTable,\n PNativeId,\n Out,\n E,\n R,\n DatabaseError,\n DatabaseRequirements,\n TxId,\n TxShape,\n>(\n acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: PasswordPreparedPersistenceMapping<S, I, C, AC, A, RS, CE, M, T, B, NativeId>;\n readonly proofMapping?:\n | PasswordPreparedProofMapping<PS, PC, PM, PSub, PI, PCr, PNativeId>\n | undefined;\n readonly target: SuppliedService<TargetId, PasswordPreparedPersistence>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;\n },\n body: Effect.Effect<Out, E, R>,\n): Effect.Effect<\n Out,\n E | PasswordUnavailable | HookConfigurationError | SqlError | DatabaseError,\n Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements\n> {\n return Effect.flatMap(acquire, (database) =>\n coordinateTargetPasswordPreparedPersistence<TransactionOf<D>, Out, E, Exclude<R, TargetId>>(\n database,\n options.mapping,\n configuration(transactionService(database)),\n options.proofMapping,\n (\n transaction: TransactionOf<D>,\n services: { readonly passwordPreparedPersistence: PasswordPreparedPersistence },\n ) => {\n const provided = Context.make(options.target, services.passwordPreparedPersistence);\n const work = Effect.provideContext(body, provided);\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n}\n"],"mappings":";;;;;;;;AAyBA,MAAa,gDAoBX,SACA,iBAEA,OAAO,QACL,OAAO,IAAI,0BAA0BA,QAAe,GAAG,aAAa,IACnE,kBACC,8CAA8C,SAAS,eAAe,YAAY,CACtF,CAAC,CAAC,KAAK,OAAO,qBAAqB,oBAAoB,eAAeA,QAAe,CAAC,CAAC;AA0FzF,SAAgB,2CA6Bd,SACA,SAQA,MAKA;CACA,OAAO,OAAO,QAAQ,UAAU,aAC9B,4CACE,UACA,QAAQ,SACR,cAAc,mBAAmB,QAAQ,CAAC,GAC1C,QAAQ,eAEN,aACA,aACG;EACH,MAAM,WAAW,QAAQ,KAAK,QAAQ,QAAQ,SAAS,2BAA2B;EAClF,MAAM,OAAO,OAAO,eAAe,MAAM,QAAQ;EAEjD,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;CAC1F,CACF,CACF;AACF"}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { PasswordPersistenceMapping, PasswordRegistrationMapping } from "./password-model.mjs";
|
|
2
2
|
import { ProofPersistenceMapping } from "./proof-model.mjs";
|
|
3
|
+
import "./standalone-guard.mjs";
|
|
3
4
|
import "./proof-sql.mjs";
|
|
4
5
|
import "./password-sql.mjs";
|
|
5
6
|
import { PasswordRegistrationAuthority } from "./password-registration.mjs";
|
|
6
7
|
import { SuppliedService } from "./SuppliedService.mjs";
|
|
8
|
+
import { Database as Database$1 } from "./mysql-database.mjs";
|
|
7
9
|
import { AnyRelations } from "drizzle-orm";
|
|
8
10
|
import { Effect } from "effect";
|
|
9
11
|
import { HookConfigurationError, LifecycleHooks } from "@yielded/auth/Hooks";
|
|
10
12
|
import { PasswordPersistence, PasswordUnavailable } from "@yielded/auth/Password";
|
|
11
13
|
import { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
|
|
12
|
-
import { SqlError } from "effect/
|
|
14
|
+
import { SqlError } from "effect/sql/SqlError";
|
|
13
15
|
import { AnyMySqlTable } from "drizzle-orm/mysql-core";
|
|
14
16
|
//#region src/drizzle/mysql-passwords.d.ts
|
|
15
17
|
type Database = EffectMysql2Database<AnyRelations>;
|
|
16
18
|
type TransactionOf<D extends Database> = Parameters<Parameters<D["transaction"]>[0]>[0];
|
|
17
19
|
type Mapping<S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, A extends AnyMySqlTable, RS extends AnyMySqlTable, CE extends AnyMySqlTable, M extends AnyMySqlTable, NativeId> = PasswordPersistenceMapping<S, I, C, AC, A, RS, CE, M, NativeId>;
|
|
18
|
-
export declare const makeMysqlPasswordPersistenceServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, A extends AnyMySqlTable, RS extends AnyMySqlTable, CE extends AnyMySqlTable, M extends AnyMySqlTable, NativeId>(
|
|
20
|
+
export declare const makeMysqlPasswordPersistenceServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, A extends AnyMySqlTable, RS extends AnyMySqlTable, CE extends AnyMySqlTable, M extends AnyMySqlTable, NativeId>(mapping: Mapping<S, I, C, AC, A, RS, CE, M, NativeId>, proofMapping?: ProofPersistenceMapping<any, any, any, any, any, any, any, any, any, any, any, any>) => Effect.Effect<{
|
|
19
21
|
passwordPersistence: {
|
|
20
22
|
readonly admitAttempt: <A_1>(input: {
|
|
21
23
|
readonly moduleId: string;
|
|
@@ -57,7 +59,7 @@ export declare const makeMysqlPasswordPersistenceServices: <S extends AnyMySqlTa
|
|
|
57
59
|
readonly hasMore: boolean;
|
|
58
60
|
}, A_1>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A_1>, PasswordUnavailable>;
|
|
59
61
|
};
|
|
60
|
-
}, never, LifecycleHooks>;
|
|
62
|
+
}, never, Database$1 | LifecycleHooks>;
|
|
61
63
|
export declare function coordinateMysqlPasswordPersistence<D extends Database, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, A extends AnyMySqlTable, RS extends AnyMySqlTable, CE extends AnyMySqlTable, M extends AnyMySqlTable, NativeId, PM extends ProofPersistenceMapping<any, any, any, any, any, any, any, any, any, any, any, any> | undefined, Out, E, R, DatabaseError, DatabaseRequirements>(acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>, options: {
|
|
62
64
|
readonly mapping: Mapping<S, I, C, AC, A, RS, CE, M, NativeId>;
|
|
63
65
|
readonly proofMapping?: PM;
|
|
@@ -68,9 +70,9 @@ export declare function coordinateMysqlPasswordPersistence<D extends Database, S
|
|
|
68
70
|
readonly proofMapping?: PM;
|
|
69
71
|
readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;
|
|
70
72
|
}, body: Effect.Effect<Out, E, R>): Effect.Effect<Out, E | PasswordUnavailable | HookConfigurationError | SqlError | DatabaseError, Exclude<R, PasswordPersistence | TxId> | LifecycleHooks | DatabaseRequirements>;
|
|
71
|
-
export declare const makeMysqlPasswordRegistrationServices: <Registration, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, Rq extends AnyMySqlTable, NativeId>(
|
|
73
|
+
export declare const makeMysqlPasswordRegistrationServices: <Registration, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, Rq extends AnyMySqlTable, NativeId>(mapping: PasswordRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>) => Effect.Effect<{
|
|
72
74
|
registrationAuthority: PasswordRegistrationAuthority<Registration>;
|
|
73
|
-
}, never, LifecycleHooks>;
|
|
75
|
+
}, never, Database$1 | LifecycleHooks>;
|
|
74
76
|
export declare function coordinateMysqlPasswordRegistration<TargetId, Registration, D extends Database, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, Rq extends AnyMySqlTable, NativeId, Out, E, R, DatabaseError, DatabaseRequirements>(acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>, options: {
|
|
75
77
|
readonly mapping: PasswordRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;
|
|
76
78
|
readonly target: SuppliedService<TargetId, PasswordRegistrationAuthority<Registration>>;
|
|
@@ -1,32 +1,36 @@
|
|
|
1
|
+
import { acquireTransactionService, transactionService } from "./standalone-guard.mjs";
|
|
2
|
+
import { CurrentPasswordSql } from "./password-sql.mjs";
|
|
1
3
|
import { coordinateTargetPasswordPersistence, coordinateTargetPasswordRegistration, makeTargetPasswordPersistenceServices, makeTargetPasswordRegistrationServices, sqlClientPasswordStandaloneGuard } from "./password-target.mjs";
|
|
2
4
|
import { sqlClientProofStandaloneGuard } from "./proof-target.mjs";
|
|
5
|
+
import { nativeDatabase } from "./native-database.mjs";
|
|
6
|
+
import { Database } from "./mysql-database.mjs";
|
|
3
7
|
import { Context, Effect } from "effect";
|
|
4
8
|
import { PasswordPersistence } from "@yielded/auth/Password";
|
|
5
9
|
//#region src/drizzle/mysql-passwords.ts
|
|
6
|
-
const configuration = (
|
|
10
|
+
const configuration = (service) => ({
|
|
7
11
|
mode: "interactive",
|
|
8
12
|
locking: true,
|
|
9
|
-
standaloneGuard: sqlClientPasswordStandaloneGuard(
|
|
13
|
+
standaloneGuard: sqlClientPasswordStandaloneGuard(service),
|
|
10
14
|
insertIfAbsent: (query, selfKey, selfValue) => query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } }),
|
|
11
15
|
generatedSubjectRows: (query) => query.$returningId(),
|
|
12
16
|
proof: {
|
|
13
17
|
mode: "interactive",
|
|
14
18
|
locking: true,
|
|
15
|
-
standaloneGuard: sqlClientProofStandaloneGuard(
|
|
19
|
+
standaloneGuard: sqlClientProofStandaloneGuard(service),
|
|
16
20
|
insertIfAbsent: (query, selfKey, selfValue) => query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } })
|
|
17
21
|
}
|
|
18
22
|
});
|
|
19
|
-
const makeMysqlPasswordPersistenceServices = (
|
|
23
|
+
const makeMysqlPasswordPersistenceServices = (mapping, proofMapping) => Effect.flatMap(Effect.map(acquireTransactionService(Database), configuration), (configuration) => makeTargetPasswordPersistenceServices(mapping, configuration, proofMapping)).pipe(Effect.provideServiceEffect(CurrentPasswordSql, nativeDatabase(Database)));
|
|
20
24
|
function coordinateMysqlPasswordPersistence(acquire, options, body) {
|
|
21
|
-
return Effect.flatMap(acquire, (database) => coordinateTargetPasswordPersistence(database, options.mapping, configuration(database), options.proofMapping, (transaction, services) => {
|
|
25
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetPasswordPersistence(database, options.mapping, configuration(transactionService(database)), options.proofMapping, (transaction, services) => {
|
|
22
26
|
const provided = Context.make(PasswordPersistence, services.passwordPersistence);
|
|
23
27
|
const work = Effect.provideContext(body, provided);
|
|
24
28
|
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
25
29
|
}));
|
|
26
30
|
}
|
|
27
|
-
const makeMysqlPasswordRegistrationServices = (
|
|
31
|
+
const makeMysqlPasswordRegistrationServices = (mapping) => Effect.flatMap(Effect.map(acquireTransactionService(Database), configuration), (configuration) => makeTargetPasswordRegistrationServices(mapping, configuration)).pipe(Effect.provideServiceEffect(CurrentPasswordSql, nativeDatabase(Database)));
|
|
28
32
|
function coordinateMysqlPasswordRegistration(acquire, options, body) {
|
|
29
|
-
return Effect.flatMap(acquire, (database) => coordinateTargetPasswordRegistration(database, options.mapping, configuration(database), (transaction, services) => {
|
|
33
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetPasswordRegistration(database, options.mapping, configuration(transactionService(database)), (transaction, services) => {
|
|
30
34
|
const provided = Context.make(options.target, services.registrationAuthority);
|
|
31
35
|
const work = Effect.provideContext(body, provided);
|
|
32
36
|
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|