@fragno-dev/test 0.0.0-canary-20251030115355

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.
@@ -0,0 +1,19 @@
1
+
2
+ > @fragno-dev/test@0.1.8 build /home/runner/work/fragno/fragno/packages/fragno-test
3
+ > tsdown
4
+
5
+ ℹ tsdown v0.15.12 powered by rolldown v1.0.0-beta.45
6
+ ℹ Using tsdown config: /home/runner/work/fragno/fragno/packages/fragno-test/tsdown.config.ts
7
+ ℹ entry: src/index.ts
8
+ ℹ tsconfig: tsconfig.json
9
+ ℹ Build start
10
+ ℹ dist/index.js  2.64 kB │ gzip: 0.81 kB
11
+ ℹ dist/adapters.js.map 16.62 kB │ gzip: 3.63 kB
12
+ ℹ dist/index.js.map  9.05 kB │ gzip: 2.51 kB
13
+ ℹ dist/adapters.js  6.74 kB │ gzip: 1.54 kB
14
+ ℹ dist/index.d.ts.map  1.60 kB │ gzip: 0.76 kB
15
+ ℹ dist/adapters.d.ts.map  0.93 kB │ gzip: 0.42 kB
16
+ ℹ dist/index.d.ts  2.98 kB │ gzip: 0.82 kB
17
+ ℹ dist/adapters.d.ts  1.28 kB │ gzip: 0.42 kB
18
+ ℹ 8 files, total: 41.82 kB
19
+ ✔ Build complete in 3747ms
package/CHANGELOG.md ADDED
@@ -0,0 +1,76 @@
1
+ # @fragno-dev/test
2
+
3
+ ## 0.0.0-canary-20251030115355
4
+
5
+ ### Patch Changes
6
+
7
+ - e99ef47: feat: expose `db` object to run queries directly in tests
8
+
9
+ ## 0.1.8
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [b6dd67a]
14
+ - Updated dependencies [ec1aed0]
15
+ - Updated dependencies [9a58d8c]
16
+ - @fragno-dev/core@0.1.5
17
+ - @fragno-dev/db@0.1.11
18
+
19
+ ## 0.1.7
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [ca57fac]
24
+ - @fragno-dev/core@0.1.4
25
+ - @fragno-dev/db@0.1.10
26
+
27
+ ## 0.1.6
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [ad3e63b]
32
+ - @fragno-dev/db@0.1.10
33
+
34
+ ## 0.1.5
35
+
36
+ ### Patch Changes
37
+
38
+ - 7445a73: feat: Added support for testing using different adapters
39
+ - Updated dependencies [8fcceb6]
40
+ - @fragno-dev/db@0.1.9
41
+
42
+ ## 0.1.4
43
+
44
+ ### Patch Changes
45
+
46
+ - Updated dependencies [f3cdb1d]
47
+ - @fragno-dev/db@0.1.8
48
+
49
+ ## 0.1.3
50
+
51
+ ### Patch Changes
52
+
53
+ - Updated dependencies [e36dbcd]
54
+ - Updated dependencies [ab6c4bf]
55
+ - Updated dependencies [d1feecd]
56
+ - @fragno-dev/db@0.1.7
57
+
58
+ ## 0.1.2
59
+
60
+ ### Patch Changes
61
+
62
+ - 6fd2528: feat(testing): add resetDatabase method to test Fragment instance
63
+ - Updated dependencies [70bdcb2]
64
+ - @fragno-dev/db@0.1.6
65
+
66
+ ## 0.1.1
67
+
68
+ ### Patch Changes
69
+
70
+ - 711226d: feat(testing): add `createDatabaseFragmentForTest` in new test package that automatically
71
+ sets up a Fragment's database and makes it ready for testing
72
+ - Updated dependencies [8b2859c]
73
+ - Updated dependencies [bef9f6c]
74
+ - Updated dependencies [711226d]
75
+ - @fragno-dev/db@0.1.5
76
+ - @fragno-dev/core@0.1.3
package/LICENSE.md ADDED
@@ -0,0 +1,16 @@
1
+ Copyright 2025 - present "ReJot Nederland B.V.", and individual contributors.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
4
+ associated documentation files (the “Software”), to deal in the Software without restriction,
5
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
6
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
7
+ furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or substantial
10
+ portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
13
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
15
+ OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ import { Kysely } from "kysely";
2
+ import { drizzle } from "drizzle-orm/pglite";
3
+ import { AnySchema } from "@fragno-dev/db/schema";
4
+ import { DatabaseAdapter } from "@fragno-dev/db/adapters";
5
+ import { AbstractQuery } from "@fragno-dev/db/query";
6
+
7
+ //#region src/adapters.d.ts
8
+ interface KyselySqliteAdapter {
9
+ type: "kysely-sqlite";
10
+ }
11
+ interface KyselyPgliteAdapter {
12
+ type: "kysely-pglite";
13
+ databasePath?: string;
14
+ }
15
+ interface DrizzlePgliteAdapter {
16
+ type: "drizzle-pglite";
17
+ databasePath?: string;
18
+ }
19
+ type SupportedAdapter = KyselySqliteAdapter | KyselyPgliteAdapter | DrizzlePgliteAdapter;
20
+ type TestContext<T extends SupportedAdapter> = T extends KyselySqliteAdapter | KyselyPgliteAdapter ? {
21
+ readonly db: AbstractQuery<any>;
22
+ readonly kysely: Kysely<any>;
23
+ readonly adapter: DatabaseAdapter<any>;
24
+ resetDatabase: () => Promise<void>;
25
+ cleanup: () => Promise<void>;
26
+ } : T extends DrizzlePgliteAdapter ? {
27
+ readonly db: AbstractQuery<any>;
28
+ readonly drizzle: ReturnType<typeof drizzle<any>>;
29
+ readonly adapter: DatabaseAdapter<any>;
30
+ resetDatabase: () => Promise<void>;
31
+ cleanup: () => Promise<void>;
32
+ } : never;
33
+ //#endregion
34
+ export { DrizzlePgliteAdapter, KyselyPgliteAdapter, KyselySqliteAdapter, SupportedAdapter, TestContext };
35
+ //# sourceMappingURL=adapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.d.ts","names":[],"sources":["../src/adapters.ts"],"sourcesContent":[],"mappings":";;;;;;;UAgBiB,mBAAA;;AAAjB;AAIiB,UAAA,mBAAA,CAAmB;EAKnB,IAAA,EAAA,eAAA;EAKL,YAAA,CAAA,EAAA,MAAgB;;AAAyB,UALpC,oBAAA,CAKoC;EAAsB,IAAA,EAAA,gBAAA;EAAoB,YAAA,CAAA,EAAA,MAAA;AAG/F;AAAkC,KAHtB,gBAAA,GAAmB,mBAGG,GAHmB,mBAGnB,GAHyC,oBAGzC;AAAoB,KAA1C,WAA0C,CAAA,UAApB,gBAAoB,CAAA,GAAA,CAAA,SAClD,mBADkD,GAElD,mBAFkD,GAAA;EAClD,SAAA,EAAA,EAGe,aAHf,CAAA,GAAA,CAAA;EACA,SAAA,MAAA,EAGmB,MAHnB,CAAA,GAAA,CAAA;EAEe,SAAA,OAAA,EAEK,eAFL,CAAA,GAAA,CAAA;EACI,aAAA,EAAA,GAAA,GAEI,OAFJ,CAAA,IAAA,CAAA;EACC,OAAA,EAAA,GAAA,GAEH,OAFG,CAAA,IAAA,CAAA;CACG,GAGvB,CAHuB,SAGb,oBAHa,GAAA;EACN,SAAA,EAAA,EAIA,aAJA,CAAA,GAAA,CAAA;EAEjB,SAAA,OAAA,EAGsB,UAHtB,CAAA,OAGwC,OAHxC,CAAA,GAAA,CAAA,CAAA;EAAU,SAAA,OAAA,EAIY,eAJZ,CAAA,GAAA,CAAA;EAEO,aAAA,EAAA,GAAA,GAGQ,OAHR,CAAA,IAAA,CAAA;EACuB,OAAA,EAAA,GAAA,GAGrB,OAHqB,CAAA,IAAA,CAAA;CAAlB,GAAA,KAAA"}
@@ -0,0 +1,220 @@
1
+ import { createRequire } from "node:module";
2
+ import { Kysely } from "kysely";
3
+ import { SQLocalKysely } from "sqlocal/kysely";
4
+ import { KyselyPGlite } from "kysely-pglite";
5
+ import { drizzle } from "drizzle-orm/pglite";
6
+ import { PGlite } from "@electric-sql/pglite";
7
+ import { KyselyAdapter } from "@fragno-dev/db/adapters/kysely";
8
+ import { DrizzleAdapter } from "@fragno-dev/db/adapters/drizzle";
9
+ import { mkdir, rm, writeFile } from "node:fs/promises";
10
+ import { join } from "node:path";
11
+ import { existsSync } from "node:fs";
12
+
13
+ //#region src/adapters.ts
14
+ /**
15
+ * Create Kysely + SQLite adapter using SQLocalKysely (always in-memory)
16
+ */
17
+ async function createKyselySqliteAdapter(_config, schema, namespace, migrateToVersion) {
18
+ const createDatabase = async () => {
19
+ const { dialect } = new SQLocalKysely(":memory:");
20
+ const kysely$1 = new Kysely({ dialect });
21
+ const adapter$1 = new KyselyAdapter({
22
+ db: kysely$1,
23
+ provider: "sqlite"
24
+ });
25
+ const migrator = adapter$1.createMigrationEngine(schema, namespace);
26
+ await (migrateToVersion ? await migrator.prepareMigrationTo(migrateToVersion, { updateSettings: false }) : await migrator.prepareMigration({ updateSettings: false })).execute();
27
+ return {
28
+ kysely: kysely$1,
29
+ adapter: adapter$1,
30
+ orm: adapter$1.createQueryEngine(schema, namespace)
31
+ };
32
+ };
33
+ let { kysely, adapter, orm } = await createDatabase();
34
+ const resetDatabase = async () => {
35
+ await kysely.destroy();
36
+ const newDb = await createDatabase();
37
+ kysely = newDb.kysely;
38
+ adapter = newDb.adapter;
39
+ orm = newDb.orm;
40
+ };
41
+ const cleanup = async () => {
42
+ await kysely.destroy();
43
+ };
44
+ return {
45
+ testContext: {
46
+ get db() {
47
+ return orm;
48
+ },
49
+ get kysely() {
50
+ return kysely;
51
+ },
52
+ get adapter() {
53
+ return adapter;
54
+ },
55
+ resetDatabase,
56
+ cleanup
57
+ },
58
+ get adapter() {
59
+ return adapter;
60
+ }
61
+ };
62
+ }
63
+ /**
64
+ * Create Kysely + PGLite adapter using kysely-pglite
65
+ */
66
+ async function createKyselyPgliteAdapter(config, schema, namespace, migrateToVersion) {
67
+ const databasePath = config.databasePath;
68
+ const createDatabase = async () => {
69
+ const kyselyPglite$1 = await KyselyPGlite.create(databasePath);
70
+ const kysely$1 = new Kysely({ dialect: kyselyPglite$1.dialect });
71
+ const adapter$1 = new KyselyAdapter({
72
+ db: kysely$1,
73
+ provider: "postgresql"
74
+ });
75
+ const migrator = adapter$1.createMigrationEngine(schema, namespace);
76
+ await (migrateToVersion ? await migrator.prepareMigrationTo(migrateToVersion, { updateSettings: false }) : await migrator.prepareMigration({ updateSettings: false })).execute();
77
+ return {
78
+ kysely: kysely$1,
79
+ adapter: adapter$1,
80
+ kyselyPglite: kyselyPglite$1,
81
+ orm: adapter$1.createQueryEngine(schema, namespace)
82
+ };
83
+ };
84
+ let { kysely, adapter, kyselyPglite, orm } = await createDatabase();
85
+ const resetDatabase = async () => {
86
+ await kysely.destroy();
87
+ try {
88
+ await kyselyPglite.client.close();
89
+ } catch {}
90
+ const newDb = await createDatabase();
91
+ kysely = newDb.kysely;
92
+ adapter = newDb.adapter;
93
+ kyselyPglite = newDb.kyselyPglite;
94
+ orm = newDb.orm;
95
+ };
96
+ const cleanup = async () => {
97
+ await kysely.destroy();
98
+ try {
99
+ await kyselyPglite.client.close();
100
+ } catch {}
101
+ if (databasePath && databasePath !== ":memory:" && existsSync(databasePath)) await rm(databasePath, {
102
+ recursive: true,
103
+ force: true
104
+ });
105
+ };
106
+ return {
107
+ testContext: {
108
+ get db() {
109
+ return orm;
110
+ },
111
+ get kysely() {
112
+ return kysely;
113
+ },
114
+ get adapter() {
115
+ return adapter;
116
+ },
117
+ resetDatabase,
118
+ cleanup
119
+ },
120
+ get adapter() {
121
+ return adapter;
122
+ }
123
+ };
124
+ }
125
+ /**
126
+ * Create Drizzle + PGLite adapter using drizzle-orm/pglite
127
+ */
128
+ async function createDrizzlePgliteAdapter(config, schema, namespace, _migrateToVersion) {
129
+ const databasePath = config.databasePath;
130
+ const { generateDrizzleJson, generateMigration } = createRequire(import.meta.url)("drizzle-kit/api");
131
+ const { generateSchema } = await import("@fragno-dev/db/adapters/drizzle/generate");
132
+ const writeAndLoadSchema = async () => {
133
+ const testDir = join(import.meta.dirname, "_generated", "drizzle-test");
134
+ await mkdir(testDir, { recursive: true }).catch(() => {});
135
+ const schemaFilePath = join(testDir, `test-schema-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.ts`);
136
+ await writeFile(schemaFilePath, generateSchema([{
137
+ namespace: namespace ?? "",
138
+ schema
139
+ }], "postgresql"), "utf-8");
140
+ const schemaModule = await import(`${schemaFilePath}?t=${Date.now()}`);
141
+ const cleanup$1 = async () => {
142
+ await rm(testDir, {
143
+ recursive: true,
144
+ force: true
145
+ });
146
+ };
147
+ return {
148
+ schemaModule,
149
+ cleanup: cleanup$1
150
+ };
151
+ };
152
+ const createDatabase = async () => {
153
+ const { schemaModule, cleanup: cleanup$1 } = await writeAndLoadSchema();
154
+ const pglite$1 = new PGlite(databasePath);
155
+ const db = drizzle(pglite$1, { schema: schemaModule });
156
+ const migrationStatements = await generateMigration(generateDrizzleJson({}), generateDrizzleJson(schemaModule));
157
+ for (const statement of migrationStatements) await db.execute(statement);
158
+ const adapter$1 = new DrizzleAdapter({
159
+ db: () => db,
160
+ provider: "postgresql"
161
+ });
162
+ return {
163
+ drizzle: db,
164
+ adapter: adapter$1,
165
+ pglite: pglite$1,
166
+ cleanup: cleanup$1,
167
+ orm: adapter$1.createQueryEngine(schema, namespace)
168
+ };
169
+ };
170
+ let { drizzle: drizzleDb, adapter, pglite, cleanup: schemaCleanup, orm } = await createDatabase();
171
+ const resetDatabase = async () => {
172
+ await pglite.close();
173
+ await schemaCleanup();
174
+ const newDb = await createDatabase();
175
+ drizzleDb = newDb.drizzle;
176
+ adapter = newDb.adapter;
177
+ pglite = newDb.pglite;
178
+ schemaCleanup = newDb.cleanup;
179
+ orm = newDb.orm;
180
+ };
181
+ const cleanup = async () => {
182
+ await pglite.close();
183
+ await schemaCleanup();
184
+ if (databasePath && databasePath !== ":memory:" && existsSync(databasePath)) await rm(databasePath, {
185
+ recursive: true,
186
+ force: true
187
+ });
188
+ };
189
+ return {
190
+ testContext: {
191
+ get db() {
192
+ return orm;
193
+ },
194
+ get drizzle() {
195
+ return drizzleDb;
196
+ },
197
+ get adapter() {
198
+ return adapter;
199
+ },
200
+ resetDatabase,
201
+ cleanup
202
+ },
203
+ get adapter() {
204
+ return adapter;
205
+ }
206
+ };
207
+ }
208
+ /**
209
+ * Create adapter based on configuration
210
+ */
211
+ async function createAdapter(adapterConfig, schema, namespace, migrateToVersion) {
212
+ if (adapterConfig.type === "kysely-sqlite") return createKyselySqliteAdapter(adapterConfig, schema, namespace, migrateToVersion);
213
+ else if (adapterConfig.type === "kysely-pglite") return createKyselyPgliteAdapter(adapterConfig, schema, namespace, migrateToVersion);
214
+ else if (adapterConfig.type === "drizzle-pglite") return createDrizzlePgliteAdapter(adapterConfig, schema, namespace, migrateToVersion);
215
+ throw new Error(`Unsupported adapter type: ${adapterConfig.type}`);
216
+ }
217
+
218
+ //#endregion
219
+ export { createAdapter };
220
+ //# sourceMappingURL=adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.js","names":["kysely","adapter","kyselyPglite","cleanup","pglite"],"sources":["../src/adapters.ts"],"sourcesContent":["import { Kysely } from \"kysely\";\nimport { SQLocalKysely } from \"sqlocal/kysely\";\nimport { KyselyPGlite } from \"kysely-pglite\";\nimport { drizzle } from \"drizzle-orm/pglite\";\nimport { PGlite } from \"@electric-sql/pglite\";\nimport { KyselyAdapter } from \"@fragno-dev/db/adapters/kysely\";\nimport { DrizzleAdapter } from \"@fragno-dev/db/adapters/drizzle\";\nimport type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type { DatabaseAdapter } from \"@fragno-dev/db/adapters\";\nimport type { AbstractQuery } from \"@fragno-dev/db/query\";\nimport { createRequire } from \"node:module\";\nimport { mkdir, writeFile, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\n\n// Adapter configuration types\nexport interface KyselySqliteAdapter {\n type: \"kysely-sqlite\";\n}\n\nexport interface KyselyPgliteAdapter {\n type: \"kysely-pglite\";\n databasePath?: string;\n}\n\nexport interface DrizzlePgliteAdapter {\n type: \"drizzle-pglite\";\n databasePath?: string;\n}\n\nexport type SupportedAdapter = KyselySqliteAdapter | KyselyPgliteAdapter | DrizzlePgliteAdapter;\n\n// Conditional return types based on adapter\nexport type TestContext<T extends SupportedAdapter> = T extends\n | KyselySqliteAdapter\n | KyselyPgliteAdapter\n ? {\n readonly db: AbstractQuery<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n readonly kysely: Kysely<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n readonly adapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n resetDatabase: () => Promise<void>;\n cleanup: () => Promise<void>;\n }\n : T extends DrizzlePgliteAdapter\n ? {\n readonly db: AbstractQuery<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n readonly drizzle: ReturnType<typeof drizzle<any>>; // eslint-disable-line @typescript-eslint/no-explicit-any\n readonly adapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n resetDatabase: () => Promise<void>;\n cleanup: () => Promise<void>;\n }\n : never;\n\n// Factory function return type\ninterface AdapterFactoryResult<T extends SupportedAdapter> {\n testContext: TestContext<T>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n adapter: DatabaseAdapter<any>;\n}\n\n/**\n * Create Kysely + SQLite adapter using SQLocalKysely (always in-memory)\n */\nexport async function createKyselySqliteAdapter(\n _config: KyselySqliteAdapter,\n schema: AnySchema,\n namespace: string,\n migrateToVersion?: number,\n): Promise<AdapterFactoryResult<KyselySqliteAdapter>> {\n // Helper to create a new database instance and run migrations\n const createDatabase = async () => {\n // Create SQLocalKysely instance (always in-memory for tests)\n const { dialect } = new SQLocalKysely(\":memory:\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const kysely = new Kysely<any>({\n dialect,\n });\n\n // Create KyselyAdapter\n const adapter = new KyselyAdapter({\n db: kysely,\n provider: \"sqlite\",\n });\n\n // Run migrations\n const migrator = adapter.createMigrationEngine(schema, namespace);\n const preparedMigration = migrateToVersion\n ? await migrator.prepareMigrationTo(migrateToVersion, {\n updateSettings: false,\n })\n : await migrator.prepareMigration({\n updateSettings: false,\n });\n await preparedMigration.execute();\n\n // Create ORM instance\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const orm = adapter.createQueryEngine(schema, namespace) as AbstractQuery<any>;\n\n return { kysely, adapter, orm };\n };\n\n // Create initial database\n let { kysely, adapter, orm } = await createDatabase();\n\n // Reset database function - creates a fresh in-memory database and re-runs migrations\n const resetDatabase = async () => {\n // Destroy the old Kysely instance\n await kysely.destroy();\n\n // Create a new database instance\n const newDb = await createDatabase();\n kysely = newDb.kysely;\n adapter = newDb.adapter;\n orm = newDb.orm;\n };\n\n // Cleanup function - closes connections (no files to delete for in-memory)\n const cleanup = async () => {\n await kysely.destroy();\n };\n\n return {\n testContext: {\n get db() {\n return orm;\n },\n get kysely() {\n return kysely;\n },\n get adapter() {\n return adapter;\n },\n resetDatabase,\n cleanup,\n },\n get adapter() {\n return adapter;\n },\n };\n}\n\n/**\n * Create Kysely + PGLite adapter using kysely-pglite\n */\nexport async function createKyselyPgliteAdapter(\n config: KyselyPgliteAdapter,\n schema: AnySchema,\n namespace: string,\n migrateToVersion?: number,\n): Promise<AdapterFactoryResult<KyselyPgliteAdapter>> {\n const databasePath = config.databasePath;\n\n // Helper to create a new database instance and run migrations\n const createDatabase = async () => {\n // Create KyselyPGlite instance\n const kyselyPglite = await KyselyPGlite.create(databasePath);\n\n // Create Kysely instance with PGlite dialect\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const kysely = new Kysely<any>({\n dialect: kyselyPglite.dialect,\n });\n\n // Create KyselyAdapter\n const adapter = new KyselyAdapter({\n db: kysely,\n provider: \"postgresql\",\n });\n\n // Run migrations\n const migrator = adapter.createMigrationEngine(schema, namespace);\n const preparedMigration = migrateToVersion\n ? await migrator.prepareMigrationTo(migrateToVersion, {\n updateSettings: false,\n })\n : await migrator.prepareMigration({\n updateSettings: false,\n });\n await preparedMigration.execute();\n\n // Create ORM instance\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const orm = adapter.createQueryEngine(schema, namespace) as AbstractQuery<any>;\n\n return { kysely, adapter, kyselyPglite, orm };\n };\n\n // Create initial database\n let { kysely, adapter, kyselyPglite, orm } = await createDatabase();\n\n // Reset database function - creates a fresh database and re-runs migrations\n const resetDatabase = async () => {\n // Close the old instances\n await kysely.destroy();\n\n try {\n await kyselyPglite.client.close();\n } catch {\n // Ignore if already closed\n }\n\n // Create a new database instance\n const newDb = await createDatabase();\n kysely = newDb.kysely;\n adapter = newDb.adapter;\n kyselyPglite = newDb.kyselyPglite;\n orm = newDb.orm;\n };\n\n // Cleanup function - closes connections and deletes database directory\n const cleanup = async () => {\n await kysely.destroy();\n\n try {\n await kyselyPglite.client.close();\n } catch {\n // Ignore if already closed\n }\n\n // Delete the database directory if it exists and is a file path\n if (databasePath && databasePath !== \":memory:\" && existsSync(databasePath)) {\n await rm(databasePath, { recursive: true, force: true });\n }\n };\n\n return {\n testContext: {\n get db() {\n return orm;\n },\n get kysely() {\n return kysely;\n },\n get adapter() {\n return adapter;\n },\n resetDatabase,\n cleanup,\n },\n get adapter() {\n return adapter;\n },\n };\n}\n\n/**\n * Create Drizzle + PGLite adapter using drizzle-orm/pglite\n */\nexport async function createDrizzlePgliteAdapter(\n config: DrizzlePgliteAdapter,\n schema: AnySchema,\n namespace: string,\n _migrateToVersion?: number,\n): Promise<AdapterFactoryResult<DrizzlePgliteAdapter>> {\n const databasePath = config.databasePath;\n\n // Import drizzle-kit for migrations\n const require = createRequire(import.meta.url);\n const { generateDrizzleJson, generateMigration } =\n require(\"drizzle-kit/api\") as typeof import(\"drizzle-kit/api\");\n\n // Import generateSchema from the properly exported module\n const { generateSchema } = await import(\"@fragno-dev/db/adapters/drizzle/generate\");\n\n // Helper to write schema to file and dynamically import it\n const writeAndLoadSchema = async () => {\n const testDir = join(import.meta.dirname, \"_generated\", \"drizzle-test\");\n await mkdir(testDir, { recursive: true }).catch(() => {\n // Ignore error if directory already exists\n });\n\n const schemaFilePath = join(\n testDir,\n `test-schema-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.ts`,\n );\n\n // Generate and write the Drizzle schema to file\n const drizzleSchemaTs = generateSchema([{ namespace: namespace ?? \"\", schema }], \"postgresql\");\n await writeFile(schemaFilePath, drizzleSchemaTs, \"utf-8\");\n\n // Dynamically import the generated schema (with cache busting)\n const schemaModule = await import(`${schemaFilePath}?t=${Date.now()}`);\n\n const cleanup = async () => {\n await rm(testDir, { recursive: true, force: true });\n };\n\n return { schemaModule, cleanup };\n };\n\n // Helper to create a new database instance and run migrations\n const createDatabase = async () => {\n // Write schema to file and load it\n const { schemaModule, cleanup } = await writeAndLoadSchema();\n\n // Create PGlite instance\n const pglite = new PGlite(databasePath);\n\n // Create Drizzle instance with PGlite\n const db = drizzle(pglite, {\n schema: schemaModule,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }) as any;\n\n // Generate and run migrations\n const migrationStatements = await generateMigration(\n generateDrizzleJson({}), // Empty schema (starting state)\n generateDrizzleJson(schemaModule), // Target schema\n );\n\n // Execute migration SQL\n for (const statement of migrationStatements) {\n await db.execute(statement);\n }\n\n // Create DrizzleAdapter\n const adapter = new DrizzleAdapter({\n db: () => db,\n provider: \"postgresql\",\n });\n\n // Create ORM instance\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const orm = adapter.createQueryEngine(schema, namespace) as AbstractQuery<any>;\n\n return { drizzle: db, adapter, pglite, cleanup, orm };\n };\n\n // Create initial database\n let { drizzle: drizzleDb, adapter, pglite, cleanup: schemaCleanup, orm } = await createDatabase();\n\n // Reset database function - creates a fresh database and re-runs migrations\n const resetDatabase = async () => {\n // Close the old instances and cleanup\n await pglite.close();\n await schemaCleanup();\n\n // Create a new database instance\n const newDb = await createDatabase();\n drizzleDb = newDb.drizzle;\n adapter = newDb.adapter;\n pglite = newDb.pglite;\n schemaCleanup = newDb.cleanup;\n orm = newDb.orm;\n };\n\n // Cleanup function - closes connections and deletes generated files and database directory\n const cleanup = async () => {\n await pglite.close();\n await schemaCleanup();\n\n // Delete the database directory if it exists and is a file path\n if (databasePath && databasePath !== \":memory:\" && existsSync(databasePath)) {\n await rm(databasePath, { recursive: true, force: true });\n }\n };\n\n return {\n testContext: {\n get db() {\n return orm;\n },\n get drizzle() {\n return drizzleDb;\n },\n get adapter() {\n return adapter;\n },\n resetDatabase,\n cleanup,\n },\n get adapter() {\n return adapter;\n },\n };\n}\n\n/**\n * Create adapter based on configuration\n */\nexport async function createAdapter<T extends SupportedAdapter>(\n adapterConfig: T,\n schema: AnySchema,\n namespace: string,\n migrateToVersion?: number,\n): Promise<AdapterFactoryResult<T>> {\n if (adapterConfig.type === \"kysely-sqlite\") {\n return createKyselySqliteAdapter(adapterConfig, schema, namespace, migrateToVersion) as Promise<\n AdapterFactoryResult<T>\n >;\n } else if (adapterConfig.type === \"kysely-pglite\") {\n return createKyselyPgliteAdapter(adapterConfig, schema, namespace, migrateToVersion) as Promise<\n AdapterFactoryResult<T>\n >;\n } else if (adapterConfig.type === \"drizzle-pglite\") {\n return createDrizzlePgliteAdapter(\n adapterConfig,\n schema,\n namespace,\n migrateToVersion,\n ) as Promise<AdapterFactoryResult<T>>;\n }\n\n throw new Error(`Unsupported adapter type: ${(adapterConfig as SupportedAdapter).type}`);\n}\n"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { DrizzlePgliteAdapter, KyselyPgliteAdapter, KyselySqliteAdapter, SupportedAdapter, TestContext } from "./adapters.js";
2
+ import { CreateFragmentForTestOptions, CreateFragmentForTestOptions as CreateFragmentForTestOptions$1, FragmentForTest, FragmentForTest as FragmentForTest$1, InitRoutesOverrides, RouteHandlerInputOptions, TestResponse, createFragmentForTest } from "@fragno-dev/core/test";
3
+ import { AnySchema } from "@fragno-dev/db/schema";
4
+ import { FragnoPublicConfig } from "@fragno-dev/core/api/fragment-instantiation";
5
+ import { FragmentDefinition } from "@fragno-dev/core/api/fragment-builder";
6
+
7
+ //#region src/index.d.ts
8
+
9
+ /**
10
+ * Options for creating a database fragment for testing
11
+ */
12
+ interface CreateDatabaseFragmentForTestOptions<TConfig, TDeps, TServices, TAdditionalContext extends Record<string, unknown>, TOptions extends FragnoPublicConfig, TAdapter extends SupportedAdapter> extends Omit<CreateFragmentForTestOptions$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>, "config"> {
13
+ adapter: TAdapter;
14
+ migrateToVersion?: number;
15
+ config?: TConfig;
16
+ }
17
+ /**
18
+ * Result of creating a database fragment for testing
19
+ * All properties are getters that return the current fragment instance
20
+ */
21
+ interface DatabaseFragmentTestResult<TConfig, TDeps, TServices, TAdditionalContext extends Record<string, unknown>, TOptions extends FragnoPublicConfig, TAdapter extends SupportedAdapter> {
22
+ readonly fragment: FragmentForTest$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>;
23
+ readonly services: TServices;
24
+ readonly initRoutes: FragmentForTest$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>["initRoutes"];
25
+ readonly handler: FragmentForTest$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>["handler"];
26
+ readonly config: TConfig;
27
+ readonly deps: TDeps;
28
+ readonly additionalContext: TAdditionalContext;
29
+ test: TestContext<TAdapter>;
30
+ }
31
+ declare function createDatabaseFragmentForTest<const TConfig, const TDeps, const TServices extends Record<string, unknown>, const TAdditionalContext extends Record<string, unknown>, const TOptions extends FragnoPublicConfig, const TSchema extends AnySchema, const TAdapter extends SupportedAdapter>(fragmentBuilder: {
32
+ definition: FragmentDefinition<TConfig, TDeps, TServices, TAdditionalContext>;
33
+ $requiredOptions: TOptions;
34
+ }, options: CreateDatabaseFragmentForTestOptions<TConfig, TDeps, TServices, TAdditionalContext, TOptions, TAdapter>): Promise<DatabaseFragmentTestResult<TConfig, TDeps, TServices, TAdditionalContext, TOptions, TAdapter>>;
35
+ //#endregion
36
+ export { CreateDatabaseFragmentForTestOptions, type CreateFragmentForTestOptions, DatabaseFragmentTestResult, type DrizzlePgliteAdapter, type FragmentForTest, type InitRoutesOverrides, type KyselyPgliteAdapter, type KyselySqliteAdapter, type RouteHandlerInputOptions, type SupportedAdapter, type TestContext, type TestResponse, createDatabaseFragmentForTest, createFragmentForTest };
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAuCA;;;AAMmB,UANF,oCAME,CAAA,OAAA,EAAA,KAAA,EAAA,SAAA,EAAA,2BAFU,MAEV,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,iBADA,kBACA,EAAA,iBAAA,gBAAA,CAAA,SACT,IADS,CAEf,8BAFe,CAEc,OAFd,EAEuB,KAFvB,EAE8B,SAF9B,EAEyC,kBAFzC,EAE6D,QAF7D,CAAA,EAAA,QAAA,CAAA,CAAA;EAEc,OAAA,EAGtB,QAHsB;EAAS,gBAAA,CAAA,EAAA,MAAA;EAAO,MAAA,CAAA,EAKtC,OALsC;;;;;;AADvC,UAaO,0BAbP,CAAA,OAAA,EAAA,KAAA,EAAA,SAAA,EAAA,2BAiBmB,MAjBnB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,iBAkBS,kBAlBT,EAAA,iBAmBS,gBAnBT,CAAA,CAAA;EAAI,SAAA,QAAA,EAqBO,iBArBP,CAqBuB,OArBvB,EAqBgC,KArBhC,EAqBuC,SArBvC,EAqBkD,kBArBlD,EAqBsE,QArBtE,CAAA;EAaG,SAAA,QAAA,EASI,SATJ;EAIY,SAAA,UAAA,EAMN,iBANM,CAOzB,OAPyB,EAQzB,KARyB,EASzB,SATyB,EAUzB,kBAVyB,EAWzB,QAXyB,CAAA,CAAA,YAAA,CAAA;EACV,SAAA,OAAA,EAYC,iBAZD,CAaf,OAbe,EAcf,KAde,EAef,SAfe,EAgBf,kBAhBe,EAiBf,QAjBe,CAAA,CAAA,SAAA,CAAA;EACA,SAAA,MAAA,EAkBA,OAlBA;EAEkB,SAAA,IAAA,EAiBpB,KAjBoB;EAAS,SAAA,iBAAA,EAkBhB,kBAlBgB;EAAO,IAAA,EAmB7C,WAnB6C,CAmBjC,QAnBiC,CAAA;;AAA+B,iBAsB9D,6BAtB8D,CAAA,aAAA,EAAA,WAAA,EAAA,wBAyB1D,MAzB0D,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,iCA0BjD,MA1BiD,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,uBA2B3D,kBA3B2D,EAAA,sBA4B5D,SA5B4D,EAAA,uBA6B3D,gBA7B2D,CAAA,CAAA,eAAA,EAAA;EAA/D,UAAA,EAgCL,kBAhCK,CAgCc,OAhCd,EAgCuB,KAhCvB,EAgC8B,SAhC9B,EAgCyC,kBAhCzC,CAAA;EACA,gBAAA,EAgCC,QAhCD;CAEjB,EAAA,OAAA,EAgCO,oCAhCP,CAiCA,OAjCA,EAkCA,KAlCA,EAmCA,SAnCA,EAoCA,kBApCA,EAqCA,QArCA,EAsCA,QAtCA,CAAA,CAAA,EAwCD,OAxCC,CAyCF,0BAzCE,CAyCyB,OAzCzB,EAyCkC,KAzClC,EAyCyC,SAzCzC,EAyCoD,kBAzCpD,EAyCwE,QAzCxE,EAyCkF,QAzClF,CAAA,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,100 @@
1
+ import { createAdapter } from "./adapters.js";
2
+ import { createFragmentForTest, createFragmentForTest as createFragmentForTest$1 } from "@fragno-dev/core/test";
3
+
4
+ //#region src/index.ts
5
+ async function createDatabaseFragmentForTest(fragmentBuilder, options) {
6
+ const { adapter: adapterConfig, migrateToVersion, config, options: fragmentOptions, deps, services, additionalContext } = options;
7
+ const fragmentAdditionalContext = fragmentBuilder.definition.additionalContext;
8
+ const schema = fragmentAdditionalContext?.databaseSchema;
9
+ const namespace = fragmentAdditionalContext?.databaseNamespace ?? "";
10
+ if (!schema) throw new Error(`Fragment '${fragmentBuilder.definition.name}' does not have a database schema. Make sure you're using defineFragmentWithDatabase().withDatabase(schema).`);
11
+ const { testContext: originalTestContext, adapter } = await createAdapter(adapterConfig, schema, namespace, migrateToVersion);
12
+ let mergedOptions = {
13
+ ...fragmentOptions,
14
+ databaseAdapter: adapter
15
+ };
16
+ let fragment = createFragmentForTest$1(fragmentBuilder, {
17
+ config,
18
+ options: mergedOptions,
19
+ deps,
20
+ services,
21
+ additionalContext
22
+ });
23
+ const originalResetDatabase = originalTestContext.resetDatabase;
24
+ return {
25
+ get fragment() {
26
+ return fragment;
27
+ },
28
+ get services() {
29
+ return fragment.services;
30
+ },
31
+ get initRoutes() {
32
+ return fragment.initRoutes;
33
+ },
34
+ get handler() {
35
+ return fragment.handler;
36
+ },
37
+ get config() {
38
+ return fragment.config;
39
+ },
40
+ get deps() {
41
+ return fragment.deps;
42
+ },
43
+ get additionalContext() {
44
+ return fragment.additionalContext;
45
+ },
46
+ test: Object.create(originalTestContext, {
47
+ db: {
48
+ get() {
49
+ return originalTestContext.db;
50
+ },
51
+ enumerable: true
52
+ },
53
+ kysely: {
54
+ get() {
55
+ return originalTestContext.kysely;
56
+ },
57
+ enumerable: true
58
+ },
59
+ drizzle: {
60
+ get() {
61
+ return originalTestContext.drizzle;
62
+ },
63
+ enumerable: true
64
+ },
65
+ adapter: {
66
+ get() {
67
+ return originalTestContext.adapter;
68
+ },
69
+ enumerable: true
70
+ },
71
+ resetDatabase: {
72
+ value: async () => {
73
+ await originalResetDatabase();
74
+ mergedOptions = {
75
+ ...fragmentOptions,
76
+ databaseAdapter: originalTestContext.adapter
77
+ };
78
+ fragment = createFragmentForTest$1(fragmentBuilder, {
79
+ config,
80
+ options: mergedOptions,
81
+ deps,
82
+ services,
83
+ additionalContext
84
+ });
85
+ },
86
+ enumerable: true
87
+ },
88
+ cleanup: {
89
+ value: async () => {
90
+ await originalTestContext.cleanup();
91
+ },
92
+ enumerable: true
93
+ }
94
+ })
95
+ };
96
+ }
97
+
98
+ //#endregion
99
+ export { createDatabaseFragmentForTest, createFragmentForTest };
100
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["createFragmentForTest"],"sources":["../src/index.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\nimport {\n createFragmentForTest,\n type FragmentForTest,\n type CreateFragmentForTestOptions,\n} from \"@fragno-dev/core/test\";\nimport type { FragnoPublicConfig } from \"@fragno-dev/core/api/fragment-instantiation\";\nimport type { FragmentDefinition } from \"@fragno-dev/core/api/fragment-builder\";\nimport {\n createAdapter,\n type SupportedAdapter,\n type TestContext,\n type KyselySqliteAdapter,\n type KyselyPgliteAdapter,\n type DrizzlePgliteAdapter,\n} from \"./adapters\";\n\n// Re-export utilities from @fragno-dev/core/test\nexport {\n createFragmentForTest,\n type TestResponse,\n type CreateFragmentForTestOptions,\n type RouteHandlerInputOptions,\n type FragmentForTest,\n type InitRoutesOverrides,\n} from \"@fragno-dev/core/test\";\n\n// Re-export adapter types\nexport type {\n SupportedAdapter,\n KyselySqliteAdapter,\n KyselyPgliteAdapter,\n DrizzlePgliteAdapter,\n TestContext,\n} from \"./adapters\";\n\n/**\n * Options for creating a database fragment for testing\n */\nexport interface CreateDatabaseFragmentForTestOptions<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext extends Record<string, unknown>,\n TOptions extends FragnoPublicConfig,\n TAdapter extends SupportedAdapter,\n> extends Omit<\n CreateFragmentForTestOptions<TConfig, TDeps, TServices, TAdditionalContext, TOptions>,\n \"config\"\n > {\n adapter: TAdapter;\n migrateToVersion?: number;\n config?: TConfig;\n}\n\n/**\n * Result of creating a database fragment for testing\n * All properties are getters that return the current fragment instance\n */\nexport interface DatabaseFragmentTestResult<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext extends Record<string, unknown>,\n TOptions extends FragnoPublicConfig,\n TAdapter extends SupportedAdapter,\n> {\n readonly fragment: FragmentForTest<TConfig, TDeps, TServices, TAdditionalContext, TOptions>;\n readonly services: TServices;\n readonly initRoutes: FragmentForTest<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext,\n TOptions\n >[\"initRoutes\"];\n readonly handler: FragmentForTest<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext,\n TOptions\n >[\"handler\"];\n readonly config: TConfig;\n readonly deps: TDeps;\n readonly additionalContext: TAdditionalContext;\n test: TestContext<TAdapter>;\n}\n\nexport async function createDatabaseFragmentForTest<\n const TConfig,\n const TDeps,\n const TServices extends Record<string, unknown>,\n const TAdditionalContext extends Record<string, unknown>,\n const TOptions extends FragnoPublicConfig,\n const TSchema extends AnySchema,\n const TAdapter extends SupportedAdapter,\n>(\n fragmentBuilder: {\n definition: FragmentDefinition<TConfig, TDeps, TServices, TAdditionalContext>;\n $requiredOptions: TOptions;\n },\n options: CreateDatabaseFragmentForTestOptions<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext,\n TOptions,\n TAdapter\n >,\n): Promise<\n DatabaseFragmentTestResult<TConfig, TDeps, TServices, TAdditionalContext, TOptions, TAdapter>\n> {\n const {\n adapter: adapterConfig,\n migrateToVersion,\n config,\n options: fragmentOptions,\n deps,\n services,\n additionalContext,\n } = options;\n\n // Get schema and namespace from fragment definition's additionalContext\n // Safe cast: DatabaseFragmentBuilder adds databaseSchema and databaseNamespace to additionalContext\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const fragmentAdditionalContext = fragmentBuilder.definition.additionalContext as any;\n const schema = fragmentAdditionalContext?.databaseSchema as TSchema | undefined;\n const namespace = (fragmentAdditionalContext?.databaseNamespace as string | undefined) ?? \"\";\n\n if (!schema) {\n throw new Error(\n `Fragment '${fragmentBuilder.definition.name}' does not have a database schema. ` +\n `Make sure you're using defineFragmentWithDatabase().withDatabase(schema).`,\n );\n }\n\n // Create adapter using the factory\n const { testContext: originalTestContext, adapter } = await createAdapter(\n adapterConfig,\n schema,\n namespace,\n migrateToVersion,\n );\n\n // Create fragment with database adapter in options\n // Safe cast: We're merging the user's options with the databaseAdapter, which is required by TOptions\n // The user's TOptions is constrained to FragnoPublicConfig (or a subtype), which we extend with databaseAdapter\n let mergedOptions = {\n ...fragmentOptions,\n databaseAdapter: adapter,\n } as unknown as TOptions;\n\n // Safe cast: If config is not provided, we pass undefined as TConfig.\n // The base createFragmentForTest expects config: TConfig, but if TConfig allows undefined\n // or if the fragment doesn't use config in its dependencies function, this will work correctly.\n let fragment = createFragmentForTest(fragmentBuilder, {\n config: config as TConfig,\n options: mergedOptions,\n deps,\n services,\n additionalContext,\n });\n\n // Wrap resetDatabase to also recreate the fragment with the new adapter\n const originalResetDatabase = originalTestContext.resetDatabase;\n\n // Create test context with getters that always return current values\n // We need to cast to any to avoid TypeScript errors when accessing kysely/drizzle properties\n // that may not exist depending on the adapter type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const testContext: any = Object.create(originalTestContext, {\n db: {\n get() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (originalTestContext as any).db;\n },\n enumerable: true,\n },\n kysely: {\n get() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (originalTestContext as any).kysely;\n },\n enumerable: true,\n },\n drizzle: {\n get() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (originalTestContext as any).drizzle;\n },\n enumerable: true,\n },\n adapter: {\n get() {\n return originalTestContext.adapter;\n },\n enumerable: true,\n },\n resetDatabase: {\n value: async () => {\n // Call the original reset database function\n await originalResetDatabase();\n\n // Recreate the fragment with the new adapter (which has been updated by the factory's resetDatabase)\n mergedOptions = {\n ...fragmentOptions,\n databaseAdapter: originalTestContext.adapter,\n } as unknown as TOptions;\n\n fragment = createFragmentForTest(fragmentBuilder, {\n config: config as TConfig,\n options: mergedOptions,\n deps,\n services,\n additionalContext,\n });\n },\n enumerable: true,\n },\n cleanup: {\n value: async () => {\n await originalTestContext.cleanup();\n },\n enumerable: true,\n },\n });\n\n // Return an object with getters for fragment properties so they always reference the current fragment\n return {\n get fragment() {\n return fragment;\n },\n get services() {\n return fragment.services;\n },\n get initRoutes() {\n return fragment.initRoutes;\n },\n get handler() {\n return fragment.handler;\n },\n get config() {\n return fragment.config;\n },\n get deps() {\n return fragment.deps;\n },\n get additionalContext() {\n return fragment.additionalContext;\n },\n test: testContext,\n };\n}\n"],"mappings":";;;;AAyFA,eAAsB,8BASpB,iBAIA,SAUA;CACA,MAAM,EACJ,SAAS,eACT,kBACA,QACA,SAAS,iBACT,MACA,UACA,sBACE;CAKJ,MAAM,4BAA4B,gBAAgB,WAAW;CAC7D,MAAM,SAAS,2BAA2B;CAC1C,MAAM,YAAa,2BAA2B,qBAA4C;AAE1F,KAAI,CAAC,OACH,OAAM,IAAI,MACR,aAAa,gBAAgB,WAAW,KAAK,8GAE9C;CAIH,MAAM,EAAE,aAAa,qBAAqB,YAAY,MAAM,cAC1D,eACA,QACA,WACA,iBACD;CAKD,IAAI,gBAAgB;EAClB,GAAG;EACH,iBAAiB;EAClB;CAKD,IAAI,WAAWA,wBAAsB,iBAAiB;EAC5C;EACR,SAAS;EACT;EACA;EACA;EACD,CAAC;CAGF,MAAM,wBAAwB,oBAAoB;AAgElD,QAAO;EACL,IAAI,WAAW;AACb,UAAO;;EAET,IAAI,WAAW;AACb,UAAO,SAAS;;EAElB,IAAI,aAAa;AACf,UAAO,SAAS;;EAElB,IAAI,UAAU;AACZ,UAAO,SAAS;;EAElB,IAAI,SAAS;AACX,UAAO,SAAS;;EAElB,IAAI,OAAO;AACT,UAAO,SAAS;;EAElB,IAAI,oBAAoB;AACtB,UAAO,SAAS;;EAElB,MAhFuB,OAAO,OAAO,qBAAqB;GAC1D,IAAI;IACF,MAAM;AAEJ,YAAQ,oBAA4B;;IAEtC,YAAY;IACb;GACD,QAAQ;IACN,MAAM;AAEJ,YAAQ,oBAA4B;;IAEtC,YAAY;IACb;GACD,SAAS;IACP,MAAM;AAEJ,YAAQ,oBAA4B;;IAEtC,YAAY;IACb;GACD,SAAS;IACP,MAAM;AACJ,YAAO,oBAAoB;;IAE7B,YAAY;IACb;GACD,eAAe;IACb,OAAO,YAAY;AAEjB,WAAM,uBAAuB;AAG7B,qBAAgB;MACd,GAAG;MACH,iBAAiB,oBAAoB;MACtC;AAED,gBAAWA,wBAAsB,iBAAiB;MACxC;MACR,SAAS;MACT;MACA;MACA;MACD,CAAC;;IAEJ,YAAY;IACb;GACD,SAAS;IACP,OAAO,YAAY;AACjB,WAAM,oBAAoB,SAAS;;IAErC,YAAY;IACb;GACF,CAAC;EA0BD"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@fragno-dev/test",
3
+ "version": "0.0.0-canary-20251030115355",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "development": "./src/index.ts",
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
+ }
11
+ },
12
+ "main": "./dist/index.js",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "dependencies": {
16
+ "kysely": "^0.28.7",
17
+ "sqlocal": "^0.15.2",
18
+ "@fragno-dev/core": "0.1.5",
19
+ "@fragno-dev/db": "0.1.11"
20
+ },
21
+ "peerDependencies": {
22
+ "@electric-sql/pglite": "^0.3.11",
23
+ "drizzle-kit": "^0.30.3",
24
+ "drizzle-orm": "^0.44.7",
25
+ "kysely-pglite": "^0.6.1"
26
+ },
27
+ "peerDependenciesMeta": {
28
+ "@electric-sql/pglite": {
29
+ "optional": true
30
+ },
31
+ "drizzle-kit": {
32
+ "optional": true
33
+ },
34
+ "drizzle-orm": {
35
+ "optional": true
36
+ },
37
+ "kysely-pglite": {
38
+ "optional": true
39
+ }
40
+ },
41
+ "devDependencies": {
42
+ "@electric-sql/pglite": "^0.3.11",
43
+ "@libsql/client": "^0.14.0",
44
+ "@types/node": "^22",
45
+ "@vitest/coverage-istanbul": "^3.2.4",
46
+ "drizzle-kit": "^0.30.3",
47
+ "drizzle-orm": "^0.44.7",
48
+ "kysely-pglite": "^0.6.1",
49
+ "vitest": "^3.2.4",
50
+ "zod": "^4.1.12",
51
+ "@fragno-private/typescript-config": "0.0.1",
52
+ "@fragno-private/vitest-config": "0.0.0"
53
+ },
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/rejot-dev/fragno.git",
57
+ "directory": "packages/fragno-test"
58
+ },
59
+ "homepage": "https://fragno.dev",
60
+ "license": "MIT",
61
+ "scripts": {
62
+ "build": "tsdown",
63
+ "build:watch": "tsdown --watch",
64
+ "types:check": "tsc --noEmit",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest --watch"
67
+ }
68
+ }