@yielded/auth-persistence-drizzle 0.1.0-beta.25 → 0.1.0-beta.26
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 +4 -2
- package/dist/D1.d.mts +495 -1151
- package/dist/D1.mjs +41 -19
- package/dist/D1.mjs.map +1 -1
- package/dist/Libsql.d.mts +385 -1996
- package/dist/Libsql.mjs +43 -47
- package/dist/Libsql.mjs.map +1 -1
- package/dist/Mysql2.d.mts +397 -1743
- package/dist/Mysql2.mjs +35 -41
- package/dist/Mysql2.mjs.map +1 -1
- package/dist/Pglite.d.mts +397 -1743
- package/dist/Pglite.mjs +42 -31
- package/dist/Pglite.mjs.map +1 -1
- package/dist/Postgres.d.mts +397 -1743
- package/dist/Postgres.mjs +42 -31
- package/dist/Postgres.mjs.map +1 -1
- package/dist/SqliteBun.d.mts +385 -1992
- package/dist/SqliteBun.mjs +43 -43
- package/dist/SqliteBun.mjs.map +1 -1
- package/dist/SqliteDo.d.mts +385 -1991
- package/dist/SqliteDo.mjs +42 -41
- package/dist/SqliteDo.mjs.map +1 -1
- package/dist/SqliteNode.d.mts +385 -1992
- package/dist/SqliteNode.mjs +43 -43
- package/dist/SqliteNode.mjs.map +1 -1
- package/dist/SqliteWasm.d.mts +385 -1992
- package/dist/SqliteWasm.mjs +43 -43
- package/dist/SqliteWasm.mjs.map +1 -1
- package/dist/drizzle/d1-identity.mjs +2 -2
- package/dist/drizzle/d1-identity.mjs.map +1 -1
- package/dist/drizzle/driver-types.d.mts +15 -0
- package/dist/drizzle/email-drivers.mjs +32 -0
- package/dist/drizzle/email-drivers.mjs.map +1 -0
- package/dist/drizzle/email-model.d.mts +9 -13
- package/dist/drizzle/email-target.d.mts +10 -11
- package/dist/drizzle/email-target.mjs +33 -70
- package/dist/drizzle/email-target.mjs.map +1 -1
- package/dist/drizzle/model.d.mts +1 -10
- package/dist/drizzle/model.mjs +1 -2
- package/dist/drizzle/model.mjs.map +1 -1
- package/dist/drizzle/mysql-identity.mjs +3 -6
- package/dist/drizzle/mysql-identity.mjs.map +1 -1
- package/dist/drizzle/native-clock.d.mts +9 -0
- package/dist/drizzle/native-clock.mjs +18 -0
- package/dist/drizzle/native-clock.mjs.map +1 -0
- package/dist/drizzle/native-database.d.mts +46 -0
- package/dist/drizzle/native-database.mjs +6 -5
- package/dist/drizzle/native-database.mjs.map +1 -1
- package/dist/drizzle/native-sql-table.mjs +13 -5
- package/dist/drizzle/native-sql-table.mjs.map +1 -1
- package/dist/drizzle/native-target.d.mts +6 -0
- package/dist/drizzle/native-target.mjs +44 -0
- package/dist/drizzle/native-target.mjs.map +1 -0
- package/dist/drizzle/oauth-connected-drivers.mjs +4 -56
- package/dist/drizzle/oauth-connected-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-connected-model.d.mts +5 -22
- package/dist/drizzle/oauth-connected-model.mjs +1 -7
- package/dist/drizzle/oauth-connected-reference.d.mts +5 -7
- package/dist/drizzle/oauth-connected-reference.mjs +11 -3
- package/dist/drizzle/oauth-connected-reference.mjs.map +1 -1
- package/dist/drizzle/oauth-drivers.mjs +1 -2
- package/dist/drizzle/oauth-drivers.mjs.map +1 -1
- package/dist/drizzle/oauth-model.d.mts +11 -37
- package/dist/drizzle/oauth-model.mjs +3 -4
- package/dist/drizzle/oauth-model.mjs.map +1 -1
- package/dist/drizzle/oauth-proxy.d.mts +1 -1
- package/dist/drizzle/oauth-proxy.mjs +1 -1
- package/dist/drizzle/oauth-target.d.mts +9 -6
- package/dist/drizzle/oauth-target.mjs +47 -15
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/passkey/target.d.mts +14 -0
- package/dist/drizzle/passkey/target.mjs +52 -0
- package/dist/drizzle/passkey/target.mjs.map +1 -0
- package/dist/drizzle/passkey/write-target.d.mts +11 -0
- package/dist/drizzle/passkey/write-target.mjs +28 -0
- package/dist/drizzle/passkey/write-target.mjs.map +1 -0
- package/dist/drizzle/passkey-drivers.mjs +2 -4
- package/dist/drizzle/passkey-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-model.d.mts +5 -26
- package/dist/drizzle/passkey-model.mjs +2 -8
- package/dist/drizzle/passkey-registration-ceremony-model.d.mts +3 -6
- package/dist/drizzle/passkey-write-drivers.mjs +2 -3
- package/dist/drizzle/passkey-write-drivers.mjs.map +1 -1
- package/dist/drizzle/passkey-write-model.d.mts +7 -9
- package/dist/drizzle/passkey-write-model.mjs +1 -3
- package/dist/drizzle/passkey-write-model.mjs.map +1 -1
- package/dist/drizzle/password-drivers.mjs +31 -0
- package/dist/drizzle/password-drivers.mjs.map +1 -0
- package/dist/drizzle/password-model.d.mts +7 -10
- package/dist/drizzle/password-target.d.mts +7 -8
- package/dist/drizzle/password-target.mjs +23 -68
- package/dist/drizzle/password-target.mjs.map +1 -1
- package/dist/drizzle/pg-identity.mjs +3 -6
- package/dist/drizzle/pg-identity.mjs.map +1 -1
- package/dist/drizzle/phone-drivers.mjs +24 -0
- package/dist/drizzle/phone-drivers.mjs.map +1 -0
- package/dist/drizzle/phone-model.d.mts +13 -104
- package/dist/drizzle/phone-model.mjs +5 -33
- package/dist/drizzle/phone-model.mjs.map +1 -1
- package/dist/drizzle/phone-target.mjs +22 -171
- package/dist/drizzle/phone-target.mjs.map +1 -1
- package/dist/drizzle/proof-drivers.mjs +24 -0
- package/dist/drizzle/proof-drivers.mjs.map +1 -0
- package/dist/drizzle/proof-model.d.mts +7 -15
- package/dist/drizzle/proof-target.d.mts +5 -5
- package/dist/drizzle/proof-target.mjs +14 -28
- package/dist/drizzle/proof-target.mjs.map +1 -1
- package/dist/drizzle/session-drivers.mjs +97 -0
- package/dist/drizzle/session-drivers.mjs.map +1 -0
- package/dist/drizzle/session-model.d.mts +11 -22
- package/dist/drizzle/sqlite-do-database.d.mts +3 -3
- package/dist/drizzle/sqlite-do-database.mjs +6 -1
- package/dist/drizzle/sqlite-do-database.mjs.map +1 -1
- package/dist/drizzle/sqlite-identity.mjs +3 -5
- package/dist/drizzle/sqlite-identity.mjs.map +1 -1
- package/dist/drizzle/step-up-model.d.mts +2 -5
- package/dist/drizzle/storage-validation.mjs +2 -1
- package/dist/drizzle/storage-validation.mjs.map +1 -1
- package/dist/drizzle/totp-model.d.mts +7 -74
- package/dist/drizzle/totp-model.mjs +1 -5
- package/dist/drizzle/totp-model.mjs.map +1 -1
- package/dist/drizzle/totp-target.mjs +39 -75
- package/dist/drizzle/totp-target.mjs.map +1 -1
- package/dist/drizzle/transaction-handle.mjs +13 -0
- package/dist/drizzle/transaction-handle.mjs.map +1 -0
- package/dist/drizzle/transaction-mysql.mjs +43 -12
- package/dist/drizzle/transaction-mysql.mjs.map +1 -1
- package/dist/index.d.mts +17 -22
- package/dist/index.mjs +10 -16
- package/dist/internal/drizzle-postgres.mjs +4 -6
- package/dist/internal/drizzle-postgres.mjs.map +1 -1
- package/dist/internal/drizzle-sqlite.mjs +4 -6
- package/dist/internal/drizzle-sqlite.mjs.map +1 -1
- package/package.json +1 -1
- package/src/D1.ts +77 -74
- package/src/Libsql.ts +65 -105
- package/src/Mysql2.ts +52 -87
- package/src/Pglite.ts +74 -81
- package/src/Postgres.ts +74 -81
- package/src/SqliteBun.ts +65 -113
- package/src/SqliteDo.ts +58 -106
- package/src/SqliteNode.ts +65 -113
- package/src/SqliteWasm.ts +65 -113
- package/src/drizzle/d1-identity.ts +2 -2
- package/src/drizzle/driver-types.ts +26 -0
- package/src/drizzle/email-drivers.ts +320 -0
- package/src/drizzle/email-model.ts +24 -78
- package/src/drizzle/email-target.ts +118 -211
- package/src/drizzle/model.ts +0 -2
- package/src/drizzle/mysql-identity.ts +4 -24
- package/src/drizzle/native-clock.ts +21 -0
- package/src/drizzle/native-database.ts +59 -18
- package/src/drizzle/native-sql-table.ts +104 -87
- package/src/drizzle/native-target.ts +120 -0
- package/src/drizzle/oauth-connected-drivers.ts +24 -233
- package/src/drizzle/oauth-connected-model.ts +3 -93
- package/src/drizzle/oauth-connected-reference.ts +16 -25
- package/src/drizzle/oauth-drivers.ts +58 -99
- package/src/drizzle/oauth-model.ts +27 -132
- package/src/drizzle/oauth-target.ts +250 -33
- package/src/drizzle/passkey/target.ts +205 -0
- package/src/drizzle/passkey/write-target.ts +91 -0
- package/src/drizzle/passkey-drivers.ts +35 -133
- package/src/drizzle/passkey-model.ts +3 -81
- package/src/drizzle/passkey-registration-ceremony-model.ts +5 -25
- package/src/drizzle/passkey-write-drivers.ts +32 -102
- package/src/drizzle/passkey-write-model.ts +10 -44
- package/src/drizzle/password-drivers.ts +286 -0
- package/src/drizzle/password-model.ts +10 -44
- package/src/drizzle/password-target.ts +85 -239
- package/src/drizzle/pg-identity.ts +4 -19
- package/src/drizzle/phone-drivers.ts +142 -0
- package/src/drizzle/phone-model.ts +22 -162
- package/src/drizzle/phone-target.ts +51 -493
- package/src/drizzle/proof-drivers.ts +123 -0
- package/src/drizzle/proof-model.ts +12 -123
- package/src/drizzle/proof-target.ts +38 -102
- package/src/drizzle/session-drivers.ts +696 -0
- package/src/drizzle/session-model.ts +54 -118
- package/src/drizzle/sqlite-do-database.ts +8 -0
- package/src/drizzle/sqlite-identity.ts +4 -22
- package/src/drizzle/step-up-model.ts +13 -37
- package/src/drizzle/storage-validation.ts +2 -1
- package/src/drizzle/totp-model.ts +20 -77
- package/src/drizzle/totp-target.ts +121 -261
- package/src/drizzle/transaction-handle.ts +41 -0
- package/src/drizzle/transaction-mysql.ts +90 -25
- package/src/index.ts +7 -122
- package/src/internal/drizzle-postgres.ts +4 -7
- package/src/internal/drizzle-sqlite.ts +4 -7
- package/dist/drizzle/crypto.mjs +0 -11
- package/dist/drizzle/crypto.mjs.map +0 -1
- package/dist/drizzle/d1-emails.d.mts +0 -62
- package/dist/drizzle/d1-emails.mjs +0 -626
- package/dist/drizzle/d1-emails.mjs.map +0 -1
- package/dist/drizzle/d1-generated-statement.mjs +0 -79
- package/dist/drizzle/d1-generated-statement.mjs.map +0 -1
- package/dist/drizzle/d1-oauth.d.mts +0 -331
- package/dist/drizzle/d1-oauth.mjs +0 -79
- package/dist/drizzle/d1-oauth.mjs.map +0 -1
- package/dist/drizzle/d1-passkey.d.mts +0 -37
- package/dist/drizzle/d1-passkey.mjs +0 -98
- package/dist/drizzle/d1-passkey.mjs.map +0 -1
- package/dist/drizzle/d1-password-prepared.d.mts +0 -25
- package/dist/drizzle/d1-password-prepared.mjs +0 -473
- package/dist/drizzle/d1-password-prepared.mjs.map +0 -1
- package/dist/drizzle/d1-passwords.d.mts +0 -70
- package/dist/drizzle/d1-passwords.mjs +0 -808
- package/dist/drizzle/d1-passwords.mjs.map +0 -1
- package/dist/drizzle/d1-phone.d.mts +0 -23
- package/dist/drizzle/d1-phone.mjs +0 -33
- package/dist/drizzle/d1-phone.mjs.map +0 -1
- package/dist/drizzle/d1-planning.d.mts +0 -11
- package/dist/drizzle/d1-planning.mjs +0 -43
- package/dist/drizzle/d1-planning.mjs.map +0 -1
- package/dist/drizzle/d1-proofs.d.mts +0 -80
- package/dist/drizzle/d1-proofs.mjs +0 -842
- package/dist/drizzle/d1-proofs.mjs.map +0 -1
- package/dist/drizzle/d1-sessions.d.mts +0 -68
- package/dist/drizzle/d1-sessions.mjs +0 -987
- package/dist/drizzle/d1-sessions.mjs.map +0 -1
- package/dist/drizzle/d1-totp.d.mts +0 -23
- package/dist/drizzle/d1-totp.mjs +0 -30
- package/dist/drizzle/d1-totp.mjs.map +0 -1
- package/dist/drizzle/email-registration.d.mts +0 -33
- package/dist/drizzle/email-registration.mjs +0 -281
- package/dist/drizzle/email-registration.mjs.map +0 -1
- package/dist/drizzle/email-sql.d.mts +0 -1
- package/dist/drizzle/email-sql.mjs +0 -9
- package/dist/drizzle/email-sql.mjs.map +0 -1
- package/dist/drizzle/mysql-emails.d.mts +0 -71
- package/dist/drizzle/mysql-emails.mjs +0 -43
- package/dist/drizzle/mysql-emails.mjs.map +0 -1
- package/dist/drizzle/mysql-password-prepared.d.mts +0 -30
- package/dist/drizzle/mysql-password-prepared.mjs +0 -21
- package/dist/drizzle/mysql-password-prepared.mjs.map +0 -1
- package/dist/drizzle/mysql-passwords.d.mts +0 -71
- package/dist/drizzle/mysql-passwords.mjs +0 -43
- package/dist/drizzle/mysql-passwords.mjs.map +0 -1
- package/dist/drizzle/mysql-proofs.d.mts +0 -75
- package/dist/drizzle/mysql-proofs.mjs +0 -28
- package/dist/drizzle/mysql-proofs.mjs.map +0 -1
- package/dist/drizzle/mysql-sessions.d.mts +0 -92
- package/dist/drizzle/mysql-sessions.mjs +0 -58
- package/dist/drizzle/mysql-sessions.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-model.mjs.map +0 -1
- package/dist/drizzle/oauth-connected-target.d.mts +0 -6
- package/dist/drizzle/oauth-connected-target.mjs +0 -12
- package/dist/drizzle/oauth-connected-target.mjs.map +0 -1
- package/dist/drizzle/oauth-kernel.mjs +0 -11
- package/dist/drizzle/oauth-kernel.mjs.map +0 -1
- package/dist/drizzle/oauth-mysql.mjs +0 -8
- package/dist/drizzle/oauth-mysql.mjs.map +0 -1
- package/dist/drizzle/passkey-kernel.mjs +0 -8
- package/dist/drizzle/passkey-kernel.mjs.map +0 -1
- package/dist/drizzle/passkey-model.mjs.map +0 -1
- package/dist/drizzle/passkey-registration-ceremony-model.mjs +0 -2
- package/dist/drizzle/passkey-state.mjs +0 -7
- package/dist/drizzle/passkey-state.mjs.map +0 -1
- package/dist/drizzle/passkey-target.d.mts +0 -2
- package/dist/drizzle/passkey-target.mjs +0 -7
- package/dist/drizzle/passkey-target.mjs.map +0 -1
- package/dist/drizzle/passkey-write-target.d.mts +0 -5
- package/dist/drizzle/passkey-write-target.mjs +0 -7
- package/dist/drizzle/passkey-write-target.mjs.map +0 -1
- package/dist/drizzle/password-prepared-model.d.mts +0 -92
- package/dist/drizzle/password-prepared-model.mjs +0 -11
- package/dist/drizzle/password-prepared-model.mjs.map +0 -1
- package/dist/drizzle/password-prepared-sql.mjs +0 -395
- package/dist/drizzle/password-prepared-sql.mjs.map +0 -1
- package/dist/drizzle/password-prepared-state.mjs +0 -104
- package/dist/drizzle/password-prepared-state.mjs.map +0 -1
- package/dist/drizzle/password-prepared-target.d.mts +0 -13
- package/dist/drizzle/password-prepared-target.mjs +0 -62
- package/dist/drizzle/password-prepared-target.mjs.map +0 -1
- package/dist/drizzle/password-registration.d.mts +0 -7
- package/dist/drizzle/password-registration.mjs +0 -137
- package/dist/drizzle/password-registration.mjs.map +0 -1
- package/dist/drizzle/password-sql.d.mts +0 -1
- package/dist/drizzle/password-sql.mjs +0 -10
- package/dist/drizzle/password-sql.mjs.map +0 -1
- package/dist/drizzle/pg-emails.d.mts +0 -72
- package/dist/drizzle/pg-emails.mjs +0 -43
- package/dist/drizzle/pg-emails.mjs.map +0 -1
- package/dist/drizzle/pg-password-prepared.d.mts +0 -31
- package/dist/drizzle/pg-password-prepared.mjs +0 -21
- package/dist/drizzle/pg-password-prepared.mjs.map +0 -1
- package/dist/drizzle/pg-passwords.d.mts +0 -72
- package/dist/drizzle/pg-passwords.mjs +0 -43
- package/dist/drizzle/pg-passwords.mjs.map +0 -1
- package/dist/drizzle/pg-proofs.d.mts +0 -76
- package/dist/drizzle/pg-proofs.mjs +0 -27
- package/dist/drizzle/pg-proofs.mjs.map +0 -1
- package/dist/drizzle/pg-sessions.d.mts +0 -93
- package/dist/drizzle/pg-sessions.mjs +0 -58
- package/dist/drizzle/pg-sessions.mjs.map +0 -1
- package/dist/drizzle/phone-state.mjs +0 -14
- package/dist/drizzle/phone-state.mjs.map +0 -1
- package/dist/drizzle/phone-target.d.mts +0 -15
- package/dist/drizzle/proof-sql.d.mts +0 -1
- package/dist/drizzle/proof-sql.mjs +0 -8
- package/dist/drizzle/proof-sql.mjs.map +0 -1
- package/dist/drizzle/query-operations.mjs +0 -31
- package/dist/drizzle/query-operations.mjs.map +0 -1
- package/dist/drizzle/session-sql.d.mts +0 -1
- package/dist/drizzle/session-sql.mjs +0 -9
- package/dist/drizzle/session-sql.mjs.map +0 -1
- package/dist/drizzle/session-target.d.mts +0 -30
- package/dist/drizzle/session-target.mjs +0 -49
- package/dist/drizzle/session-target.mjs.map +0 -1
- package/dist/drizzle/sqlite-emails.mjs +0 -50
- package/dist/drizzle/sqlite-emails.mjs.map +0 -1
- package/dist/drizzle/sqlite-password-prepared.mjs +0 -26
- package/dist/drizzle/sqlite-password-prepared.mjs.map +0 -1
- package/dist/drizzle/sqlite-passwords.mjs +0 -54
- package/dist/drizzle/sqlite-passwords.mjs.map +0 -1
- package/dist/drizzle/sqlite-proofs.mjs +0 -34
- package/dist/drizzle/sqlite-proofs.mjs.map +0 -1
- package/dist/drizzle/sqlite-sessions.mjs +0 -79
- package/dist/drizzle/sqlite-sessions.mjs.map +0 -1
- package/dist/drizzle/standalone-guard.d.mts +0 -2
- package/dist/drizzle/standalone-guard.mjs +0 -21
- package/dist/drizzle/standalone-guard.mjs.map +0 -1
- package/dist/drizzle/totp-state.d.mts +0 -37
- package/dist/drizzle/totp-state.mjs +0 -287
- package/dist/drizzle/totp-state.mjs.map +0 -1
- package/dist/drizzle/totp-target.d.mts +0 -15
- package/dist/drizzle/transaction-execution.d.mts +0 -2
- package/dist/drizzle/transaction-execution.mjs +0 -11
- package/dist/drizzle/transaction-execution.mjs.map +0 -1
- package/dist/drizzle/transaction-owner.d.mts +0 -1
- package/dist/drizzle/transaction-owner.mjs +0 -8
- package/dist/drizzle/transaction-owner.mjs.map +0 -1
- package/src/drizzle/crypto.ts +0 -14
- package/src/drizzle/d1-emails.ts +0 -1945
- package/src/drizzle/d1-generated-statement.ts +0 -129
- package/src/drizzle/d1-oauth.ts +0 -360
- package/src/drizzle/d1-passkey.ts +0 -383
- package/src/drizzle/d1-password-prepared.ts +0 -1266
- package/src/drizzle/d1-passwords.ts +0 -2061
- package/src/drizzle/d1-phone.ts +0 -103
- package/src/drizzle/d1-planning.ts +0 -104
- package/src/drizzle/d1-proofs.ts +0 -2354
- package/src/drizzle/d1-sessions.ts +0 -2940
- package/src/drizzle/d1-totp.ts +0 -88
- package/src/drizzle/email-registration.ts +0 -850
- package/src/drizzle/email-sql.ts +0 -25
- package/src/drizzle/mysql-emails.ts +0 -343
- package/src/drizzle/mysql-password-prepared.ts +0 -198
- package/src/drizzle/mysql-passwords.ts +0 -343
- package/src/drizzle/mysql-proofs.ts +0 -196
- package/src/drizzle/mysql-sessions.ts +0 -780
- package/src/drizzle/oauth-connected-target.ts +0 -21
- package/src/drizzle/oauth-kernel.ts +0 -10
- package/src/drizzle/oauth-mysql.ts +0 -10
- package/src/drizzle/passkey-kernel.ts +0 -4
- package/src/drizzle/passkey-state.ts +0 -3
- package/src/drizzle/passkey-target.ts +0 -23
- package/src/drizzle/passkey-write-target.ts +0 -9
- package/src/drizzle/password-prepared-model.ts +0 -241
- package/src/drizzle/password-prepared-sql.ts +0 -1202
- package/src/drizzle/password-prepared-state.ts +0 -231
- package/src/drizzle/password-prepared-target.ts +0 -169
- package/src/drizzle/password-registration.ts +0 -369
- package/src/drizzle/password-sql.ts +0 -16
- package/src/drizzle/pg-emails.ts +0 -343
- package/src/drizzle/pg-password-prepared.ts +0 -199
- package/src/drizzle/pg-passwords.ts +0 -342
- package/src/drizzle/pg-proofs.ts +0 -206
- package/src/drizzle/pg-sessions.ts +0 -789
- package/src/drizzle/phone-state.ts +0 -21
- package/src/drizzle/proof-sql.ts +0 -10
- package/src/drizzle/query-operations.ts +0 -49
- package/src/drizzle/session-sql.ts +0 -15
- package/src/drizzle/session-target.ts +0 -337
- package/src/drizzle/sqlite-emails.ts +0 -393
- package/src/drizzle/sqlite-password-prepared.ts +0 -230
- package/src/drizzle/sqlite-passwords.ts +0 -497
- package/src/drizzle/sqlite-proofs.ts +0 -229
- package/src/drizzle/sqlite-sessions.ts +0 -1013
- package/src/drizzle/totp-state.ts +0 -525
- package/src/drizzle/transaction-execution.ts +0 -13
- package/src/drizzle/transaction-owner.ts +0 -11
|
@@ -1,31 +1,20 @@
|
|
|
1
|
+
import { ClockMapping } from "./native-clock.mjs";
|
|
1
2
|
import { DrizzleTableModel } from "./table-model.mjs";
|
|
2
3
|
import * as Shared from "@yielded/auth-persistence/Adapter";
|
|
3
|
-
import { RequiredPendingAuthenticationConstraints, RequiredSessionConstraints, RequiredSignedValidityConstraints, RequiredStatefulPendingConstraints,
|
|
4
|
+
import { RequiredPendingAuthenticationConstraints, RequiredSessionConstraints, RequiredSignedValidityConstraints, RequiredStatefulPendingConstraints, SessionIdCodec, SessionPendingInsert, requiredPendingAuthenticationConstraints, requiredSessionConstraints, requiredSignedValidityConstraints, requiredStatefulPendingConstraints } from "@yielded/auth-persistence/Adapter";
|
|
4
5
|
import { SQL, Table } from "drizzle-orm";
|
|
5
6
|
//#region src/drizzle/session-model.d.ts
|
|
6
7
|
export type SessionSubjectTables<Subject extends Table, NativeId> = Shared.SessionSubjectTables<DrizzleTableModel<Subject>, NativeId>;
|
|
7
8
|
export type SessionAuthorityTables<Subject extends Table, Credential extends Table, NativeId> = Shared.SessionAuthorityTables<DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, NativeId>;
|
|
8
|
-
export type
|
|
9
|
-
export type
|
|
10
|
-
export type PendingAuthenticationTables<Claims, Pending extends Table,
|
|
9
|
+
export type StatefulSessionTables<Claims, Session extends Table, NativeSubjectId, NativeSessionId> = Shared.StatefulSessionTables<Claims, DrizzleTableModel<Session>, NativeSubjectId, NativeSessionId>;
|
|
10
|
+
export type SessionPendingTables<Pending extends Table, NativeSubjectId> = Shared.SessionPendingTables<DrizzleTableModel<Pending>, NativeSubjectId>;
|
|
11
|
+
export type PendingAuthenticationTables<Claims, Pending extends Table, NativeSubjectId> = Shared.PendingAuthenticationTables<Claims, DrizzleTableModel<Pending>, NativeSubjectId>;
|
|
11
12
|
export type SignedSessionValidityTables<Tombstone extends Table, NativeSubjectId, NativeSessionId> = Shared.SignedSessionValidityTables<DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId>;
|
|
12
|
-
export type AuthenticationAuthorityMapping<Claims, Subject extends Table, Credential extends Table,
|
|
13
|
-
export type StatefulSessionMapping<Claims, Subject extends Table, Credential extends Table, Session extends Table,
|
|
14
|
-
export type PendingAuthenticationMapping<Claims, Subject extends Table, Credential extends Table, Pending extends Table,
|
|
15
|
-
export type SignedSessionValidityMapping<Subject extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = Shared.SignedSessionValidityMapping<DrizzleTableModel<Subject>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId
|
|
16
|
-
|
|
17
|
-
* `engineNow` must use the exact native representation of every mapped instant
|
|
18
|
-
* column. `engineNowMillis` is Unix epoch milliseconds for proof freshness.
|
|
19
|
-
* Changes to the consumer's factor policy MUST bump subject.securityRevision.
|
|
20
|
-
* Supply the authoritative primary D1 database, never a replica-affined
|
|
21
|
-
* `withSession` handle, because verification and security revision reads must
|
|
22
|
-
* observe completed revocation writes across clients.
|
|
23
|
-
*/
|
|
24
|
-
export type D1SessionClockMapping = Shared.D1SessionClockMapping<SQL>;
|
|
25
|
-
export type D1AuthenticationAuthorityMapping<Claims, Subject extends Table, Credential extends Table, Flow extends Table, Pending extends Table, NativeSubjectId> = Shared.D1AuthenticationAuthorityMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Flow>, DrizzleTableModel<Pending>, NativeSubjectId, SQL>;
|
|
26
|
-
export type D1PendingAuthenticationMapping<Claims, Subject extends Table, Credential extends Table, Pending extends Table, Flow extends Table, NativeSubjectId> = Shared.D1PendingAuthenticationMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Pending>, DrizzleTableModel<Flow>, NativeSubjectId, SQL>;
|
|
27
|
-
export type D1StatefulSessionMapping<Claims, Subject extends Table, Credential extends Table, Session extends Table, Flow extends Table, Pending extends Table, NativeSubjectId, NativeSessionId> = Shared.D1StatefulSessionMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Session>, DrizzleTableModel<Flow>, DrizzleTableModel<Pending>, NativeSubjectId, NativeSessionId, SQL>;
|
|
28
|
-
export type D1SignedSessionValidityMapping<Subject extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = Shared.D1SignedSessionValidityMapping<DrizzleTableModel<Subject>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId, SQL>;
|
|
13
|
+
export type AuthenticationAuthorityMapping<Claims, Subject extends Table, Credential extends Table, Pending extends Table, NativeSubjectId> = ClockMapping<Shared.AuthenticationAuthorityMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Pending>, NativeSubjectId, SQL>>;
|
|
14
|
+
export type StatefulSessionMapping<Claims, Subject extends Table, Credential extends Table, Session extends Table, Pending extends Table, NativeSubjectId, NativeSessionId> = ClockMapping<Shared.StatefulSessionMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Session>, DrizzleTableModel<Pending>, NativeSubjectId, NativeSessionId, SQL>>;
|
|
15
|
+
export type PendingAuthenticationMapping<Claims, Subject extends Table, Credential extends Table, Pending extends Table, NativeSubjectId> = ClockMapping<Shared.PendingAuthenticationMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Pending>, NativeSubjectId, SQL>>;
|
|
16
|
+
export type SignedSessionValidityMapping<Subject extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = ClockMapping<Shared.SignedSessionValidityMapping<DrizzleTableModel<Subject>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId, SQL>>;
|
|
17
|
+
export type SessionCleanupMapping<Pending extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = ClockMapping<Shared.SessionCleanupMapping<DrizzleTableModel<Pending>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId, SQL>>;
|
|
29
18
|
//#endregion
|
|
30
|
-
export { type RequiredPendingAuthenticationConstraints, type RequiredSessionConstraints, type RequiredSignedValidityConstraints, type RequiredStatefulPendingConstraints, type
|
|
19
|
+
export { type RequiredPendingAuthenticationConstraints, type RequiredSessionConstraints, type RequiredSignedValidityConstraints, type RequiredStatefulPendingConstraints, type SessionIdCodec, type SessionPendingInsert, requiredPendingAuthenticationConstraints, requiredSessionConstraints, requiredSignedValidityConstraints, requiredStatefulPendingConstraints };
|
|
31
20
|
//# sourceMappingURL=session-model.d.mts.map
|
|
@@ -6,10 +6,10 @@ import { EffectSQLiteDoDatabase } from "drizzle-orm/effect-sqlite-do";
|
|
|
6
6
|
import { EffectTransactionRollbackError } from "drizzle-orm/effect-core";
|
|
7
7
|
import { SqlError } from "effect/sql/SqlError";
|
|
8
8
|
//#region src/drizzle/sqlite-do-database.d.ts
|
|
9
|
-
type NativeDatabase
|
|
9
|
+
type NativeDatabase<T extends AnyRelations> = EffectSQLiteDoDatabase<T> & {
|
|
10
10
|
readonly $client: SqliteClient;
|
|
11
11
|
};
|
|
12
|
-
type Queries<T extends AnyRelations> = Pick<NativeDatabase
|
|
12
|
+
type Queries<T extends AnyRelations> = Pick<NativeDatabase<T>, "query" | "$cache" | "$with" | "$count" | "with" | "select" | "selectDistinct" | "insert" | "update" | "delete" | "run" | "all" | "get" | "values">;
|
|
13
13
|
/** Drizzle queries with transactions owned by the captured Effect SQL client. */
|
|
14
14
|
export type DatabaseValue<T extends AnyRelations = AnyRelations> = Queries<T> & {
|
|
15
15
|
readonly $client: SqliteClient;
|
|
@@ -24,6 +24,6 @@ export type Transaction<T extends AnyRelations = AnyRelations> = DatabaseValue<T
|
|
|
24
24
|
* Effect SQL owns storage.transaction, so cryptography may suspend before commit.
|
|
25
25
|
* Raw Drizzle transactionSync callbacks are not supported outer owners.
|
|
26
26
|
*/
|
|
27
|
-
export declare const makeDatabase: <T extends AnyRelations>(database: NativeDatabase
|
|
27
|
+
export declare const makeDatabase: <T extends AnyRelations>(database: NativeDatabase<T>) => Effect.Effect<DatabaseValue<T>, PersistenceConfigurationError, never>;
|
|
28
28
|
//#endregion
|
|
29
29
|
//# sourceMappingURL=sqlite-do-database.d.mts.map
|
|
@@ -2,6 +2,11 @@ import { PersistenceConfigurationError } from "@yielded/auth-persistence/Adapter
|
|
|
2
2
|
import { Effect } from "effect";
|
|
3
3
|
import { EffectTransactionRollbackError } from "drizzle-orm/effect-core";
|
|
4
4
|
//#region src/drizzle/sqlite-do-database.ts
|
|
5
|
+
/** Construct a query handle inside an existing asynchronous SQL owner. */
|
|
6
|
+
const makeTransactionHandle = (database) => ({
|
|
7
|
+
...database,
|
|
8
|
+
rollback: () => new EffectTransactionRollbackError()
|
|
9
|
+
});
|
|
5
10
|
/**
|
|
6
11
|
* Keep the application's Drizzle query configuration and capture its SQL client.
|
|
7
12
|
* Effect SQL owns storage.transaction, so cryptography may suspend before commit.
|
|
@@ -40,6 +45,6 @@ const makeDatabase = Effect.fnUntraced(function* (database) {
|
|
|
40
45
|
};
|
|
41
46
|
});
|
|
42
47
|
//#endregion
|
|
43
|
-
export { makeDatabase };
|
|
48
|
+
export { makeDatabase, makeTransactionHandle };
|
|
44
49
|
|
|
45
50
|
//# sourceMappingURL=sqlite-do-database.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-do-database.mjs","names":[],"sources":["../../src/drizzle/sqlite-do-database.ts"],"sourcesContent":["import type { SqliteClient } from \"@effect/sql-sqlite-do/SqliteClient\";\nimport { PersistenceConfigurationError } from \"@yielded/auth-persistence/Adapter\";\nimport type { AnyRelations } from \"drizzle-orm\";\nimport { EffectTransactionRollbackError } from \"drizzle-orm/effect-core\";\nimport type { EffectSQLiteDoDatabase } from \"drizzle-orm/effect-sqlite-do\";\nimport { Effect } from \"effect\";\nimport type { SqlError } from \"effect/sql/SqlError\";\n\ntype NativeDatabase<T extends AnyRelations> = EffectSQLiteDoDatabase<T> & {\n readonly $client: SqliteClient;\n};\n\ntype Queries<T extends AnyRelations> = Pick<\n NativeDatabase<T>,\n | \"query\"\n | \"$cache\"\n | \"$with\"\n | \"$count\"\n | \"with\"\n | \"select\"\n | \"selectDistinct\"\n | \"insert\"\n | \"update\"\n | \"delete\"\n | \"run\"\n | \"all\"\n | \"get\"\n | \"values\"\n>;\n\n/** Drizzle queries with transactions owned by the captured Effect SQL client. */\nexport type DatabaseValue<T extends AnyRelations = AnyRelations> = Queries<T> & {\n readonly $client: SqliteClient;\n readonly transaction: <A, E, R>(\n body: (transaction: Transaction<T>) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SqlError, R>;\n};\n\n/** An asynchronous Durable Object transaction, including nested rollback. */\nexport type Transaction<T extends AnyRelations = AnyRelations> = DatabaseValue<T> & {\n readonly rollback: () => EffectTransactionRollbackError;\n};\n\n/**\n * Keep the application's Drizzle query configuration and capture its SQL client.\n * Effect SQL owns storage.transaction, so cryptography may suspend before commit.\n * Raw Drizzle transactionSync callbacks are not supported outer owners.\n */\nexport const makeDatabase = Effect.fnUntraced(function* <T extends AnyRelations>(\n database: NativeDatabase<T>,\n): Effect.fn.Return<DatabaseValue<T>, PersistenceConfigurationError> {\n const client = database.$client;\n\n if (client.config.storage === undefined)\n return yield* PersistenceConfigurationError.make({\n reason: \"SqliteDo requires a SQL client configured with Durable Object storage\",\n });\n\n const queries: Queries<T> = {\n query: database.query,\n $cache: database.$cache,\n $with: database.$with.bind(database),\n $count: database.$count.bind(database),\n with: database.with.bind(database),\n select: database.select.bind(database),\n selectDistinct: database.selectDistinct.bind(database),\n insert: database.insert.bind(database),\n update: database.update.bind(database),\n delete: database.delete.bind(database),\n run: database.run.bind(database),\n all: database.all.bind(database),\n get: database.get.bind(database),\n values: database.values.bind(database),\n };\n\n const transaction: DatabaseValue<T>[\"transaction\"] = (body) =>\n client.withTransaction(Effect.suspend(() => body(makeTransaction())));\n\n const makeTransaction = (): Transaction<T> => ({\n ...queries,\n $client: client,\n transaction,\n rollback: () => new EffectTransactionRollbackError(),\n });\n\n return { ...queries, $client: client, transaction };\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"sqlite-do-database.mjs","names":[],"sources":["../../src/drizzle/sqlite-do-database.ts"],"sourcesContent":["import type { SqliteClient } from \"@effect/sql-sqlite-do/SqliteClient\";\nimport { PersistenceConfigurationError } from \"@yielded/auth-persistence/Adapter\";\nimport type { AnyRelations } from \"drizzle-orm\";\nimport { EffectTransactionRollbackError } from \"drizzle-orm/effect-core\";\nimport type { EffectSQLiteDoDatabase } from \"drizzle-orm/effect-sqlite-do\";\nimport { Effect } from \"effect\";\nimport type { SqlError } from \"effect/sql/SqlError\";\n\ntype NativeDatabase<T extends AnyRelations> = EffectSQLiteDoDatabase<T> & {\n readonly $client: SqliteClient;\n};\n\ntype Queries<T extends AnyRelations> = Pick<\n NativeDatabase<T>,\n | \"query\"\n | \"$cache\"\n | \"$with\"\n | \"$count\"\n | \"with\"\n | \"select\"\n | \"selectDistinct\"\n | \"insert\"\n | \"update\"\n | \"delete\"\n | \"run\"\n | \"all\"\n | \"get\"\n | \"values\"\n>;\n\n/** Drizzle queries with transactions owned by the captured Effect SQL client. */\nexport type DatabaseValue<T extends AnyRelations = AnyRelations> = Queries<T> & {\n readonly $client: SqliteClient;\n readonly transaction: <A, E, R>(\n body: (transaction: Transaction<T>) => Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | SqlError, R>;\n};\n\n/** An asynchronous Durable Object transaction, including nested rollback. */\nexport type Transaction<T extends AnyRelations = AnyRelations> = DatabaseValue<T> & {\n readonly rollback: () => EffectTransactionRollbackError;\n};\n\n/** Construct a query handle inside an existing asynchronous SQL owner. */\nexport const makeTransactionHandle = <T extends AnyRelations>(\n database: DatabaseValue<T>,\n): Transaction<T> => ({\n ...database,\n rollback: () => new EffectTransactionRollbackError(),\n});\n\n/**\n * Keep the application's Drizzle query configuration and capture its SQL client.\n * Effect SQL owns storage.transaction, so cryptography may suspend before commit.\n * Raw Drizzle transactionSync callbacks are not supported outer owners.\n */\nexport const makeDatabase = Effect.fnUntraced(function* <T extends AnyRelations>(\n database: NativeDatabase<T>,\n): Effect.fn.Return<DatabaseValue<T>, PersistenceConfigurationError> {\n const client = database.$client;\n\n if (client.config.storage === undefined)\n return yield* PersistenceConfigurationError.make({\n reason: \"SqliteDo requires a SQL client configured with Durable Object storage\",\n });\n\n const queries: Queries<T> = {\n query: database.query,\n $cache: database.$cache,\n $with: database.$with.bind(database),\n $count: database.$count.bind(database),\n with: database.with.bind(database),\n select: database.select.bind(database),\n selectDistinct: database.selectDistinct.bind(database),\n insert: database.insert.bind(database),\n update: database.update.bind(database),\n delete: database.delete.bind(database),\n run: database.run.bind(database),\n all: database.all.bind(database),\n get: database.get.bind(database),\n values: database.values.bind(database),\n };\n\n const transaction: DatabaseValue<T>[\"transaction\"] = (body) =>\n client.withTransaction(Effect.suspend(() => body(makeTransaction())));\n\n const makeTransaction = (): Transaction<T> => ({\n ...queries,\n $client: client,\n transaction,\n rollback: () => new EffectTransactionRollbackError(),\n });\n\n return { ...queries, $client: client, transaction };\n});\n"],"mappings":";;;;;AA4CA,MAAa,yBACX,cACoB;CACpB,GAAG;CACH,gBAAgB,IAAI,+BAA+B;AACrD;;;;;;AAOA,MAAa,eAAe,OAAO,WAAW,WAC5C,UACmE;CACnE,MAAM,SAAS,SAAS;CAExB,IAAI,OAAO,OAAO,YAAY,KAAA,GAC5B,OAAO,OAAO,8BAA8B,KAAK,EAC/C,QAAQ,wEACV,CAAC;CAEH,MAAM,UAAsB;EAC1B,OAAO,SAAS;EAChB,QAAQ,SAAS;EACjB,OAAO,SAAS,MAAM,KAAK,QAAQ;EACnC,QAAQ,SAAS,OAAO,KAAK,QAAQ;EACrC,MAAM,SAAS,KAAK,KAAK,QAAQ;EACjC,QAAQ,SAAS,OAAO,KAAK,QAAQ;EACrC,gBAAgB,SAAS,eAAe,KAAK,QAAQ;EACrD,QAAQ,SAAS,OAAO,KAAK,QAAQ;EACrC,QAAQ,SAAS,OAAO,KAAK,QAAQ;EACrC,QAAQ,SAAS,OAAO,KAAK,QAAQ;EACrC,KAAK,SAAS,IAAI,KAAK,QAAQ;EAC/B,KAAK,SAAS,IAAI,KAAK,QAAQ;EAC/B,KAAK,SAAS,IAAI,KAAK,QAAQ;EAC/B,QAAQ,SAAS,OAAO,KAAK,QAAQ;CACvC;CAEA,MAAM,eAAgD,SACpD,OAAO,gBAAgB,OAAO,cAAc,KAAK,gBAAgB,CAAC,CAAC,CAAC;CAEtE,MAAM,yBAAyC;EAC7C,GAAG;EACH,SAAS;EACT;EACA,gBAAgB,IAAI,+BAA+B;CACrD;CAEA,OAAO;EAAE,GAAG;EAAS,SAAS;EAAQ;CAAY;AACpD,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PersistenceMappingError as PersistenceMappingError$1, column, isMappedConstraintConflict, provisioningFingerprint } from "./model.mjs";
|
|
2
|
+
import { NativeDatabase } from "./native-database.mjs";
|
|
2
3
|
import { validateDrizzleStorage } from "./storage-validation.mjs";
|
|
3
|
-
import {
|
|
4
|
+
import { withStorageValidation } from "@yielded/auth-persistence/Adapter";
|
|
4
5
|
import { ExternalIdentityMutation, IdentityConflict, IdentityUnavailable, SubjectProvisioned, SubjectProvisioner } from "@yielded/auth/Identity";
|
|
5
6
|
import { and, eq } from "drizzle-orm";
|
|
6
7
|
import { Cause, Effect, Schema } from "effect";
|
|
@@ -18,8 +19,6 @@ const makeSqliteSubjectProvisioningServices = Effect.fnUntraced(function* (mappi
|
|
|
18
19
|
const requestFingerprintColumn = column(requestTable, mapping.provisioningRequest.fingerprint);
|
|
19
20
|
const requestSubjectColumn = column(requestTable, mapping.provisioningRequest.subjectId);
|
|
20
21
|
const identifierTable = mapping.identifier.table;
|
|
21
|
-
const identifierNamespaceColumn = column(identifierTable, mapping.identifier.namespace);
|
|
22
|
-
const identifierValueColumn = column(identifierTable, mapping.identifier.value);
|
|
23
22
|
const subjectIdColumn = column(mapping.subject.table, mapping.subject.id);
|
|
24
23
|
const findReceipt = Effect.fn("DrizzleSqliteIdentity.findReceipt")(function* (requestId) {
|
|
25
24
|
return (yield* db.select({
|
|
@@ -50,8 +49,7 @@ const makeSqliteSubjectProvisioningServices = Effect.fnUntraced(function* (mappi
|
|
|
50
49
|
if (cause.reasons.length === 0 || !cause.reasons.every((reason) => Cause.isFailReason(reason) && isMappedConstraintConflict(mapping.isConstraintConflict, reason.error))) return Effect.failCause(cause);
|
|
51
50
|
return findReceipt(input.requestId).pipe(Effect.flatMap((receipt) => {
|
|
52
51
|
if (receipt !== void 0 && receipt.fingerprint === fingerprint) return Effect.succeed(receipt.subjectId);
|
|
53
|
-
|
|
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()));
|
|
52
|
+
return IdentityConflict.make();
|
|
55
53
|
}));
|
|
56
54
|
}));
|
|
57
55
|
const subjectId = yield* mapping.subjectId.toSubject(nativeId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-identity.mjs","names":["PersistenceMappingError"],"sources":["../../src/drizzle/sqlite-identity.ts"],"sourcesContent":["import { withStorageValidation, NativeDatabase } from \"@yielded/auth-persistence/Adapter\";\nimport {\n ExternalIdentityMutation,\n type ExternalIdentity,\n IdentityConflict,\n IdentityUnavailable,\n SubjectProvisioned,\n SubjectProvisioner,\n type SubjectProvisioningInput,\n} from \"@yielded/auth/Identity\";\nimport { reportPersistenceFailure } from \"@yielded/auth/Persistence\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\n/* oxlint-disable no-explicit-any -- Drizzle generic query types are narrowed at this technology boundary. */\nimport { and, eq } from \"drizzle-orm\";\nimport type { QueryEffectHKTBase } from \"drizzle-orm/effect-core\";\nimport type { AnySQLiteTable, SQLiteColumn } from \"drizzle-orm/sqlite-core\";\nimport type { SQLiteEffectDatabase } from \"drizzle-orm/sqlite-core/effect/db\";\nimport { Cause, Effect, Schema } from \"effect\";\n\nimport {\n column,\n isMappedConstraintConflict,\n PersistenceMappingError,\n provisioningFingerprint,\n type ExternalIdentityTables,\n type IdentityTables,\n type SubjectProvisioningTables,\n} from \"./model\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\n\ntype ClosedQueryEffectHKT = QueryEffectHKTBase & { readonly context: never };\ntype RuntimeDatabase = SQLiteEffectDatabase<ClosedQueryEffectHKT, unknown, any>;\nconst unavailable = () => IdentityUnavailable.make();\nconst isIdentityFailure = Schema.is(Schema.Union([IdentityConflict, IdentityUnavailable]));\n\nconst mapUnavailable = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n reportPersistenceFailure(effect, isIdentityFailure).pipe(\n Effect.catchCause((cause) =>\n Effect.failCause(\n Cause.map(cause, (error) => (isIdentityFailure(error) ? error : unavailable())),\n ),\n ),\n );\n\nexport const makeSqliteSubjectProvisioningServices = Effect.fnUntraced(function* <\n Subject extends AnySQLiteTable,\n Identifier extends AnySQLiteTable,\n Request extends AnySQLiteTable,\n NativeId,\n>(\n mapping: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>,\n mode: \"interactive\" | \"synchronous\",\n) {\n const database = yield* NativeDatabase;\n\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(() => IdentityUnavailable.make()));\n\n const db = database as unknown as RuntimeDatabase;\n const requestTable = mapping.provisioningRequest.table;\n\n const requestIdColumn = column(\n requestTable,\n mapping.provisioningRequest.requestId,\n ) as SQLiteColumn;\n\n const requestFingerprintColumn = column(\n requestTable,\n mapping.provisioningRequest.fingerprint,\n ) as SQLiteColumn;\n\n const requestSubjectColumn = column(\n requestTable,\n mapping.provisioningRequest.subjectId,\n ) as SQLiteColumn;\n\n const identifierTable = mapping.identifier.table;\n\n const identifierNamespaceColumn = column(\n identifierTable,\n mapping.identifier.namespace,\n ) as SQLiteColumn;\n\n const identifierValueColumn = column(identifierTable, mapping.identifier.value) as SQLiteColumn;\n const subjectIdColumn = column(mapping.subject.table, mapping.subject.id) as SQLiteColumn;\n\n const findReceipt = Effect.fn(\"DrizzleSqliteIdentity.findReceipt\")(function* (requestId: string) {\n const rows = yield* db\n .select({ fingerprint: requestFingerprintColumn, subjectId: requestSubjectColumn })\n .from(requestTable as any)\n .where(eq(requestIdColumn, requestId))\n .limit(1);\n\n return rows[0];\n });\n\n const provision = Effect.fn(\"DrizzleSqliteIdentity.provision\")(function* (\n input: SubjectProvisioningInput,\n ) {\n if (\n mode === \"synchronous\" &&\n mapping.subject.allocateId !== undefined &&\n mapping.subject.allocateIdSync === undefined\n ) {\n return yield* unavailable();\n }\n const fingerprint = provisioningFingerprint(input);\n const existing = yield* findReceipt(input.requestId);\n\n if (existing !== undefined) {\n if (existing.fingerprint !== fingerprint) return yield* IdentityConflict.make();\n const subjectId = yield* mapping.subjectId.toSubject(existing.subjectId as NativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }\n\n const attempt = db.transaction((tx) =>\n Effect.gen(function* () {\n const allocated =\n mode === \"synchronous\"\n ? mapping.subject.allocateIdSync?.()\n : mapping.subject.allocateId === undefined\n ? mapping.subject.allocateIdSync?.()\n : yield* mapping.subject.allocateId;\n\n const inserted = yield* tx\n .insert(mapping.subject.table as any)\n .values(mapping.subject.encodeInsert(input, allocated) as any)\n .returning({ id: subjectIdColumn });\n\n const nativeId = (inserted[0]?.id ?? allocated) as NativeId | undefined;\n\n if (nativeId === undefined)\n return yield* PersistenceMappingError.make({\n operation: \"provisionSubject.generatedId\",\n cause: new Error(\"subject insert did not return its native id\"),\n });\n if (input.identifier !== undefined)\n yield* tx\n .insert(identifierTable as any)\n .values(\n mapping.identifier.encodeInsert(input.identifier, nativeId, input.verifiedAt) as any,\n );\n yield* tx\n .insert(requestTable as any)\n .values(\n mapping.provisioningRequest.encodeInsert(input.requestId, fingerprint, nativeId) as any,\n );\n\n return nativeId;\n }),\n );\n\n const nativeId = yield* attempt.pipe(\n Effect.catchCause(\n (cause): Effect.Effect<NativeId, Effect.Error<typeof attempt> | IdentityConflict> => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return findReceipt(input.requestId).pipe(\n Effect.flatMap((receipt) => {\n if (receipt !== undefined && receipt.fingerprint === fingerprint)\n return Effect.succeed(receipt.subjectId as NativeId);\n if (input.identifier === undefined) return IdentityConflict.make();\n\n return db\n .select({\n subjectId: column(identifierTable, mapping.identifier.subjectId) as SQLiteColumn,\n })\n .from(identifierTable as any)\n .where(\n and(\n eq(identifierNamespaceColumn, input.identifier.namespace),\n eq(identifierValueColumn, input.identifier.value),\n ),\n )\n .limit(1)\n .pipe(Effect.flatMap(() => IdentityConflict.make()));\n }),\n );\n },\n ),\n );\n\n const subjectId = yield* mapping.subjectId.toSubject(nativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }, mapUnavailable);\n\n return { subjectProvisioner: SubjectProvisioner.of({ provision }) } as const;\n});\n\nexport const makeSqliteExternalIdentityServices = Effect.fnUntraced(function* <\n Subject extends AnySQLiteTable,\n External extends AnySQLiteTable,\n NativeId,\n>(mapping: ExternalIdentityTables<Subject, External, NativeId>) {\n const database = yield* NativeDatabase;\n\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(() => IdentityUnavailable.make()));\n\n const db = database as unknown as RuntimeDatabase;\n const externalTable = mapping.externalIdentity.table;\n\n const externalProviderColumn = column(\n externalTable,\n mapping.externalIdentity.provider,\n ) as SQLiteColumn;\n\n const externalIssuerColumn = column(\n externalTable,\n mapping.externalIdentity.issuer,\n ) as SQLiteColumn;\n\n const externalSubjectColumn = column(\n externalTable,\n mapping.externalIdentity.subject,\n ) as SQLiteColumn;\n\n const externalSubjectIdColumn = column(\n externalTable,\n mapping.externalIdentity.subjectId,\n ) as SQLiteColumn;\n\n const subjectIdColumn = column(mapping.subject.table, mapping.subject.id) as SQLiteColumn;\n const subjectStatusColumn = column(mapping.subject.table, mapping.subject.status) as SQLiteColumn;\n\n const bind = Effect.fn(\"DrizzleSqliteIdentity.bindExternalIdentity\")(function* (\n subjectId: SubjectId,\n identity: ExternalIdentity,\n ) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const decision = yield* db\n .transaction((tx) =>\n Effect.gen(function* () {\n const subjects = yield* tx\n .select({ status: subjectStatusColumn })\n .from(mapping.subject.table as any)\n .where(eq(subjectIdColumn, nativeId))\n .limit(1);\n\n if (subjects[0] === undefined || !mapping.subject.isActiveStatus(subjects[0].status))\n return { _tag: \"conflict\" } as const;\n\n const links = yield* tx\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .limit(1);\n\n if (links[0] !== undefined)\n return mapping.subjectId.equals(links[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const);\n yield* tx\n .insert(externalTable as any)\n .values(mapping.externalIdentity.encodeInsert(identity, nativeId) as any);\n\n return { _tag: \"bound\" } as const;\n }),\n )\n .pipe(\n Effect.catchCause((cause) => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return db\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .limit(1)\n .pipe(\n Effect.map((rows) =>\n rows[0] !== undefined &&\n mapping.subjectId.equals(rows[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const),\n ),\n );\n }),\n );\n\n if (decision._tag === \"conflict\") return yield* IdentityConflict.make();\n }, mapUnavailable);\n\n return { externalIdentityMutation: ExternalIdentityMutation.of({ bind }) } as const;\n});\n\nexport const makeSqliteIdentityServices = Effect.fnUntraced(function* <\n Subject extends AnySQLiteTable,\n Identifier extends AnySQLiteTable,\n External extends AnySQLiteTable,\n Request extends AnySQLiteTable,\n NativeId,\n>(\n mapping: IdentityTables<Subject, Identifier, External, Request, NativeId>,\n mode: \"interactive\" | \"synchronous\",\n) {\n return {\n ...(yield* makeSqliteSubjectProvisioningServices(mapping, mode)),\n ...(yield* makeSqliteExternalIdentityServices(mapping)),\n };\n}, withStorageValidation);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sqlite-identity.mjs","names":["PersistenceMappingError"],"sources":["../../src/drizzle/sqlite-identity.ts"],"sourcesContent":["import { withStorageValidation } from \"@yielded/auth-persistence/Adapter\";\nimport {\n ExternalIdentityMutation,\n type ExternalIdentity,\n IdentityConflict,\n IdentityUnavailable,\n SubjectProvisioned,\n SubjectProvisioner,\n type SubjectProvisioningInput,\n} from \"@yielded/auth/Identity\";\nimport { reportPersistenceFailure } from \"@yielded/auth/Persistence\";\nimport type { SubjectId } from \"@yielded/auth/Schema\";\n/* oxlint-disable no-explicit-any -- Drizzle generic query types are narrowed at this technology boundary. */\nimport { and, eq } from \"drizzle-orm\";\nimport type { QueryEffectHKTBase } from \"drizzle-orm/effect-core\";\nimport type { AnySQLiteTable, SQLiteColumn } from \"drizzle-orm/sqlite-core\";\nimport type { SQLiteEffectDatabase } from \"drizzle-orm/sqlite-core/effect/db\";\nimport { Cause, Effect, Schema } from \"effect\";\n\nimport {\n column,\n isMappedConstraintConflict,\n PersistenceMappingError,\n provisioningFingerprint,\n type ExternalIdentityTables,\n type IdentityTables,\n type SubjectProvisioningTables,\n} from \"./model\";\nimport { NativeDatabase } from \"./native-database\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\n\ntype ClosedQueryEffectHKT = QueryEffectHKTBase & { readonly context: never };\ntype RuntimeDatabase = SQLiteEffectDatabase<ClosedQueryEffectHKT, unknown, any>;\nconst unavailable = () => IdentityUnavailable.make();\nconst isIdentityFailure = Schema.is(Schema.Union([IdentityConflict, IdentityUnavailable]));\n\nconst mapUnavailable = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n reportPersistenceFailure(effect, isIdentityFailure).pipe(\n Effect.catchCause((cause) =>\n Effect.failCause(\n Cause.map(cause, (error) => (isIdentityFailure(error) ? error : unavailable())),\n ),\n ),\n );\n\nexport const makeSqliteSubjectProvisioningServices = Effect.fnUntraced(function* <\n Subject extends AnySQLiteTable,\n Identifier extends AnySQLiteTable,\n Request extends AnySQLiteTable,\n NativeId,\n>(\n mapping: SubjectProvisioningTables<Subject, Identifier, Request, NativeId>,\n mode: \"interactive\" | \"synchronous\",\n) {\n const database = yield* NativeDatabase;\n\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(() => IdentityUnavailable.make()));\n\n const db = database as unknown as RuntimeDatabase;\n const requestTable = mapping.provisioningRequest.table;\n\n const requestIdColumn = column(\n requestTable,\n mapping.provisioningRequest.requestId,\n ) as SQLiteColumn;\n\n const requestFingerprintColumn = column(\n requestTable,\n mapping.provisioningRequest.fingerprint,\n ) as SQLiteColumn;\n\n const requestSubjectColumn = column(\n requestTable,\n mapping.provisioningRequest.subjectId,\n ) as SQLiteColumn;\n\n const identifierTable = mapping.identifier.table;\n\n const subjectIdColumn = column(mapping.subject.table, mapping.subject.id) as SQLiteColumn;\n\n const findReceipt = Effect.fn(\"DrizzleSqliteIdentity.findReceipt\")(function* (requestId: string) {\n const rows = yield* db\n .select({ fingerprint: requestFingerprintColumn, subjectId: requestSubjectColumn })\n .from(requestTable as any)\n .where(eq(requestIdColumn, requestId))\n .limit(1);\n\n return rows[0];\n });\n\n const provision = Effect.fn(\"DrizzleSqliteIdentity.provision\")(function* (\n input: SubjectProvisioningInput,\n ) {\n if (\n mode === \"synchronous\" &&\n mapping.subject.allocateId !== undefined &&\n mapping.subject.allocateIdSync === undefined\n ) {\n return yield* unavailable();\n }\n const fingerprint = provisioningFingerprint(input);\n const existing = yield* findReceipt(input.requestId);\n\n if (existing !== undefined) {\n if (existing.fingerprint !== fingerprint) return yield* IdentityConflict.make();\n const subjectId = yield* mapping.subjectId.toSubject(existing.subjectId as NativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }\n\n const attempt = db.transaction((tx) =>\n Effect.gen(function* () {\n const allocated =\n mode === \"synchronous\"\n ? mapping.subject.allocateIdSync?.()\n : mapping.subject.allocateId === undefined\n ? mapping.subject.allocateIdSync?.()\n : yield* mapping.subject.allocateId;\n\n const inserted = yield* tx\n .insert(mapping.subject.table as any)\n .values(mapping.subject.encodeInsert(input, allocated) as any)\n .returning({ id: subjectIdColumn });\n\n const nativeId = (inserted[0]?.id ?? allocated) as NativeId | undefined;\n\n if (nativeId === undefined)\n return yield* PersistenceMappingError.make({\n operation: \"provisionSubject.generatedId\",\n cause: new Error(\"subject insert did not return its native id\"),\n });\n if (input.identifier !== undefined)\n yield* tx\n .insert(identifierTable as any)\n .values(\n mapping.identifier.encodeInsert(input.identifier, nativeId, input.verifiedAt) as any,\n );\n yield* tx\n .insert(requestTable as any)\n .values(\n mapping.provisioningRequest.encodeInsert(input.requestId, fingerprint, nativeId) as any,\n );\n\n return nativeId;\n }),\n );\n\n const nativeId = yield* attempt.pipe(\n Effect.catchCause(\n (cause): Effect.Effect<NativeId, Effect.Error<typeof attempt> | IdentityConflict> => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return findReceipt(input.requestId).pipe(\n Effect.flatMap((receipt) => {\n if (receipt !== undefined && receipt.fingerprint === fingerprint)\n return Effect.succeed(receipt.subjectId as NativeId);\n\n return IdentityConflict.make();\n }),\n );\n },\n ),\n );\n\n const subjectId = yield* mapping.subjectId.toSubject(nativeId);\n\n return SubjectProvisioned.make({ subjectId });\n }, mapUnavailable);\n\n return { subjectProvisioner: SubjectProvisioner.of({ provision }) } as const;\n});\n\nexport const makeSqliteExternalIdentityServices = Effect.fnUntraced(function* <\n Subject extends AnySQLiteTable,\n External extends AnySQLiteTable,\n NativeId,\n>(mapping: ExternalIdentityTables<Subject, External, NativeId>) {\n const database = yield* NativeDatabase;\n\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(() => IdentityUnavailable.make()));\n\n const db = database as unknown as RuntimeDatabase;\n const externalTable = mapping.externalIdentity.table;\n\n const externalProviderColumn = column(\n externalTable,\n mapping.externalIdentity.provider,\n ) as SQLiteColumn;\n\n const externalIssuerColumn = column(\n externalTable,\n mapping.externalIdentity.issuer,\n ) as SQLiteColumn;\n\n const externalSubjectColumn = column(\n externalTable,\n mapping.externalIdentity.subject,\n ) as SQLiteColumn;\n\n const externalSubjectIdColumn = column(\n externalTable,\n mapping.externalIdentity.subjectId,\n ) as SQLiteColumn;\n\n const subjectIdColumn = column(mapping.subject.table, mapping.subject.id) as SQLiteColumn;\n const subjectStatusColumn = column(mapping.subject.table, mapping.subject.status) as SQLiteColumn;\n\n const bind = Effect.fn(\"DrizzleSqliteIdentity.bindExternalIdentity\")(function* (\n subjectId: SubjectId,\n identity: ExternalIdentity,\n ) {\n const nativeId = yield* mapping.subjectId.toNative(subjectId);\n\n const decision = yield* db\n .transaction((tx) =>\n Effect.gen(function* () {\n const subjects = yield* tx\n .select({ status: subjectStatusColumn })\n .from(mapping.subject.table as any)\n .where(eq(subjectIdColumn, nativeId))\n .limit(1);\n\n if (subjects[0] === undefined || !mapping.subject.isActiveStatus(subjects[0].status))\n return { _tag: \"conflict\" } as const;\n\n const links = yield* tx\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .limit(1);\n\n if (links[0] !== undefined)\n return mapping.subjectId.equals(links[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const);\n yield* tx\n .insert(externalTable as any)\n .values(mapping.externalIdentity.encodeInsert(identity, nativeId) as any);\n\n return { _tag: \"bound\" } as const;\n }),\n )\n .pipe(\n Effect.catchCause((cause) => {\n if (\n cause.reasons.length === 0 ||\n !cause.reasons.every(\n (reason) =>\n Cause.isFailReason(reason) &&\n isMappedConstraintConflict(mapping.isConstraintConflict, reason.error),\n )\n )\n return Effect.failCause(cause);\n\n return db\n .select({ subjectId: externalSubjectIdColumn })\n .from(externalTable as any)\n .where(\n and(\n eq(externalProviderColumn, identity.provider),\n eq(externalIssuerColumn, identity.issuer),\n eq(externalSubjectColumn, identity.subject),\n ),\n )\n .limit(1)\n .pipe(\n Effect.map((rows) =>\n rows[0] !== undefined &&\n mapping.subjectId.equals(rows[0].subjectId as NativeId, nativeId)\n ? ({ _tag: \"bound\" } as const)\n : ({ _tag: \"conflict\" } as const),\n ),\n );\n }),\n );\n\n if (decision._tag === \"conflict\") return yield* IdentityConflict.make();\n }, mapUnavailable);\n\n return { externalIdentityMutation: ExternalIdentityMutation.of({ bind }) } as const;\n});\n\nexport const makeSqliteIdentityServices = Effect.fnUntraced(function* <\n Subject extends AnySQLiteTable,\n Identifier extends AnySQLiteTable,\n External extends AnySQLiteTable,\n Request extends AnySQLiteTable,\n NativeId,\n>(\n mapping: IdentityTables<Subject, Identifier, External, Request, NativeId>,\n mode: \"interactive\" | \"synchronous\",\n) {\n return {\n ...(yield* makeSqliteSubjectProvisioningServices(mapping, mode)),\n ...(yield* makeSqliteExternalIdentityServices(mapping)),\n };\n}, withStorageValidation);\n"],"mappings":"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"}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
+
import { ClockMapping } from "./native-clock.mjs";
|
|
1
2
|
import { DrizzleTableModel } from "./table-model.mjs";
|
|
2
3
|
import * as Shared from "@yielded/auth-persistence/Adapter";
|
|
3
4
|
import { RequiredSessionStepUpConstraints, requiredSessionStepUpConstraints } from "@yielded/auth-persistence/Adapter";
|
|
4
5
|
import { SQL, Table } from "drizzle-orm";
|
|
5
6
|
//#region src/drizzle/step-up-model.d.ts
|
|
6
|
-
/** Distinct from login-pending storage. Snapshot is TEXT encoded by the core's
|
|
7
|
-
* SessionStepUpIntent schema; it contains no Claims and needs no consumer decoder. */
|
|
8
|
-
export type SessionStepUpIntentTables<Intent extends Table, NativeSubjectId> = Shared.SessionStepUpIntentTables<DrizzleTableModel<Intent>, NativeSubjectId>;
|
|
9
7
|
/** Fixed source discriminator is checked against every stored intent. A minimal
|
|
10
8
|
* pure-signed installation does not provide dummy session or tombstone tables. */
|
|
11
9
|
export type SessionStepUpSourceTables<Claims, Session extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = Shared.SessionStepUpSourceTables<Claims, DrizzleTableModel<Session>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId>;
|
|
12
|
-
export type SessionStepUpMapping<Claims, Subject extends Table, Credential extends Table, Intent extends Table, Session extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = Shared.SessionStepUpMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Intent>, DrizzleTableModel<Session>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId
|
|
13
|
-
export type D1SessionStepUpMapping<Claims, Subject extends Table, Credential extends Table, Intent extends Table, Session extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = Shared.D1SessionStepUpMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Intent>, DrizzleTableModel<Session>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId, SQL>;
|
|
10
|
+
export type SessionStepUpMapping<Claims, Subject extends Table, Credential extends Table, Intent extends Table, Session extends Table, Tombstone extends Table, NativeSubjectId, NativeSessionId> = ClockMapping<Shared.SessionStepUpMapping<Claims, DrizzleTableModel<Subject>, DrizzleTableModel<Credential>, DrizzleTableModel<Intent>, DrizzleTableModel<Session>, DrizzleTableModel<Tombstone>, NativeSubjectId, NativeSessionId, SQL>>;
|
|
14
11
|
//#endregion
|
|
15
12
|
export { type RequiredSessionStepUpConstraints, requiredSessionStepUpConstraints };
|
|
16
13
|
//# sourceMappingURL=step-up-model.d.mts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { NativeDatabase
|
|
1
|
+
import { NativeDatabase } from "./native-database.mjs";
|
|
2
|
+
import { PersistenceMappingError, storageKeyPlans, validateStorageBatch } from "@yielded/auth-persistence/Adapter";
|
|
2
3
|
import { Table, getTableColumns, getTableName, is } from "drizzle-orm";
|
|
3
4
|
import { Effect } from "effect";
|
|
4
5
|
import { MySqlTable, getTableConfig } from "drizzle-orm/mysql-core";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-validation.mjs","names":["getPgTableConfig","getMysqlTableConfig"],"sources":["../../src/drizzle/storage-validation.ts"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"file":"storage-validation.mjs","names":["getPgTableConfig","getMysqlTableConfig"],"sources":["../../src/drizzle/storage-validation.ts"],"sourcesContent":["import {\n PersistenceMappingError,\n validateStorageBatch,\n type StorageValidation,\n storageKeyPlans,\n} from \"@yielded/auth-persistence/Adapter\";\nimport { getTableColumns, getTableName, is, Table } from \"drizzle-orm\";\nimport { getTableConfig as getMysqlTableConfig, MySqlTable } from \"drizzle-orm/mysql-core\";\nimport { getTableConfig as getPgTableConfig, PgTable } from \"drizzle-orm/pg-core\";\nimport { Effect } from \"effect\";\nimport { SqlClient } from \"effect/sql/SqlClient\";\n\nimport { NativeDatabase } from \"./native-database\";\n\n/** Validate at acquisition using the root database supplied by the adapter. */\nexport const validateDrizzleStorage = Effect.fnUntraced(\n function* (mapping: unknown) {\n const physical = yield* Effect.try({\n try: () =>\n storageKeyPlans(mapping, (table) => {\n if (!is(table, Table)) throw new Error(\"Missing storage table\");\n\n return getTableColumns(table);\n }),\n catch: () =>\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Invalid storage key mapping\",\n }),\n });\n\n const { $client: client } = yield* NativeDatabase;\n\n const batches = new Map<\"pg\" | \"mysql\" | \"sqlite\", StorageValidation[]>();\n\n for (const plan of physical) {\n if (!is(plan.table, Table))\n return yield* PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Missing storage table\",\n });\n const pg = is(plan.table, PgTable);\n const mysql = is(plan.table, MySqlTable);\n\n const schema = pg\n ? getPgTableConfig(plan.table).schema\n : mysql\n ? getMysqlTableConfig(plan.table).schema\n : undefined;\n\n const columns = getTableColumns(plan.table);\n\n const dialect = pg ? \"pg\" : mysql ? \"mysql\" : \"sqlite\";\n const batch = batches.get(dialect) ?? [];\n\n batch.push({\n table: {\n name: getTableName(plan.table),\n ...(schema === undefined ? {} : { schema }),\n columns: Object.fromEntries(plan.keys.map((key) => [key, { name: columns[key]!.name }])),\n },\n required: [plan.keys],\n });\n batches.set(dialect, batch);\n }\n for (const [dialect, requirements] of batches) {\n yield* validateStorageBatch(dialect, requirements).pipe(\n Effect.provideService(SqlClient, client),\n Effect.mapError(() =>\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Required SQL storage key is unavailable\",\n }),\n ),\n );\n }\n },\n Effect.catchDefect(() =>\n Effect.fail(\n PersistenceMappingError.make({\n operation: \"mapping\",\n cause: \"Cannot inspect SQL storage metadata\",\n }),\n ),\n ),\n);\n"],"mappings":";;;;;;;;;AAeA,MAAa,yBAAyB,OAAO,WAC3C,WAAW,SAAkB;CAC3B,MAAM,WAAW,OAAO,OAAO,IAAI;EACjC,WACE,gBAAgB,UAAU,UAAU;GAClC,IAAI,CAAC,GAAG,OAAO,KAAK,GAAG,MAAM,IAAI,MAAM,uBAAuB;GAE9D,OAAO,gBAAgB,KAAK;EAC9B,CAAC;EACH,aACE,wBAAwB,KAAK;GAC3B,WAAW;GACX,OAAO;EACT,CAAC;CACL,CAAC;CAED,MAAM,EAAE,SAAS,WAAW,OAAO;CAEnC,MAAM,0BAAU,IAAI,IAAoD;CAExE,KAAK,MAAM,QAAQ,UAAU;EAC3B,IAAI,CAAC,GAAG,KAAK,OAAO,KAAK,GACvB,OAAO,OAAO,wBAAwB,KAAK;GACzC,WAAW;GACX,OAAO;EACT,CAAC;EACH,MAAM,KAAK,GAAG,KAAK,OAAO,OAAO;EACjC,MAAM,QAAQ,GAAG,KAAK,OAAO,UAAU;EAEvC,MAAM,SAAS,KACXA,iBAAiB,KAAK,KAAK,CAAC,CAAC,SAC7B,QACEC,eAAoB,KAAK,KAAK,CAAC,CAAC,SAChC,KAAA;EAEN,MAAM,UAAU,gBAAgB,KAAK,KAAK;EAE1C,MAAM,UAAU,KAAK,OAAO,QAAQ,UAAU;EAC9C,MAAM,QAAQ,QAAQ,IAAI,OAAO,KAAK,CAAC;EAEvC,MAAM,KAAK;GACT,OAAO;IACL,MAAM,aAAa,KAAK,KAAK;IAC7B,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;IACzC,SAAS,OAAO,YAAY,KAAK,KAAK,KAAK,QAAQ,CAAC,KAAK,EAAE,MAAM,QAAQ,IAAI,CAAE,KAAK,CAAC,CAAC,CAAC;GACzF;GACA,UAAU,CAAC,KAAK,IAAI;EACtB,CAAC;EACD,QAAQ,IAAI,SAAS,KAAK;CAC5B;CACA,KAAK,MAAM,CAAC,SAAS,iBAAiB,SACpC,OAAO,qBAAqB,SAAS,YAAY,CAAC,CAAC,KACjD,OAAO,eAAe,WAAW,MAAM,GACvC,OAAO,eACL,wBAAwB,KAAK;EAC3B,WAAW;EACX,OAAO;CACT,CAAC,CACH,CACF;AAEJ,GACA,OAAO,kBACL,OAAO,KACL,wBAAwB,KAAK;CAC3B,WAAW;CACX,OAAO;AACT,CAAC,CACH,CACF,CACF"}
|
|
@@ -1,82 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { DrizzleTableModel } from "./table-model.mjs";
|
|
2
|
+
import * as Shared from "@yielded/auth-persistence/Adapter";
|
|
3
|
+
import { TotpMappingSource, requiredTotpConstraints } from "@yielded/auth-persistence/Adapter";
|
|
4
|
+
import { SQL, Table } from "drizzle-orm";
|
|
3
5
|
import { Effect, Layer } from "effect";
|
|
4
|
-
import {
|
|
5
|
-
import { SubjectId } from "@yielded/auth/Schema";
|
|
6
|
-
import { TotpPersistence, TotpPolicy } from "@yielded/auth/Totp";
|
|
6
|
+
import { TotpPersistence } from "@yielded/auth/Totp";
|
|
7
7
|
//#region src/drizzle/totp-model.d.ts
|
|
8
|
-
export type
|
|
9
|
-
export type TotpMappingSource<M, R = never> = M | Effect.Effect<M, PersistenceMappingError, R>;
|
|
10
|
-
export declare const requiredTotpConstraints: {
|
|
11
|
-
readonly factor: "unique(scope)";
|
|
12
|
-
readonly credential: "unique(credentialId)";
|
|
13
|
-
readonly subject: "unique(id)";
|
|
14
|
-
};
|
|
15
|
-
/** A dedicated encrypted factor row plus the shared authentication credential authority.
|
|
16
|
-
* factorEnabled is the consumer's TOTP requirement bit; central primary methods must
|
|
17
|
-
* read it when choosing their AuthenticationRequirement. Other factor policy is untouched.
|
|
18
|
-
* State JSON stores ciphertext and recovery digests only. The same table retains
|
|
19
|
-
* domain-separated management command tombstones; retain them while command IDs
|
|
20
|
-
* can be replayed. Encoders and current requirement decoding cannot suspend.
|
|
21
|
-
*/
|
|
22
|
-
export interface TotpMapping<S extends Table, F extends Table, C extends Table, N> {
|
|
23
|
-
readonly moduleId: string;
|
|
24
|
-
readonly policy: TotpPolicy;
|
|
25
|
-
readonly constraints: typeof requiredTotpConstraints;
|
|
26
|
-
readonly subjectIds: {
|
|
27
|
-
readonly toNative: (id: SubjectId) => N;
|
|
28
|
-
readonly toSubject: (id: N) => SubjectId;
|
|
29
|
-
};
|
|
30
|
-
readonly subject: {
|
|
31
|
-
readonly table: S;
|
|
32
|
-
readonly id: TotpColumn<S>;
|
|
33
|
-
readonly securityRevision: TotpColumn<S>;
|
|
34
|
-
readonly factorEnabled: TotpColumn<S>;
|
|
35
|
-
readonly activeCondition: SQL;
|
|
36
|
-
readonly encodeEnabled: (enabled: boolean) => unknown;
|
|
37
|
-
readonly decodeRequirement: (row: InferSelectModel<S>) => AuthenticationRequirement;
|
|
38
|
-
};
|
|
39
|
-
readonly factor: {
|
|
40
|
-
readonly table: F;
|
|
41
|
-
readonly scope: TotpColumn<F>;
|
|
42
|
-
readonly state: TotpColumn<F>;
|
|
43
|
-
readonly version: TotpColumn<F>;
|
|
44
|
-
readonly encodeInsert: (value: {
|
|
45
|
-
readonly scope: string;
|
|
46
|
-
readonly state: string;
|
|
47
|
-
readonly version: string;
|
|
48
|
-
}) => InferInsertModel<F>;
|
|
49
|
-
};
|
|
50
|
-
readonly credential: {
|
|
51
|
-
readonly table: C;
|
|
52
|
-
readonly id: TotpColumn<C>;
|
|
53
|
-
readonly subjectId: TotpColumn<C>;
|
|
54
|
-
readonly revision: TotpColumn<C>;
|
|
55
|
-
readonly status: TotpColumn<C>;
|
|
56
|
-
readonly activeCondition: SQL;
|
|
57
|
-
readonly encodeStatus: (active: boolean) => unknown;
|
|
58
|
-
readonly encodeInsert: (value: {
|
|
59
|
-
readonly credentialId: string;
|
|
60
|
-
readonly subjectId: N;
|
|
61
|
-
readonly revision: string;
|
|
62
|
-
readonly active: boolean;
|
|
63
|
-
}) => InferInsertModel<C>;
|
|
64
|
-
};
|
|
65
|
-
/** Unix epoch milliseconds, evaluated again at the final conditional write. */
|
|
66
|
-
readonly engineNowMillis: SQL;
|
|
67
|
-
/** Required for reset-with-recovery-code. Must assert the exact unconsumed,
|
|
68
|
-
* unexpired, unexhausted pending flow, binding digest and original credential
|
|
69
|
-
* revisions. No request-supplied SQL or external I/O is accepted. */
|
|
70
|
-
readonly pendingCondition?: (target: PendingAuthenticationContext, subjectId: N) => SQL;
|
|
71
|
-
}
|
|
72
|
-
export interface D1TotpMapping {
|
|
73
|
-
readonly d1: {
|
|
74
|
-
readonly primary: true;
|
|
75
|
-
};
|
|
76
|
-
}
|
|
8
|
+
export type TotpMapping<S extends Table, F extends Table, C extends Table, N, P extends Table = Table> = Shared.TotpMapping<DrizzleTableModel<S>, DrizzleTableModel<F>, DrizzleTableModel<C>, N, DrizzleTableModel<P>, SQL>;
|
|
77
9
|
export interface TotpPersistenceServices {
|
|
78
10
|
readonly totpPersistence: TotpPersistence["Service"];
|
|
79
11
|
}
|
|
80
12
|
export declare const totpPersistenceLayer: <E, R>(services: Effect.Effect<TotpPersistenceServices, E, R>) => Layer.Layer<TotpPersistence, E, Exclude<R, import("effect/Scope").Scope>>;
|
|
81
13
|
//#endregion
|
|
14
|
+
export { type TotpMappingSource, requiredTotpConstraints };
|
|
82
15
|
//# sourceMappingURL=totp-model.d.mts.map
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
+
import { requiredTotpConstraints } from "@yielded/auth-persistence/Adapter";
|
|
1
2
|
import { Effect, Layer } from "effect";
|
|
2
3
|
import { TotpPersistence } from "@yielded/auth/Totp";
|
|
3
4
|
//#region src/drizzle/totp-model.ts
|
|
4
|
-
const requiredTotpConstraints = {
|
|
5
|
-
factor: "unique(scope)",
|
|
6
|
-
credential: "unique(credentialId)",
|
|
7
|
-
subject: "unique(id)"
|
|
8
|
-
};
|
|
9
5
|
const totpPersistenceLayer = (services) => Layer.effect(TotpPersistence, Effect.map(services, (value) => value.totpPersistence));
|
|
10
6
|
//#endregion
|
|
11
7
|
export { requiredTotpConstraints, totpPersistenceLayer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"totp-model.mjs","names":[],"sources":["../../src/drizzle/totp-model.ts"],"sourcesContent":["import type
|
|
1
|
+
{"version":3,"file":"totp-model.mjs","names":[],"sources":["../../src/drizzle/totp-model.ts"],"sourcesContent":["import type * as Shared from \"@yielded/auth-persistence/Adapter\";\nimport { TotpPersistence } from \"@yielded/auth/Totp\";\nimport type { SQL, Table } from \"drizzle-orm\";\nimport { Effect, Layer } from \"effect\";\n\nimport type { DrizzleTableModel } from \"./table-model\";\nexport { requiredTotpConstraints, type TotpMappingSource } from \"@yielded/auth-persistence/Adapter\";\nexport type TotpColumn<T extends Table> = DrizzleTableModel<T>[\"column\"];\n\nexport type TotpMapping<\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n P extends Table = Table,\n> = Shared.TotpMapping<\n DrizzleTableModel<S>,\n DrizzleTableModel<F>,\n DrizzleTableModel<C>,\n N,\n DrizzleTableModel<P>,\n SQL\n>;\n\nexport interface TotpPersistenceServices {\n readonly totpPersistence: TotpPersistence[\"Service\"];\n}\n\nexport const totpPersistenceLayer = <E, R>(\n services: Effect.Effect<TotpPersistenceServices, E, R>,\n) =>\n Layer.effect(\n TotpPersistence,\n Effect.map(services, (value) => value.totpPersistence),\n );\n"],"mappings":";;;;AA4BA,MAAa,wBACX,aAEA,MAAM,OACJ,iBACA,OAAO,IAAI,WAAW,UAAU,MAAM,eAAe,CACvD"}
|
|
@@ -1,87 +1,51 @@
|
|
|
1
|
+
import { nativeClock } from "./native-clock.mjs";
|
|
2
|
+
import { NativeDatabase, nativeDatabase } from "./native-database.mjs";
|
|
3
|
+
import { coordinateNativeTarget, nativeTarget } from "./native-target.mjs";
|
|
1
4
|
import { validateDrizzleStorage } from "./storage-validation.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { nativeDatabase } from "./native-database.mjs";
|
|
6
|
-
import { coordinateTransactionOwner, makeTransactionExecution, sqlClientTransactionStandaloneGuard } from "./transaction-execution.mjs";
|
|
7
|
-
import { NativeDatabase } from "@yielded/auth-persistence/Adapter";
|
|
8
|
-
import { Context, Effect, Schema } from "effect";
|
|
9
|
-
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
10
|
-
import { TotpConfigurationError, TotpMutation, TotpPersistence, TotpPolicy } from "@yielded/auth/Totp";
|
|
5
|
+
import { makeNativeTotpServices } from "@yielded/auth-persistence/Adapter";
|
|
6
|
+
import { Effect, Schema } from "effect";
|
|
7
|
+
import { TotpConfigurationError, TotpPersistence, TotpPolicy, TotpUnavailable } from "@yielded/auth/Totp";
|
|
11
8
|
//#region src/drizzle/totp-target.ts
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
factor: Object.freeze({ ...mapping.factor }),
|
|
24
|
-
credential: Object.freeze({ ...mapping.credential }),
|
|
25
|
-
subjectIds: Object.freeze({ ...mapping.subjectIds })
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
const services = Effect.fnUntraced(function* (mapping, execution) {
|
|
29
|
-
const hooks = yield* LifecycleHooks;
|
|
30
|
-
return { totpPersistence: TotpPersistence.of({
|
|
31
|
-
snapshot: Effect.fn("TotpNative.snapshot")(function* (input) {
|
|
32
|
-
const captured = { ...input };
|
|
33
|
-
invariant(captured.moduleId === mapping.moduleId);
|
|
34
|
-
yield* execution.admit;
|
|
35
|
-
return yield* execution.run(Effect.map(captureTotp(mapping, captured.subjectId), (value) => value?.snapshot), false).pipe(Effect.provideService(LifecycleHooks, hooks));
|
|
36
|
-
}, Effect.catchDefect(() => Effect.fail(unavailable()))),
|
|
37
|
-
mutate: (original, prepare) => Effect.suspend(() => {
|
|
38
|
-
const codec = Schema.toCodecIso(TotpMutation);
|
|
39
|
-
const input = Schema.decodeSync(codec)(Schema.encodeSync(codec)(original));
|
|
40
|
-
return execution.admit.pipe(Effect.andThen(execution.run(Effect.gen(function* () {
|
|
41
|
-
const decision = yield* mutateTotp(mapping, input), owner = yield* CurrentTotpTransaction;
|
|
42
|
-
owner.guards.push(owner.journal.prepare(void 0));
|
|
43
|
-
const receipt = prepare(decision, owner.journal);
|
|
44
|
-
invariant(receipt?._tag === "PreparedCommit" && Effect.isEffect(receipt.read));
|
|
45
|
-
owner.guards.push(receipt);
|
|
46
|
-
return receipt;
|
|
47
|
-
}))), Effect.provideService(LifecycleHooks, hooks));
|
|
48
|
-
}).pipe(Effect.catchDefect(() => Effect.fail(unavailable())))
|
|
49
|
-
}) };
|
|
50
|
-
});
|
|
51
|
-
const makeTargetTotpPersistence = (source, configuration) => Effect.gen(function* () {
|
|
52
|
-
const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);
|
|
53
|
-
const mapping = yield* Effect.try({
|
|
54
|
-
try: () => validateMapping(original, configuration),
|
|
55
|
-
catch: () => TotpConfigurationError.make({})
|
|
9
|
+
const unavailable = () => TotpUnavailable.make({});
|
|
10
|
+
/** Driver metadata is compiled once; the factor workflow and commit owner are shared. */
|
|
11
|
+
const makeTotpTarget = (databaseService, configuration) => {
|
|
12
|
+
const validate = Effect.fnUntraced(function* (mapping) {
|
|
13
|
+
yield* validateDrizzleStorage(mapping);
|
|
14
|
+
yield* Schema.decodeEffect(TotpPolicy)(mapping.policy);
|
|
15
|
+
if (mapping.moduleId.length === 0 || configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* TotpConfigurationError.make({});
|
|
16
|
+
}, Effect.mapError(() => TotpConfigurationError.make({})));
|
|
17
|
+
const services = Effect.fnUntraced(function* (mapping) {
|
|
18
|
+
const target = yield* nativeTarget(configuration);
|
|
19
|
+
return yield* target.provide(makeNativeTotpServices(target.tables, mapping));
|
|
56
20
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const mapping = yield* Effect.try({
|
|
64
|
-
try: () => validateMapping(original, configuration),
|
|
65
|
-
catch: () => TotpConfigurationError.make({})
|
|
21
|
+
const mapping = (value) => ({
|
|
22
|
+
...value,
|
|
23
|
+
...value.pending === void 0 ? {} : { pending: {
|
|
24
|
+
...value.pending,
|
|
25
|
+
clock: nativeClock(value.pending.clock)
|
|
26
|
+
} }
|
|
66
27
|
});
|
|
67
|
-
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(() => TotpConfigurationError.make({})));
|
|
68
|
-
return yield* coordinateTransactionOwner(database, CurrentTotpTransaction, configuration, Effect.void, unavailable, randomId, (execution) => services(mapping, execution), (transaction, acquireServices, append) => Effect.flatMap(acquireServices, (boundServices) => body(transaction, boundServices, append)));
|
|
69
|
-
});
|
|
70
|
-
/** Concrete driver wrappers select transaction mode. */
|
|
71
|
-
const makeTotpTarget = (databaseService, configuration) => {
|
|
72
28
|
function coordinateTotpPersistence(acquire, options, body) {
|
|
73
|
-
return Effect.
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
29
|
+
return Effect.gen(function* () {
|
|
30
|
+
const value = mapping(yield* Effect.isEffect(options.mapping) ? options.mapping : Effect.succeed(options.mapping));
|
|
31
|
+
const database = yield* nativeDatabase(acquire);
|
|
32
|
+
yield* validate(value).pipe(Effect.provideService(NativeDatabase, database));
|
|
33
|
+
return yield* coordinateNativeTarget(unavailable, database, configuration, services(value), (transaction, bound) => {
|
|
34
|
+
const work = body.pipe(Effect.provideService(TotpPersistence, bound.totpPersistence));
|
|
35
|
+
return options.transaction === void 0 ? work : Effect.provideService(work, options.transaction, options.transaction.of(transaction));
|
|
36
|
+
});
|
|
37
|
+
});
|
|
78
38
|
}
|
|
79
39
|
return {
|
|
80
|
-
|
|
81
|
-
|
|
40
|
+
coordinateTotpPersistence,
|
|
41
|
+
makeTotpPersistenceServices: (source) => Effect.gen(function* () {
|
|
42
|
+
const value = mapping(yield* Effect.isEffect(source) ? source : Effect.succeed(source));
|
|
43
|
+
yield* validate(value);
|
|
44
|
+
return yield* services(value);
|
|
45
|
+
}).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)))
|
|
82
46
|
};
|
|
83
47
|
};
|
|
84
48
|
//#endregion
|
|
85
|
-
export {
|
|
49
|
+
export { makeTotpTarget };
|
|
86
50
|
|
|
87
51
|
//# sourceMappingURL=totp-target.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"totp-target.mjs","names":[],"sources":["../../src/drizzle/totp-target.ts"],"sourcesContent":["import { NativeDatabase } from \"@yielded/auth-persistence/Adapter\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n TotpConfigurationError,\n type TotpUnavailable,\n TotpMutation,\n TotpPolicy,\n TotpPersistence,\n} from \"@yielded/auth/Totp\";\nimport type { Table } from \"drizzle-orm\";\n/* oxlint-disable no-explicit-any -- shared native implementation; driver entrypoints retain exact database and table types. */\nimport { type Crypto, Context, Effect, Schema } from \"effect\";\nimport type { Statement } from \"effect/sql/Statement\";\n\nimport { randomId } from \"./crypto\";\nimport type { PersistenceMappingError } from \"./model\";\nimport { nativeDatabase } from \"./native-database\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\nimport type { SuppliedService } from \"./SuppliedService\";\nimport {\n type TotpMapping,\n type TotpMappingSource,\n type TotpPersistenceServices,\n requiredTotpConstraints,\n} from \"./totp-model\";\nimport {\n captureTotp,\n CurrentTotpTransaction,\n invariant,\n mutateTotp,\n unavailable,\n} from \"./totp-state\";\nimport {\n coordinateTransactionOwner,\n makeTransactionExecution,\n sqlClientTransactionStandaloneGuard,\n type TransactionExecution,\n type TransactionTargetConfiguration,\n type TransactionCoordinatorError,\n} from \"./transaction-execution\";\nimport type { TransactionNativeDatabase } from \"./transaction-owner\";\nexport type TotpTargetConfiguration = TransactionTargetConfiguration<TotpUnavailable>;\n\nexport type TotpCoordinatorError<E> =\n | TransactionCoordinatorError<E, TotpUnavailable>\n | TotpConfigurationError\n | PersistenceMappingError;\n\nexport const sqlClientTotpStandaloneGuard = (\n service: Parameters<typeof sqlClientTransactionStandaloneGuard>[1],\n) => sqlClientTransactionStandaloneGuard(unavailable, service);\n\nconst validateMapping = <M>(original: M, configuration: TotpTargetConfiguration): M => {\n const mapping = original as any;\n\n invariant(mapping.moduleId.length > 0);\n Schema.decodeSync(TotpPolicy)(mapping.policy);\n for (const [key, value] of Object.entries(requiredTotpConstraints))\n invariant(mapping.constraints?.[key] === value);\n if (configuration.mode === \"batch\") invariant(mapping.d1?.primary === true);\n\n return Object.freeze({\n ...mapping,\n policy: Object.freeze({ ...mapping.policy }),\n subject: Object.freeze({ ...mapping.subject }),\n factor: Object.freeze({ ...mapping.factor }),\n credential: Object.freeze({ ...mapping.credential }),\n subjectIds: Object.freeze({ ...mapping.subjectIds }),\n });\n};\n\nconst services = Effect.fnUntraced(function* (\n mapping: any,\n execution: TransactionExecution<TotpUnavailable, CurrentTotpTransaction>,\n): Effect.fn.Return<TotpPersistenceServices, never, LifecycleHooks> {\n const hooks = yield* LifecycleHooks;\n\n return {\n totpPersistence: TotpPersistence.of({\n snapshot: Effect.fn(\"TotpNative.snapshot\")(\n function* (input) {\n const captured = { ...input };\n\n invariant(captured.moduleId === mapping.moduleId);\n yield* execution.admit;\n\n return yield* execution\n .run(\n Effect.map(captureTotp(mapping, captured.subjectId), (value) => value?.snapshot),\n false,\n )\n .pipe(Effect.provideService(LifecycleHooks, hooks));\n },\n Effect.catchDefect(() => Effect.fail(unavailable())),\n ),\n mutate: (original, prepare) =>\n Effect.suspend(() => {\n // Detach caller-owned payloads before any driver or hook can suspend.\n const codec = Schema.toCodecIso(TotpMutation);\n const input = Schema.decodeSync(codec)(Schema.encodeSync(codec)(original));\n\n return execution.admit.pipe(\n Effect.andThen(\n execution.run(\n Effect.gen(function* () {\n const decision = yield* mutateTotp(mapping, input),\n owner = yield* CurrentTotpTransaction;\n\n owner.guards.push(owner.journal.prepare(undefined));\n const receipt = prepare(decision, owner.journal);\n\n invariant(receipt?._tag === \"PreparedCommit\" && Effect.isEffect(receipt.read));\n owner.guards.push(receipt as any);\n\n return receipt;\n }),\n ),\n ),\n Effect.provideService(LifecycleHooks, hooks),\n );\n }).pipe(Effect.catchDefect(() => Effect.fail(unavailable()))),\n }),\n };\n});\n\nexport const makeTargetTotpPersistence = <\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n RSetup = never,\n>(\n source: TotpMappingSource<TotpMapping<S, F, C, N>, RSetup>,\n configuration: TotpTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n const execution = yield* makeTransactionExecution(\n CurrentTotpTransaction,\n configuration,\n unavailable,\n randomId,\n );\n\n return yield* services(mapping, execution);\n });\n\nexport const coordinateTargetTotp = <M, A, E, R, RSetup = never>(\n database: TransactionNativeDatabase,\n source: TotpMappingSource<M, RSetup>,\n configuration: TotpTargetConfiguration,\n body: (\n transaction: any,\n services: TotpPersistenceServices,\n append: (statement: Statement<any>) => void,\n ) => Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n TotpCoordinatorError<E>,\n R | RSetup | Crypto.Crypto | LifecycleHooks | NativeDatabase\n> =>\n Effect.gen(function* () {\n const original = yield* Effect.isEffect(source) ? source : Effect.succeed(source);\n\n const mapping = yield* Effect.try({\n try: () => validateMapping(original, configuration),\n catch: () => TotpConfigurationError.make({}),\n });\n\n yield* validateDrizzleStorage(mapping).pipe(\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n return yield* coordinateTransactionOwner(\n database,\n CurrentTotpTransaction,\n configuration,\n Effect.void,\n unavailable,\n randomId,\n (execution) => services(mapping, execution),\n (transaction, acquireServices, append) =>\n Effect.flatMap(acquireServices, (boundServices) =>\n body(transaction, boundServices, append),\n ),\n );\n });\n\ntype TransactionOf<D> = D extends { readonly transaction: (...args: any[]) => any }\n ? Parameters<Parameters<D[\"transaction\"]>[0]>[0]\n : never;\n\n/** Concrete driver wrappers select transaction mode. */\nexport const makeTotpTarget = <\n DatabaseId,\n D extends { readonly transaction: any },\n T extends Table,\n Extra = unknown,\n Synchronous extends boolean = false,\n>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: TotpTargetConfiguration,\n) => {\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence>)\n | Crypto.Crypto\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, Synchronous extends true ? NoInfer<TotpPersistence | TxId> : R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n | (Synchronous extends true ? never : Exclude<R, TotpPersistence | TxId>)\n | Crypto.Crypto\n | LifecycleHooks\n | RSetup\n | DatabaseRequirements\n >;\n function coordinateTotpPersistence<\n Database extends D,\n S extends T,\n F extends T,\n C extends T,\n N,\n A,\n E,\n R,\n TxId,\n TxShape,\n RSetup = never,\n DatabaseError = never,\n DatabaseRequirements = never,\n >(\n acquire: Effect.Effect<Database, DatabaseError, DatabaseRequirements>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>;\n readonly transaction?: SuppliedService<TxId, NoInfer<TransactionOf<Database>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n TotpCoordinatorError<E> | DatabaseError,\n Exclude<R, TotpPersistence> | Crypto.Crypto | LifecycleHooks | RSetup | DatabaseRequirements\n > {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateTargetTotp(\n database as any,\n options.mapping,\n configuration,\n (\n transaction: TransactionOf<Database>,\n services,\n ): Effect.Effect<A, E, Exclude<R, TotpPersistence>> => {\n const provided = Context.make(TotpPersistence, services.totpPersistence);\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 ).pipe(Effect.provideService(NativeDatabase, database)),\n );\n }\n\n return {\n makeTotpPersistenceServices: <S extends T, F extends T, C extends T, N, RSetup = never>(\n mapping: TotpMappingSource<TotpMapping<S, F, C, N> & Extra, RSetup>,\n ) =>\n makeTargetTotpPersistence(mapping, configuration).pipe(\n Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)),\n ),\n coordinateTotpPersistence,\n };\n};\n"],"mappings":";;;;;;;;;;;AAgDA,MAAa,gCACX,YACG,oCAAoC,aAAa,OAAO;AAE7D,MAAM,mBAAsB,UAAa,kBAA8C;CACrF,MAAM,UAAU;CAEhB,UAAU,QAAQ,SAAS,SAAS,CAAC;CACrC,OAAO,WAAW,UAAU,CAAC,CAAC,QAAQ,MAAM;CAC5C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,uBAAuB,GAC/D,UAAU,QAAQ,cAAc,SAAS,KAAK;CAChD,IAAI,cAAc,SAAS,SAAS,UAAU,QAAQ,IAAI,YAAY,IAAI;CAE1E,OAAO,OAAO,OAAO;EACnB,GAAG;EACH,QAAQ,OAAO,OAAO,EAAE,GAAG,QAAQ,OAAO,CAAC;EAC3C,SAAS,OAAO,OAAO,EAAE,GAAG,QAAQ,QAAQ,CAAC;EAC7C,QAAQ,OAAO,OAAO,EAAE,GAAG,QAAQ,OAAO,CAAC;EAC3C,YAAY,OAAO,OAAO,EAAE,GAAG,QAAQ,WAAW,CAAC;EACnD,YAAY,OAAO,OAAO,EAAE,GAAG,QAAQ,WAAW,CAAC;CACrD,CAAC;AACH;AAEA,MAAM,WAAW,OAAO,WAAW,WACjC,SACA,WACkE;CAClE,MAAM,QAAQ,OAAO;CAErB,OAAO,EACL,iBAAiB,gBAAgB,GAAG;EAClC,UAAU,OAAO,GAAG,qBAAqB,CAAC,CACxC,WAAW,OAAO;GAChB,MAAM,WAAW,EAAE,GAAG,MAAM;GAE5B,UAAU,SAAS,aAAa,QAAQ,QAAQ;GAChD,OAAO,UAAU;GAEjB,OAAO,OAAO,UACX,IACC,OAAO,IAAI,YAAY,SAAS,SAAS,SAAS,IAAI,UAAU,OAAO,QAAQ,GAC/E,KACF,CAAC,CACA,KAAK,OAAO,eAAe,gBAAgB,KAAK,CAAC;EACtD,GACA,OAAO,kBAAkB,OAAO,KAAK,YAAY,CAAC,CAAC,CACrD;EACA,SAAS,UAAU,YACjB,OAAO,cAAc;GAEnB,MAAM,QAAQ,OAAO,WAAW,YAAY;GAC5C,MAAM,QAAQ,OAAO,WAAW,KAAK,CAAC,CAAC,OAAO,WAAW,KAAK,CAAC,CAAC,QAAQ,CAAC;GAEzE,OAAO,UAAU,MAAM,KACrB,OAAO,QACL,UAAU,IACR,OAAO,IAAI,aAAa;IACtB,MAAM,WAAW,OAAO,WAAW,SAAS,KAAK,GAC/C,QAAQ,OAAO;IAEjB,MAAM,OAAO,KAAK,MAAM,QAAQ,QAAQ,KAAA,CAAS,CAAC;IAClD,MAAM,UAAU,QAAQ,UAAU,MAAM,OAAO;IAE/C,UAAU,SAAS,SAAS,oBAAoB,OAAO,SAAS,QAAQ,IAAI,CAAC;IAC7E,MAAM,OAAO,KAAK,OAAc;IAEhC,OAAO;GACT,CAAC,CACH,CACF,GACA,OAAO,eAAe,gBAAgB,KAAK,CAC7C;EACF,CAAC,CAAC,CAAC,KAAK,OAAO,kBAAkB,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC;CAChE,CAAC,EACH;AACF,CAAC;AAED,MAAa,6BAOX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO,QAAQ,MAAM;CAEhF,MAAM,UAAU,OAAO,OAAO,IAAI;EAChC,WAAW,gBAAgB,UAAU,aAAa;EAClD,aAAa,uBAAuB,KAAK,CAAC,CAAC;CAC7C,CAAC;CAED,OAAO,uBAAuB,OAAO,CAAC,CAAC,KACrC,OAAO,eAAe,uBAAuB,KAAK,CAAC,CAAC,CAAC,CACvD;CAEA,MAAM,YAAY,OAAO,yBACvB,wBACA,eACA,aACA,QACF;CAEA,OAAO,OAAO,SAAS,SAAS,SAAS;AAC3C,CAAC;AAEH,MAAa,wBACX,UACA,QACA,eACA,SAUA,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO,QAAQ,MAAM;CAEhF,MAAM,UAAU,OAAO,OAAO,IAAI;EAChC,WAAW,gBAAgB,UAAU,aAAa;EAClD,aAAa,uBAAuB,KAAK,CAAC,CAAC;CAC7C,CAAC;CAED,OAAO,uBAAuB,OAAO,CAAC,CAAC,KACrC,OAAO,eAAe,uBAAuB,KAAK,CAAC,CAAC,CAAC,CACvD;CAEA,OAAO,OAAO,2BACZ,UACA,wBACA,eACA,OAAO,MACP,aACA,WACC,cAAc,SAAS,SAAS,SAAS,IACzC,aAAa,iBAAiB,WAC7B,OAAO,QAAQ,kBAAkB,kBAC/B,KAAK,aAAa,eAAe,MAAM,CACzC,CACJ;AACF,CAAC;;AAOH,MAAa,kBAOX,iBACA,kBACG;CA2DH,SAAS,0BAeP,SACA,SAIA,MAKA;EACA,OAAO,OAAO,QAAQ,eAAe,OAAO,IAAI,aAC9C,qBACE,UACA,QAAQ,SACR,gBAEE,aACA,aACqD;GACrD,MAAM,WAAW,QAAQ,KAAK,iBAAiB,SAAS,eAAe;GACvE,MAAM,OAAO,OAAO,eAAe,MAAM,QAAQ;GAEjD,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;EAC1F,CACF,CAAC,CAAC,KAAK,OAAO,eAAe,gBAAgB,QAAQ,CAAC,CACxD;CACF;CAEA,OAAO;EACL,8BACE,YAEA,0BAA0B,SAAS,aAAa,CAAC,CAAC,KAChD,OAAO,qBAAqB,gBAAgB,eAAe,eAAe,CAAC,CAC7E;EACF;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"totp-target.mjs","names":[],"sources":["../../src/drizzle/totp-target.ts"],"sourcesContent":["import { makeNativeTotpServices, type NativeTotpMapping } from \"@yielded/auth-persistence/Adapter\";\nimport type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n TotpConfigurationError,\n TotpUnavailable,\n TotpPolicy,\n TotpPersistence,\n} from \"@yielded/auth/Totp\";\nimport type { Table } from \"drizzle-orm\";\nimport { Effect, Schema, type Context, type Crypto } from \"effect\";\n\nimport type { D1BatchStatements } from \"./D1BatchStatements\";\nimport type { NativeDriverDatabase, NativeDriverTransaction } from \"./driver-types\";\nimport type { PersistenceMappingError } from \"./model\";\nimport { nativeClock } from \"./native-clock\";\nimport { NativeDatabase, nativeDatabase } from \"./native-database\";\nimport {\n nativeTarget,\n coordinateNativeTarget,\n type NativeTargetConfiguration,\n} from \"./native-target\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\nimport type { SuppliedService } from \"./SuppliedService\";\nimport type { TotpMapping, TotpMappingSource } from \"./totp-model\";\n\nconst unavailable = () => TotpUnavailable.make({});\n\n/** Driver metadata is compiled once; the factor workflow and commit owner are shared. */\nexport const makeTotpTarget = <DatabaseId, D extends NativeDriverDatabase>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: NativeTargetConfiguration,\n) => {\n const validate = Effect.fnUntraced(\n function* (mapping: NativeTotpMapping) {\n yield* validateDrizzleStorage(mapping);\n yield* Schema.decodeEffect(TotpPolicy)(mapping.policy);\n if (\n mapping.moduleId.length === 0 ||\n (configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined))\n )\n return yield* TotpConfigurationError.make({});\n },\n Effect.mapError(() => TotpConfigurationError.make({})),\n );\n\n const services = Effect.fnUntraced(function* (mapping: NativeTotpMapping) {\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativeTotpServices(target.tables, mapping));\n });\n\n const mapping = <S extends Table, F extends Table, C extends Table, N, P extends Table>(\n value: TotpMapping<S, F, C, N, P>,\n ): NativeTotpMapping =>\n ({\n ...value,\n ...(value.pending === undefined\n ? {}\n : { pending: { ...value.pending, clock: nativeClock(value.pending.clock) } }),\n }) as unknown as NativeTotpMapping;\n\n function coordinateTotpPersistence<\n DB extends D,\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n P extends Table,\n A,\n E,\n R,\n DE,\n DR,\n RS = never,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N, P>, RS>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n E | DE | TotpUnavailable | TotpConfigurationError | PersistenceMappingError,\n Exclude<R, TotpPersistence | D1BatchStatements> | DR | RS | LifecycleHooks | Crypto.Crypto\n >;\n function coordinateTotpPersistence<\n DB extends D,\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n P extends Table,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n RS = never,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N, P>, RS>;\n readonly transaction: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n E | DE | TotpUnavailable | TotpConfigurationError | PersistenceMappingError,\n | Exclude<R, TotpPersistence | D1BatchStatements | TxId>\n | DR\n | RS\n | LifecycleHooks\n | Crypto.Crypto\n >;\n function coordinateTotpPersistence<\n DB extends D,\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n P extends Table,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n RS = never,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: TotpMappingSource<TotpMapping<S, F, C, N, P>, RS>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.gen(function* () {\n const value = mapping(\n yield* Effect.isEffect(options.mapping) ? options.mapping : Effect.succeed(options.mapping),\n );\n\n const database = yield* nativeDatabase(acquire);\n\n yield* validate(value).pipe(Effect.provideService(NativeDatabase, database));\n\n return yield* coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n services(value),\n (transaction: NativeDriverTransaction<DB>, bound) => {\n const work = body.pipe(Effect.provideService(TotpPersistence, bound.totpPersistence));\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n );\n });\n }\n\n return {\n coordinateTotpPersistence,\n makeTotpPersistenceServices: <\n S extends Table,\n F extends Table,\n C extends Table,\n N,\n P extends Table = Table,\n RS = never,\n >(\n source: TotpMappingSource<TotpMapping<S, F, C, N, P>, RS>,\n ) =>\n Effect.gen(function* () {\n const value = mapping(yield* Effect.isEffect(source) ? source : Effect.succeed(source));\n\n yield* validate(value);\n\n return yield* services(value);\n }).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n };\n};\n"],"mappings":";;;;;;;;AAyBA,MAAM,oBAAoB,gBAAgB,KAAK,CAAC,CAAC;;AAGjD,MAAa,kBACX,iBACA,kBACG;CACH,MAAM,WAAW,OAAO,WACtB,WAAW,SAA4B;EACrC,OAAO,uBAAuB,OAAO;EACrC,OAAO,OAAO,aAAa,UAAU,CAAC,CAAC,QAAQ,MAAM;EACrD,IACE,QAAQ,SAAS,WAAW,KAC3B,cAAc,SAAS,YACrB,QAAQ,IAAI,YAAY,QAAQ,QAAQ,QAAQ,uBAAuB,KAAA,IAE1E,OAAO,OAAO,uBAAuB,KAAK,CAAC,CAAC;CAChD,GACA,OAAO,eAAe,uBAAuB,KAAK,CAAC,CAAC,CAAC,CACvD;CAEA,MAAM,WAAW,OAAO,WAAW,WAAW,SAA4B;EACxE,MAAM,SAAS,OAAO,aAAa,aAAa;EAEhD,OAAO,OAAO,OAAO,QAAQ,uBAAuB,OAAO,QAAQ,OAAO,CAAC;CAC7E,CAAC;CAED,MAAM,WACJ,WAEC;EACC,GAAG;EACH,GAAI,MAAM,YAAY,KAAA,IAClB,CAAC,IACD,EAAE,SAAS;GAAE,GAAG,MAAM;GAAS,OAAO,YAAY,MAAM,QAAQ,KAAK;EAAE,EAAE;CAC/E;CA0DF,SAAS,0BAgBP,SACA,SAIA,MACA;EACA,OAAO,OAAO,IAAI,aAAa;GAC7B,MAAM,QAAQ,QACZ,OAAO,OAAO,SAAS,QAAQ,OAAO,IAAI,QAAQ,UAAU,OAAO,QAAQ,QAAQ,OAAO,CAC5F;GAEA,MAAM,WAAW,OAAO,eAAe,OAAO;GAE9C,OAAO,SAAS,KAAK,CAAC,CAAC,KAAK,OAAO,eAAe,gBAAgB,QAAQ,CAAC;GAE3E,OAAO,OAAO,uBACZ,aACA,UACA,eACA,SAAS,KAAK,IACb,aAA0C,UAAU;IACnD,MAAM,OAAO,KAAK,KAAK,OAAO,eAAe,iBAAiB,MAAM,eAAe,CAAC;IAEpF,OAAO,QAAQ,gBAAgB,KAAA,IAC3B,OACA,OAAO,eAAe,MAAM,QAAQ,aAAa,QAAQ,YAAY,GAAG,WAAW,CAAC;GAC1F,CACF;EACF,CAAC;CACH;CAEA,OAAO;EACL;EACA,8BAQE,WAEA,OAAO,IAAI,aAAa;GACtB,MAAM,QAAQ,QAAQ,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO,QAAQ,MAAM,CAAC;GAEtF,OAAO,SAAS,KAAK;GAErB,OAAO,OAAO,SAAS,KAAK;EAC9B,CAAC,CAAC,CAAC,KAAK,OAAO,qBAAqB,gBAAgB,eAAe,eAAe,CAAC,CAAC;CACxF;AACF"}
|