@yielded/auth-persistence 0.1.0-beta.7
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 +21 -0
- package/dist/Drizzle.d.mts +28 -0
- package/dist/Drizzle.mjs +28 -0
- package/dist/DrizzleD1.d.mts +963 -0
- package/dist/DrizzleD1.mjs +29 -0
- package/dist/DrizzleD1.mjs.map +1 -0
- package/dist/DrizzleLibsql.d.mts +2284 -0
- package/dist/DrizzleLibsql.mjs +92 -0
- package/dist/DrizzleLibsql.mjs.map +1 -0
- package/dist/DrizzleMysql2.d.mts +1820 -0
- package/dist/DrizzleMysql2.mjs +55 -0
- package/dist/DrizzleMysql2.mjs.map +1 -0
- package/dist/DrizzlePglite.d.mts +1826 -0
- package/dist/DrizzlePglite.mjs +53 -0
- package/dist/DrizzlePglite.mjs.map +1 -0
- package/dist/DrizzlePostgres.d.mts +1826 -0
- package/dist/DrizzlePostgres.mjs +53 -0
- package/dist/DrizzlePostgres.mjs.map +1 -0
- package/dist/DrizzleSqliteBun.d.mts +2279 -0
- package/dist/DrizzleSqliteBun.mjs +70 -0
- package/dist/DrizzleSqliteBun.mjs.map +1 -0
- package/dist/DrizzleSqliteDo.d.mts +2329 -0
- package/dist/DrizzleSqliteDo.mjs +105 -0
- package/dist/DrizzleSqliteDo.mjs.map +1 -0
- package/dist/DrizzleSqliteNode.d.mts +2279 -0
- package/dist/DrizzleSqliteNode.mjs +70 -0
- package/dist/DrizzleSqliteNode.mjs.map +1 -0
- package/dist/DrizzleSqliteWasm.d.mts +2282 -0
- package/dist/DrizzleSqliteWasm.mjs +70 -0
- package/dist/DrizzleSqliteWasm.mjs.map +1 -0
- package/dist/drizzle/D1BatchStatements.d.mts +11 -0
- package/dist/drizzle/D1BatchStatements.mjs +8 -0
- package/dist/drizzle/D1BatchStatements.mjs.map +1 -0
- package/dist/drizzle/PasswordPreparedPostconditions.mjs +12 -0
- package/dist/drizzle/PasswordPreparedPostconditions.mjs.map +1 -0
- package/dist/drizzle/SuppliedService.d.mts +10 -0
- package/dist/drizzle/d1-emails.d.mts +62 -0
- package/dist/drizzle/d1-emails.mjs +580 -0
- package/dist/drizzle/d1-emails.mjs.map +1 -0
- package/dist/drizzle/d1-generated-statement.d.mts +2 -0
- package/dist/drizzle/d1-generated-statement.mjs +79 -0
- package/dist/drizzle/d1-generated-statement.mjs.map +1 -0
- package/dist/drizzle/d1-identity.d.mts +31 -0
- package/dist/drizzle/d1-identity.mjs +119 -0
- package/dist/drizzle/d1-identity.mjs.map +1 -0
- package/dist/drizzle/d1-oauth.d.mts +301 -0
- package/dist/drizzle/d1-oauth.mjs +76 -0
- package/dist/drizzle/d1-oauth.mjs.map +1 -0
- package/dist/drizzle/d1-passkey.d.mts +51 -0
- package/dist/drizzle/d1-passkey.mjs +95 -0
- package/dist/drizzle/d1-passkey.mjs.map +1 -0
- package/dist/drizzle/d1-password-prepared.d.mts +25 -0
- package/dist/drizzle/d1-password-prepared.mjs +461 -0
- package/dist/drizzle/d1-password-prepared.mjs.map +1 -0
- package/dist/drizzle/d1-passwords.d.mts +87 -0
- package/dist/drizzle/d1-passwords.mjs +1004 -0
- package/dist/drizzle/d1-passwords.mjs.map +1 -0
- package/dist/drizzle/d1-phone.d.mts +26 -0
- package/dist/drizzle/d1-phone.mjs +30 -0
- package/dist/drizzle/d1-phone.mjs.map +1 -0
- package/dist/drizzle/d1-planning.d.mts +12 -0
- package/dist/drizzle/d1-planning.mjs +43 -0
- package/dist/drizzle/d1-planning.mjs.map +1 -0
- package/dist/drizzle/d1-proofs.d.mts +80 -0
- package/dist/drizzle/d1-proofs.mjs +830 -0
- package/dist/drizzle/d1-proofs.mjs.map +1 -0
- package/dist/drizzle/d1-sessions.d.mts +67 -0
- package/dist/drizzle/d1-sessions.mjs +966 -0
- package/dist/drizzle/d1-sessions.mjs.map +1 -0
- package/dist/drizzle/d1-totp.d.mts +26 -0
- package/dist/drizzle/d1-totp.mjs +27 -0
- package/dist/drizzle/d1-totp.mjs.map +1 -0
- package/dist/drizzle/email-model.d.mts +354 -0
- package/dist/drizzle/email-model.mjs +21 -0
- package/dist/drizzle/email-model.mjs.map +1 -0
- package/dist/drizzle/email-registration.d.mts +30 -0
- package/dist/drizzle/email-registration.mjs +238 -0
- package/dist/drizzle/email-registration.mjs.map +1 -0
- package/dist/drizzle/email-sql.d.mts +4 -0
- package/dist/drizzle/email-sql.mjs +9 -0
- package/dist/drizzle/email-sql.mjs.map +1 -0
- package/dist/drizzle/email-target.d.mts +20 -0
- package/dist/drizzle/email-target.mjs +72 -0
- package/dist/drizzle/email-target.mjs.map +1 -0
- package/dist/drizzle/model.d.mts +250 -0
- package/dist/drizzle/model.mjs +58 -0
- package/dist/drizzle/model.mjs.map +1 -0
- package/dist/drizzle/mysql-emails.d.mts +71 -0
- package/dist/drizzle/mysql-emails.mjs +38 -0
- package/dist/drizzle/mysql-emails.mjs.map +1 -0
- package/dist/drizzle/mysql-identity.d.mts +22 -0
- package/dist/drizzle/mysql-identity.mjs +94 -0
- package/dist/drizzle/mysql-identity.mjs.map +1 -0
- package/dist/drizzle/mysql-password-prepared.d.mts +30 -0
- package/dist/drizzle/mysql-password-prepared.mjs +16 -0
- package/dist/drizzle/mysql-password-prepared.mjs.map +1 -0
- package/dist/drizzle/mysql-passwords.d.mts +86 -0
- package/dist/drizzle/mysql-passwords.mjs +38 -0
- package/dist/drizzle/mysql-passwords.mjs.map +1 -0
- package/dist/drizzle/mysql-proofs.d.mts +75 -0
- package/dist/drizzle/mysql-proofs.mjs +23 -0
- package/dist/drizzle/mysql-proofs.mjs.map +1 -0
- package/dist/drizzle/mysql-sessions.d.mts +237 -0
- package/dist/drizzle/mysql-sessions.mjs +53 -0
- package/dist/drizzle/mysql-sessions.mjs.map +1 -0
- package/dist/drizzle/mysql.d.mts +70 -0
- package/dist/drizzle/mysql.mjs +218 -0
- package/dist/drizzle/mysql.mjs.map +1 -0
- package/dist/drizzle/oauth-accounts.mjs +358 -0
- package/dist/drizzle/oauth-accounts.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-access.mjs +210 -0
- package/dist/drizzle/oauth-connected-access.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-collection.mjs +202 -0
- package/dist/drizzle/oauth-connected-collection.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-custody.mjs +146 -0
- package/dist/drizzle/oauth-connected-custody.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-drivers.mjs +76 -0
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-flow.mjs +247 -0
- package/dist/drizzle/oauth-connected-flow.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-input.mjs +103 -0
- package/dist/drizzle/oauth-connected-input.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-maintenance.mjs +214 -0
- package/dist/drizzle/oauth-connected-maintenance.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-management.mjs +228 -0
- package/dist/drizzle/oauth-connected-management.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-model.d.mts +278 -0
- package/dist/drizzle/oauth-connected-model.mjs +22 -0
- package/dist/drizzle/oauth-connected-model.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-reference.d.mts +17 -0
- package/dist/drizzle/oauth-connected-reference.mjs +53 -0
- package/dist/drizzle/oauth-connected-reference.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-settlement.mjs +117 -0
- package/dist/drizzle/oauth-connected-settlement.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-state.d.mts +14 -0
- package/dist/drizzle/oauth-connected-state.mjs +422 -0
- package/dist/drizzle/oauth-connected-state.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-target.d.mts +753 -0
- package/dist/drizzle/oauth-connected-target.mjs +91 -0
- package/dist/drizzle/oauth-connected-target.mjs.map +1 -0
- package/dist/drizzle/oauth-drivers.mjs +51 -0
- package/dist/drizzle/oauth-drivers.mjs.map +1 -0
- package/dist/drizzle/oauth-flow.d.mts +5 -0
- package/dist/drizzle/oauth-flow.mjs +253 -0
- package/dist/drizzle/oauth-flow.mjs.map +1 -0
- package/dist/drizzle/oauth-input.mjs +127 -0
- package/dist/drizzle/oauth-input.mjs.map +1 -0
- package/dist/drizzle/oauth-model.d.mts +463 -0
- package/dist/drizzle/oauth-model.mjs +49 -0
- package/dist/drizzle/oauth-model.mjs.map +1 -0
- package/dist/drizzle/oauth-mysql.mjs +8 -0
- package/dist/drizzle/oauth-mysql.mjs.map +1 -0
- package/dist/drizzle/oauth-owner.d.mts +4 -0
- package/dist/drizzle/oauth-owner.mjs +10 -0
- package/dist/drizzle/oauth-owner.mjs.map +1 -0
- package/dist/drizzle/oauth-registration.d.mts +6 -0
- package/dist/drizzle/oauth-registration.mjs +374 -0
- package/dist/drizzle/oauth-registration.mjs.map +1 -0
- package/dist/drizzle/oauth-state.mjs +107 -0
- package/dist/drizzle/oauth-state.mjs.map +1 -0
- package/dist/drizzle/oauth-target.d.mts +111 -0
- package/dist/drizzle/oauth-target.mjs +246 -0
- package/dist/drizzle/oauth-target.mjs.map +1 -0
- package/dist/drizzle/passkey-drivers.mjs +34 -0
- package/dist/drizzle/passkey-drivers.mjs.map +1 -0
- package/dist/drizzle/passkey-kernel.mjs +8 -0
- package/dist/drizzle/passkey-kernel.mjs.map +1 -0
- package/dist/drizzle/passkey-model.d.mts +272 -0
- package/dist/drizzle/passkey-model.mjs +34 -0
- package/dist/drizzle/passkey-model.mjs.map +1 -0
- package/dist/drizzle/passkey-registration-ceremony-model.d.mts +50 -0
- package/dist/drizzle/passkey-registration-ceremony-model.mjs +18 -0
- package/dist/drizzle/passkey-registration-ceremony-model.mjs.map +1 -0
- package/dist/drizzle/passkey-state.mjs +7 -0
- package/dist/drizzle/passkey-state.mjs.map +1 -0
- package/dist/drizzle/passkey-target.d.mts +9 -0
- package/dist/drizzle/passkey-target.mjs +7 -0
- package/dist/drizzle/passkey-target.mjs.map +1 -0
- package/dist/drizzle/passkey-write-drivers.mjs +32 -0
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -0
- package/dist/drizzle/passkey-write-model.d.mts +190 -0
- package/dist/drizzle/passkey-write-model.mjs +13 -0
- package/dist/drizzle/passkey-write-model.mjs.map +1 -0
- package/dist/drizzle/passkey-write-target.d.mts +11 -0
- package/dist/drizzle/passkey-write-target.mjs +7 -0
- package/dist/drizzle/passkey-write-target.mjs.map +1 -0
- package/dist/drizzle/password-model.d.mts +329 -0
- package/dist/drizzle/password-model.mjs +23 -0
- package/dist/drizzle/password-model.mjs.map +1 -0
- package/dist/drizzle/password-prepared-model.d.mts +94 -0
- package/dist/drizzle/password-prepared-model.mjs +11 -0
- package/dist/drizzle/password-prepared-model.mjs.map +1 -0
- package/dist/drizzle/password-prepared-sql.mjs +390 -0
- package/dist/drizzle/password-prepared-sql.mjs.map +1 -0
- package/dist/drizzle/password-prepared-state.mjs +104 -0
- package/dist/drizzle/password-prepared-state.mjs.map +1 -0
- package/dist/drizzle/password-prepared-target.d.mts +12 -0
- package/dist/drizzle/password-prepared-target.mjs +56 -0
- package/dist/drizzle/password-prepared-target.mjs.map +1 -0
- package/dist/drizzle/password-registration.d.mts +19 -0
- package/dist/drizzle/password-registration.mjs +135 -0
- package/dist/drizzle/password-registration.mjs.map +1 -0
- package/dist/drizzle/password-sql.d.mts +5 -0
- package/dist/drizzle/password-sql.mjs +9 -0
- package/dist/drizzle/password-sql.mjs.map +1 -0
- package/dist/drizzle/password-target.d.mts +17 -0
- package/dist/drizzle/password-target.mjs +61 -0
- package/dist/drizzle/password-target.mjs.map +1 -0
- package/dist/drizzle/pg-emails.d.mts +72 -0
- package/dist/drizzle/pg-emails.mjs +38 -0
- package/dist/drizzle/pg-emails.mjs.map +1 -0
- package/dist/drizzle/pg-password-prepared.d.mts +31 -0
- package/dist/drizzle/pg-password-prepared.mjs +16 -0
- package/dist/drizzle/pg-password-prepared.mjs.map +1 -0
- package/dist/drizzle/pg-passwords.d.mts +87 -0
- package/dist/drizzle/pg-passwords.mjs +38 -0
- package/dist/drizzle/pg-passwords.mjs.map +1 -0
- package/dist/drizzle/pg-proofs.d.mts +76 -0
- package/dist/drizzle/pg-proofs.mjs +22 -0
- package/dist/drizzle/pg-proofs.mjs.map +1 -0
- package/dist/drizzle/pg-sessions.d.mts +238 -0
- package/dist/drizzle/pg-sessions.mjs +53 -0
- package/dist/drizzle/pg-sessions.mjs.map +1 -0
- package/dist/drizzle/pg.d.mts +81 -0
- package/dist/drizzle/pg.mjs +290 -0
- package/dist/drizzle/pg.mjs.map +1 -0
- package/dist/drizzle/phone-model.d.mts +115 -0
- package/dist/drizzle/phone-model.mjs +39 -0
- package/dist/drizzle/phone-model.mjs.map +1 -0
- package/dist/drizzle/phone-state.mjs +16 -0
- package/dist/drizzle/phone-state.mjs.map +1 -0
- package/dist/drizzle/phone-target.d.mts +17 -0
- package/dist/drizzle/phone-target.mjs +170 -0
- package/dist/drizzle/phone-target.mjs.map +1 -0
- package/dist/drizzle/proof-model.d.mts +286 -0
- package/dist/drizzle/proof-model.mjs +17 -0
- package/dist/drizzle/proof-model.mjs.map +1 -0
- package/dist/drizzle/proof-sql.d.mts +4 -0
- package/dist/drizzle/proof-sql.mjs +8 -0
- package/dist/drizzle/proof-sql.mjs.map +1 -0
- package/dist/drizzle/proof-target.d.mts +12 -0
- package/dist/drizzle/proof-target.mjs +36 -0
- package/dist/drizzle/proof-target.mjs.map +1 -0
- package/dist/drizzle/query-operations.mjs +26 -0
- package/dist/drizzle/query-operations.mjs.map +1 -0
- package/dist/drizzle/session-model.d.mts +200 -0
- package/dist/drizzle/session-model.mjs +20 -0
- package/dist/drizzle/session-model.mjs.map +1 -0
- package/dist/drizzle/session-sql.mjs +8 -0
- package/dist/drizzle/session-sql.mjs.map +1 -0
- package/dist/drizzle/session-target.d.mts +28 -0
- package/dist/drizzle/session-target.mjs +47 -0
- package/dist/drizzle/session-target.mjs.map +1 -0
- package/dist/drizzle/sqlite-emails.mjs +45 -0
- package/dist/drizzle/sqlite-emails.mjs.map +1 -0
- package/dist/drizzle/sqlite-identity.mjs +91 -0
- package/dist/drizzle/sqlite-identity.mjs.map +1 -0
- package/dist/drizzle/sqlite-password-prepared.mjs +21 -0
- package/dist/drizzle/sqlite-password-prepared.mjs.map +1 -0
- package/dist/drizzle/sqlite-passwords.mjs +49 -0
- package/dist/drizzle/sqlite-passwords.mjs.map +1 -0
- package/dist/drizzle/sqlite-proofs.mjs +29 -0
- package/dist/drizzle/sqlite-proofs.mjs.map +1 -0
- package/dist/drizzle/sqlite-sessions.mjs +74 -0
- package/dist/drizzle/sqlite-sessions.mjs.map +1 -0
- package/dist/drizzle/sqlite.d.mts +78 -0
- package/dist/drizzle/sqlite.mjs +217 -0
- package/dist/drizzle/sqlite.mjs.map +1 -0
- package/dist/drizzle/standalone-guard.mjs +19 -0
- package/dist/drizzle/standalone-guard.mjs.map +1 -0
- package/dist/drizzle/step-up-model.d.mts +65 -0
- package/dist/drizzle/step-up-model.mjs +9 -0
- package/dist/drizzle/step-up-model.mjs.map +1 -0
- package/dist/drizzle/step-up-state.mjs +32 -0
- package/dist/drizzle/step-up-state.mjs.map +1 -0
- package/dist/drizzle/totp-model.d.mts +84 -0
- package/dist/drizzle/totp-model.mjs +13 -0
- package/dist/drizzle/totp-model.mjs.map +1 -0
- package/dist/drizzle/totp-state.d.mts +38 -0
- package/dist/drizzle/totp-state.mjs +287 -0
- package/dist/drizzle/totp-state.mjs.map +1 -0
- package/dist/drizzle/totp-target.d.mts +17 -0
- package/dist/drizzle/totp-target.mjs +81 -0
- package/dist/drizzle/totp-target.mjs.map +1 -0
- package/dist/drizzle/transaction-execution.d.mts +4 -0
- package/dist/drizzle/transaction-execution.mjs +11 -0
- package/dist/drizzle/transaction-execution.mjs.map +1 -0
- package/dist/drizzle/transaction-mysql.mjs +46 -0
- package/dist/drizzle/transaction-mysql.mjs.map +1 -0
- package/dist/drizzle/transaction-owner.d.mts +2 -0
- package/dist/drizzle/transaction-owner.mjs +8 -0
- package/dist/drizzle/transaction-owner.mjs.map +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +5 -0
- package/dist/internal/configuration.d.mts +174 -0
- package/dist/internal/configuration.mjs +7 -0
- package/dist/internal/configuration.mjs.map +1 -0
- package/dist/internal/drizzle-migrations.mjs +19 -0
- package/dist/internal/drizzle-migrations.mjs.map +1 -0
- package/dist/internal/drizzle-postgres.mjs +39 -0
- package/dist/internal/drizzle-postgres.mjs.map +1 -0
- package/dist/internal/drizzle-sqlite.mjs +37 -0
- package/dist/internal/drizzle-sqlite.mjs.map +1 -0
- package/dist/internal/email-kernel.d.mts +13 -0
- package/dist/internal/email-kernel.mjs +487 -0
- package/dist/internal/email-kernel.mjs.map +1 -0
- package/dist/internal/mapping-error.d.mts +11 -0
- package/dist/internal/mapping-error.mjs +30 -0
- package/dist/internal/mapping-error.mjs.map +1 -0
- package/dist/internal/passkey/admission.d.mts +7 -0
- package/dist/internal/passkey/admission.mjs +216 -0
- package/dist/internal/passkey/admission.mjs.map +1 -0
- package/dist/internal/passkey/credentials.d.mts +6 -0
- package/dist/internal/passkey/credentials.mjs +249 -0
- package/dist/internal/passkey/credentials.mjs.map +1 -0
- package/dist/internal/passkey/enrollment.mjs +138 -0
- package/dist/internal/passkey/enrollment.mjs.map +1 -0
- package/dist/internal/passkey/flow.d.mts +10 -0
- package/dist/internal/passkey/flow.mjs +452 -0
- package/dist/internal/passkey/flow.mjs.map +1 -0
- package/dist/internal/passkey/management.mjs +231 -0
- package/dist/internal/passkey/management.mjs.map +1 -0
- package/dist/internal/passkey/registration-ceremony.d.mts +9 -0
- package/dist/internal/passkey/registration-ceremony.mjs +129 -0
- package/dist/internal/passkey/registration-ceremony.mjs.map +1 -0
- package/dist/internal/passkey/registration-custody.d.mts +2 -0
- package/dist/internal/passkey/registration-custody.mjs +52 -0
- package/dist/internal/passkey/registration-custody.mjs.map +1 -0
- package/dist/internal/passkey/registration-write.mjs +211 -0
- package/dist/internal/passkey/registration-write.mjs.map +1 -0
- package/dist/internal/passkey/state.d.mts +5 -0
- package/dist/internal/passkey/state.mjs +234 -0
- package/dist/internal/passkey/state.mjs.map +1 -0
- package/dist/internal/passkey/target.d.mts +19 -0
- package/dist/internal/passkey/target.mjs +190 -0
- package/dist/internal/passkey/target.mjs.map +1 -0
- package/dist/internal/passkey/write-state.mjs +345 -0
- package/dist/internal/passkey/write-state.mjs.map +1 -0
- package/dist/internal/passkey/write-target.mjs +192 -0
- package/dist/internal/passkey/write-target.mjs.map +1 -0
- package/dist/internal/passkey-kernel.mjs +49 -0
- package/dist/internal/passkey-kernel.mjs.map +1 -0
- package/dist/internal/passkeys.mjs +367 -0
- package/dist/internal/passkeys.mjs.map +1 -0
- package/dist/internal/password-kernel.d.mts +13 -0
- package/dist/internal/password-kernel.mjs +704 -0
- package/dist/internal/password-kernel.mjs.map +1 -0
- package/dist/internal/persistence.mjs +289 -0
- package/dist/internal/persistence.mjs.map +1 -0
- package/dist/internal/phone-kernel.mjs +434 -0
- package/dist/internal/phone-kernel.mjs.map +1 -0
- package/dist/internal/proof-kernel.d.mts +9 -0
- package/dist/internal/proof-kernel.mjs +619 -0
- package/dist/internal/proof-kernel.mjs.map +1 -0
- package/dist/internal/query-operations.d.mts +3 -0
- package/dist/internal/registration.mjs +65 -0
- package/dist/internal/registration.mjs.map +1 -0
- package/dist/internal/session-kernel.mjs +737 -0
- package/dist/internal/session-kernel.mjs.map +1 -0
- package/dist/internal/sql-persistence.d.mts +11 -0
- package/dist/internal/sql-persistence.mjs +37 -0
- package/dist/internal/sql-persistence.mjs.map +1 -0
- package/dist/internal/sql-query.mjs +207 -0
- package/dist/internal/sql-query.mjs.map +1 -0
- package/dist/internal/sql-table.d.mts +37 -0
- package/dist/internal/sql-table.mjs +71 -0
- package/dist/internal/sql-table.mjs.map +1 -0
- package/dist/internal/storage-mapping.mjs +687 -0
- package/dist/internal/storage-mapping.mjs.map +1 -0
- package/dist/internal/storage-tables.d.mts +914 -0
- package/dist/internal/storage-tables.mjs +387 -0
- package/dist/internal/storage-tables.mjs.map +1 -0
- package/dist/internal/storage-validation.mjs +58 -0
- package/dist/internal/storage-validation.mjs.map +1 -0
- package/dist/internal/transaction-execution-kernel.d.mts +18 -0
- package/dist/internal/transaction-execution-kernel.mjs +118 -0
- package/dist/internal/transaction-execution-kernel.mjs.map +1 -0
- package/dist/internal/transaction-kernel.d.mts +7 -0
- package/dist/internal/transaction-kernel.mjs +260 -0
- package/dist/internal/transaction-kernel.mjs.map +1 -0
- package/package.json +1 -0
- package/src/Drizzle.ts +378 -0
- package/src/DrizzleD1.ts +136 -0
- package/src/DrizzleLibsql.ts +301 -0
- package/src/DrizzleMysql2.ts +184 -0
- package/src/DrizzlePglite.ts +174 -0
- package/src/DrizzlePostgres.ts +174 -0
- package/src/DrizzleSqliteBun.ts +258 -0
- package/src/DrizzleSqliteDo.ts +473 -0
- package/src/DrizzleSqliteNode.ts +259 -0
- package/src/DrizzleSqliteWasm.ts +263 -0
- package/src/drizzle/D1BatchStatements.ts +10 -0
- package/src/drizzle/PasswordPreparedPostconditions.ts +30 -0
- package/src/drizzle/SuppliedService.ts +10 -0
- package/src/drizzle/d1-emails.ts +1829 -0
- package/src/drizzle/d1-generated-statement.ts +129 -0
- package/src/drizzle/d1-identity.ts +375 -0
- package/src/drizzle/d1-oauth.ts +340 -0
- package/src/drizzle/d1-passkey.ts +373 -0
- package/src/drizzle/d1-password-prepared.ts +1270 -0
- package/src/drizzle/d1-passwords.ts +2656 -0
- package/src/drizzle/d1-phone.ts +96 -0
- package/src/drizzle/d1-planning.ts +104 -0
- package/src/drizzle/d1-proofs.ts +2305 -0
- package/src/drizzle/d1-sessions.ts +2857 -0
- package/src/drizzle/d1-totp.ts +78 -0
- package/src/drizzle/email-model.ts +516 -0
- package/src/drizzle/email-registration.ts +698 -0
- package/src/drizzle/email-sql.ts +24 -0
- package/src/drizzle/email-target.ts +243 -0
- package/src/drizzle/model.ts +463 -0
- package/src/drizzle/mysql-emails.ts +321 -0
- package/src/drizzle/mysql-identity.ts +324 -0
- package/src/drizzle/mysql-password-prepared.ts +204 -0
- package/src/drizzle/mysql-passwords.ts +339 -0
- package/src/drizzle/mysql-proofs.ts +181 -0
- package/src/drizzle/mysql-sessions.ts +741 -0
- package/src/drizzle/mysql.ts +687 -0
- package/src/drizzle/oauth-accounts.ts +804 -0
- package/src/drizzle/oauth-connected-access.ts +354 -0
- package/src/drizzle/oauth-connected-collection.ts +324 -0
- package/src/drizzle/oauth-connected-custody.ts +277 -0
- package/src/drizzle/oauth-connected-drivers.ts +465 -0
- package/src/drizzle/oauth-connected-flow.ts +441 -0
- package/src/drizzle/oauth-connected-input.ts +127 -0
- package/src/drizzle/oauth-connected-maintenance.ts +345 -0
- package/src/drizzle/oauth-connected-management.ts +365 -0
- package/src/drizzle/oauth-connected-model.ts +347 -0
- package/src/drizzle/oauth-connected-reference.ts +112 -0
- package/src/drizzle/oauth-connected-settlement.ts +226 -0
- package/src/drizzle/oauth-connected-state.ts +845 -0
- package/src/drizzle/oauth-connected-target.ts +264 -0
- package/src/drizzle/oauth-drivers.ts +569 -0
- package/src/drizzle/oauth-flow.ts +462 -0
- package/src/drizzle/oauth-input.ts +201 -0
- package/src/drizzle/oauth-model.ts +617 -0
- package/src/drizzle/oauth-mysql.ts +10 -0
- package/src/drizzle/oauth-owner.ts +29 -0
- package/src/drizzle/oauth-registration.ts +640 -0
- package/src/drizzle/oauth-state.ts +215 -0
- package/src/drizzle/oauth-target.ts +750 -0
- package/src/drizzle/passkey-drivers.ts +385 -0
- package/src/drizzle/passkey-kernel.ts +3 -0
- package/src/drizzle/passkey-model.ts +353 -0
- package/src/drizzle/passkey-registration-ceremony-model.ts +69 -0
- package/src/drizzle/passkey-state.ts +3 -0
- package/src/drizzle/passkey-target.ts +23 -0
- package/src/drizzle/passkey-write-drivers.ts +395 -0
- package/src/drizzle/passkey-write-model.ts +271 -0
- package/src/drizzle/passkey-write-target.ts +9 -0
- package/src/drizzle/password-model.ts +491 -0
- package/src/drizzle/password-prepared-model.ts +259 -0
- package/src/drizzle/password-prepared-sql.ts +1191 -0
- package/src/drizzle/password-prepared-state.ts +231 -0
- package/src/drizzle/password-prepared-target.ts +160 -0
- package/src/drizzle/password-registration.ts +374 -0
- package/src/drizzle/password-sql.ts +12 -0
- package/src/drizzle/password-target.ts +224 -0
- package/src/drizzle/pg-emails.ts +321 -0
- package/src/drizzle/pg-password-prepared.ts +205 -0
- package/src/drizzle/pg-passwords.ts +338 -0
- package/src/drizzle/pg-proofs.ts +191 -0
- package/src/drizzle/pg-sessions.ts +750 -0
- package/src/drizzle/pg.ts +984 -0
- package/src/drizzle/phone-model.ts +190 -0
- package/src/drizzle/phone-state.ts +21 -0
- package/src/drizzle/phone-target.ts +472 -0
- package/src/drizzle/proof-model.ts +398 -0
- package/src/drizzle/proof-sql.ts +9 -0
- package/src/drizzle/proof-target.ts +122 -0
- package/src/drizzle/query-operations.ts +37 -0
- package/src/drizzle/session-model.ts +370 -0
- package/src/drizzle/session-sql.ts +13 -0
- package/src/drizzle/session-target.ts +338 -0
- package/src/drizzle/sqlite-emails.ts +366 -0
- package/src/drizzle/sqlite-identity.ts +344 -0
- package/src/drizzle/sqlite-password-prepared.ts +260 -0
- package/src/drizzle/sqlite-passwords.ts +497 -0
- package/src/drizzle/sqlite-proofs.ts +202 -0
- package/src/drizzle/sqlite-sessions.ts +971 -0
- package/src/drizzle/sqlite.ts +705 -0
- package/src/drizzle/standalone-guard.ts +38 -0
- package/src/drizzle/step-up-model.ts +128 -0
- package/src/drizzle/step-up-state.ts +139 -0
- package/src/drizzle/totp-model.ts +92 -0
- package/src/drizzle/totp-state.ts +525 -0
- package/src/drizzle/totp-target.ts +308 -0
- package/src/drizzle/transaction-execution.ts +12 -0
- package/src/drizzle/transaction-mysql.ts +104 -0
- package/src/drizzle/transaction-owner.ts +10 -0
- package/src/index.ts +4 -0
- package/src/internal/configuration.ts +282 -0
- package/src/internal/drizzle-migrations.ts +30 -0
- package/src/internal/drizzle-postgres.ts +81 -0
- package/src/internal/drizzle-sqlite.ts +79 -0
- package/src/internal/email-kernel.ts +1532 -0
- package/src/internal/mapping-error.ts +36 -0
- package/src/internal/passkey/admission.ts +362 -0
- package/src/internal/passkey/credentials.ts +511 -0
- package/src/internal/passkey/enrollment.ts +326 -0
- package/src/internal/passkey/flow.ts +1062 -0
- package/src/internal/passkey/management.ts +422 -0
- package/src/internal/passkey/registration-ceremony.ts +283 -0
- package/src/internal/passkey/registration-custody.ts +91 -0
- package/src/internal/passkey/registration-write.ts +426 -0
- package/src/internal/passkey/state.ts +354 -0
- package/src/internal/passkey/target.ts +586 -0
- package/src/internal/passkey/write-state.ts +681 -0
- package/src/internal/passkey/write-target.ts +452 -0
- package/src/internal/passkey-kernel.ts +102 -0
- package/src/internal/passkeys.ts +597 -0
- package/src/internal/password-kernel.ts +2122 -0
- package/src/internal/persistence.ts +590 -0
- package/src/internal/phone-kernel.ts +843 -0
- package/src/internal/proof-kernel.ts +1949 -0
- package/src/internal/query-operations.ts +26 -0
- package/src/internal/registration.ts +160 -0
- package/src/internal/session-kernel.ts +2210 -0
- package/src/internal/sql-persistence.ts +45 -0
- package/src/internal/sql-query.ts +298 -0
- package/src/internal/sql-table.ts +89 -0
- package/src/internal/storage-mapping.ts +706 -0
- package/src/internal/storage-tables.ts +408 -0
- package/src/internal/storage-validation.ts +117 -0
- package/src/internal/transaction-execution-kernel.ts +317 -0
- package/src/internal/transaction-kernel.ts +582 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { PersistenceMappingError, isMappedConstraintConflict } from "../internal/mapping-error.mjs";
|
|
2
|
+
import { DateTime, Effect, Layer } from "effect";
|
|
3
|
+
import { ChallengeConsumeDecision } from "@yielded/auth/Persistence";
|
|
4
|
+
import { ConsumeChallenge, NewChallenge, NewRegistration, PendingRegistration, SubjectId } from "@yielded/auth/Schema";
|
|
5
|
+
import { ExternalIdentity, ExternalIdentityMutation, LoginIdentifier, SubjectProvisioner, SubjectProvisioningInput } from "@yielded/auth/Identity";
|
|
6
|
+
import { AuthStore, ConsumeDecision } from "@yielded/auth/AuthStore";
|
|
7
|
+
import { AuthStoreError } from "@yielded/auth/Errors";
|
|
8
|
+
import { OAuthState, OAuthStateStore } from "@yielded/auth/OAuth";
|
|
9
|
+
import { AnyColumn, InferInsertModel, InferSelectModel, Table } from "drizzle-orm";
|
|
10
|
+
import * as SqlClient from "effect/unstable/sql/SqlClient";
|
|
11
|
+
//#region src/drizzle/model.d.ts
|
|
12
|
+
type CommitMode = "interactive" | "synchronous" | "batch";
|
|
13
|
+
/**
|
|
14
|
+
* Ordinary error-channel consumes must own their commit. Coordinated callers
|
|
15
|
+
* use the decision methods inside their outer transaction and translate only
|
|
16
|
+
* after that owner commits.
|
|
17
|
+
*/
|
|
18
|
+
interface SqlClientTransactionDatabase {
|
|
19
|
+
readonly $client: Pick<SqlClient.SqlClient, "transactionService">;
|
|
20
|
+
}
|
|
21
|
+
declare const requireStandaloneConsume: (database: SqlClientTransactionDatabase) => Effect.Effect<void, AuthStoreError>;
|
|
22
|
+
interface InstantCodec<NativeInstant> {
|
|
23
|
+
readonly encode: (instant: DateTime.Utc) => NativeInstant;
|
|
24
|
+
readonly decode: (native: NativeInstant) => Effect.Effect<DateTime.Utc, PersistenceMappingError>;
|
|
25
|
+
}
|
|
26
|
+
interface RequiredAuthStoreConstraints {
|
|
27
|
+
readonly series: "unique(namespace,value,purpose)";
|
|
28
|
+
readonly challengeDigest: "unique(tokenDigest)";
|
|
29
|
+
readonly registrationDigest: "unique(tokenDigest)";
|
|
30
|
+
}
|
|
31
|
+
interface RequiredOAuthStateConstraints {
|
|
32
|
+
readonly oauthStateDigest: "unique(stateDigest)";
|
|
33
|
+
}
|
|
34
|
+
interface RequiredAuthConstraints extends RequiredAuthStoreConstraints, RequiredOAuthStateConstraints {}
|
|
35
|
+
declare const requiredAuthConstraints: RequiredAuthConstraints;
|
|
36
|
+
declare const requiredAuthStoreConstraints: RequiredAuthStoreConstraints;
|
|
37
|
+
declare const requiredOAuthStateConstraints: RequiredOAuthStateConstraints;
|
|
38
|
+
type ColumnKey<T extends Table> = Extract<keyof T["_"]["columns"], string>;
|
|
39
|
+
interface ChallengeRecord {
|
|
40
|
+
readonly challenge: NewChallenge;
|
|
41
|
+
readonly namespace: string;
|
|
42
|
+
readonly failedAttempts: number;
|
|
43
|
+
readonly consumed: boolean;
|
|
44
|
+
}
|
|
45
|
+
interface ChallengeColumns<T extends Table> {
|
|
46
|
+
readonly challengeId: ColumnKey<T>;
|
|
47
|
+
readonly tokenDigest: ColumnKey<T>;
|
|
48
|
+
readonly namespace: ColumnKey<T>;
|
|
49
|
+
readonly value: ColumnKey<T>;
|
|
50
|
+
readonly purpose: ColumnKey<T>;
|
|
51
|
+
readonly otpKeyId: ColumnKey<T>;
|
|
52
|
+
readonly otpDigest: ColumnKey<T>;
|
|
53
|
+
readonly issuedAt: ColumnKey<T>;
|
|
54
|
+
readonly expiresAt: ColumnKey<T>;
|
|
55
|
+
readonly attemptLimit: ColumnKey<T>;
|
|
56
|
+
readonly failedAttempts: ColumnKey<T>;
|
|
57
|
+
readonly consumed: ColumnKey<T>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Inputs are immutable server-created issuances. Replacements must advance
|
|
61
|
+
* issuedAt; equal or older issuances fail even after consumption or expiry.
|
|
62
|
+
* Instant encoding must preserve this ordering. Retain the series row as an
|
|
63
|
+
* issuance watermark until every previously accepted issuance has expired;
|
|
64
|
+
* current-row expiry alone is insufficient if historical lifetimes were longer.
|
|
65
|
+
*/
|
|
66
|
+
interface ChallengeTableMapping<T extends Table> {
|
|
67
|
+
readonly table: T;
|
|
68
|
+
readonly columns: ChallengeColumns<T>;
|
|
69
|
+
readonly identifierNamespace: string;
|
|
70
|
+
readonly encodeInstant: (instant: DateTime.Utc) => unknown;
|
|
71
|
+
readonly encodeInsert: (input: NewChallenge, state: {
|
|
72
|
+
readonly namespace: string;
|
|
73
|
+
readonly failedAttempts: number;
|
|
74
|
+
readonly consumed: false;
|
|
75
|
+
}) => InferInsertModel<T>;
|
|
76
|
+
readonly encodeUpdate: (input: NewChallenge, state: {
|
|
77
|
+
readonly namespace: string;
|
|
78
|
+
readonly failedAttempts: unknown;
|
|
79
|
+
readonly consumed: false;
|
|
80
|
+
}) => Readonly<Record<string, unknown>>;
|
|
81
|
+
readonly decode: (row: InferSelectModel<T>) => Effect.Effect<ChallengeRecord, PersistenceMappingError>;
|
|
82
|
+
}
|
|
83
|
+
interface RegistrationRecord {
|
|
84
|
+
readonly registration: PendingRegistration;
|
|
85
|
+
readonly consumed: boolean;
|
|
86
|
+
}
|
|
87
|
+
interface RegistrationColumns<T extends Table> {
|
|
88
|
+
readonly registrationId: ColumnKey<T>;
|
|
89
|
+
readonly tokenDigest: ColumnKey<T>;
|
|
90
|
+
readonly expiresAt: ColumnKey<T>;
|
|
91
|
+
readonly consumed: ColumnKey<T>;
|
|
92
|
+
}
|
|
93
|
+
interface RegistrationTableMapping<T extends Table> {
|
|
94
|
+
readonly table: T;
|
|
95
|
+
readonly columns: RegistrationColumns<T>;
|
|
96
|
+
readonly encodeInstant: (instant: DateTime.Utc) => unknown;
|
|
97
|
+
readonly encodeInsert: (input: NewRegistration, consumed: false) => InferInsertModel<T>;
|
|
98
|
+
readonly decode: (row: InferSelectModel<T>) => Effect.Effect<RegistrationRecord, PersistenceMappingError>;
|
|
99
|
+
}
|
|
100
|
+
interface OAuthStateColumns<T extends Table> {
|
|
101
|
+
readonly stateDigest: ColumnKey<T>;
|
|
102
|
+
readonly expiresAt: ColumnKey<T>;
|
|
103
|
+
readonly consumed: ColumnKey<T>;
|
|
104
|
+
}
|
|
105
|
+
interface OAuthStateTableMapping<T extends Table> {
|
|
106
|
+
readonly table: T;
|
|
107
|
+
readonly columns: OAuthStateColumns<T>;
|
|
108
|
+
readonly encodeInstant: (instant: DateTime.Utc) => unknown;
|
|
109
|
+
readonly encodeInsert: (state: OAuthState, consumed: false) => InferInsertModel<T>;
|
|
110
|
+
readonly decode: (row: InferSelectModel<T>) => Effect.Effect<{
|
|
111
|
+
readonly state: OAuthState;
|
|
112
|
+
readonly consumed: boolean;
|
|
113
|
+
}, PersistenceMappingError>;
|
|
114
|
+
}
|
|
115
|
+
interface AuthStoreTables<Challenge extends Table, Registration extends Table> {
|
|
116
|
+
readonly constraints: RequiredAuthStoreConstraints;
|
|
117
|
+
readonly challenge: ChallengeTableMapping<Challenge>;
|
|
118
|
+
readonly registration: RegistrationTableMapping<Registration>;
|
|
119
|
+
}
|
|
120
|
+
interface OAuthStateTables<State extends Table> {
|
|
121
|
+
readonly constraints: RequiredOAuthStateConstraints;
|
|
122
|
+
readonly oauthState: OAuthStateTableMapping<State>;
|
|
123
|
+
}
|
|
124
|
+
interface AuthTables<Challenge extends Table, Registration extends Table, State extends Table> {
|
|
125
|
+
readonly constraints: RequiredAuthConstraints;
|
|
126
|
+
readonly challenge: ChallengeTableMapping<Challenge>;
|
|
127
|
+
readonly registration: RegistrationTableMapping<Registration>;
|
|
128
|
+
readonly oauthState: OAuthStateTableMapping<State>;
|
|
129
|
+
}
|
|
130
|
+
interface RequiredIdentityConstraints {
|
|
131
|
+
readonly identifier: "unique(namespace,value)";
|
|
132
|
+
readonly externalIdentity: "unique(provider,issuer,subject)";
|
|
133
|
+
readonly provisioningRequest: "unique(requestId)";
|
|
134
|
+
readonly provisioningSubject: "notNull(provisioningRequest.subjectId)";
|
|
135
|
+
}
|
|
136
|
+
interface RequiredSubjectProvisioningConstraints {
|
|
137
|
+
readonly identifier: "unique(namespace,value)";
|
|
138
|
+
readonly provisioningRequest: "unique(requestId)";
|
|
139
|
+
readonly provisioningSubject: "notNull(provisioningRequest.subjectId)";
|
|
140
|
+
}
|
|
141
|
+
interface RequiredExternalIdentityConstraints {
|
|
142
|
+
readonly externalIdentity: "unique(provider,issuer,subject)";
|
|
143
|
+
}
|
|
144
|
+
declare const requiredIdentityConstraints: RequiredIdentityConstraints;
|
|
145
|
+
declare const requiredSubjectProvisioningConstraints: RequiredSubjectProvisioningConstraints;
|
|
146
|
+
declare const requiredExternalIdentityConstraints: RequiredExternalIdentityConstraints;
|
|
147
|
+
interface SubjectIdCodec<NativeId> {
|
|
148
|
+
readonly toNative: (id: SubjectId) => Effect.Effect<NativeId, PersistenceMappingError>;
|
|
149
|
+
readonly toSubject: (id: NativeId) => Effect.Effect<SubjectId, PersistenceMappingError>;
|
|
150
|
+
readonly equals: (left: NativeId, right: NativeId) => boolean;
|
|
151
|
+
}
|
|
152
|
+
interface SubjectProvisioningTables<Subject extends Table, Identifier extends Table, Request extends Table, NativeId> {
|
|
153
|
+
readonly constraints: RequiredSubjectProvisioningConstraints;
|
|
154
|
+
readonly subject: {
|
|
155
|
+
readonly table: Subject;
|
|
156
|
+
readonly id: ColumnKey<Subject>;
|
|
157
|
+
readonly status: ColumnKey<Subject>;
|
|
158
|
+
readonly isActiveStatus: (value: unknown) => boolean;
|
|
159
|
+
readonly encodeInsert: (input: SubjectProvisioningInput, allocatedId: NativeId | undefined) => InferInsertModel<Subject>;
|
|
160
|
+
readonly allocateId?: Effect.Effect<NativeId, PersistenceMappingError>;
|
|
161
|
+
/** Required instead of allocateId when a synchronous-only DO transaction preallocates IDs. */
|
|
162
|
+
readonly allocateIdSync?: () => NativeId;
|
|
163
|
+
/** Decodes MySQL `$returningId()` for an autoincrement/runtime-default key. */
|
|
164
|
+
readonly decodeGeneratedId?: (rows: ReadonlyArray<unknown>) => Effect.Effect<NativeId, PersistenceMappingError>;
|
|
165
|
+
};
|
|
166
|
+
readonly identifier: {
|
|
167
|
+
readonly table: Identifier;
|
|
168
|
+
readonly namespace: ColumnKey<Identifier>;
|
|
169
|
+
readonly value: ColumnKey<Identifier>;
|
|
170
|
+
readonly subjectId: ColumnKey<Identifier>;
|
|
171
|
+
readonly encodeInsert: (identifier: LoginIdentifier, subjectId: NativeId, verifiedAt: DateTime.Utc | undefined) => InferInsertModel<Identifier>;
|
|
172
|
+
};
|
|
173
|
+
readonly provisioningRequest: {
|
|
174
|
+
readonly table: Request;
|
|
175
|
+
readonly requestId: ColumnKey<Request>;
|
|
176
|
+
readonly fingerprint: ColumnKey<Request>;
|
|
177
|
+
readonly subjectId: ColumnKey<Request>;
|
|
178
|
+
readonly encodeInsert: (requestId: string, fingerprint: string, subjectId: NativeId) => InferInsertModel<Request>;
|
|
179
|
+
};
|
|
180
|
+
readonly subjectId: SubjectIdCodec<NativeId>;
|
|
181
|
+
/** Narrows only database constraint failures; every other cause is unavailable. */
|
|
182
|
+
readonly isConstraintConflict: (cause: unknown) => boolean;
|
|
183
|
+
}
|
|
184
|
+
interface ExternalIdentityTables<Subject extends Table, External extends Table, NativeId> {
|
|
185
|
+
readonly constraints: RequiredExternalIdentityConstraints;
|
|
186
|
+
readonly subject: {
|
|
187
|
+
readonly table: Subject;
|
|
188
|
+
readonly id: ColumnKey<Subject>;
|
|
189
|
+
readonly status: ColumnKey<Subject>;
|
|
190
|
+
readonly isActiveStatus: (value: unknown) => boolean;
|
|
191
|
+
};
|
|
192
|
+
readonly externalIdentity: {
|
|
193
|
+
readonly table: External;
|
|
194
|
+
readonly provider: ColumnKey<External>;
|
|
195
|
+
readonly issuer: ColumnKey<External>;
|
|
196
|
+
readonly subject: ColumnKey<External>;
|
|
197
|
+
readonly subjectId: ColumnKey<External>;
|
|
198
|
+
readonly encodeInsert: (identity: ExternalIdentity, subjectId: NativeId) => InferInsertModel<External>;
|
|
199
|
+
};
|
|
200
|
+
readonly subjectId: SubjectIdCodec<NativeId>;
|
|
201
|
+
readonly isConstraintConflict: (cause: unknown) => boolean;
|
|
202
|
+
}
|
|
203
|
+
interface IdentityTables<Subject extends Table, Identifier extends Table, External extends Table, Request extends Table, NativeId> {
|
|
204
|
+
readonly constraints: RequiredIdentityConstraints;
|
|
205
|
+
readonly subject: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>["subject"];
|
|
206
|
+
readonly identifier: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>["identifier"];
|
|
207
|
+
readonly externalIdentity: ExternalIdentityTables<Subject, External, NativeId>["externalIdentity"];
|
|
208
|
+
readonly provisioningRequest: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>["provisioningRequest"];
|
|
209
|
+
readonly subjectId: SubjectIdCodec<NativeId>;
|
|
210
|
+
readonly isConstraintConflict: (cause: unknown) => boolean;
|
|
211
|
+
}
|
|
212
|
+
/** Extra encoders used by D1's ordered batch when the subject id is database-generated. */
|
|
213
|
+
interface D1SubjectProvisioningMapping<Subject extends Table, Identifier extends Table, Request extends Table, NativeId> extends SubjectProvisioningTables<Subject, Identifier, Request, NativeId> {
|
|
214
|
+
readonly d1: {
|
|
215
|
+
readonly requestInsertWithoutSubject: (requestId: string, fingerprint: string) => Partial<InferInsertModel<Request>>;
|
|
216
|
+
readonly identifierInsertWithoutSubject: (identifier: LoginIdentifier, verifiedAt: DateTime.Utc | undefined) => Partial<InferInsertModel<Identifier>>;
|
|
217
|
+
/** Unshadowed hidden-rowid alias; omit for WITHOUT ROWID or preallocated IDs. */
|
|
218
|
+
readonly generatedRowIdAlias?: "rowid" | "_rowid_" | "oid";
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
interface D1ExternalIdentityMapping<Subject extends Table, External extends Table, NativeId> extends ExternalIdentityTables<Subject, External, NativeId> {
|
|
222
|
+
readonly d1: {
|
|
223
|
+
readonly activeStatusValue: unknown;
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
interface D1GeneratedIdentityMapping<Subject extends Table, Identifier extends Table, External extends Table, Request extends Table, NativeId> extends IdentityTables<Subject, Identifier, External, Request, NativeId> {
|
|
227
|
+
readonly d1: D1SubjectProvisioningMapping<Subject, Identifier, Request, NativeId>["d1"] & D1ExternalIdentityMapping<Subject, External, NativeId>["d1"];
|
|
228
|
+
}
|
|
229
|
+
declare const provisioningFingerprint: (input: SubjectProvisioningInput) => string;
|
|
230
|
+
/**
|
|
231
|
+
* Drizzle wraps Effect SQL failures before adapters observe them. Give the
|
|
232
|
+
* consumer classifier each semantic wrapper in the short `cause`/`reason`
|
|
233
|
+
* chain without exposing query text or bound parameters through public errors.
|
|
234
|
+
*/
|
|
235
|
+
declare const column: <T extends Table>(table: T, key: ColumnKey<T>) => AnyColumn;
|
|
236
|
+
declare const updateValues: <T extends Table>(entries: ReadonlyArray<readonly [ColumnKey<T>, unknown]>) => Partial<InferInsertModel<T>>;
|
|
237
|
+
type ChallengeInput = ConsumeChallenge;
|
|
238
|
+
/** Acquire an application database in Effect and expose the auth stores as one layer. */
|
|
239
|
+
declare const authServicesLayer: <E, R>(acquire: Effect.Effect<{
|
|
240
|
+
readonly authStore: AuthStore["Service"];
|
|
241
|
+
readonly oauthStateStore: OAuthStateStore["Service"];
|
|
242
|
+
}, E, R>) => Layer.Layer<AuthStore | OAuthStateStore, E, Exclude<R, import("effect/Scope").Scope>>;
|
|
243
|
+
/** Acquire an application database in Effect and expose the identity services as one layer. */
|
|
244
|
+
declare const identityServicesLayer: <E, R>(acquire: Effect.Effect<{
|
|
245
|
+
readonly subjectProvisioner: SubjectProvisioner["Service"];
|
|
246
|
+
readonly externalIdentityMutation: ExternalIdentityMutation["Service"];
|
|
247
|
+
}, E, R>) => Layer.Layer<ExternalIdentityMutation | SubjectProvisioner, E, Exclude<R, import("effect/Scope").Scope>>;
|
|
248
|
+
//#endregion
|
|
249
|
+
export { AuthStoreTables, AuthTables, ChallengeColumns, type ChallengeConsumeDecision, ChallengeInput, ChallengeRecord, ChallengeTableMapping, CommitMode, type ConsumeDecision, D1ExternalIdentityMapping, D1GeneratedIdentityMapping, D1SubjectProvisioningMapping, ExternalIdentityTables, IdentityTables, InstantCodec, OAuthStateColumns, OAuthStateTableMapping, OAuthStateTables, PersistenceMappingError, RegistrationColumns, RegistrationRecord, RegistrationTableMapping, RequiredAuthConstraints, RequiredAuthStoreConstraints, RequiredExternalIdentityConstraints, RequiredIdentityConstraints, RequiredOAuthStateConstraints, RequiredSubjectProvisioningConstraints, SqlClientTransactionDatabase, SubjectIdCodec, SubjectProvisioningTables, authServicesLayer, column, identityServicesLayer, isMappedConstraintConflict, provisioningFingerprint, requireStandaloneConsume, requiredAuthConstraints, requiredAuthStoreConstraints, requiredExternalIdentityConstraints, requiredIdentityConstraints, requiredOAuthStateConstraints, requiredSubjectProvisioningConstraints, updateValues };
|
|
250
|
+
//# sourceMappingURL=model.d.mts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { PersistenceMappingError, isMappedConstraintConflict } from "../internal/mapping-error.mjs";
|
|
2
|
+
import { Context, DateTime, Effect, Layer, Option } from "effect";
|
|
3
|
+
import "@yielded/auth/Schema";
|
|
4
|
+
import { ExternalIdentityMutation, SubjectProvisioner } from "@yielded/auth/Identity";
|
|
5
|
+
import { AuthStore } from "@yielded/auth/AuthStore";
|
|
6
|
+
import { AuthStoreError } from "@yielded/auth/Errors";
|
|
7
|
+
import { OAuthStateStore } from "@yielded/auth/OAuth";
|
|
8
|
+
import { getTableColumns } from "drizzle-orm";
|
|
9
|
+
//#region src/drizzle/model.ts
|
|
10
|
+
const requireStandaloneConsume = (database) => Effect.serviceOption(database.$client.transactionService).pipe(Effect.flatMap(Option.match({
|
|
11
|
+
onNone: () => Effect.void,
|
|
12
|
+
onSome: () => AuthStoreError.make({ message: "Use the decision consume API inside an outer database transaction" })
|
|
13
|
+
})));
|
|
14
|
+
const requiredAuthConstraints = {
|
|
15
|
+
series: "unique(namespace,value,purpose)",
|
|
16
|
+
challengeDigest: "unique(tokenDigest)",
|
|
17
|
+
registrationDigest: "unique(tokenDigest)",
|
|
18
|
+
oauthStateDigest: "unique(stateDigest)"
|
|
19
|
+
};
|
|
20
|
+
const requiredAuthStoreConstraints = {
|
|
21
|
+
series: "unique(namespace,value,purpose)",
|
|
22
|
+
challengeDigest: "unique(tokenDigest)",
|
|
23
|
+
registrationDigest: "unique(tokenDigest)"
|
|
24
|
+
};
|
|
25
|
+
const requiredOAuthStateConstraints = { oauthStateDigest: "unique(stateDigest)" };
|
|
26
|
+
const requiredIdentityConstraints = {
|
|
27
|
+
identifier: "unique(namespace,value)",
|
|
28
|
+
externalIdentity: "unique(provider,issuer,subject)",
|
|
29
|
+
provisioningRequest: "unique(requestId)",
|
|
30
|
+
provisioningSubject: "notNull(provisioningRequest.subjectId)"
|
|
31
|
+
};
|
|
32
|
+
const requiredSubjectProvisioningConstraints = {
|
|
33
|
+
identifier: "unique(namespace,value)",
|
|
34
|
+
provisioningRequest: "unique(requestId)",
|
|
35
|
+
provisioningSubject: "notNull(provisioningRequest.subjectId)"
|
|
36
|
+
};
|
|
37
|
+
const requiredExternalIdentityConstraints = { externalIdentity: "unique(provider,issuer,subject)" };
|
|
38
|
+
const provisioningFingerprint = (input) => JSON.stringify(input.identifier === void 0 ? ["v1", null] : [
|
|
39
|
+
"v1",
|
|
40
|
+
input.identifier.namespace,
|
|
41
|
+
input.identifier.value,
|
|
42
|
+
input.verifiedAt === void 0 ? null : DateTime.toEpochMillis(input.verifiedAt)
|
|
43
|
+
]);
|
|
44
|
+
/**
|
|
45
|
+
* Drizzle wraps Effect SQL failures before adapters observe them. Give the
|
|
46
|
+
* consumer classifier each semantic wrapper in the short `cause`/`reason`
|
|
47
|
+
* chain without exposing query text or bound parameters through public errors.
|
|
48
|
+
*/
|
|
49
|
+
const column = (table, key) => getTableColumns(table)[key];
|
|
50
|
+
const updateValues = (entries) => Object.fromEntries(entries);
|
|
51
|
+
/** Acquire an application database in Effect and expose the auth stores as one layer. */
|
|
52
|
+
const authServicesLayer = (acquire) => Layer.effectContext(Effect.map(acquire, ({ authStore, oauthStateStore }) => Context.make(AuthStore, authStore).pipe(Context.add(OAuthStateStore, oauthStateStore))));
|
|
53
|
+
/** Acquire an application database in Effect and expose the identity services as one layer. */
|
|
54
|
+
const identityServicesLayer = (acquire) => Layer.effectContext(Effect.map(acquire, ({ subjectProvisioner, externalIdentityMutation }) => Context.make(SubjectProvisioner, subjectProvisioner).pipe(Context.add(ExternalIdentityMutation, externalIdentityMutation))));
|
|
55
|
+
//#endregion
|
|
56
|
+
export { PersistenceMappingError, authServicesLayer, column, identityServicesLayer, isMappedConstraintConflict, provisioningFingerprint, requireStandaloneConsume, requiredAuthConstraints, requiredAuthStoreConstraints, requiredExternalIdentityConstraints, requiredIdentityConstraints, requiredOAuthStateConstraints, requiredSubjectProvisioningConstraints, updateValues };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=model.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.mjs","names":[],"sources":["../../src/drizzle/model.ts"],"sourcesContent":["import { 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 type SubjectId,\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, Option } 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 Effect.serviceOption(database.$client.transactionService).pipe(\n Effect.flatMap(\n Option.match({\n onNone: () => Effect.void,\n onSome: () =>\n AuthStoreError.make({\n message: \"Use the decision consume API inside an outer database transaction\",\n }),\n }),\n ),\n );\n\nexport type { ChallengeConsumeDecision } from \"@yielded/auth/Persistence\";\nexport type { ConsumeDecision } from \"@yielded/auth/AuthStore\";\n\nexport { PersistenceMappingError, isMappedConstraintConflict } from \"../internal/mapping-error\";\nimport type { PersistenceMappingError } from \"../internal/mapping-error\";\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 interface SubjectIdCodec<NativeId> {\n readonly toNative: (id: SubjectId) => Effect.Effect<NativeId, PersistenceMappingError>;\n readonly toSubject: (id: NativeId) => Effect.Effect<SubjectId, PersistenceMappingError>;\n readonly equals: (left: NativeId, right: NativeId) => boolean;\n}\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,OAAO,cAAc,SAAS,QAAQ,kBAAkB,CAAC,CAAC,KACxD,OAAO,QACL,OAAO,MAAM;CACX,cAAc,OAAO;CACrB,cACE,eAAe,KAAK,EAClB,SAAS,oEACX,CAAC;AACL,CAAC,CACH,CACF;AA0BF,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;AA0JA,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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { EmailAddressMapping, EmailRegistrationMapping, EmailSignInMapping } from "./email-model.mjs";
|
|
2
|
+
import { ProofPersistenceMapping } from "./proof-model.mjs";
|
|
3
|
+
import { EmailRegistrationAuthority } from "./email-registration.mjs";
|
|
4
|
+
import { SuppliedService } from "./SuppliedService.mjs";
|
|
5
|
+
import { Effect } from "effect";
|
|
6
|
+
import { HookConfigurationError, LifecycleHooks } from "@yielded/auth/Hooks";
|
|
7
|
+
import { EmailAddressPersistence, EmailUnavailable } from "@yielded/auth/Email";
|
|
8
|
+
import { AnyRelations } from "drizzle-orm";
|
|
9
|
+
import { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
|
|
10
|
+
import { SqlError } from "effect/unstable/sql/SqlError";
|
|
11
|
+
import { AnyMySqlTable } from "drizzle-orm/mysql-core";
|
|
12
|
+
//#region src/drizzle/mysql-emails.d.ts
|
|
13
|
+
type Database = EffectMysql2Database<AnyRelations>;
|
|
14
|
+
type TransactionOf<D extends Database> = Parameters<Parameters<D["transaction"]>[0]>[0];
|
|
15
|
+
type ProofMapping = ProofPersistenceMapping<any, any, any, any, any, any, any, any, any, any, any, any>;
|
|
16
|
+
declare const makeMysqlEmailSignInServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, NativeId>(database: Database, mapping: EmailSignInMapping<S, I, C, NativeId>) => Effect.Effect<{
|
|
17
|
+
emailSignInTargets: {
|
|
18
|
+
readonly lookup: (input: {
|
|
19
|
+
readonly moduleId: string;
|
|
20
|
+
readonly identifier: import("@yielded/auth/Identity").LoginIdentifier;
|
|
21
|
+
}) => Effect.Effect<import("effect/Option").Option<import("@yielded/auth/Email").EmailCredentialSnapshot>, EmailUnavailable>;
|
|
22
|
+
};
|
|
23
|
+
}, never, never>;
|
|
24
|
+
declare const makeMysqlEmailAddressServices: <S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, M extends AnyMySqlTable, NativeId>(database: Database, mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>, proofMapping: ProofMapping) => Effect.Effect<{
|
|
25
|
+
emailAddressPersistence: {
|
|
26
|
+
readonly target: (input: {
|
|
27
|
+
readonly moduleId: string;
|
|
28
|
+
readonly subjectId: import("@yielded/auth/Schema").SubjectId;
|
|
29
|
+
readonly target: import("@yielded/auth/Identity").LoginIdentifier;
|
|
30
|
+
readonly sourceCredentialId?: string;
|
|
31
|
+
}) => Effect.Effect<import("@yielded/auth/Email").EmailAddressTarget, EmailUnavailable>;
|
|
32
|
+
readonly checkCompletion: (input: import("@yielded/auth/Proofs").ProofCompletionInput) => Effect.Effect<boolean, EmailUnavailable>;
|
|
33
|
+
readonly verifyWithProof: <A>(input: import("@yielded/auth/Email").EmailAddressMutation, prepare: import("@yielded/auth/Email").PrepareEmailCommit<import("@yielded/auth/Email").EmailAddressDecision, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, EmailUnavailable>;
|
|
34
|
+
readonly changeWithProof: <A>(input: import("@yielded/auth/Email").EmailAddressMutation, prepare: import("@yielded/auth/Email").PrepareEmailCommit<import("@yielded/auth/Email").EmailAddressDecision, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, EmailUnavailable>;
|
|
35
|
+
readonly cleanup: <A>(input: {
|
|
36
|
+
readonly moduleId: string;
|
|
37
|
+
readonly limit: number;
|
|
38
|
+
}, prepare: import("@yielded/auth/Email").PrepareEmailCommit<{
|
|
39
|
+
readonly removed: number;
|
|
40
|
+
readonly hasMore: boolean;
|
|
41
|
+
}, A>) => Effect.Effect<import("@yielded/auth/Hooks").PreparedCommit<A>, EmailUnavailable>;
|
|
42
|
+
};
|
|
43
|
+
}, never, LifecycleHooks>;
|
|
44
|
+
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
|
+
readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;
|
|
46
|
+
readonly proofMapping: ProofMapping;
|
|
47
|
+
readonly transaction?: never;
|
|
48
|
+
}, body: Effect.Effect<Out, E, R>): Effect.Effect<Out, E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError, Exclude<R, EmailAddressPersistence> | LifecycleHooks | DatabaseRequirements>;
|
|
49
|
+
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, TxId, TxShape>(acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>, options: {
|
|
50
|
+
readonly mapping: EmailAddressMapping<S, I, C, AC, M, NativeId>;
|
|
51
|
+
readonly proofMapping: ProofMapping;
|
|
52
|
+
readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;
|
|
53
|
+
}, body: Effect.Effect<Out, E, R>): Effect.Effect<Out, E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError, Exclude<R, EmailAddressPersistence | TxId> | LifecycleHooks | DatabaseRequirements>;
|
|
54
|
+
declare const makeMysqlEmailRegistrationServices: <Registration, S extends AnyMySqlTable, I extends AnyMySqlTable, C extends AnyMySqlTable, AC extends AnyMySqlTable, Rq extends AnyMySqlTable, NativeId>(database: Database, mapping: EmailRegistrationMapping<Registration, S, I, C, AC, Rq, NativeId>, proofMapping: ProofMapping) => Effect.Effect<{
|
|
55
|
+
registrationAuthority: EmailRegistrationAuthority<Registration>;
|
|
56
|
+
}, never, LifecycleHooks>;
|
|
57
|
+
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
|
+
readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;
|
|
59
|
+
readonly proofMapping: ProofMapping;
|
|
60
|
+
readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;
|
|
61
|
+
readonly transaction?: never;
|
|
62
|
+
}, body: Effect.Effect<Out, E, R>): Effect.Effect<Out, E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError, Exclude<R, TargetId> | LifecycleHooks | DatabaseRequirements>;
|
|
63
|
+
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, TxId, TxShape>(acquire: Effect.Effect<D, DatabaseError, DatabaseRequirements>, options: {
|
|
64
|
+
readonly mapping: EmailRegistrationMapping<NoInfer<Registration>, S, I, C, AC, Rq, NativeId>;
|
|
65
|
+
readonly proofMapping: ProofMapping;
|
|
66
|
+
readonly target: SuppliedService<TargetId, EmailRegistrationAuthority<Registration>>;
|
|
67
|
+
readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<D>>, TxShape>;
|
|
68
|
+
}, body: Effect.Effect<Out, E, R>): Effect.Effect<Out, E | EmailUnavailable | HookConfigurationError | SqlError | DatabaseError, Exclude<R, TargetId | TxId> | LifecycleHooks | DatabaseRequirements>;
|
|
69
|
+
//#endregion
|
|
70
|
+
export { coordinateMysqlEmailAddress, coordinateMysqlEmailRegistration, makeMysqlEmailAddressServices, makeMysqlEmailRegistrationServices, makeMysqlEmailSignInServices };
|
|
71
|
+
//# sourceMappingURL=mysql-emails.d.mts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { coordinateTargetEmailAddress, coordinateTargetEmailRegistration, makeTargetEmailAddressServices, makeTargetEmailRegistrationServices, makeTargetEmailSignInServices, sqlClientEmailStandaloneGuard } from "./email-target.mjs";
|
|
2
|
+
import { sqlClientProofStandaloneGuard } from "./proof-target.mjs";
|
|
3
|
+
import { Context, Effect } from "effect";
|
|
4
|
+
import { EmailAddressPersistence } from "@yielded/auth/Email";
|
|
5
|
+
//#region src/drizzle/mysql-emails.ts
|
|
6
|
+
const configuration = (database) => ({
|
|
7
|
+
mode: "interactive",
|
|
8
|
+
locking: true,
|
|
9
|
+
standaloneGuard: sqlClientEmailStandaloneGuard(database),
|
|
10
|
+
generatedSubjectRows: (query) => query.$returningId(),
|
|
11
|
+
proof: {
|
|
12
|
+
mode: "interactive",
|
|
13
|
+
locking: true,
|
|
14
|
+
standaloneGuard: sqlClientProofStandaloneGuard(database),
|
|
15
|
+
insertIfAbsent: (query, selfKey, selfValue) => query.onDuplicateKeyUpdate({ set: { [selfKey]: selfValue } })
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const makeMysqlEmailSignInServices = (database, mapping) => makeTargetEmailSignInServices(database, mapping, configuration(database));
|
|
19
|
+
const makeMysqlEmailAddressServices = (database, mapping, proofMapping) => makeTargetEmailAddressServices(database, mapping, proofMapping, configuration(database));
|
|
20
|
+
function coordinateMysqlEmailAddress(acquire, options, body) {
|
|
21
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetEmailAddress(database, options.mapping, options.proofMapping, configuration(database), (transaction, services) => {
|
|
22
|
+
const provided = Context.make(EmailAddressPersistence, services.emailAddressPersistence);
|
|
23
|
+
const work = Effect.provideContext(body, provided);
|
|
24
|
+
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
const makeMysqlEmailRegistrationServices = (database, mapping, proofMapping) => makeTargetEmailRegistrationServices(database, mapping, proofMapping, configuration(database));
|
|
28
|
+
function coordinateMysqlEmailRegistration(acquire, options, body) {
|
|
29
|
+
return Effect.flatMap(acquire, (database) => coordinateTargetEmailRegistration(database, options.mapping, options.proofMapping, configuration(database), (transaction, services) => {
|
|
30
|
+
const provided = Context.make(options.target, services.registrationAuthority);
|
|
31
|
+
const work = Effect.provideContext(body, provided);
|
|
32
|
+
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { coordinateMysqlEmailAddress, coordinateMysqlEmailRegistration, makeMysqlEmailAddressServices, makeMysqlEmailRegistrationServices, makeMysqlEmailSignInServices };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=mysql-emails.mjs.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ExternalIdentityTables, SubjectProvisioningTables } from "./model.mjs";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { SubjectId } from "@yielded/auth/Schema";
|
|
4
|
+
import { ExternalIdentity, IdentityConflict, IdentityUnavailable, SubjectProvisioningInput } from "@yielded/auth/Identity";
|
|
5
|
+
import { AnyRelations } from "drizzle-orm";
|
|
6
|
+
import { EffectMysql2Database } from "drizzle-orm/effect-mysql2";
|
|
7
|
+
import { AnyMySqlTable } from "drizzle-orm/mysql-core";
|
|
8
|
+
//#region src/drizzle/mysql-identity.d.ts
|
|
9
|
+
type Database = EffectMysql2Database<AnyRelations>;
|
|
10
|
+
declare const makeMysqlSubjectProvisioningServices: <Subject extends AnyMySqlTable, Identifier extends AnyMySqlTable, Request extends AnyMySqlTable, NativeId>(database: Database, mapping: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>) => {
|
|
11
|
+
readonly subjectProvisioner: {
|
|
12
|
+
readonly provision: (input: SubjectProvisioningInput) => Effect.Effect<import("@yielded/auth/Identity").ProvisioningResult, IdentityConflict | IdentityUnavailable>;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
declare const makeMysqlExternalIdentityServices: <Subject extends AnyMySqlTable, External extends AnyMySqlTable, NativeId>(database: Database, mapping: ExternalIdentityTables<Subject, External, NativeId>) => {
|
|
16
|
+
readonly externalIdentityMutation: {
|
|
17
|
+
readonly bind: (subjectId: SubjectId, identity: ExternalIdentity) => Effect.Effect<void, IdentityConflict | IdentityUnavailable>;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { makeMysqlExternalIdentityServices, makeMysqlSubjectProvisioningServices };
|
|
22
|
+
//# sourceMappingURL=mysql-identity.d.mts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { PersistenceMappingError, isMappedConstraintConflict } from "../internal/mapping-error.mjs";
|
|
2
|
+
import { column, provisioningFingerprint } from "./model.mjs";
|
|
3
|
+
import { Cause, Effect, Schema } from "effect";
|
|
4
|
+
import { reportPersistenceFailure } from "@yielded/auth/Persistence";
|
|
5
|
+
import { ExternalIdentityMutation, IdentityConflict, IdentityUnavailable, SubjectProvisioned, SubjectProvisioner } from "@yielded/auth/Identity";
|
|
6
|
+
import { and, eq } from "drizzle-orm";
|
|
7
|
+
//#region src/drizzle/mysql-identity.ts
|
|
8
|
+
const unavailable = () => IdentityUnavailable.make();
|
|
9
|
+
const isIdentityFailure = Schema.is(Schema.Union([IdentityConflict, IdentityUnavailable]));
|
|
10
|
+
const mapUnavailable = (effect) => reportPersistenceFailure(effect, isIdentityFailure).pipe(Effect.catchCause((cause) => Effect.failCause(Cause.map(cause, (error) => isIdentityFailure(error) ? error : unavailable()))));
|
|
11
|
+
const makeMysqlSubjectProvisioningServices = (database, mapping) => {
|
|
12
|
+
const db = database;
|
|
13
|
+
const requestTable = mapping.provisioningRequest.table;
|
|
14
|
+
const requestIdColumn = column(requestTable, mapping.provisioningRequest.requestId);
|
|
15
|
+
const requestFingerprintColumn = column(requestTable, mapping.provisioningRequest.fingerprint);
|
|
16
|
+
const requestSubjectColumn = column(requestTable, mapping.provisioningRequest.subjectId);
|
|
17
|
+
const identifierTable = mapping.identifier.table;
|
|
18
|
+
const identifierNamespaceColumn = column(identifierTable, mapping.identifier.namespace);
|
|
19
|
+
const identifierValueColumn = column(identifierTable, mapping.identifier.value);
|
|
20
|
+
const findReceipt = Effect.fn("DrizzleMysqlIdentity.findReceipt")(function* (requestId) {
|
|
21
|
+
return (yield* db.select({
|
|
22
|
+
fingerprint: requestFingerprintColumn,
|
|
23
|
+
subjectId: requestSubjectColumn
|
|
24
|
+
}).from(requestTable).where(eq(requestIdColumn, requestId)).limit(1))[0];
|
|
25
|
+
});
|
|
26
|
+
const provision = Effect.fn("DrizzleMysqlIdentity.provision")(function* (input) {
|
|
27
|
+
const fingerprint = provisioningFingerprint(input);
|
|
28
|
+
const existing = yield* findReceipt(input.requestId);
|
|
29
|
+
if (existing !== void 0) {
|
|
30
|
+
if (existing.fingerprint !== fingerprint) return yield* IdentityConflict.make();
|
|
31
|
+
const subjectId = yield* mapping.subjectId.toSubject(existing.subjectId);
|
|
32
|
+
return SubjectProvisioned.make({ subjectId });
|
|
33
|
+
}
|
|
34
|
+
const nativeId = yield* db.transaction((tx) => Effect.gen(function* () {
|
|
35
|
+
const allocated = mapping.subject.allocateId === void 0 ? mapping.subject.allocateIdSync?.() : yield* mapping.subject.allocateId;
|
|
36
|
+
const insert = tx.insert(mapping.subject.table).values(mapping.subject.encodeInsert(input, allocated));
|
|
37
|
+
let nativeId = allocated;
|
|
38
|
+
if (nativeId === void 0) {
|
|
39
|
+
if (mapping.subject.decodeGeneratedId === void 0) return yield* PersistenceMappingError.make({
|
|
40
|
+
operation: "provisionSubject.generatedId",
|
|
41
|
+
cause: /* @__PURE__ */ new Error("MySQL generated IDs require decodeGeneratedId")
|
|
42
|
+
});
|
|
43
|
+
const ids = yield* insert.$returningId();
|
|
44
|
+
nativeId = yield* mapping.subject.decodeGeneratedId(ids);
|
|
45
|
+
} else yield* insert;
|
|
46
|
+
if (input.identifier !== void 0) yield* tx.insert(identifierTable).values(mapping.identifier.encodeInsert(input.identifier, nativeId, input.verifiedAt));
|
|
47
|
+
yield* tx.insert(requestTable).values(mapping.provisioningRequest.encodeInsert(input.requestId, fingerprint, nativeId));
|
|
48
|
+
return nativeId;
|
|
49
|
+
})).pipe(Effect.catchCause((cause) => {
|
|
50
|
+
if (cause.reasons.length === 0 || !cause.reasons.every((reason) => Cause.isFailReason(reason) && isMappedConstraintConflict(mapping.isConstraintConflict, reason.error))) return Effect.failCause(cause);
|
|
51
|
+
return findReceipt(input.requestId).pipe(Effect.flatMap((receipt) => {
|
|
52
|
+
if (receipt !== void 0 && receipt.fingerprint === fingerprint) return Effect.succeed(receipt.subjectId);
|
|
53
|
+
if (input.identifier === void 0) return IdentityConflict.make();
|
|
54
|
+
return db.select({ subjectId: column(identifierTable, mapping.identifier.subjectId) }).from(identifierTable).where(and(eq(identifierNamespaceColumn, input.identifier.namespace), eq(identifierValueColumn, input.identifier.value))).limit(1).pipe(Effect.flatMap(() => IdentityConflict.make()));
|
|
55
|
+
}));
|
|
56
|
+
}));
|
|
57
|
+
const subjectId = yield* mapping.subjectId.toSubject(nativeId);
|
|
58
|
+
return SubjectProvisioned.make({ subjectId });
|
|
59
|
+
}, mapUnavailable);
|
|
60
|
+
return { subjectProvisioner: SubjectProvisioner.of({ provision }) };
|
|
61
|
+
};
|
|
62
|
+
const makeMysqlExternalIdentityServices = (database, mapping) => {
|
|
63
|
+
const db = database;
|
|
64
|
+
const externalTable = mapping.externalIdentity.table;
|
|
65
|
+
const externalProviderColumn = column(externalTable, mapping.externalIdentity.provider);
|
|
66
|
+
const externalIssuerColumn = column(externalTable, mapping.externalIdentity.issuer);
|
|
67
|
+
const externalSubjectColumn = column(externalTable, mapping.externalIdentity.subject);
|
|
68
|
+
const externalSubjectIdColumn = column(externalTable, mapping.externalIdentity.subjectId);
|
|
69
|
+
const subjectIdColumn = column(mapping.subject.table, mapping.subject.id);
|
|
70
|
+
const subjectStatusColumn = column(mapping.subject.table, mapping.subject.status);
|
|
71
|
+
const bind = Effect.fn("DrizzleMysqlIdentity.bindExternalIdentity")(function* (subjectId, identity) {
|
|
72
|
+
const nativeId = yield* mapping.subjectId.toNative(subjectId);
|
|
73
|
+
if ((yield* db.transaction((tx) => Effect.gen(function* () {
|
|
74
|
+
const subjects = yield* tx.select({ status: subjectStatusColumn }).from(mapping.subject.table).where(eq(subjectIdColumn, nativeId)).for("update").limit(1);
|
|
75
|
+
if (subjects[0] === void 0 || !mapping.subject.isActiveStatus(subjects[0].status)) return { _tag: "conflict" };
|
|
76
|
+
const links = yield* tx.select({ subjectId: externalSubjectIdColumn }).from(externalTable).where(and(eq(externalProviderColumn, identity.provider), eq(externalIssuerColumn, identity.issuer), eq(externalSubjectColumn, identity.subject))).for("update").limit(1);
|
|
77
|
+
if (links[0] !== void 0) return mapping.subjectId.equals(links[0].subjectId, nativeId) ? { _tag: "bound" } : { _tag: "conflict" };
|
|
78
|
+
yield* tx.insert(externalTable).values(mapping.externalIdentity.encodeInsert(identity, nativeId));
|
|
79
|
+
return { _tag: "bound" };
|
|
80
|
+
})).pipe(Effect.catchCause((cause) => {
|
|
81
|
+
if (cause.reasons.length === 0 || !cause.reasons.every((reason) => Cause.isFailReason(reason) && isMappedConstraintConflict(mapping.isConstraintConflict, reason.error))) return Effect.failCause(cause);
|
|
82
|
+
return db.select({ subjectId: externalSubjectIdColumn }).from(externalTable).where(and(eq(externalProviderColumn, identity.provider), eq(externalIssuerColumn, identity.issuer), eq(externalSubjectColumn, identity.subject))).limit(1).pipe(Effect.map((rows) => rows[0] !== void 0 && mapping.subjectId.equals(rows[0].subjectId, nativeId) ? { _tag: "bound" } : { _tag: "conflict" }));
|
|
83
|
+
})))._tag === "conflict") return yield* IdentityConflict.make();
|
|
84
|
+
}, mapUnavailable);
|
|
85
|
+
return { externalIdentityMutation: ExternalIdentityMutation.of({ bind }) };
|
|
86
|
+
};
|
|
87
|
+
const makeMysqlIdentityServices = (database, mapping) => ({
|
|
88
|
+
...makeMysqlSubjectProvisioningServices(database, mapping),
|
|
89
|
+
...makeMysqlExternalIdentityServices(database, mapping)
|
|
90
|
+
});
|
|
91
|
+
//#endregion
|
|
92
|
+
export { makeMysqlExternalIdentityServices, makeMysqlIdentityServices, makeMysqlSubjectProvisioningServices };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=mysql-identity.mjs.map
|