@yielded/auth-persistence-drizzle 0.1.0-beta.30 → 0.1.0-beta.32
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 +13 -8
- package/dist/D1.d.mts +13 -4
- package/dist/D1.mjs +11 -1
- package/dist/D1.mjs.map +1 -1
- package/dist/Libsql.d.mts +4 -4
- package/dist/Libsql.mjs +1 -1
- package/dist/Mysql2.d.mts +4 -4
- package/dist/Pglite.d.mts +4 -4
- package/dist/Postgres.d.mts +4 -4
- package/dist/SqliteBun.d.mts +4 -4
- package/dist/SqliteBun.mjs +1 -1
- package/dist/SqliteDo.d.mts +4 -4
- package/dist/SqliteNode.d.mts +4 -4
- package/dist/SqliteNode.mjs +1 -1
- package/dist/SqliteWasm.d.mts +4 -4
- package/dist/SqliteWasm.mjs +1 -1
- package/dist/drizzle/oauth-target.mjs +5 -1
- package/dist/drizzle/oauth-target.mjs.map +1 -1
- package/dist/drizzle/passkey/target.d.mts +1 -1
- package/dist/drizzle/passkey/target.mjs.map +1 -1
- package/dist/drizzle/session-drivers.mjs +6 -5
- package/dist/drizzle/session-drivers.mjs.map +1 -1
- package/dist/drizzle/storage-validation.mjs +2 -1
- package/dist/drizzle/storage-validation.mjs.map +1 -1
- package/dist/internal/drizzle-d1-migrations.d.mts +14 -0
- package/dist/internal/drizzle-d1-migrations.mjs +83 -0
- package/dist/internal/drizzle-d1-migrations.mjs.map +1 -0
- package/dist/internal/drizzle-sqlite.mjs +7 -2
- package/dist/internal/drizzle-sqlite.mjs.map +1 -1
- package/package.json +1 -1
- package/src/D1.ts +12 -0
- package/src/drizzle/oauth-target.ts +5 -1
- package/src/drizzle/passkey/target.ts +5 -1
- package/src/drizzle/session-drivers.ts +16 -5
- package/src/drizzle/storage-validation.ts +2 -0
- package/src/internal/drizzle-d1-migrations.ts +150 -0
- package/src/internal/drizzle-sqlite.ts +14 -2
|
@@ -2,13 +2,17 @@ import { coordinateNativeTarget, nativeTarget } from "./native-target.mjs";
|
|
|
2
2
|
import { validateDrizzleStorage } from "./storage-validation.mjs";
|
|
3
3
|
import { captureOAuthMapping, makeNativeOAuthAccountsServices, makeNativeOAuthConnectedServices, makeNativeOAuthRegistrationIntentServices, makeNativeOAuthRegistrationServices, makeNativeOAuthRevocationServices, makeNativeOAuthSignInServices, oauthAccountsPersistenceLayer, oauthConnectedPersistenceLayer, oauthConnectedRevocationsLayer, oauthRegistrationAuthorityLayer, oauthRegistrationIntentsLayer, oauthSignInPersistenceLayer } from "@yielded/auth-persistence/Adapter";
|
|
4
4
|
import { Effect } from "effect";
|
|
5
|
+
import { reportAuthDiagnostic } from "@yielded/auth/Persistence";
|
|
5
6
|
import { OAuthUnavailable } from "@yielded/auth/OAuth";
|
|
6
7
|
//#region src/drizzle/oauth-target.ts
|
|
7
8
|
const unavailable = () => OAuthUnavailable.make({});
|
|
8
9
|
const mapped = Effect.fnUntraced(function* (original, configuration) {
|
|
9
10
|
const mapping = captureOAuthMapping(original);
|
|
10
11
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
|
|
11
|
-
if (configuration.mode === "batch" && !(typeof mapping === "object" && mapping !== null && "d1" in mapping && typeof mapping.d1 === "object" && mapping.d1 !== null && "primary" in mapping.d1 && mapping.d1.primary === true))
|
|
12
|
+
if (configuration.mode === "batch" && !(typeof mapping === "object" && mapping !== null && "d1" in mapping && typeof mapping.d1 === "object" && mapping.d1 !== null && "primary" in mapping.d1 && mapping.d1.primary === true)) {
|
|
13
|
+
yield* reportAuthDiagnostic("persistence-validation", "configuration");
|
|
14
|
+
return yield* unavailable();
|
|
15
|
+
}
|
|
12
16
|
return {
|
|
13
17
|
mapping,
|
|
14
18
|
...yield* nativeTarget(configuration)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-target.mjs","names":[],"sources":["../../src/drizzle/oauth-target.ts"],"sourcesContent":["import {\n captureOAuthMapping,\n makeNativeOAuthSignInServices,\n makeNativeOAuthAccountsServices,\n makeNativeOAuthRegistrationIntentServices,\n makeNativeOAuthRegistrationServices,\n makeNativeOAuthConnectedServices,\n makeNativeOAuthRevocationServices,\n type OAuthNativeReadMapping,\n type OAuthNativeAccountsMapping,\n type OAuthNativeRegistrationIntentMapping,\n type OAuthNativeRegistrationMapping,\n type OAuthNativeConnectedMapping,\n type OAuthNativeRevocationMapping,\n} from \"@yielded/auth-persistence/Adapter\";\nimport type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { OAuthUnavailable } from \"@yielded/auth/OAuth\";\nimport { Effect } from \"effect\";\n\nimport type { D1BatchStatements } from \"./D1BatchStatements\";\nimport type { NativeDatabaseHandle } from \"./native-database\";\nimport {\n nativeTarget,\n coordinateNativeTarget,\n type NativeTargetConfiguration,\n} from \"./native-target\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\n\nexport {\n oauthAccountsPersistenceLayer,\n oauthSignInPersistenceLayer,\n oauthRegistrationIntentsLayer,\n oauthRegistrationAuthorityLayer,\n oauthConnectedPersistenceLayer,\n oauthConnectedRevocationsLayer,\n} from \"@yielded/auth-persistence/Adapter\";\n\nexport type OAuthTargetConfiguration = NativeTargetConfiguration;\n\nexport type OAuthCoordinatorError<E> = E | OAuthUnavailable;\nconst unavailable = () => OAuthUnavailable.make({});\n\nconst mapped = Effect.fnUntraced(function* (\n original: unknown,\n configuration: OAuthTargetConfiguration,\n) {\n const mapping = captureOAuthMapping(original);\n\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n !(\n typeof mapping === \"object\" &&\n mapping !== null &&\n \"d1\" in mapping &&\n typeof mapping.d1 === \"object\" &&\n mapping.d1 !== null &&\n \"primary\" in mapping.d1 &&\n mapping.d1.primary === true\n )\n )\n return yield* unavailable();\n\n return { mapping, ...(yield* nativeTarget(configuration)) };\n});\n\nexport const makeTargetOAuthSignInServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthSignInServices(\n target.tables,\n target.mapping as OAuthNativeReadMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthAccountsServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthAccountsServices(\n target.tables,\n target.mapping as OAuthNativeAccountsMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthRegistrationIntentServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthRegistrationIntentServices(\n target.tables,\n target.mapping as OAuthNativeRegistrationIntentMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthConnectedServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthConnectedServices(\n target.tables,\n target.mapping as OAuthNativeConnectedMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthConnectedRevocationServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthRevocationServices(\n target.tables,\n target.mapping as OAuthNativeRevocationMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthRegistrationServices = <Registration>(\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthRegistrationServices(\n target.tables,\n target.mapping as OAuthNativeRegistrationMapping<Registration>,\n target.batch,\n ),\n );\n });\n\nconst coordinateOwner = <Services, Transaction, A, E, R, ES, RS>(\n database: NativeDatabaseHandle,\n configuration: OAuthTargetConfiguration,\n make: Effect.Effect<Services, ES, RS>,\n body: (transaction: Transaction, services: Services) => Effect.Effect<A, E, R>,\n): Effect.Effect<A, E | OAuthUnavailable, Exclude<R, D1BatchStatements> | RS | LifecycleHooks> =>\n coordinateNativeTarget(unavailable, database, configuration, make, body);\n\nexport const coordinateTargetOAuthSignIn = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthSignInServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthSignInServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthAccounts = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthAccountsServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthAccountsServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthRegistrationIntents = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthRegistrationIntentServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthRegistrationIntentServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthConnected = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthConnectedServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthConnectedServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthConnectedRevocations = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthConnectedRevocationServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthConnectedRevocationServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthRegistration = <Registration, Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthRegistrationServices<Registration>>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthRegistrationServices<Registration>(mapping, configuration),\n body,\n );\n"],"mappings":";;;;;;AAwCA,MAAM,oBAAoB,iBAAiB,KAAK,CAAC,CAAC;AAElD,MAAM,SAAS,OAAO,WAAW,WAC/B,UACA,eACA;CACA,MAAM,UAAU,oBAAoB,QAAQ;CAE5C,OAAO,uBAAuB,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,WAAW,CAAC;CACxE,IACE,cAAc,SAAS,WACvB,EACE,OAAO,YAAY,YACnB,YAAY,QACZ,QAAQ,WACR,OAAO,QAAQ,OAAO,YACtB,QAAQ,OAAO,QACf,aAAa,QAAQ,MACrB,QAAQ,GAAG,YAAY,OAGzB,OAAO,OAAO,YAAY;CAE5B,OAAO;EAAE;EAAS,GAAI,OAAO,aAAa,aAAa;CAAG;AAC5D,CAAC;AAED,MAAa,iCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,8BACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,mCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,gCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,6CACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,0CACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,oCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,iCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,8CACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,kCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,uCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,oCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAM,mBACJ,UACA,eACA,MACA,SAEA,uBAAuB,aAAa,UAAU,eAAe,MAAM,IAAI;AAEzE,MAAa,+BACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,8BAA8B,SAAS,aAAa,GACpD,IACF;AAEF,MAAa,iCACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,gCAAgC,SAAS,aAAa,GACtD,IACF;AAEF,MAAa,4CACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,0CAA0C,SAAS,aAAa,GAChE,IACF;AAEF,MAAa,kCACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,iCAAiC,SAAS,aAAa,GACvD,IACF;AAEF,MAAa,6CACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,2CAA2C,SAAS,aAAa,GACjE,IACF;AAEF,MAAa,qCACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,oCAAkD,SAAS,aAAa,GACxE,IACF"}
|
|
1
|
+
{"version":3,"file":"oauth-target.mjs","names":[],"sources":["../../src/drizzle/oauth-target.ts"],"sourcesContent":["import {\n captureOAuthMapping,\n makeNativeOAuthSignInServices,\n makeNativeOAuthAccountsServices,\n makeNativeOAuthRegistrationIntentServices,\n makeNativeOAuthRegistrationServices,\n makeNativeOAuthConnectedServices,\n makeNativeOAuthRevocationServices,\n type OAuthNativeReadMapping,\n type OAuthNativeAccountsMapping,\n type OAuthNativeRegistrationIntentMapping,\n type OAuthNativeRegistrationMapping,\n type OAuthNativeConnectedMapping,\n type OAuthNativeRevocationMapping,\n} from \"@yielded/auth-persistence/Adapter\";\nimport type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { OAuthUnavailable } from \"@yielded/auth/OAuth\";\nimport { reportAuthDiagnostic } from \"@yielded/auth/Persistence\";\nimport { Effect } from \"effect\";\n\nimport type { D1BatchStatements } from \"./D1BatchStatements\";\nimport type { NativeDatabaseHandle } from \"./native-database\";\nimport {\n nativeTarget,\n coordinateNativeTarget,\n type NativeTargetConfiguration,\n} from \"./native-target\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\n\nexport {\n oauthAccountsPersistenceLayer,\n oauthSignInPersistenceLayer,\n oauthRegistrationIntentsLayer,\n oauthRegistrationAuthorityLayer,\n oauthConnectedPersistenceLayer,\n oauthConnectedRevocationsLayer,\n} from \"@yielded/auth-persistence/Adapter\";\n\nexport type OAuthTargetConfiguration = NativeTargetConfiguration;\n\nexport type OAuthCoordinatorError<E> = E | OAuthUnavailable;\nconst unavailable = () => OAuthUnavailable.make({});\n\nconst mapped = Effect.fnUntraced(function* (\n original: unknown,\n configuration: OAuthTargetConfiguration,\n) {\n const mapping = captureOAuthMapping(original);\n\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n !(\n typeof mapping === \"object\" &&\n mapping !== null &&\n \"d1\" in mapping &&\n typeof mapping.d1 === \"object\" &&\n mapping.d1 !== null &&\n \"primary\" in mapping.d1 &&\n mapping.d1.primary === true\n )\n ) {\n yield* reportAuthDiagnostic(\"persistence-validation\", \"configuration\");\n\n return yield* unavailable();\n }\n\n return { mapping, ...(yield* nativeTarget(configuration)) };\n});\n\nexport const makeTargetOAuthSignInServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthSignInServices(\n target.tables,\n target.mapping as OAuthNativeReadMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthAccountsServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthAccountsServices(\n target.tables,\n target.mapping as OAuthNativeAccountsMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthRegistrationIntentServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthRegistrationIntentServices(\n target.tables,\n target.mapping as OAuthNativeRegistrationIntentMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthConnectedServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthConnectedServices(\n target.tables,\n target.mapping as OAuthNativeConnectedMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthConnectedRevocationServices = (\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthRevocationServices(\n target.tables,\n target.mapping as OAuthNativeRevocationMapping,\n target.batch,\n ),\n );\n });\n\nexport const makeTargetOAuthRegistrationServices = <Registration>(\n source: unknown,\n configuration: OAuthTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* mapped(source, configuration);\n\n return yield* target.provide(\n makeNativeOAuthRegistrationServices(\n target.tables,\n target.mapping as OAuthNativeRegistrationMapping<Registration>,\n target.batch,\n ),\n );\n });\n\nconst coordinateOwner = <Services, Transaction, A, E, R, ES, RS>(\n database: NativeDatabaseHandle,\n configuration: OAuthTargetConfiguration,\n make: Effect.Effect<Services, ES, RS>,\n body: (transaction: Transaction, services: Services) => Effect.Effect<A, E, R>,\n): Effect.Effect<A, E | OAuthUnavailable, Exclude<R, D1BatchStatements> | RS | LifecycleHooks> =>\n coordinateNativeTarget(unavailable, database, configuration, make, body);\n\nexport const coordinateTargetOAuthSignIn = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthSignInServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthSignInServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthAccounts = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthAccountsServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthAccountsServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthRegistrationIntents = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthRegistrationIntentServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthRegistrationIntentServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthConnected = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthConnectedServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthConnectedServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthConnectedRevocations = <Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthConnectedRevocationServices>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthConnectedRevocationServices(mapping, configuration),\n body,\n );\n\nexport const coordinateTargetOAuthRegistration = <Registration, Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n mapping: unknown,\n configuration: OAuthTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetOAuthRegistrationServices<Registration>>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinateOwner(\n database,\n configuration,\n makeTargetOAuthRegistrationServices<Registration>(mapping, configuration),\n body,\n );\n"],"mappings":";;;;;;;AAyCA,MAAM,oBAAoB,iBAAiB,KAAK,CAAC,CAAC;AAElD,MAAM,SAAS,OAAO,WAAW,WAC/B,UACA,eACA;CACA,MAAM,UAAU,oBAAoB,QAAQ;CAE5C,OAAO,uBAAuB,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,WAAW,CAAC;CACxE,IACE,cAAc,SAAS,WACvB,EACE,OAAO,YAAY,YACnB,YAAY,QACZ,QAAQ,WACR,OAAO,QAAQ,OAAO,YACtB,QAAQ,OAAO,QACf,aAAa,QAAQ,MACrB,QAAQ,GAAG,YAAY,OAEzB;EACA,OAAO,qBAAqB,0BAA0B,eAAe;EAErE,OAAO,OAAO,YAAY;CAC5B;CAEA,OAAO;EAAE;EAAS,GAAI,OAAO,aAAa,aAAa;CAAG;AAC5D,CAAC;AAED,MAAa,iCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,8BACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,mCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,gCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,6CACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,0CACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,oCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,iCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,8CACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,kCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAa,uCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,aAAa;CAElD,OAAO,OAAO,OAAO,QACnB,oCACE,OAAO,QACP,OAAO,SACP,OAAO,KACT,CACF;AACF,CAAC;AAEH,MAAM,mBACJ,UACA,eACA,MACA,SAEA,uBAAuB,aAAa,UAAU,eAAe,MAAM,IAAI;AAEzE,MAAa,+BACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,8BAA8B,SAAS,aAAa,GACpD,IACF;AAEF,MAAa,iCACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,gCAAgC,SAAS,aAAa,GACtD,IACF;AAEF,MAAa,4CACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,0CAA0C,SAAS,aAAa,GAChE,IACF;AAEF,MAAa,kCACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,iCAAiC,SAAS,aAAa,GACvD,IACF;AAEF,MAAa,6CACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,2CAA2C,SAAS,aAAa,GACjE,IACF;AAEF,MAAa,qCACX,UACA,SACA,eACA,SAKA,gBACE,UACA,eACA,oCAAkD,SAAS,aAAa,GACxE,IACF"}
|
|
@@ -4,7 +4,7 @@ import "../native-database.mjs";
|
|
|
4
4
|
import "../D1BatchStatements.mjs";
|
|
5
5
|
import "../native-target.mjs";
|
|
6
6
|
import { SqlBatchCommit, makeNativePasskeyServices } from "@yielded/auth-persistence/Adapter";
|
|
7
|
-
import { Effect } from "effect";
|
|
7
|
+
import { Crypto, Effect } from "effect";
|
|
8
8
|
import { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
9
9
|
import { SqlClient } from "effect/sql";
|
|
10
10
|
import { PasskeyConfigurationError, PasskeyUnavailable } from "@yielded/auth/Passkey";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"target.mjs","names":[],"sources":["../../../src/drizzle/passkey/target.ts"],"sourcesContent":["import {\n type SqlBatchCommit,\n makeBatchPasskeyServices,\n makeNativePasskeyCeremonyServices,\n makeNativePasskeyCredentialServices,\n makeNativePasskeyServices,\n type NativeSqlTables,\n type NativePasskeyCeremonyMapping,\n type PasskeyNativeMapping,\n type PasskeyNativeRead,\n} from \"@yielded/auth-persistence/Adapter\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { PasskeyConfigurationError, PasskeyUnavailable } from \"@yielded/auth/Passkey\";\nimport { type Crypto, Effect } from \"effect\";\nimport type { SqlClient } from \"effect/sql\";\n\nimport type { D1BatchStatements } from \"../D1BatchStatements\";\nimport type { PersistenceMappingError } from \"../model\";\nimport {\n NativeDatabase,\n type NativeDatabaseHandle,\n type NativePhysicalDatabase,\n} from \"../native-database\";\nimport {\n nativeTarget,\n coordinateNativeTarget,\n type NativeTargetConfiguration,\n} from \"../native-target\";\nimport type { PasskeyPersistenceServices, PasskeyMappingSource } from \"../passkey-model\";\nimport { validateDrizzleStorage } from \"../storage-validation\";\nexport type PasskeyTargetConfiguration = NativeTargetConfiguration;\n\nexport type PasskeyCoordinatorError<E> =\n | E\n | PasskeyUnavailable\n | PasskeyConfigurationError\n | PersistenceMappingError;\n\nconst unavailable = () => PasskeyUnavailable.make({});\n\nconst emptyHooks: LifecycleHooks[\"Service\"] = {\n before: () => Effect.void,\n after: () => Effect.succeed([]),\n};\n\n// Mapped table/SQL generics end here. Persisted values are decoded by shared schemas.\nexport const capturePasskeyMapping = <M, R>(\n source: PasskeyMappingSource<M, R>,\n configuration: PasskeyTargetConfiguration,\n) =>\n Effect.flatMap(Effect.isEffect(source) ? source : Effect.succeed(source), (mapping) =>\n validateDrizzleStorage(mapping).pipe(\n Effect.andThen(\n Effect.try({\n try: () => {\n if (\n configuration.mode === \"batch\" &&\n !(\n typeof mapping === \"object\" &&\n mapping !== null &&\n \"d1\" in mapping &&\n typeof mapping.d1 === \"object\" &&\n mapping.d1 !== null &&\n \"primary\" in mapping.d1 &&\n mapping.d1.primary === true\n )\n )\n throw PasskeyConfigurationError.make({});\n\n return mapping;\n },\n catch: () => PasskeyConfigurationError.make({}),\n }),\n ),\n ),\n );\n\ntype NativePasskeyServices = Effect.Success<ReturnType<typeof makeNativePasskeyServices>>;\n\ninterface PasskeyMapped<M> {\n readonly mapping: M;\n readonly database: NativePhysicalDatabase;\n readonly tables: NativeSqlTables;\n readonly batch: SqlBatchCommit[\"Service\"] | undefined;\n readonly provide: <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E, Exclude<Exclude<R, SqlClient.SqlClient>, SqlBatchCommit>>;\n readonly base: () => Effect.Effect
|
|
1
|
+
{"version":3,"file":"target.mjs","names":[],"sources":["../../../src/drizzle/passkey/target.ts"],"sourcesContent":["import {\n type SqlBatchCommit,\n makeBatchPasskeyServices,\n makeNativePasskeyCeremonyServices,\n makeNativePasskeyCredentialServices,\n makeNativePasskeyServices,\n type NativeSqlTables,\n type NativePasskeyCeremonyMapping,\n type PasskeyNativeMapping,\n type PasskeyNativeRead,\n} from \"@yielded/auth-persistence/Adapter\";\nimport { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { PasskeyConfigurationError, PasskeyUnavailable } from \"@yielded/auth/Passkey\";\nimport { type Crypto, Effect } from \"effect\";\nimport type { SqlClient } from \"effect/sql\";\n\nimport type { D1BatchStatements } from \"../D1BatchStatements\";\nimport type { PersistenceMappingError } from \"../model\";\nimport {\n NativeDatabase,\n type NativeDatabaseHandle,\n type NativePhysicalDatabase,\n} from \"../native-database\";\nimport {\n nativeTarget,\n coordinateNativeTarget,\n type NativeTargetConfiguration,\n} from \"../native-target\";\nimport type { PasskeyPersistenceServices, PasskeyMappingSource } from \"../passkey-model\";\nimport { validateDrizzleStorage } from \"../storage-validation\";\nexport type PasskeyTargetConfiguration = NativeTargetConfiguration;\n\nexport type PasskeyCoordinatorError<E> =\n | E\n | PasskeyUnavailable\n | PasskeyConfigurationError\n | PersistenceMappingError;\n\nconst unavailable = () => PasskeyUnavailable.make({});\n\nconst emptyHooks: LifecycleHooks[\"Service\"] = {\n before: () => Effect.void,\n after: () => Effect.succeed([]),\n};\n\n// Mapped table/SQL generics end here. Persisted values are decoded by shared schemas.\nexport const capturePasskeyMapping = <M, R>(\n source: PasskeyMappingSource<M, R>,\n configuration: PasskeyTargetConfiguration,\n) =>\n Effect.flatMap(Effect.isEffect(source) ? source : Effect.succeed(source), (mapping) =>\n validateDrizzleStorage(mapping).pipe(\n Effect.andThen(\n Effect.try({\n try: () => {\n if (\n configuration.mode === \"batch\" &&\n !(\n typeof mapping === \"object\" &&\n mapping !== null &&\n \"d1\" in mapping &&\n typeof mapping.d1 === \"object\" &&\n mapping.d1 !== null &&\n \"primary\" in mapping.d1 &&\n mapping.d1.primary === true\n )\n )\n throw PasskeyConfigurationError.make({});\n\n return mapping;\n },\n catch: () => PasskeyConfigurationError.make({}),\n }),\n ),\n ),\n );\n\ntype NativePasskeyServices = Effect.Success<ReturnType<typeof makeNativePasskeyServices>>;\n\ninterface PasskeyMapped<M> {\n readonly mapping: M;\n readonly database: NativePhysicalDatabase;\n readonly tables: NativeSqlTables;\n readonly batch: SqlBatchCommit[\"Service\"] | undefined;\n readonly provide: <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E, Exclude<Exclude<R, SqlClient.SqlClient>, SqlBatchCommit>>;\n readonly base: () => Effect.Effect<\n NativePasskeyServices,\n PasskeyUnavailable,\n Crypto.Crypto | LifecycleHooks\n >;\n}\n\nexport const makePasskeyMapped = Effect.fnUntraced(function* <M, R>(\n source: PasskeyMappingSource<M, R>,\n configuration: PasskeyTargetConfiguration,\n): Effect.fn.Return<\n PasskeyMapped<M>,\n PasskeyConfigurationError | PersistenceMappingError,\n R | NativeDatabase\n> {\n const mapping = yield* capturePasskeyMapping(source, configuration);\n const database = yield* NativeDatabase;\n const { tables, batch, provide } = yield* nativeTarget(configuration);\n const native = mapping as unknown as PasskeyNativeMapping;\n\n return {\n mapping,\n database,\n tables,\n batch,\n provide,\n base: () =>\n provide(\n configuration.mode === \"batch\"\n ? makeBatchPasskeyServices(tables, native)\n : makeNativePasskeyServices(tables, native),\n ),\n };\n});\n\nexport const makeTargetPasskeyCredentials = <M, R>(\n source: PasskeyMappingSource<M, R>,\n configuration: PasskeyTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* makePasskeyMapped(source, configuration);\n\n return yield* target\n .provide(\n makeNativePasskeyCredentialServices(\n target.tables,\n target.mapping as unknown as PasskeyNativeRead,\n ),\n )\n .pipe(Effect.provideService(LifecycleHooks, emptyHooks));\n }).pipe(Effect.catchDefect(() => Effect.fail(PasskeyConfigurationError.make({}))));\n\nexport const makeTargetPasskeyPersistence = <M, R>(\n source: PasskeyMappingSource<M, R>,\n configuration: PasskeyTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* makePasskeyMapped(source, configuration);\n\n const base = yield* target.base();\n\n return { passkeyPersistence: base.passkeyPersistence } satisfies PasskeyPersistenceServices;\n });\n\nexport const makeTargetPasskeyRegistration = <M, R>(\n source: PasskeyMappingSource<M, R>,\n configuration: PasskeyTargetConfiguration,\n) =>\n Effect.gen(function* () {\n const target = yield* makePasskeyMapped(source, configuration);\n\n return yield* target.provide(\n makeNativePasskeyCeremonyServices(\n target.tables,\n target.mapping as unknown as NativePasskeyCeremonyMapping,\n configuration.mode === \"batch\" ? target.batch : undefined,\n ),\n );\n });\n\nexport const coordinatePasskeyOwner = <S, Transaction, A, E, R, ESetup, RSetup>(\n database: NativeDatabaseHandle,\n configuration: PasskeyTargetConfiguration,\n make: Effect.Effect<S, ESetup, RSetup>,\n body: (transaction: Transaction, services: S) => Effect.Effect<A, E, R>,\n): Effect.Effect<\n A,\n E | PasskeyUnavailable,\n Exclude<R, D1BatchStatements> | RSetup | LifecycleHooks\n> => coordinateNativeTarget(unavailable, database, configuration, make, body);\n\nexport const coordinateTargetPasskey = <M, RSetup, Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n source: PasskeyMappingSource<M, RSetup>,\n configuration: PasskeyTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetPasskeyPersistence>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinatePasskeyOwner(\n database,\n configuration,\n makeTargetPasskeyPersistence(source, configuration),\n body,\n );\n\nexport const coordinateTargetPasskeyRegistration = <M, RSetup, Transaction, A, E, R>(\n database: NativeDatabaseHandle,\n source: PasskeyMappingSource<M, RSetup>,\n configuration: PasskeyTargetConfiguration,\n body: (\n transaction: Transaction,\n services: Effect.Success<ReturnType<typeof makeTargetPasskeyRegistration>>,\n ) => Effect.Effect<A, E, R>,\n) =>\n coordinatePasskeyOwner(\n database,\n configuration,\n makeTargetPasskeyRegistration(source, configuration),\n body,\n );\n"],"mappings":";;;;;;;;AAsCA,MAAM,oBAAoB,mBAAmB,KAAK,CAAC,CAAC;AAEpD,MAAM,aAAwC;CAC5C,cAAc,OAAO;CACrB,aAAa,OAAO,QAAQ,CAAC,CAAC;AAChC;AAGA,MAAa,yBACX,QACA,kBAEA,OAAO,QAAQ,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO,QAAQ,MAAM,IAAI,YACzE,uBAAuB,OAAO,CAAC,CAAC,KAC9B,OAAO,QACL,OAAO,IAAI;CACT,WAAW;EACT,IACE,cAAc,SAAS,WACvB,EACE,OAAO,YAAY,YACnB,YAAY,QACZ,QAAQ,WACR,OAAO,QAAQ,OAAO,YACtB,QAAQ,OAAO,QACf,aAAa,QAAQ,MACrB,QAAQ,GAAG,YAAY,OAGzB,MAAM,0BAA0B,KAAK,CAAC,CAAC;EAEzC,OAAO;CACT;CACA,aAAa,0BAA0B,KAAK,CAAC,CAAC;AAChD,CAAC,CACH,CACF,CACF;AAmBF,MAAa,oBAAoB,OAAO,WAAW,WACjD,QACA,eAKA;CACA,MAAM,UAAU,OAAO,sBAAsB,QAAQ,aAAa;CAClE,MAAM,WAAW,OAAO;CACxB,MAAM,EAAE,QAAQ,OAAO,YAAY,OAAO,aAAa,aAAa;CACpE,MAAM,SAAS;CAEf,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,YACE,QACE,cAAc,SAAS,UACnB,yBAAyB,QAAQ,MAAM,IACvC,0BAA0B,QAAQ,MAAM,CAC9C;CACJ;AACF,CAAC;AAED,MAAa,gCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,kBAAkB,QAAQ,aAAa;CAE7D,OAAO,OAAO,OACX,QACC,oCACE,OAAO,QACP,OAAO,OACT,CACF,CAAC,CACA,KAAK,OAAO,eAAe,gBAAgB,UAAU,CAAC;AAC3D,CAAC,CAAC,CAAC,KAAK,OAAO,kBAAkB,OAAO,KAAK,0BAA0B,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnF,MAAa,gCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CAKtB,OAAO,EAAE,qBAAoB,QAFT,OAFE,kBAAkB,QAAQ,aAAa,EAAA,CAElC,KAAK,EAAA,CAEE,mBAAmB;AACvD,CAAC;AAEH,MAAa,iCACX,QACA,kBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,kBAAkB,QAAQ,aAAa;CAE7D,OAAO,OAAO,OAAO,QACnB,kCACE,OAAO,QACP,OAAO,SACP,cAAc,SAAS,UAAU,OAAO,QAAQ,KAAA,CAClD,CACF;AACF,CAAC;AAEH,MAAa,0BACX,UACA,eACA,MACA,SAKG,uBAAuB,aAAa,UAAU,eAAe,MAAM,IAAI;AAE5E,MAAa,2BACX,UACA,QACA,eACA,SAKA,uBACE,UACA,eACA,6BAA6B,QAAQ,aAAa,GAClD,IACF;AAEF,MAAa,uCACX,UACA,QACA,eACA,SAKA,uBACE,UACA,eACA,8BAA8B,QAAQ,aAAa,GACnD,IACF"}
|
|
@@ -4,6 +4,7 @@ import { coordinateNativeTarget, nativeTarget } from "./native-target.mjs";
|
|
|
4
4
|
import { validateDrizzleStorage } from "./storage-validation.mjs";
|
|
5
5
|
import { makeNativeAuthenticationAuthorityServices, makeNativePendingAuthenticationServices, makeNativeSessionCleanupServices, makeNativeSessionStepUpServices, makeNativeSignedSessionValidityServices, makeNativeStatefulSessionServices } from "@yielded/auth-persistence/Adapter";
|
|
6
6
|
import { Effect } from "effect";
|
|
7
|
+
import { reportAuthDiagnostic } from "@yielded/auth/Persistence";
|
|
7
8
|
import { AuthenticationAuthority, SessionUnavailable } from "@yielded/auth/Sessions";
|
|
8
9
|
//#region src/drizzle/session-drivers.ts
|
|
9
10
|
const unavailable = () => SessionUnavailable.make({});
|
|
@@ -16,7 +17,7 @@ const clockMapping = (mapping) => ({
|
|
|
16
17
|
const makeSessionTarget = (databaseService, configuration) => {
|
|
17
18
|
const authenticationAuthority = (mapping) => Effect.gen(function* () {
|
|
18
19
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
|
|
19
|
-
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* unavailable();
|
|
20
|
+
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* reportAuthDiagnostic("persistence-validation", "configuration").pipe(Effect.andThen(unavailable()));
|
|
20
21
|
const target = yield* nativeTarget(configuration);
|
|
21
22
|
return yield* target.provide(makeNativeAuthenticationAuthorityServices(target.tables, mapping));
|
|
22
23
|
});
|
|
@@ -28,7 +29,7 @@ const makeSessionTarget = (databaseService, configuration) => {
|
|
|
28
29
|
}
|
|
29
30
|
const pendingAuthentication = (mapping) => Effect.gen(function* () {
|
|
30
31
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
|
|
31
|
-
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* unavailable();
|
|
32
|
+
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* reportAuthDiagnostic("persistence-validation", "configuration").pipe(Effect.andThen(unavailable()));
|
|
32
33
|
const target = yield* nativeTarget(configuration);
|
|
33
34
|
return yield* target.provide(makeNativePendingAuthenticationServices(target.tables, mapping));
|
|
34
35
|
});
|
|
@@ -40,7 +41,7 @@ const makeSessionTarget = (databaseService, configuration) => {
|
|
|
40
41
|
}
|
|
41
42
|
const statefulSessionPersistence = (mapping) => Effect.gen(function* () {
|
|
42
43
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
|
|
43
|
-
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* unavailable();
|
|
44
|
+
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* reportAuthDiagnostic("persistence-validation", "configuration").pipe(Effect.andThen(unavailable()));
|
|
44
45
|
const target = yield* nativeTarget(configuration);
|
|
45
46
|
return yield* target.provide(makeNativeStatefulSessionServices(target.tables, mapping));
|
|
46
47
|
});
|
|
@@ -52,7 +53,7 @@ const makeSessionTarget = (databaseService, configuration) => {
|
|
|
52
53
|
}
|
|
53
54
|
const signedSessionValidity = (mapping) => Effect.gen(function* () {
|
|
54
55
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
|
|
55
|
-
if (configuration.mode === "batch" && mapping.d1?.primary !== true) return yield* unavailable();
|
|
56
|
+
if (configuration.mode === "batch" && mapping.d1?.primary !== true) return yield* reportAuthDiagnostic("persistence-validation", "configuration").pipe(Effect.andThen(unavailable()));
|
|
56
57
|
const target = yield* nativeTarget(configuration);
|
|
57
58
|
return yield* target.provide(makeNativeSignedSessionValidityServices(target.tables, mapping));
|
|
58
59
|
});
|
|
@@ -64,7 +65,7 @@ const makeSessionTarget = (databaseService, configuration) => {
|
|
|
64
65
|
}
|
|
65
66
|
const sessionStepUpPersistence = (mapping) => Effect.gen(function* () {
|
|
66
67
|
yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));
|
|
67
|
-
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* unavailable();
|
|
68
|
+
if (configuration.mode === "batch" && (mapping.d1?.primary !== true || mapping.subject.requirementColumns === void 0)) return yield* reportAuthDiagnostic("persistence-validation", "configuration").pipe(Effect.andThen(unavailable()));
|
|
68
69
|
const target = yield* nativeTarget(configuration);
|
|
69
70
|
return yield* target.provide(makeNativeSessionStepUpServices(target.tables, mapping));
|
|
70
71
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-drivers.mjs","names":[],"sources":["../../src/drizzle/session-drivers.ts"],"sourcesContent":["import {\n makeNativeAuthenticationAuthorityServices,\n type NativeAuthenticationAuthorityMapping,\n makeNativePendingAuthenticationServices,\n type NativePendingAuthenticationMapping,\n makeNativeStatefulSessionServices,\n type NativeStatefulSessionMapping,\n makeNativeSignedSessionValidityServices,\n type NativeSignedSessionValidityMapping,\n makeNativeSessionStepUpServices,\n type NativeSessionStepUpMapping,\n makeNativeSessionCleanupServices,\n} from \"@yielded/auth-persistence/Adapter\";\nimport type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport {\n AuthenticationAuthority,\n SessionUnavailable,\n type PendingAuthentication,\n type StatefulSessionPersistence,\n type SessionRepository,\n type SignedSessionValidity,\n type SessionStepUpPersistence,\n} from \"@yielded/auth/Sessions\";\nimport type { Table } from \"drizzle-orm\";\nimport { Effect, type Context } from \"effect\";\n\nimport type { NativeDriverDatabase, NativeDriverTransaction } from \"./driver-types\";\nimport { nativeClock, type MappedClock } from \"./native-clock\";\nimport { NativeDatabase, nativeDatabase } from \"./native-database\";\nimport {\n nativeTarget,\n coordinateNativeTarget,\n type NativeTargetConfiguration,\n} from \"./native-target\";\nimport type {\n AuthenticationAuthorityMapping,\n PendingAuthenticationMapping,\n StatefulSessionMapping,\n SignedSessionValidityMapping,\n SessionCleanupMapping,\n} from \"./session-model\";\nimport type { SessionStepUpMapping } from \"./step-up-model\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\nimport type { SuppliedService } from \"./SuppliedService\";\n\nconst unavailable = () => SessionUnavailable.make({});\n\nconst clockMapping = <T extends { readonly clock: MappedClock }>(mapping: T) => ({\n ...mapping,\n clock: nativeClock(mapping.clock),\n});\n\n/** Foreign table/ID callback variance is erased only at this physical mapping\n * boundary. All subjects, sessions, pending payloads and policy use their codecs. */\nexport const makeSessionTarget = <DatabaseId, D extends NativeDriverDatabase>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: NativeTargetConfiguration,\n) => {\n const authenticationAuthority = <Claims>(mapping: NativeAuthenticationAuthorityMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* unavailable();\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(\n makeNativeAuthenticationAuthorityServices(target.tables, mapping),\n );\n });\n\n function coordinateAuthenticationAuthority<\n DB extends D,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n E | DE | SessionUnavailable,\n Exclude<R, AuthenticationAuthority> | DR | LifecycleHooks\n >;\n function coordinateAuthenticationAuthority<\n DB extends D,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>;\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 | SessionUnavailable,\n Exclude<R, AuthenticationAuthority | TxId> | DR | LifecycleHooks\n >;\n function coordinateAuthenticationAuthority<\n DB extends D,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n authenticationAuthority(\n clockMapping(options.mapping) as unknown as NativeAuthenticationAuthorityMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(AuthenticationAuthority, services.authenticationAuthority),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const pendingAuthentication = <Claims>(mapping: NativePendingAuthenticationMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* unavailable();\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativePendingAuthenticationServices(target.tables, mapping));\n });\n\n function coordinatePendingAuthentication<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: PendingAuthenticationMapping<NoInfer<Claims>, S, C, P, N>;\n readonly target: SuppliedService<Id, PendingAuthentication<Claims>>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id> | DR | LifecycleHooks>;\n function coordinatePendingAuthentication<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: PendingAuthenticationMapping<NoInfer<Claims>, S, C, P, N>;\n readonly target: SuppliedService<Id, PendingAuthentication<Claims>>;\n readonly transaction: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id | TxId> | DR | LifecycleHooks>;\n function coordinatePendingAuthentication<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: PendingAuthenticationMapping<NoInfer<Claims>, S, C, P, N>;\n readonly target: SuppliedService<Id, PendingAuthentication<Claims>>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n pendingAuthentication(\n clockMapping(options.mapping) as unknown as NativePendingAuthenticationMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.target, services.pendingAuthentication),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const statefulSessionPersistence = <Claims>(mapping: NativeStatefulSessionMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* unavailable();\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativeStatefulSessionServices(target.tables, mapping));\n });\n\n function coordinateStatefulSessions<\n DB extends D,\n Id,\n RepositoryId,\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: StatefulSessionMapping<NoInfer<Claims>, S, C, Session, P, N, NS>;\n readonly persistence: SuppliedService<Id, StatefulSessionPersistence<Claims>>;\n readonly repository: SuppliedService<RepositoryId, SessionRepository>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n E | DE | SessionUnavailable,\n Exclude<R, Id | RepositoryId> | DR | LifecycleHooks\n >;\n function coordinateStatefulSessions<\n DB extends D,\n Id,\n RepositoryId,\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: StatefulSessionMapping<NoInfer<Claims>, S, C, Session, P, N, NS>;\n readonly persistence: SuppliedService<Id, StatefulSessionPersistence<Claims>>;\n readonly repository: SuppliedService<RepositoryId, SessionRepository>;\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 | SessionUnavailable,\n Exclude<R, Id | RepositoryId | TxId> | DR | LifecycleHooks\n >;\n function coordinateStatefulSessions<\n DB extends D,\n Id,\n RepositoryId,\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: StatefulSessionMapping<NoInfer<Claims>, S, C, Session, P, N, NS>;\n readonly persistence: SuppliedService<Id, StatefulSessionPersistence<Claims>>;\n readonly repository: SuppliedService<RepositoryId, SessionRepository>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n statefulSessionPersistence(\n clockMapping(options.mapping) as unknown as NativeStatefulSessionMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.persistence, services.statefulSessionPersistence),\n Effect.provideService(options.repository, services.sessionRepository),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const signedSessionValidity = (mapping: NativeSignedSessionValidityMapping) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (configuration.mode === \"batch\" && mapping.d1?.primary !== true)\n return yield* unavailable();\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativeSignedSessionValidityServices(target.tables, mapping));\n });\n\n function coordinateSignedSessionValidity<\n DB extends D,\n Id,\n S extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SignedSessionValidityMapping<S, T, N, NS>;\n readonly target: SuppliedService<Id, SignedSessionValidity>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id> | DR | LifecycleHooks>;\n function coordinateSignedSessionValidity<\n DB extends D,\n Id,\n S extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SignedSessionValidityMapping<S, T, N, NS>;\n readonly target: SuppliedService<Id, SignedSessionValidity>;\n readonly transaction: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id | TxId> | DR | LifecycleHooks>;\n function coordinateSignedSessionValidity<\n DB extends D,\n Id,\n S extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SignedSessionValidityMapping<S, T, N, NS>;\n readonly target: SuppliedService<Id, SignedSessionValidity>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n signedSessionValidity(\n clockMapping(options.mapping) as unknown as NativeSignedSessionValidityMapping,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.target, services.signedSessionValidity),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const sessionStepUpPersistence = <Claims>(mapping: NativeSessionStepUpMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* unavailable();\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativeSessionStepUpServices(target.tables, mapping));\n });\n\n function coordinateSessionStepUp<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>;\n readonly target: SuppliedService<Id, SessionStepUpPersistence<Claims>>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id> | DR | LifecycleHooks>;\n function coordinateSessionStepUp<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>;\n readonly target: SuppliedService<Id, SessionStepUpPersistence<Claims>>;\n readonly transaction: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id | TxId> | DR | LifecycleHooks>;\n function coordinateSessionStepUp<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>;\n readonly target: SuppliedService<Id, SessionStepUpPersistence<Claims>>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n sessionStepUpPersistence(\n clockMapping(options.mapping) as unknown as NativeSessionStepUpMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.target, services.sessionStepUpPersistence),\n );\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 coordinateAuthenticationAuthority,\n makeAuthenticationAuthorityServices: <\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n >(\n mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>,\n ) =>\n authenticationAuthority(\n clockMapping(mapping) as unknown as NativeAuthenticationAuthorityMapping<Claims>,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinatePendingAuthentication,\n makePendingAuthenticationServices: <\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n >(\n mapping: PendingAuthenticationMapping<Claims, S, C, P, N>,\n ) =>\n pendingAuthentication(\n clockMapping(mapping) as unknown as NativePendingAuthenticationMapping<Claims>,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinateStatefulSessions,\n makeStatefulSessionServices: <\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n >(\n mapping: StatefulSessionMapping<Claims, S, C, Session, P, N, NS>,\n ) =>\n statefulSessionPersistence(\n clockMapping(mapping) as unknown as NativeStatefulSessionMapping<Claims>,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinateSignedSessionValidity,\n makeSignedSessionValidityServices: <S extends Table, T extends Table, N, NS>(\n mapping: SignedSessionValidityMapping<S, T, N, NS>,\n ) =>\n signedSessionValidity(\n clockMapping(mapping) as unknown as NativeSignedSessionValidityMapping,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinateSessionStepUp,\n makeSessionStepUpServices: <\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n Id,\n >(\n mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>,\n target: Context.Service<Id, SessionStepUpPersistence<Claims>>,\n ) =>\n sessionStepUpPersistence(\n clockMapping(mapping) as unknown as NativeSessionStepUpMapping<Claims>,\n )\n .pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)))\n .pipe(\n Effect.map((services) => ({\n sessionStepUpPersistence: target.of(services.sessionStepUpPersistence),\n })),\n ),\n makeSessionCleanupServices: <P extends Table, T extends Table, N, NS>(\n mapping: SessionCleanupMapping<P, T, N, NS>,\n ) =>\n Effect.gen(function* () {\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(\n makeNativeSessionCleanupServices(\n target.tables,\n clockMapping(mapping) as unknown as Parameters<\n typeof makeNativeSessionCleanupServices\n >[1],\n ),\n );\n }).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-drivers.mjs","names":[],"sources":["../../src/drizzle/session-drivers.ts"],"sourcesContent":["import {\n makeNativeAuthenticationAuthorityServices,\n type NativeAuthenticationAuthorityMapping,\n makeNativePendingAuthenticationServices,\n type NativePendingAuthenticationMapping,\n makeNativeStatefulSessionServices,\n type NativeStatefulSessionMapping,\n makeNativeSignedSessionValidityServices,\n type NativeSignedSessionValidityMapping,\n makeNativeSessionStepUpServices,\n type NativeSessionStepUpMapping,\n makeNativeSessionCleanupServices,\n} from \"@yielded/auth-persistence/Adapter\";\nimport type { LifecycleHooks } from \"@yielded/auth/Hooks\";\nimport { reportAuthDiagnostic } from \"@yielded/auth/Persistence\";\nimport {\n AuthenticationAuthority,\n SessionUnavailable,\n type PendingAuthentication,\n type StatefulSessionPersistence,\n type SessionRepository,\n type SignedSessionValidity,\n type SessionStepUpPersistence,\n} from \"@yielded/auth/Sessions\";\nimport type { Table } from \"drizzle-orm\";\nimport { Effect, type Context } from \"effect\";\n\nimport type { NativeDriverDatabase, NativeDriverTransaction } from \"./driver-types\";\nimport { nativeClock, type MappedClock } from \"./native-clock\";\nimport { NativeDatabase, nativeDatabase } from \"./native-database\";\nimport {\n nativeTarget,\n coordinateNativeTarget,\n type NativeTargetConfiguration,\n} from \"./native-target\";\nimport type {\n AuthenticationAuthorityMapping,\n PendingAuthenticationMapping,\n StatefulSessionMapping,\n SignedSessionValidityMapping,\n SessionCleanupMapping,\n} from \"./session-model\";\nimport type { SessionStepUpMapping } from \"./step-up-model\";\nimport { validateDrizzleStorage } from \"./storage-validation\";\nimport type { SuppliedService } from \"./SuppliedService\";\n\nconst unavailable = () => SessionUnavailable.make({});\n\nconst clockMapping = <T extends { readonly clock: MappedClock }>(mapping: T) => ({\n ...mapping,\n clock: nativeClock(mapping.clock),\n});\n\n/** Foreign table/ID callback variance is erased only at this physical mapping\n * boundary. All subjects, sessions, pending payloads and policy use their codecs. */\nexport const makeSessionTarget = <DatabaseId, D extends NativeDriverDatabase>(\n databaseService: Context.Service<DatabaseId, D>,\n configuration: NativeTargetConfiguration,\n) => {\n const authenticationAuthority = <Claims>(mapping: NativeAuthenticationAuthorityMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* reportAuthDiagnostic(\"persistence-validation\", \"configuration\").pipe(\n Effect.andThen(unavailable()),\n );\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(\n makeNativeAuthenticationAuthorityServices(target.tables, mapping),\n );\n });\n\n function coordinateAuthenticationAuthority<\n DB extends D,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n E | DE | SessionUnavailable,\n Exclude<R, AuthenticationAuthority> | DR | LifecycleHooks\n >;\n function coordinateAuthenticationAuthority<\n DB extends D,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>;\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 | SessionUnavailable,\n Exclude<R, AuthenticationAuthority | TxId> | DR | LifecycleHooks\n >;\n function coordinateAuthenticationAuthority<\n DB extends D,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n authenticationAuthority(\n clockMapping(options.mapping) as unknown as NativeAuthenticationAuthorityMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(AuthenticationAuthority, services.authenticationAuthority),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const pendingAuthentication = <Claims>(mapping: NativePendingAuthenticationMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* reportAuthDiagnostic(\"persistence-validation\", \"configuration\").pipe(\n Effect.andThen(unavailable()),\n );\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativePendingAuthenticationServices(target.tables, mapping));\n });\n\n function coordinatePendingAuthentication<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: PendingAuthenticationMapping<NoInfer<Claims>, S, C, P, N>;\n readonly target: SuppliedService<Id, PendingAuthentication<Claims>>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id> | DR | LifecycleHooks>;\n function coordinatePendingAuthentication<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: PendingAuthenticationMapping<NoInfer<Claims>, S, C, P, N>;\n readonly target: SuppliedService<Id, PendingAuthentication<Claims>>;\n readonly transaction: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id | TxId> | DR | LifecycleHooks>;\n function coordinatePendingAuthentication<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: PendingAuthenticationMapping<NoInfer<Claims>, S, C, P, N>;\n readonly target: SuppliedService<Id, PendingAuthentication<Claims>>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n pendingAuthentication(\n clockMapping(options.mapping) as unknown as NativePendingAuthenticationMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.target, services.pendingAuthentication),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const statefulSessionPersistence = <Claims>(mapping: NativeStatefulSessionMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* reportAuthDiagnostic(\"persistence-validation\", \"configuration\").pipe(\n Effect.andThen(unavailable()),\n );\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativeStatefulSessionServices(target.tables, mapping));\n });\n\n function coordinateStatefulSessions<\n DB extends D,\n Id,\n RepositoryId,\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: StatefulSessionMapping<NoInfer<Claims>, S, C, Session, P, N, NS>;\n readonly persistence: SuppliedService<Id, StatefulSessionPersistence<Claims>>;\n readonly repository: SuppliedService<RepositoryId, SessionRepository>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<\n A,\n E | DE | SessionUnavailable,\n Exclude<R, Id | RepositoryId> | DR | LifecycleHooks\n >;\n function coordinateStatefulSessions<\n DB extends D,\n Id,\n RepositoryId,\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: StatefulSessionMapping<NoInfer<Claims>, S, C, Session, P, N, NS>;\n readonly persistence: SuppliedService<Id, StatefulSessionPersistence<Claims>>;\n readonly repository: SuppliedService<RepositoryId, SessionRepository>;\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 | SessionUnavailable,\n Exclude<R, Id | RepositoryId | TxId> | DR | LifecycleHooks\n >;\n function coordinateStatefulSessions<\n DB extends D,\n Id,\n RepositoryId,\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: StatefulSessionMapping<NoInfer<Claims>, S, C, Session, P, N, NS>;\n readonly persistence: SuppliedService<Id, StatefulSessionPersistence<Claims>>;\n readonly repository: SuppliedService<RepositoryId, SessionRepository>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n statefulSessionPersistence(\n clockMapping(options.mapping) as unknown as NativeStatefulSessionMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.persistence, services.statefulSessionPersistence),\n Effect.provideService(options.repository, services.sessionRepository),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const signedSessionValidity = (mapping: NativeSignedSessionValidityMapping) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (configuration.mode === \"batch\" && mapping.d1?.primary !== true)\n return yield* reportAuthDiagnostic(\"persistence-validation\", \"configuration\").pipe(\n Effect.andThen(unavailable()),\n );\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativeSignedSessionValidityServices(target.tables, mapping));\n });\n\n function coordinateSignedSessionValidity<\n DB extends D,\n Id,\n S extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SignedSessionValidityMapping<S, T, N, NS>;\n readonly target: SuppliedService<Id, SignedSessionValidity>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id> | DR | LifecycleHooks>;\n function coordinateSignedSessionValidity<\n DB extends D,\n Id,\n S extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SignedSessionValidityMapping<S, T, N, NS>;\n readonly target: SuppliedService<Id, SignedSessionValidity>;\n readonly transaction: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id | TxId> | DR | LifecycleHooks>;\n function coordinateSignedSessionValidity<\n DB extends D,\n Id,\n S extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SignedSessionValidityMapping<S, T, N, NS>;\n readonly target: SuppliedService<Id, SignedSessionValidity>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n signedSessionValidity(\n clockMapping(options.mapping) as unknown as NativeSignedSessionValidityMapping,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.target, services.signedSessionValidity),\n );\n\n return options.transaction === undefined\n ? work\n : Effect.provideService(work, options.transaction, options.transaction.of(transaction));\n },\n ),\n );\n }\n\n const sessionStepUpPersistence = <Claims>(mapping: NativeSessionStepUpMapping<Claims>) =>\n Effect.gen(function* () {\n yield* validateDrizzleStorage(mapping).pipe(Effect.mapError(unavailable));\n if (\n configuration.mode === \"batch\" &&\n (mapping.d1?.primary !== true || mapping.subject.requirementColumns === undefined)\n )\n return yield* reportAuthDiagnostic(\"persistence-validation\", \"configuration\").pipe(\n Effect.andThen(unavailable()),\n );\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(makeNativeSessionStepUpServices(target.tables, mapping));\n });\n\n function coordinateSessionStepUp<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>;\n readonly target: SuppliedService<Id, SessionStepUpPersistence<Claims>>;\n readonly transaction?: never;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id> | DR | LifecycleHooks>;\n function coordinateSessionStepUp<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>;\n readonly target: SuppliedService<Id, SessionStepUpPersistence<Claims>>;\n readonly transaction: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DE | SessionUnavailable, Exclude<R, Id | TxId> | DR | LifecycleHooks>;\n function coordinateSessionStepUp<\n DB extends D,\n Id,\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n A,\n E,\n R,\n DE,\n DR,\n TxId,\n TxShape,\n >(\n acquire: Effect.Effect<DB, DE, DR>,\n options: {\n readonly mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>;\n readonly target: SuppliedService<Id, SessionStepUpPersistence<Claims>>;\n readonly transaction?: SuppliedService<TxId, NoInfer<NativeDriverTransaction<DB>>, TxShape>;\n },\n body: Effect.Effect<A, E, R>,\n ) {\n return Effect.flatMap(nativeDatabase(acquire), (database) =>\n coordinateNativeTarget(\n unavailable,\n database,\n configuration,\n sessionStepUpPersistence(\n clockMapping(options.mapping) as unknown as NativeSessionStepUpMapping<Claims>,\n ),\n (transaction: NativeDriverTransaction<DB>, services) => {\n const work = body.pipe(\n Effect.provideService(options.target, services.sessionStepUpPersistence),\n );\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 coordinateAuthenticationAuthority,\n makeAuthenticationAuthorityServices: <\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n >(\n mapping: AuthenticationAuthorityMapping<Claims, S, C, P, N>,\n ) =>\n authenticationAuthority(\n clockMapping(mapping) as unknown as NativeAuthenticationAuthorityMapping<Claims>,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinatePendingAuthentication,\n makePendingAuthenticationServices: <\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n N,\n >(\n mapping: PendingAuthenticationMapping<Claims, S, C, P, N>,\n ) =>\n pendingAuthentication(\n clockMapping(mapping) as unknown as NativePendingAuthenticationMapping<Claims>,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinateStatefulSessions,\n makeStatefulSessionServices: <\n Claims,\n S extends Table,\n C extends Table,\n Session extends Table,\n P extends Table,\n N,\n NS,\n >(\n mapping: StatefulSessionMapping<Claims, S, C, Session, P, N, NS>,\n ) =>\n statefulSessionPersistence(\n clockMapping(mapping) as unknown as NativeStatefulSessionMapping<Claims>,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinateSignedSessionValidity,\n makeSignedSessionValidityServices: <S extends Table, T extends Table, N, NS>(\n mapping: SignedSessionValidityMapping<S, T, N, NS>,\n ) =>\n signedSessionValidity(\n clockMapping(mapping) as unknown as NativeSignedSessionValidityMapping,\n ).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n coordinateSessionStepUp,\n makeSessionStepUpServices: <\n Claims,\n S extends Table,\n C extends Table,\n P extends Table,\n Session extends Table,\n T extends Table,\n N,\n NS,\n Id,\n >(\n mapping: SessionStepUpMapping<NoInfer<Claims>, S, C, P, Session, T, N, NS>,\n target: Context.Service<Id, SessionStepUpPersistence<Claims>>,\n ) =>\n sessionStepUpPersistence(\n clockMapping(mapping) as unknown as NativeSessionStepUpMapping<Claims>,\n )\n .pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService)))\n .pipe(\n Effect.map((services) => ({\n sessionStepUpPersistence: target.of(services.sessionStepUpPersistence),\n })),\n ),\n makeSessionCleanupServices: <P extends Table, T extends Table, N, NS>(\n mapping: SessionCleanupMapping<P, T, N, NS>,\n ) =>\n Effect.gen(function* () {\n const target = yield* nativeTarget(configuration);\n\n return yield* target.provide(\n makeNativeSessionCleanupServices(\n target.tables,\n clockMapping(mapping) as unknown as Parameters<\n typeof makeNativeSessionCleanupServices\n >[1],\n ),\n );\n }).pipe(Effect.provideServiceEffect(NativeDatabase, nativeDatabase(databaseService))),\n };\n};\n"],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { Effect } from "effect";
|
|
|
5
5
|
import { MySqlTable, getTableConfig } from "drizzle-orm/mysql-core";
|
|
6
6
|
import { PgTable, getTableConfig as getTableConfig$1 } from "drizzle-orm/pg-core";
|
|
7
7
|
import { SqlClient } from "effect/sql/SqlClient";
|
|
8
|
+
import { reportAuthDiagnostic } from "@yielded/auth/Persistence";
|
|
8
9
|
//#region src/drizzle/storage-validation.ts
|
|
9
10
|
/** Validate at acquisition using the root database supplied by the adapter. */
|
|
10
11
|
const validateDrizzleStorage = Effect.fnUntraced(function* (mapping) {
|
|
@@ -48,7 +49,7 @@ const validateDrizzleStorage = Effect.fnUntraced(function* (mapping) {
|
|
|
48
49
|
}, Effect.catchDefect(() => Effect.fail(PersistenceMappingError.make({
|
|
49
50
|
operation: "mapping",
|
|
50
51
|
cause: "Cannot inspect SQL storage metadata"
|
|
51
|
-
}))));
|
|
52
|
+
}))), Effect.tapError(() => reportAuthDiagnostic("persistence-validation", "mapping")));
|
|
52
53
|
//#endregion
|
|
53
54
|
export { validateDrizzleStorage };
|
|
54
55
|
|
|
@@ -1 +1 @@
|
|
|
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":"
|
|
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 { reportAuthDiagnostic } from \"@yielded/auth/Persistence\";\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 Effect.tapError(() => reportAuthDiagnostic(\"persistence-validation\", \"mapping\")),\n);\n"],"mappings":";;;;;;;;;;AAgBA,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,GACA,OAAO,eAAe,qBAAqB,0BAA0B,SAAS,CAAC,CACjF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PersistenceConfigurationError } from "@yielded/auth-persistence/Adapter";
|
|
2
|
+
import { Crypto, Layer } from "effect";
|
|
3
|
+
import { D1Client } from "@effect/sql-d1/D1Client";
|
|
4
|
+
//#region src/internal/drizzle-d1-migrations.d.ts
|
|
5
|
+
/** Drizzle's D1 migration journal and selection, with bundled SQL in place of
|
|
6
|
+
* filesystem loading. Pending statements and journal entries share one D1 batch.
|
|
7
|
+
* Applications own when migrations run; do not run competing migration owners.
|
|
8
|
+
*/
|
|
9
|
+
export declare const d1MigrationsLayer: (options: {
|
|
10
|
+
readonly migrations: Readonly<Record<string, string>>;
|
|
11
|
+
readonly migrationsTable?: string;
|
|
12
|
+
}) => Layer.Layer<never, PersistenceConfigurationError, Crypto.Crypto | D1Client>;
|
|
13
|
+
//#endregion
|
|
14
|
+
//# sourceMappingURL=drizzle-d1-migrations.d.mts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { PersistenceConfigurationError } from "@yielded/auth-persistence/Adapter";
|
|
2
|
+
import { sql } from "drizzle-orm";
|
|
3
|
+
import { Crypto, DateTime, Effect, Layer, Schema } from "effect";
|
|
4
|
+
import { D1Client } from "@effect/sql-d1/D1Client";
|
|
5
|
+
import { drizzle } from "drizzle-orm/d1";
|
|
6
|
+
import { formatToMillis, getMigrationsToRun } from "drizzle-orm/migrator.utils";
|
|
7
|
+
//#region src/internal/drizzle-d1-migrations.ts
|
|
8
|
+
const MigrationFiles = Schema.Record(Schema.String, Schema.NonEmptyString);
|
|
9
|
+
const MigrationName = Schema.String.check(Schema.isPattern(/^\d{14}_.+$/));
|
|
10
|
+
const JournalColumns = Schema.Array(Schema.Struct({ name: Schema.String }));
|
|
11
|
+
const configurationError = () => PersistenceConfigurationError.make({ reason: "Could not apply D1 migrations; check the bundled SQL and database binding" });
|
|
12
|
+
const JournalRows = Schema.Array(Schema.Struct({
|
|
13
|
+
id: Schema.Int,
|
|
14
|
+
hash: Schema.String,
|
|
15
|
+
created_at: Schema.String,
|
|
16
|
+
name: Schema.NullOr(Schema.String)
|
|
17
|
+
}));
|
|
18
|
+
/** Drizzle's D1 migration journal and selection, with bundled SQL in place of
|
|
19
|
+
* filesystem loading. Pending statements and journal entries share one D1 batch.
|
|
20
|
+
* Applications own when migrations run; do not run competing migration owners.
|
|
21
|
+
*/
|
|
22
|
+
const d1MigrationsLayer = (options) => Layer.effectDiscard(Effect.gen(function* () {
|
|
23
|
+
const files = yield* Schema.decodeEffect(MigrationFiles)(options.migrations);
|
|
24
|
+
const client = yield* D1Client;
|
|
25
|
+
const crypto = yield* Crypto.Crypto;
|
|
26
|
+
const appliedAt = DateTime.formatIso(yield* DateTime.now);
|
|
27
|
+
const migrations = yield* Effect.forEach(Object.entries(files).sort(([left], [right]) => left.localeCompare(right)), Effect.fnUntraced(function* ([name, contents]) {
|
|
28
|
+
yield* Schema.decodeEffect(MigrationName)(name);
|
|
29
|
+
const folderMillis = yield* Schema.decodeEffect(Schema.Int)(formatToMillis(name.slice(0, 14)));
|
|
30
|
+
const digest = yield* crypto.digest("SHA-256", new TextEncoder().encode(contents));
|
|
31
|
+
return {
|
|
32
|
+
name,
|
|
33
|
+
folderMillis,
|
|
34
|
+
hash: Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join(""),
|
|
35
|
+
sql: contents.split("--> statement-breakpoint"),
|
|
36
|
+
bps: true
|
|
37
|
+
};
|
|
38
|
+
}));
|
|
39
|
+
yield* Effect.tryPromise({
|
|
40
|
+
try: async () => {
|
|
41
|
+
const db = drizzle(client.config.db);
|
|
42
|
+
const name = options.migrationsTable ?? "__drizzle_migrations";
|
|
43
|
+
const table = sql.identifier(name);
|
|
44
|
+
const columns = Schema.decodeUnknownSync(JournalColumns)(await db.all(sql`select name from pragma_table_info(${name})`)).map((column) => column.name);
|
|
45
|
+
const newDb = columns.length === 0;
|
|
46
|
+
const legacy = !newDb && !columns.includes("name");
|
|
47
|
+
if (!newDb && (![
|
|
48
|
+
"id",
|
|
49
|
+
"hash",
|
|
50
|
+
"created_at"
|
|
51
|
+
].every((column) => columns.includes(column)) || legacy === columns.includes("applied_at"))) throw configurationError();
|
|
52
|
+
const journal = newDb ? [] : Schema.decodeUnknownSync(JournalRows)(await db.all(sql`select rowid as id, hash, cast(created_at as text) as created_at,
|
|
53
|
+
${legacy ? sql`null` : sql`name`} as name from ${table} order by rowid`)).map((entry) => ({ ...entry }));
|
|
54
|
+
const journalStatements = newDb ? [db.run(sql`create table ${table} (
|
|
55
|
+
id integer primary key, hash text not null, created_at numeric,
|
|
56
|
+
name text, applied_at text
|
|
57
|
+
)`)] : [];
|
|
58
|
+
if (legacy) {
|
|
59
|
+
journalStatements.push(db.run(sql`alter table ${table} add column name text`), db.run(sql`alter table ${table} add column applied_at text`));
|
|
60
|
+
for (const entry of journal) {
|
|
61
|
+
const millis = Math.floor(Number(entry.created_at) / 1e3) * 1e3;
|
|
62
|
+
const candidates = migrations.filter((migration) => migration.folderMillis === millis);
|
|
63
|
+
const matches = candidates.length === 1 ? candidates : (candidates.length === 0 ? migrations : candidates).filter((migration) => migration.hash === entry.hash);
|
|
64
|
+
const match = matches[0];
|
|
65
|
+
if (matches.length !== 1 || match === void 0) throw configurationError();
|
|
66
|
+
entry.name = match.name;
|
|
67
|
+
journalStatements.push(db.run(sql`update ${table} set name = ${match.name} where rowid = ${entry.id}`));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const [first, ...rest] = [...journalStatements, ...getMigrationsToRun({
|
|
71
|
+
localMigrations: migrations,
|
|
72
|
+
dbMigrations: [...journal]
|
|
73
|
+
}).flatMap((migration) => [...migration.sql.map((statement) => db.run(sql.raw(statement))), db.run(sql`insert into ${table} (hash, created_at, name, applied_at)
|
|
74
|
+
values (${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${appliedAt})`)])];
|
|
75
|
+
if (first !== void 0) await db.batch([first, ...rest]);
|
|
76
|
+
},
|
|
77
|
+
catch: configurationError
|
|
78
|
+
});
|
|
79
|
+
}).pipe(Effect.mapError(configurationError)));
|
|
80
|
+
//#endregion
|
|
81
|
+
export { d1MigrationsLayer };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=drizzle-d1-migrations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-d1-migrations.mjs","names":[],"sources":["../../src/internal/drizzle-d1-migrations.ts"],"sourcesContent":["import { D1Client } from \"@effect/sql-d1/D1Client\";\nimport { PersistenceConfigurationError } from \"@yielded/auth-persistence/Adapter\";\nimport { sql } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/d1\";\nimport { formatToMillis, getMigrationsToRun } from \"drizzle-orm/migrator.utils\";\nimport { Crypto, DateTime, Effect, Layer, Schema } from \"effect\";\n\nconst MigrationFiles = Schema.Record(Schema.String, Schema.NonEmptyString);\nconst MigrationName = Schema.String.check(Schema.isPattern(/^\\d{14}_.+$/));\nconst JournalColumns = Schema.Array(Schema.Struct({ name: Schema.String }));\n\nconst configurationError = () =>\n PersistenceConfigurationError.make({\n reason: \"Could not apply D1 migrations; check the bundled SQL and database binding\",\n });\n\nconst JournalRows = Schema.Array(\n Schema.Struct({\n id: Schema.Int,\n hash: Schema.String,\n created_at: Schema.String,\n name: Schema.NullOr(Schema.String),\n }),\n);\n\n/** Drizzle's D1 migration journal and selection, with bundled SQL in place of\n * filesystem loading. Pending statements and journal entries share one D1 batch.\n * Applications own when migrations run; do not run competing migration owners.\n */\nexport const d1MigrationsLayer = (options: {\n readonly migrations: Readonly<Record<string, string>>;\n readonly migrationsTable?: string;\n}) =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n const files = yield* Schema.decodeEffect(MigrationFiles)(options.migrations);\n const client = yield* D1Client;\n const crypto = yield* Crypto.Crypto;\n const appliedAt = DateTime.formatIso(yield* DateTime.now);\n\n const migrations = yield* Effect.forEach(\n Object.entries(files).sort(([left], [right]) => left.localeCompare(right)),\n Effect.fnUntraced(function* ([name, contents]) {\n yield* Schema.decodeEffect(MigrationName)(name);\n\n const folderMillis = yield* Schema.decodeEffect(Schema.Int)(\n formatToMillis(name.slice(0, 14)),\n );\n\n const digest = yield* crypto.digest(\"SHA-256\", new TextEncoder().encode(contents));\n\n return {\n name,\n folderMillis,\n hash: Array.from(digest, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\"),\n sql: contents.split(\"--> statement-breakpoint\"),\n bps: true,\n };\n }),\n );\n\n yield* Effect.tryPromise({\n try: async () => {\n const db = drizzle(client.config.db);\n const name = options.migrationsTable ?? \"__drizzle_migrations\";\n const table = sql.identifier(name);\n\n const columns = Schema.decodeUnknownSync(JournalColumns)(\n await db.all(sql`select name from pragma_table_info(${name})`),\n ).map((column) => column.name);\n\n const newDb = columns.length === 0;\n const legacy = !newDb && !columns.includes(\"name\");\n\n if (\n !newDb &&\n (![\"id\", \"hash\", \"created_at\"].every((column) => columns.includes(column)) ||\n legacy === columns.includes(\"applied_at\"))\n )\n throw configurationError();\n\n // Original Drizzle SQLite journals can have NULL serial IDs. Use the\n // physical rowid to backfill each retained entry without changing it.\n const journal = newDb\n ? []\n : Schema.decodeUnknownSync(JournalRows)(\n await db.all(sql`select rowid as id, hash, cast(created_at as text) as created_at,\n ${legacy ? sql`null` : sql`name`} as name from ${table} order by rowid`),\n ).map((entry) => ({ ...entry }));\n\n const journalStatements = newDb\n ? [\n db.run(sql`create table ${table} (\n id integer primary key, hash text not null, created_at numeric,\n name text, applied_at text\n )`),\n ]\n : [];\n\n if (legacy) {\n // Match retained entries using Drizzle's timestamp/hash convention,\n // but stage the upgrade with pending SQL: D1 cannot run BEGIN.\n journalStatements.push(\n db.run(sql`alter table ${table} add column name text`),\n db.run(sql`alter table ${table} add column applied_at text`),\n );\n for (const entry of journal) {\n const millis = Math.floor(Number(entry.created_at) / 1000) * 1000;\n\n const candidates = migrations.filter(\n (migration) => migration.folderMillis === millis,\n );\n\n const matches =\n candidates.length === 1\n ? candidates\n : (candidates.length === 0 ? migrations : candidates).filter(\n (migration) => migration.hash === entry.hash,\n );\n\n const match = matches[0];\n\n if (matches.length !== 1 || match === undefined) throw configurationError();\n entry.name = match.name;\n journalStatements.push(\n db.run(sql`update ${table} set name = ${match.name} where rowid = ${entry.id}`),\n );\n }\n }\n\n const statements = [\n ...journalStatements,\n ...getMigrationsToRun({\n localMigrations: migrations,\n dbMigrations: [...journal],\n }).flatMap((migration) => [\n ...migration.sql.map((statement) => db.run(sql.raw(statement))),\n db.run(sql`insert into ${table} (hash, created_at, name, applied_at)\n values (${migration.hash}, ${migration.folderMillis}, ${migration.name}, ${appliedAt})`),\n ]),\n ];\n\n const [first, ...rest] = statements;\n\n if (first !== undefined) await db.batch([first, ...rest]);\n },\n catch: configurationError,\n });\n }).pipe(Effect.mapError(configurationError)),\n );\n"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { nativeDatabase } from "../drizzle/native-database.mjs";
|
|
|
2
2
|
import { makeDrizzleSqlTables } from "../drizzle/native-sql-table.mjs";
|
|
3
3
|
import { PersistenceConfigurationError, createPersistence } from "@yielded/auth-persistence/Adapter";
|
|
4
4
|
import { getTableColumns } from "drizzle-orm";
|
|
5
|
+
import { Effect } from "effect";
|
|
5
6
|
import { getTableConfig, integer, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
|
6
7
|
//#region src/internal/drizzle-sqlite.ts
|
|
7
8
|
const makeTable = (definition) => sqliteTable(definition.name, Object.fromEntries(Object.entries(definition.columns).map(([key, column]) => {
|
|
@@ -23,11 +24,15 @@ const describe = (table) => {
|
|
|
23
24
|
unique: []
|
|
24
25
|
};
|
|
25
26
|
};
|
|
26
|
-
const sqlitePersistence = (acquire) => createPersistence({
|
|
27
|
+
const sqlitePersistence = (acquire, options) => createPersistence({
|
|
27
28
|
nativeTables: (database) => makeDrizzleSqlTables(database.$client, database),
|
|
28
29
|
makeTable,
|
|
29
30
|
describe,
|
|
30
|
-
acquire: nativeDatabase(acquire)
|
|
31
|
+
acquire: nativeDatabase(acquire),
|
|
32
|
+
...options?.batch === true ? { batch: (database) => ({
|
|
33
|
+
client: database.$client,
|
|
34
|
+
execute: (statements) => database.$client.batch(statements).pipe(Effect.asVoid)
|
|
35
|
+
}) } : {}
|
|
31
36
|
});
|
|
32
37
|
//#endregion
|
|
33
38
|
export { sqlitePersistence };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drizzle-sqlite.mjs","names":[],"sources":["../../src/internal/drizzle-sqlite.ts"],"sourcesContent":["import {\n PersistenceConfigurationError,\n createPersistence,\n} from \"@yielded/auth-persistence/Adapter\";\nimport type { StorageTable } from \"@yielded/auth-persistence/Adapter\";\nimport { getTableColumns } from \"drizzle-orm\";\nimport {\n getTableConfig,\n integer,\n sqliteTable,\n text,\n uniqueIndex,\n type SQLiteTable,\n} from \"drizzle-orm/sqlite-core\";\nimport
|
|
1
|
+
{"version":3,"file":"drizzle-sqlite.mjs","names":[],"sources":["../../src/internal/drizzle-sqlite.ts"],"sourcesContent":["import {\n PersistenceConfigurationError,\n createPersistence,\n} from \"@yielded/auth-persistence/Adapter\";\nimport type { StorageTable } from \"@yielded/auth-persistence/Adapter\";\nimport { getTableColumns } from \"drizzle-orm\";\nimport {\n getTableConfig,\n integer,\n sqliteTable,\n text,\n uniqueIndex,\n type SQLiteTable,\n} from \"drizzle-orm/sqlite-core\";\nimport { Effect } from \"effect\";\nimport type { SqlClient } from \"effect/sql/SqlClient\";\n\nimport { nativeDatabase, type NativeDatabaseHandle } from \"../drizzle/native-database\";\nimport { makeDrizzleSqlTables } from \"../drizzle/native-sql-table\";\n\nconst makeTable = (definition: StorageTable) =>\n sqliteTable(\n definition.name,\n Object.fromEntries(\n Object.entries(definition.columns).map(([key, column]) => {\n const builder =\n column.type === \"text\"\n ? text(column.name)\n : column.type === \"boolean\"\n ? integer(column.name, { mode: \"boolean\" })\n : integer(column.name);\n\n return [key, column.nullable ? builder : builder.notNull()];\n }),\n ),\n (columns) =>\n definition.unique.map((keys, i) => {\n const [first, ...rest] = keys;\n\n if (first === undefined)\n throw PersistenceConfigurationError.make({ reason: \"An empty unique key is invalid\" });\n\n return uniqueIndex(`${definition.name}_key_${i}`).on(\n columns[first],\n ...rest.map((key) => columns[key]),\n );\n }),\n );\n\nconst describe = (table: SQLiteTable): StorageTable => {\n const config = getTableConfig(table);\n\n return {\n name: config.name,\n columns: Object.fromEntries(\n Object.entries(getTableColumns(table)).map(([key, column]) => [\n key,\n {\n name: column.name,\n type:\n column.dataType === \"boolean\"\n ? \"boolean\"\n : column.dataType === \"number\"\n ? \"integer\"\n : \"text\",\n nullable: !column.notNull,\n },\n ]),\n ),\n unique: [],\n };\n};\n\nexport const sqlitePersistence = <R>(\n acquire: Effect.Effect<object, never, R | SqlClient>,\n options?: { readonly batch: true },\n) =>\n createPersistence<SQLiteTable, R, NativeDatabaseHandle>({\n nativeTables: (database) => makeDrizzleSqlTables(database.$client, database),\n makeTable,\n describe,\n acquire: nativeDatabase(acquire),\n ...(options?.batch === true\n ? {\n batch: (database: NativeDatabaseHandle) => ({\n client: database.$client,\n execute: (statements: Parameters<typeof database.$client.batch>[0]) =>\n database.$client.batch(statements).pipe(Effect.asVoid),\n }),\n }\n : {}),\n });\n"],"mappings":";;;;;;;AAoBA,MAAM,aAAa,eACjB,YACE,WAAW,MACX,OAAO,YACL,OAAO,QAAQ,WAAW,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,YAAY;CACxD,MAAM,UACJ,OAAO,SAAS,SACZ,KAAK,OAAO,IAAI,IAChB,OAAO,SAAS,YACd,QAAQ,OAAO,MAAM,EAAE,MAAM,UAAU,CAAC,IACxC,QAAQ,OAAO,IAAI;CAE3B,OAAO,CAAC,KAAK,OAAO,WAAW,UAAU,QAAQ,QAAQ,CAAC;AAC5D,CAAC,CACH,IACC,YACC,WAAW,OAAO,KAAK,MAAM,MAAM;CACjC,MAAM,CAAC,OAAO,GAAG,QAAQ;CAEzB,IAAI,UAAU,KAAA,GACZ,MAAM,8BAA8B,KAAK,EAAE,QAAQ,iCAAiC,CAAC;CAEvF,OAAO,YAAY,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,GAChD,QAAQ,QACR,GAAG,KAAK,KAAK,QAAQ,QAAQ,IAAI,CACnC;AACF,CAAC,CACL;AAEF,MAAM,YAAY,UAAqC;CAGrD,OAAO;EACL,MAHa,eAAe,KAGjB,CAAC,CAAC;EACb,SAAS,OAAO,YACd,OAAO,QAAQ,gBAAgB,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,YAAY,CAC5D,KACA;GACE,MAAM,OAAO;GACb,MACE,OAAO,aAAa,YAChB,YACA,OAAO,aAAa,WAClB,YACA;GACR,UAAU,CAAC,OAAO;EACpB,CACF,CAAC,CACH;EACA,QAAQ,CAAC;CACX;AACF;AAEA,MAAa,qBACX,SACA,YAEA,kBAAwD;CACtD,eAAe,aAAa,qBAAqB,SAAS,SAAS,QAAQ;CAC3E;CACA;CACA,SAAS,eAAe,OAAO;CAC/B,GAAI,SAAS,UAAU,OACnB,EACE,QAAQ,cAAoC;EAC1C,QAAQ,SAAS;EACjB,UAAU,eACR,SAAS,QAAQ,MAAM,UAAU,CAAC,CAAC,KAAK,OAAO,MAAM;CACzD,GACF,IACA,CAAC;AACP,CAAC"}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@yielded/auth-persistence-drizzle","version":"0.1.0-beta.
|
|
1
|
+
{"name":"@yielded/auth-persistence-drizzle","version":"0.1.0-beta.32","dependencies":{"@yielded/auth":"0.1.0-beta.32","@yielded/auth-persistence":"0.1.0-beta.32"},"devDependencies":{"@effect/platform-bun":"4.0.0","@effect/platform-node":"4.0.0","@effect/sql-d1":"4.0.0","@effect/sql-libsql":"4.0.0","@effect/sql-mysql2":"4.0.0","@effect/sql-pg":"4.0.0","@effect/sql-pglite":"4.0.0","@effect/sql-sqlite-bun":"4.0.0","@effect/sql-sqlite-do":"4.0.0","@effect/sql-sqlite-node":"4.0.0","@effect/sql-sqlite-wasm":"4.0.0","@effect/vitest":"4.0.0","@yielded/crypto":"0.1.0-beta.32","drizzle-orm":"1.0.0-rc.4","effect":"4.0.0","typescript":"7.0.2","vite":"npm:@voidzero-dev/vite-plus-core@1.1.0","vite-plus":"1.1.0","vitest":"5.0.3"},"peerDependencies":{"@effect/sql-d1":">=4.0.0","@effect/sql-libsql":">=4.0.0","@effect/sql-mysql2":">=4.0.0","@effect/sql-pg":">=4.0.0","@effect/sql-pglite":">=4.0.0","@effect/sql-sqlite-bun":">=4.0.0","@effect/sql-sqlite-do":">=4.0.0","@effect/sql-sqlite-node":">=4.0.0","@effect/sql-sqlite-wasm":">=4.0.0","drizzle-orm":">=1.0.0-rc.4","effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./D1":{"types":"./dist/D1.d.mts","default":"./dist/D1.mjs"},"./Libsql":{"types":"./dist/Libsql.d.mts","default":"./dist/Libsql.mjs"},"./Mysql2":{"types":"./dist/Mysql2.d.mts","default":"./dist/Mysql2.mjs"},"./Pglite":{"types":"./dist/Pglite.d.mts","default":"./dist/Pglite.mjs"},"./Postgres":{"types":"./dist/Postgres.d.mts","default":"./dist/Postgres.mjs"},"./SqliteBun":{"types":"./dist/SqliteBun.d.mts","default":"./dist/SqliteBun.mjs"},"./SqliteDo":{"types":"./dist/SqliteDo.d.mts","default":"./dist/SqliteDo.mjs"},"./SqliteNode":{"types":"./dist/SqliteNode.d.mts","default":"./dist/SqliteNode.mjs"},"./SqliteWasm":{"types":"./dist/SqliteWasm.d.mts","default":"./dist/SqliteWasm.mjs"}},"description":"Drizzle persistence, table mappings, and migration adapters for Yielded Auth.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/auth-persistence-drizzle"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests","example:totp":"bun test/fixtures/totp-sqlite-bun.ts"},"peerDependenciesMeta":{"@effect/sql-d1":{"optional":true},"@effect/sql-libsql":{"optional":true},"@effect/sql-mysql2":{"optional":true},"@effect/sql-pg":{"optional":true},"@effect/sql-pglite":{"optional":true},"@effect/sql-sqlite-bun":{"optional":true},"@effect/sql-sqlite-do":{"optional":true},"@effect/sql-sqlite-node":{"optional":true},"@effect/sql-sqlite-wasm":{"optional":true}}}
|
package/src/D1.ts
CHANGED
|
@@ -74,6 +74,18 @@ export const makeIdentityServices = <
|
|
|
74
74
|
|
|
75
75
|
import { Layer } from "effect";
|
|
76
76
|
|
|
77
|
+
import { d1MigrationsLayer } from "./internal/drizzle-d1-migrations";
|
|
78
|
+
import { sqlitePersistence } from "./internal/drizzle-sqlite";
|
|
79
|
+
|
|
80
|
+
/** Managed or mapped auth tables committed through D1's atomic batches.
|
|
81
|
+
* Supply D1Client.layer({ db: env.DB }) with the primary database binding.
|
|
82
|
+
* Registration supplies subject values; the account and credentials commit together.
|
|
83
|
+
*/
|
|
84
|
+
export const AuthPersistence = {
|
|
85
|
+
...sqlitePersistence(makeWithDefaults({}), { batch: true }),
|
|
86
|
+
migrationsLayer: d1MigrationsLayer,
|
|
87
|
+
};
|
|
88
|
+
|
|
77
89
|
import type { D1BatchStatements } from "./drizzle/D1BatchStatements";
|
|
78
90
|
import { makeOAuthTarget } from "./drizzle/oauth-drivers";
|
|
79
91
|
import type { OAuthD1Mapping } from "./drizzle/oauth-model";
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "@yielded/auth-persistence/Adapter";
|
|
16
16
|
import type { LifecycleHooks } from "@yielded/auth/Hooks";
|
|
17
17
|
import { OAuthUnavailable } from "@yielded/auth/OAuth";
|
|
18
|
+
import { reportAuthDiagnostic } from "@yielded/auth/Persistence";
|
|
18
19
|
import { Effect } from "effect";
|
|
19
20
|
|
|
20
21
|
import type { D1BatchStatements } from "./D1BatchStatements";
|
|
@@ -58,8 +59,11 @@ const mapped = Effect.fnUntraced(function* (
|
|
|
58
59
|
"primary" in mapping.d1 &&
|
|
59
60
|
mapping.d1.primary === true
|
|
60
61
|
)
|
|
61
|
-
)
|
|
62
|
+
) {
|
|
63
|
+
yield* reportAuthDiagnostic("persistence-validation", "configuration");
|
|
64
|
+
|
|
62
65
|
return yield* unavailable();
|
|
66
|
+
}
|
|
63
67
|
|
|
64
68
|
return { mapping, ...(yield* nativeTarget(configuration)) };
|
|
65
69
|
});
|