@firtoz/drizzle-sqlite-wasm 1.1.2 → 2.0.0
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/CHANGELOG.md +22 -0
- package/README.md +21 -4
- package/dist/chunk-7TDQNWT6.js +181 -0
- package/dist/chunk-7TDQNWT6.js.map +1 -0
- package/dist/{chunk-FRONXNEA.js → chunk-BQBL6E44.js} +2 -2
- package/dist/chunk-BQBL6E44.js.map +1 -0
- package/dist/{chunk-H2F2HZ2A.js → chunk-EQOHJW3Q.js} +3 -3
- package/dist/{chunk-H2F2HZ2A.js.map → chunk-EQOHJW3Q.js.map} +1 -1
- package/dist/{chunk-7JJHY44Q.js → chunk-NNPU7YTX.js} +3 -3
- package/dist/{chunk-7JJHY44Q.js.map → chunk-NNPU7YTX.js.map} +1 -1
- package/dist/{chunk-WFFFP6DB.js → chunk-QOFRLODK.js} +74 -19
- package/dist/chunk-QOFRLODK.js.map +1 -0
- package/dist/{chunk-BZVMUTJ7.js → chunk-VLFDMAFH.js} +2 -2
- package/dist/chunk-VLFDMAFH.js.map +1 -0
- package/dist/collections/sqlite-collection.d.ts +0 -1
- package/dist/collections/sqlite-collection.js +1 -1
- package/dist/collections/synced-sqlite-collection.js +2 -2
- package/dist/context/DrizzleSqliteProvider.d.ts +46 -4
- package/dist/context/DrizzleSqliteProvider.js +4 -4
- package/dist/context/useDrizzleSqlite.d.ts +4 -1
- package/dist/context/useDrizzleSqlite.js +5 -5
- package/dist/drizzle/worker.js +1 -1
- package/dist/hooks/useDrizzleSqliteDb.d.ts +35 -7
- package/dist/hooks/useDrizzleSqliteDb.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/dist/worker/schema.d.ts +4 -4
- package/dist/worker/sqlite.worker.js +1 -1
- package/dist/worker/sqlite.worker.js.map +1 -1
- package/package.json +5 -5
- package/src/collections/sqlite-collection.ts +0 -2
- package/src/drizzle/worker.ts +1 -4
- package/src/hooks/useDrizzleSqliteDb.ts +133 -15
- package/src/index.ts +9 -12
- package/src/worker/sqlite.worker.ts +4 -1
- package/dist/chunk-AEYHRJVN.js +0 -130
- package/dist/chunk-AEYHRJVN.js.map +0 -1
- package/dist/chunk-BZVMUTJ7.js.map +0 -1
- package/dist/chunk-FRONXNEA.js.map +0 -1
- package/dist/chunk-WFFFP6DB.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import type { SqliteRemoteDatabase } from "drizzle-orm/sqlite-proxy";
|
|
2
3
|
import {
|
|
3
4
|
customSqliteMigrate,
|
|
4
5
|
type DurableSqliteMigrationConfig,
|
|
@@ -12,9 +13,86 @@ import {
|
|
|
12
13
|
initializeSqliteWorker,
|
|
13
14
|
isSqliteWorkerInitialized,
|
|
14
15
|
} from "../worker/global-manager";
|
|
15
|
-
import type { SQLInterceptor } from "
|
|
16
|
+
import type { SQLInterceptor } from "@firtoz/drizzle-utils";
|
|
16
17
|
import type { SqliteWasmWorkerOpenOptions } from "../worker/sqlite-open-options";
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* `useEffect` can run in Node (e.g. unit tests) with no `window`. We only install the no-op
|
|
21
|
+
* DB stub there when a test runner is active — not for arbitrary headless Node usage.
|
|
22
|
+
*
|
|
23
|
+
* Playwright E2E is irrelevant here: the app under test runs in a real browser (`window` exists),
|
|
24
|
+
* so the normal client path is used, not this stub.
|
|
25
|
+
*/
|
|
26
|
+
function isNodeTestRuntime(): boolean {
|
|
27
|
+
if (typeof window !== "undefined") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (typeof process === "undefined" || typeof process.env === "undefined") {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const e = process.env;
|
|
34
|
+
if (e.NODE_ENV === "test") {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
// Vitest sets this; avoids relying on NODE_ENV alone
|
|
38
|
+
if (e.VITEST !== undefined) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* `connecting` — no worker client yet, or migrations not finished.
|
|
46
|
+
* `ready` — migrations applied, `readyPromise` resolved.
|
|
47
|
+
* `error` — migration (or init) failed; see `sessionError`.
|
|
48
|
+
*/
|
|
49
|
+
export type DrizzleSqliteSessionStatus = "connecting" | "ready" | "error";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Error payload when the hook reports `sessionStatus: "error"`.
|
|
53
|
+
* Add further `| { kind: … }` members later; discriminate on `kind` in UI or logging.
|
|
54
|
+
*/
|
|
55
|
+
export type DrizzleSqliteSessionError = {
|
|
56
|
+
kind: "migration_failed";
|
|
57
|
+
/** String for display or logs */
|
|
58
|
+
message: string;
|
|
59
|
+
/** The value that was thrown (often an `Error`) */
|
|
60
|
+
original: unknown;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Normalises `catch` bindings so UI can rely on a stable shape. */
|
|
64
|
+
export function toDrizzleSqliteSessionError(
|
|
65
|
+
caught: unknown,
|
|
66
|
+
): DrizzleSqliteSessionError {
|
|
67
|
+
const message =
|
|
68
|
+
caught instanceof Error
|
|
69
|
+
? caught.message
|
|
70
|
+
: typeof caught === "string"
|
|
71
|
+
? caught
|
|
72
|
+
: "Database error";
|
|
73
|
+
return { kind: "migration_failed", message, original: caught };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type InternalSessionState =
|
|
77
|
+
| { status: "connecting" | "ready"; error: null }
|
|
78
|
+
| { status: "error"; error: DrizzleSqliteSessionError };
|
|
79
|
+
|
|
80
|
+
export type UseDrizzleSqliteDbResult<TSchema extends Record<string, unknown>> =
|
|
81
|
+
| {
|
|
82
|
+
drizzle: SqliteRemoteDatabase<TSchema>;
|
|
83
|
+
readyPromise: Promise<void>;
|
|
84
|
+
sqliteClient: ISqliteWorkerClient | null;
|
|
85
|
+
sessionStatus: "connecting" | "ready";
|
|
86
|
+
sessionError: null;
|
|
87
|
+
}
|
|
88
|
+
| {
|
|
89
|
+
drizzle: SqliteRemoteDatabase<TSchema>;
|
|
90
|
+
readyPromise: Promise<void>;
|
|
91
|
+
sqliteClient: ISqliteWorkerClient | null;
|
|
92
|
+
sessionStatus: "error";
|
|
93
|
+
sessionError: DrizzleSqliteSessionError;
|
|
94
|
+
};
|
|
95
|
+
|
|
18
96
|
export const useDrizzleSqliteDb = <TSchema extends Record<string, unknown>>(
|
|
19
97
|
WorkerConstructor: new () => Worker,
|
|
20
98
|
dbName: string,
|
|
@@ -28,34 +106,49 @@ export const useDrizzleSqliteDb = <TSchema extends Record<string, unknown>>(
|
|
|
28
106
|
* Ignored if that database was already started (same global worker + dbName).
|
|
29
107
|
*/
|
|
30
108
|
workerOpenOptions?: SqliteWasmWorkerOpenOptions,
|
|
31
|
-
) => {
|
|
109
|
+
): UseDrizzleSqliteDbResult<TSchema> => {
|
|
32
110
|
const resolveRef = useRef<null | (() => void)>(null);
|
|
33
111
|
const rejectRef = useRef<null | ((error: unknown) => void)>(null);
|
|
112
|
+
// "ready" = migrations done and `readyPromise` resolved (or the rare Node `useEffect` stub).
|
|
113
|
+
// Start as "connecting" on every first paint so we do not show "ready" and then go backward
|
|
114
|
+
// to "connecting" when the first client `useEffect` runs.
|
|
115
|
+
const [internalSession, setInternalSession] = useState<InternalSessionState>(
|
|
116
|
+
() => ({ status: "connecting", error: null }),
|
|
117
|
+
);
|
|
34
118
|
const [sqliteClient, setSqliteClient] = useState<ISqliteWorkerClient | null>(
|
|
35
119
|
null,
|
|
36
120
|
);
|
|
37
121
|
const sqliteClientRef = useRef<ISqliteWorkerClient | null>(null);
|
|
38
122
|
|
|
123
|
+
/** New promise per logical DB open so a resolved session does not mask the next `dbName`. */
|
|
39
124
|
const readyPromise = useMemo(() => {
|
|
40
125
|
return new Promise<void>((resolve, reject) => {
|
|
41
126
|
resolveRef.current = resolve;
|
|
42
127
|
rejectRef.current = reject;
|
|
43
128
|
});
|
|
44
|
-
}, []);
|
|
129
|
+
}, [dbName]);
|
|
45
130
|
|
|
46
131
|
// Initialize the global manager and get db instance
|
|
47
132
|
useEffect(() => {
|
|
48
133
|
if (typeof window === "undefined") {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
134
|
+
if (isNodeTestRuntime()) {
|
|
135
|
+
// e.g. Vitest without jsdom: no worker; unlock `ready` + `readyPromise` for the test tree
|
|
136
|
+
setInternalSession({ status: "ready", error: null });
|
|
137
|
+
setSqliteClient({
|
|
138
|
+
performRemoteCallback: () => {},
|
|
139
|
+
checkpoint: () => Promise.resolve(),
|
|
140
|
+
onStarted: () => {},
|
|
141
|
+
terminate: () => {},
|
|
142
|
+
});
|
|
143
|
+
queueMicrotask(() => {
|
|
144
|
+
resolveRef.current?.();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
56
147
|
return;
|
|
57
148
|
}
|
|
58
149
|
|
|
150
|
+
setInternalSession({ status: "connecting", error: null });
|
|
151
|
+
|
|
59
152
|
let mounted = true;
|
|
60
153
|
|
|
61
154
|
const init = async () => {
|
|
@@ -146,6 +239,9 @@ export const useDrizzleSqliteDb = <TSchema extends Record<string, unknown>>(
|
|
|
146
239
|
}, [schema, dbName, !!interceptor]); // Only recreate if interceptor presence changes, not on every render
|
|
147
240
|
|
|
148
241
|
useEffect(() => {
|
|
242
|
+
if (typeof window === "undefined") {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
149
245
|
if (!sqliteClient) {
|
|
150
246
|
if (debug) {
|
|
151
247
|
console.log(`[DEBUG] ${dbName} - waiting for sqliteClient...`);
|
|
@@ -154,19 +250,41 @@ export const useDrizzleSqliteDb = <TSchema extends Record<string, unknown>>(
|
|
|
154
250
|
}
|
|
155
251
|
|
|
156
252
|
sqliteClient.onStarted(async () => {
|
|
253
|
+
if (typeof window === "undefined") {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
157
256
|
try {
|
|
257
|
+
setInternalSession({ status: "connecting", error: null });
|
|
158
258
|
await customSqliteMigrate(drizzle, migrations);
|
|
159
259
|
resolveRef.current?.();
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
260
|
+
setInternalSession({ status: "ready", error: null });
|
|
261
|
+
} catch (caught) {
|
|
262
|
+
console.error(`Migration error for ${dbName}:`, caught);
|
|
263
|
+
const err = toDrizzleSqliteSessionError(caught);
|
|
264
|
+
setInternalSession({ status: "error", error: err });
|
|
265
|
+
rejectRef.current?.(caught);
|
|
163
266
|
}
|
|
164
267
|
});
|
|
165
268
|
|
|
166
269
|
return () => {
|
|
167
270
|
sqliteClient.terminate();
|
|
168
271
|
};
|
|
169
|
-
}, [sqliteClient, drizzle, migrations, dbName]);
|
|
272
|
+
}, [sqliteClient, drizzle, migrations, dbName, debug]);
|
|
170
273
|
|
|
171
|
-
|
|
274
|
+
if (internalSession.status === "error") {
|
|
275
|
+
return {
|
|
276
|
+
drizzle,
|
|
277
|
+
readyPromise,
|
|
278
|
+
sqliteClient,
|
|
279
|
+
sessionStatus: "error" as const,
|
|
280
|
+
sessionError: internalSession.error,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
drizzle,
|
|
285
|
+
readyPromise,
|
|
286
|
+
sqliteClient,
|
|
287
|
+
sessionStatus: internalSession.status,
|
|
288
|
+
sessionError: null,
|
|
289
|
+
};
|
|
172
290
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
export { drizzleSqliteWasm } from "./drizzle/direct";
|
|
2
2
|
export {
|
|
3
|
-
sqliteCollectionOptions
|
|
3
|
+
sqliteCollectionOptions,
|
|
4
4
|
type SqliteCollectionConfig,
|
|
5
|
-
type SQLOperation,
|
|
6
|
-
type SQLInterceptor,
|
|
7
5
|
} from "./collections/sqlite-collection";
|
|
8
6
|
export { createSyncedSqliteCollection } from "./collections/synced-sqlite-collection";
|
|
9
|
-
export {
|
|
10
|
-
|
|
7
|
+
export {
|
|
8
|
+
toDrizzleSqliteSessionError,
|
|
9
|
+
useDrizzleSqliteDb,
|
|
10
|
+
} from "./hooks/useDrizzleSqliteDb";
|
|
11
11
|
export type {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
InsertSchema,
|
|
17
|
-
} from "@firtoz/drizzle-utils";
|
|
18
|
-
export { useDrizzleSqliteDb } from "./hooks/useDrizzleSqliteDb";
|
|
12
|
+
DrizzleSqliteSessionError,
|
|
13
|
+
DrizzleSqliteSessionStatus,
|
|
14
|
+
UseDrizzleSqliteDbResult,
|
|
15
|
+
} from "./hooks/useDrizzleSqliteDb";
|
|
19
16
|
// SQLite WASM Provider
|
|
20
17
|
export {
|
|
21
18
|
DrizzleSqliteProvider,
|
|
@@ -165,7 +165,10 @@ class SqliteWorkerHelper extends WorkerHelper<
|
|
|
165
165
|
const dbFileName = `${dbName}.sqlite3`;
|
|
166
166
|
let db: Database;
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
// After full init, sqlite-wasm removes `sqlite3.opfs` in non-test builds
|
|
169
|
+
// (`asyncPostInit`), so `"opfs" in sqlite3` is a false negative. Prefer the
|
|
170
|
+
// OpfsDb constructor installed by the OPFS VFS initializer.
|
|
171
|
+
if (typeof sqlite3.oo1.OpfsDb === "function") {
|
|
169
172
|
db = new sqlite3.oo1.OpfsDb(dbFileName);
|
|
170
173
|
this.log("OPFS database created:", db.filename);
|
|
171
174
|
this.applyOpenPragmas(db, openOptions);
|
package/dist/chunk-AEYHRJVN.js
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { useDrizzleSqliteDb } from './chunk-WFFFP6DB.js';
|
|
2
|
-
import { sqliteCollectionOptions } from './chunk-BZVMUTJ7.js';
|
|
3
|
-
import { createContext, useMemo, useCallback, useEffect } from 'react';
|
|
4
|
-
import { createCollection } from '@tanstack/db';
|
|
5
|
-
import { jsx } from 'react/jsx-runtime';
|
|
6
|
-
|
|
7
|
-
var DrizzleSqliteContext = (
|
|
8
|
-
// biome-ignore lint/suspicious/noExplicitAny: Context needs to accept any schema type
|
|
9
|
-
createContext(null)
|
|
10
|
-
);
|
|
11
|
-
function DrizzleSqliteProvider({
|
|
12
|
-
children,
|
|
13
|
-
worker,
|
|
14
|
-
dbName,
|
|
15
|
-
schema,
|
|
16
|
-
migrations,
|
|
17
|
-
debug,
|
|
18
|
-
enableCheckpoint = false,
|
|
19
|
-
syncMode = "eager",
|
|
20
|
-
interceptor,
|
|
21
|
-
workerOpenOptions
|
|
22
|
-
}) {
|
|
23
|
-
const { drizzle, readyPromise, sqliteClient } = useDrizzleSqliteDb(
|
|
24
|
-
worker,
|
|
25
|
-
dbName,
|
|
26
|
-
schema,
|
|
27
|
-
migrations,
|
|
28
|
-
debug,
|
|
29
|
-
interceptor,
|
|
30
|
-
// Pass interceptor to log ALL Drizzle queries
|
|
31
|
-
workerOpenOptions
|
|
32
|
-
);
|
|
33
|
-
const collections = useMemo(
|
|
34
|
-
() => /* @__PURE__ */ new Map(),
|
|
35
|
-
[]
|
|
36
|
-
);
|
|
37
|
-
const getCollection = useCallback(
|
|
38
|
-
(tableName) => {
|
|
39
|
-
const cacheKey = tableName;
|
|
40
|
-
if (!collections.has(cacheKey)) {
|
|
41
|
-
const options = sqliteCollectionOptions({
|
|
42
|
-
drizzle,
|
|
43
|
-
tableName,
|
|
44
|
-
readyPromise,
|
|
45
|
-
syncMode,
|
|
46
|
-
checkpoint: enableCheckpoint && sqliteClient ? () => sqliteClient.checkpoint() : void 0,
|
|
47
|
-
interceptor,
|
|
48
|
-
debug
|
|
49
|
-
});
|
|
50
|
-
const collection = createCollection(options);
|
|
51
|
-
collections.set(cacheKey, {
|
|
52
|
-
collection,
|
|
53
|
-
refCount: 0
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
return collections.get(cacheKey).collection;
|
|
57
|
-
},
|
|
58
|
-
[
|
|
59
|
-
drizzle,
|
|
60
|
-
collections,
|
|
61
|
-
schema,
|
|
62
|
-
readyPromise,
|
|
63
|
-
sqliteClient,
|
|
64
|
-
enableCheckpoint,
|
|
65
|
-
syncMode,
|
|
66
|
-
interceptor,
|
|
67
|
-
debug
|
|
68
|
-
]
|
|
69
|
-
);
|
|
70
|
-
const incrementRefCount = useCallback(
|
|
71
|
-
(tableName) => {
|
|
72
|
-
const entry = collections.get(tableName);
|
|
73
|
-
if (entry) {
|
|
74
|
-
entry.refCount++;
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
[collections]
|
|
78
|
-
);
|
|
79
|
-
const decrementRefCount = useCallback(
|
|
80
|
-
(tableName) => {
|
|
81
|
-
const entry = collections.get(tableName);
|
|
82
|
-
if (entry) {
|
|
83
|
-
entry.refCount--;
|
|
84
|
-
if (entry.refCount <= 0) {
|
|
85
|
-
collections.delete(tableName);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
[collections]
|
|
90
|
-
);
|
|
91
|
-
const contextValue = useMemo(
|
|
92
|
-
() => ({
|
|
93
|
-
drizzle,
|
|
94
|
-
readyPromise,
|
|
95
|
-
getCollection,
|
|
96
|
-
incrementRefCount,
|
|
97
|
-
decrementRefCount
|
|
98
|
-
}),
|
|
99
|
-
[
|
|
100
|
-
drizzle,
|
|
101
|
-
readyPromise,
|
|
102
|
-
getCollection,
|
|
103
|
-
incrementRefCount,
|
|
104
|
-
decrementRefCount
|
|
105
|
-
]
|
|
106
|
-
);
|
|
107
|
-
return /* @__PURE__ */ jsx(DrizzleSqliteContext.Provider, { value: contextValue, children });
|
|
108
|
-
}
|
|
109
|
-
function useSqliteCollection(context, tableName) {
|
|
110
|
-
const { collection, unsubscribe } = useMemo(() => {
|
|
111
|
-
const col = context.getCollection(tableName);
|
|
112
|
-
context.incrementRefCount(tableName);
|
|
113
|
-
return {
|
|
114
|
-
collection: col,
|
|
115
|
-
unsubscribe: () => {
|
|
116
|
-
context.decrementRefCount(tableName);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
}, [context, tableName]);
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
return () => {
|
|
122
|
-
unsubscribe();
|
|
123
|
-
};
|
|
124
|
-
}, [unsubscribe]);
|
|
125
|
-
return collection;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export { DrizzleSqliteContext, DrizzleSqliteProvider, useSqliteCollection };
|
|
129
|
-
//# sourceMappingURL=chunk-AEYHRJVN.js.map
|
|
130
|
-
//# sourceMappingURL=chunk-AEYHRJVN.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context/DrizzleSqliteProvider.tsx"],"names":[],"mappings":"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","file":"chunk-AEYHRJVN.js","sourcesContent":["import type { PropsWithChildren } from \"react\";\nimport { createContext, useMemo, useCallback, useEffect } from \"react\";\nimport type { SqliteRemoteDatabase } from \"drizzle-orm/sqlite-proxy\";\nimport {\n\tcreateCollection,\n\ttype Collection,\n\ttype InferSchemaOutput,\n\ttype UtilsRecord,\n} from \"@tanstack/db\";\nimport {\n\ttype AnyDrizzleDatabase,\n\ttype ValidTableNames,\n\ttype DrizzleSchema,\n\tsqliteCollectionOptions,\n\ttype SQLInterceptor,\n} from \"../collections/sqlite-collection\";\nimport { useDrizzleSqliteDb } from \"../hooks/useDrizzleSqliteDb\";\nimport type { DurableSqliteMigrationConfig } from \"../migration/migrator\";\nimport type { SqliteWasmWorkerOpenOptions } from \"../worker/sqlite-open-options\";\nimport type {\n\tIdOf,\n\tGetTableFromSchema,\n\tInferCollectionFromTable,\n} from \"@firtoz/drizzle-utils\";\n\ninterface CollectionCacheEntry {\n\t// biome-ignore lint/suspicious/noExplicitAny: Cache needs to store collections of various types\n\tcollection: Collection<any, string>;\n\trefCount: number;\n}\n\ntype SqliteCollection<\n\tTSchema extends Record<string, unknown>,\n\tTTableName extends string & ValidTableNames<TSchema>,\n> = Collection<\n\tInferSchemaOutput<GetTableFromSchema<TSchema, TTableName>[\"$inferSelect\"]>,\n\tIdOf<GetTableFromSchema<TSchema, TTableName>>,\n\t// biome-ignore lint/suspicious/noExplicitAny: We need to use any here to match the Collection type\n\tany,\n\t// biome-ignore lint/suspicious/noExplicitAny: We need to use any here to match the Collection type\n\tany,\n\tOmit<GetTableFromSchema<TSchema, TTableName>[\"$inferInsert\"], \"id\"> & {\n\t\tid?: IdOf<GetTableFromSchema<TSchema, TTableName>>;\n\t}\n>;\n\nexport type DrizzleSqliteContextValue<TSchema extends Record<string, unknown>> =\n\t{\n\t\tdrizzle: SqliteRemoteDatabase<TSchema>;\n\t\treadyPromise: Promise<void>;\n\t\tgetCollection: <TTableName extends string & ValidTableNames<TSchema>>(\n\t\t\ttableName: TTableName,\n\t\t) => SqliteCollection<TSchema, TTableName>;\n\t\tincrementRefCount: (tableName: string) => void;\n\t\tdecrementRefCount: (tableName: string) => void;\n\t};\n\nexport const DrizzleSqliteContext =\n\t// biome-ignore lint/suspicious/noExplicitAny: Context needs to accept any schema type\n\tcreateContext<DrizzleSqliteContextValue<any> | null>(null);\n\ntype DrizzleSqliteProviderProps<TSchema extends Record<string, unknown>> =\n\tPropsWithChildren<{\n\t\tworker: new () => Worker;\n\t\tdbName: string;\n\t\tschema: TSchema;\n\t\tmigrations: DurableSqliteMigrationConfig;\n\t\tdebug?: boolean;\n\t\tenableCheckpoint?: boolean;\n\t\t/**\n\t\t * Sync mode: 'eager' (immediate) or 'on-demand' (lazy)\n\t\t */\n\t\tsyncMode?: \"eager\" | \"on-demand\";\n\t\t/**\n\t\t * Optional interceptor for tracking SQLite operations (for testing/debugging)\n\t\t */\n\t\tinterceptor?: SQLInterceptor;\n\t\t/**\n\t\t * Worker DB pragmas on first open of `dbName` this session (see `useDrizzleSqliteDb`).\n\t\t */\n\t\tworkerOpenOptions?: SqliteWasmWorkerOpenOptions;\n\t}>;\n\nexport function DrizzleSqliteProvider<TSchema extends Record<string, unknown>>({\n\tchildren,\n\tworker,\n\tdbName,\n\tschema,\n\tmigrations,\n\tdebug,\n\tenableCheckpoint = false,\n\tsyncMode = \"eager\",\n\tinterceptor,\n\tworkerOpenOptions,\n}: DrizzleSqliteProviderProps<TSchema>) {\n\tconst { drizzle, readyPromise, sqliteClient } = useDrizzleSqliteDb(\n\t\tworker,\n\t\tdbName,\n\t\tschema,\n\t\tmigrations,\n\t\tdebug,\n\t\tinterceptor, // Pass interceptor to log ALL Drizzle queries\n\t\tworkerOpenOptions,\n\t);\n\n\t// Collection cache with ref counting\n\tconst collections = useMemo<Map<string, CollectionCacheEntry>>(\n\t\t() => new Map(),\n\t\t[],\n\t);\n\n\tconst getCollection = useCallback(\n\t\t<TTableName extends string & ValidTableNames<TSchema>>(\n\t\t\ttableName: TTableName,\n\t\t): SqliteCollection<TSchema, TTableName> => {\n\t\t\tconst cacheKey = tableName;\n\n\t\t\t// Check if collection already exists in cache\n\t\t\tif (!collections.has(cacheKey)) {\n\t\t\t\t// Create new collection and cache it with ref count 0\n\t\t\t\tconst options = sqliteCollectionOptions({\n\t\t\t\t\tdrizzle,\n\t\t\t\t\ttableName: tableName as string &\n\t\t\t\t\t\tValidTableNames<DrizzleSchema<AnyDrizzleDatabase>>,\n\t\t\t\t\treadyPromise,\n\t\t\t\t\tsyncMode,\n\t\t\t\t\tcheckpoint:\n\t\t\t\t\t\tenableCheckpoint && sqliteClient\n\t\t\t\t\t\t\t? () => sqliteClient.checkpoint()\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\tinterceptor,\n\t\t\t\t\tdebug,\n\t\t\t\t});\n\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: Table type degenerates through AnyDrizzleDatabase; collection is re-typed on cache retrieval\n\t\t\t\tconst collection = createCollection(options as any) as Collection<\n\t\t\t\t\tRecord<string, unknown>,\n\t\t\t\t\tstring,\n\t\t\t\t\tUtilsRecord\n\t\t\t\t>;\n\t\t\t\tcollections.set(cacheKey, {\n\t\t\t\t\tcollection,\n\t\t\t\t\trefCount: 0,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// biome-ignore lint/style/noNonNullAssertion: We just ensured the collection exists\n\t\t\treturn collections.get(cacheKey)!\n\t\t\t\t.collection as unknown as SqliteCollection<TSchema, TTableName>;\n\t\t},\n\t\t[\n\t\t\tdrizzle,\n\t\t\tcollections,\n\t\t\tschema,\n\t\t\treadyPromise,\n\t\t\tsqliteClient,\n\t\t\tenableCheckpoint,\n\t\t\tsyncMode,\n\t\t\tinterceptor,\n\t\t\tdebug,\n\t\t],\n\t);\n\n\tconst incrementRefCount: DrizzleSqliteContextValue<TSchema>[\"incrementRefCount\"] =\n\t\tuseCallback(\n\t\t\t(tableName: string) => {\n\t\t\t\tconst entry = collections.get(tableName);\n\t\t\t\tif (entry) {\n\t\t\t\t\tentry.refCount++;\n\t\t\t\t}\n\t\t\t},\n\t\t\t[collections],\n\t\t);\n\n\tconst decrementRefCount: DrizzleSqliteContextValue<TSchema>[\"decrementRefCount\"] =\n\t\tuseCallback(\n\t\t\t(tableName: string) => {\n\t\t\t\tconst entry = collections.get(tableName);\n\t\t\t\tif (entry) {\n\t\t\t\t\tentry.refCount--;\n\n\t\t\t\t\t// If ref count reaches 0, remove from cache\n\t\t\t\t\tif (entry.refCount <= 0) {\n\t\t\t\t\t\tcollections.delete(tableName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t[collections],\n\t\t);\n\n\tconst contextValue: DrizzleSqliteContextValue<TSchema> = useMemo(\n\t\t() => ({\n\t\t\tdrizzle,\n\t\t\treadyPromise,\n\t\t\tgetCollection,\n\t\t\tincrementRefCount,\n\t\t\tdecrementRefCount,\n\t\t}),\n\t\t[\n\t\t\tdrizzle,\n\t\t\treadyPromise,\n\t\t\tgetCollection,\n\t\t\tincrementRefCount,\n\t\t\tdecrementRefCount,\n\t\t],\n\t);\n\n\treturn (\n\t\t<DrizzleSqliteContext.Provider value={contextValue}>\n\t\t\t{children}\n\t\t</DrizzleSqliteContext.Provider>\n\t);\n}\n\n// Hook that components use to get a collection with automatic ref counting\nexport function useSqliteCollection<\n\tTSchema extends Record<string, unknown>,\n\tTTableName extends string & ValidTableNames<TSchema>,\n>(\n\tcontext: DrizzleSqliteContextValue<TSchema>,\n\ttableName: TTableName,\n): InferCollectionFromTable<GetTableFromSchema<TSchema, TTableName>> {\n\tconst { collection, unsubscribe } = useMemo(() => {\n\t\t// Get the collection and increment ref count\n\t\tconst col = context.getCollection(tableName);\n\t\tcontext.incrementRefCount(tableName);\n\n\t\t// Return collection and unsubscribe function\n\t\treturn {\n\t\t\tcollection: col,\n\t\t\tunsubscribe: () => {\n\t\t\t\tcontext.decrementRefCount(tableName);\n\t\t\t},\n\t\t};\n\t}, [context, tableName]);\n\n\t// Cleanup on unmount\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tunsubscribe();\n\t\t};\n\t}, [unsubscribe]);\n\n\treturn collection as unknown as InferCollectionFromTable<\n\t\tGetTableFromSchema<TSchema, TTableName>\n\t>;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/collections/sqlite-collection.ts"],"names":[],"mappings":";;;AA+EO,SAAS,wBAKf,MAAA,EACiC;AACjC,EAAA,MAAM,YAAY,MAAA,CAAO,SAAA;AAGzB,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,EAAS,CAAA,CAAE,WAAW,SAAS,CAAA;AAEpD,EAAA,MAAM,MAAA,GAAS,CACd,IAAA,KACmB,IAAA,CAA8B,EAAA;AAElD,EAAA,MAAM,UAAU,4BAAA,CAA6B;AAAA,IAC5C,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,KAAA;AAAA,IACA,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,aAAa,MAAA,CAAO,WAAA;AAAA,IACpB,UAAA,EAAY;AAAA,GACZ,CAAA;AAED,EAAA,MAAM,cAAA,GAAyC;AAAA,IAC9C,KAAA;AAAA,IACA,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,mBAAmB,CAAC,IAAA,KAAS,MAAA,CAAO,MAAA,CAAO,IAAI,CAAC;AAAA,GACjD;AAEA,EAAA,MAAM,UAAA,GAAa,kBAAA,CAAmB,cAAA,EAAgB,OAAO,CAAA;AAE7D,EAAA,MAAM,MAAA,GAAS,gCAAgC,KAAK,CAAA;AAEpD,EAAA,MAAM,mBAAmB,sBAAA,CAAuB;AAAA,IAC/C,MAAA;AAAA,IACA,MAAA;AAAA,IACA,UAAA;AAAA,IACA,QAAA,EAAU,MAAA,CAAO,KAAA,GACd,OAAO,MAAA,KAAW;AAClB,MAAA,OAAA,CAAQ,GAAA,CAAI,YAAY,MAAM,CAAA;AAE9B,MAAA,MAAM,UAAA,CAAW,SAAU,MAAM,CAAA;AAAA,IAClC,CAAA,GACC,MAAA;AAAA,IACH,QAAA,EAAU,MAAA,CAAO,KAAA,GACd,OAAO,MAAA,KAAW;AAClB,MAAA,OAAA,CAAQ,GAAA,CAAI,YAAY,MAAM,CAAA;AAE9B,MAAA,MAAM,UAAA,CAAW,SAAU,MAAM,CAAA;AAAA,IAClC,CAAA,GACC,MAAA;AAAA,IACH,QAAA,EAAU,MAAA,CAAO,KAAA,GACd,OAAO,MAAA,KAAW;AAClB,MAAA,OAAA,CAAQ,GAAA,CAAI,YAAY,MAAM,CAAA;AAE9B,MAAA,MAAM,UAAA,CAAW,SAAU,MAAM,CAAA;AAAA,IAClC,CAAA,GACC,MAAA;AAAA,IACH,UAAU,MAAA,CAAO;AAAA,GACjB,CAAA;AAED,EAAA,OAAO,gBAAA;AACR","file":"chunk-BZVMUTJ7.js","sourcesContent":["import type {\n\tInferSchemaOutput,\n\tSyncMode,\n\tCollectionConfig,\n} from \"@tanstack/db\";\nimport type { Table } from \"drizzle-orm\";\nimport type { BaseSQLiteDatabase } from \"drizzle-orm/sqlite-core\";\nimport type { CollectionUtils } from \"@firtoz/db-helpers\";\nimport type {\n\tSelectSchema,\n\tInsertToSelectSchema,\n\tTableWithRequiredFields,\n\tBaseSyncConfig,\n\tIdOf,\n} from \"@firtoz/drizzle-utils\";\nimport {\n\tcreateSyncFunction,\n\tcreateInsertSchemaWithIdDefault,\n\tcreateCollectionConfig,\n\tcreateSqliteTableSyncBackend,\n\ttype SQLOperation,\n\ttype SQLInterceptor,\n} from \"@firtoz/drizzle-utils\";\nexport type { SQLOperation, SQLInterceptor };\n\nexport type AnyDrizzleDatabase = BaseSQLiteDatabase<\n\t\"async\",\n\t// biome-ignore lint/suspicious/noExplicitAny: We really want to use any here.\n\tany,\n\tRecord<string, unknown>\n>;\n\nexport type DrizzleSchema<TDrizzle extends AnyDrizzleDatabase> =\n\tTDrizzle[\"_\"][\"fullSchema\"];\n\nexport interface DrizzleSqliteCollectionConfig<\n\tTDrizzle extends AnyDrizzleDatabase,\n\tTTableName extends ValidTableNames<DrizzleSchema<TDrizzle>>,\n> {\n\tdrizzle: TDrizzle;\n\ttableName: ValidTableNames<DrizzleSchema<TDrizzle>> extends never\n\t\t? {\n\t\t\t\t$error: \"The schema needs to include at least one table that uses the syncableTable function.\";\n\t\t\t}\n\t\t: TTableName;\n\treadyPromise: Promise<void>;\n\tsyncMode?: SyncMode;\n\t/**\n\t * Enable debug logging for query execution and mutations\n\t */\n\tdebug?: boolean;\n\t/**\n\t * Optional callback to checkpoint the database after mutations\n\t * This ensures WAL is flushed to the main database file for OPFS persistence\n\t */\n\tcheckpoint?: () => Promise<void>;\n\t/**\n\t * Optional interceptor for tracking SQLite operations (for testing/debugging)\n\t */\n\tinterceptor?: SQLInterceptor;\n}\n\nexport type ValidTableNames<TSchema extends Record<string, unknown>> = {\n\t[K in keyof TSchema]: TSchema[K] extends TableWithRequiredFields ? K : never;\n}[keyof TSchema];\n\nexport type SqliteCollectionConfig<TTable extends Table> = Omit<\n\tCollectionConfig<\n\t\tInferSchemaOutput<SelectSchema<TTable>>,\n\t\tIdOf<TTable>,\n\t\tInsertToSelectSchema<TTable>,\n\t\tCollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>\n\t>,\n\t\"utils\"\n> & {\n\tschema: InsertToSelectSchema<TTable>;\n\tutils: CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>;\n};\n\nexport function sqliteCollectionOptions<\n\tconst TDrizzle extends AnyDrizzleDatabase,\n\tconst TTableName extends string & ValidTableNames<DrizzleSchema<TDrizzle>>,\n\tTTable extends DrizzleSchema<TDrizzle>[TTableName] & TableWithRequiredFields,\n>(\n\tconfig: DrizzleSqliteCollectionConfig<TDrizzle, TTableName>,\n): SqliteCollectionConfig<TTable> {\n\tconst tableName = config.tableName as string &\n\t\tValidTableNames<DrizzleSchema<TDrizzle>>;\n\n\tconst table = config.drizzle?._.fullSchema[tableName] as TTable;\n\n\tconst getKey = (\n\t\titem: InferSchemaOutput<SelectSchema<TTable>>,\n\t): IdOf<TTable> => (item as { id: IdOf<TTable> }).id;\n\n\tconst backend = createSqliteTableSyncBackend({\n\t\tdrizzle: config.drizzle,\n\t\ttable,\n\t\ttableName: config.tableName as string,\n\t\tdebug: config.debug,\n\t\tcheckpoint: config.checkpoint,\n\t\tinterceptor: config.interceptor,\n\t\tdriverMode: \"async\",\n\t});\n\n\tconst baseSyncConfig: BaseSyncConfig<TTable> = {\n\t\ttable,\n\t\treadyPromise: config.readyPromise,\n\t\tsyncMode: config.syncMode,\n\t\tdebug: config.debug,\n\t\tgetSyncPersistKey: (item) => String(getKey(item)),\n\t};\n\n\tconst syncResult = createSyncFunction(baseSyncConfig, backend);\n\n\tconst schema = createInsertSchemaWithIdDefault(table);\n\n\tconst collectionConfig = createCollectionConfig({\n\t\tschema,\n\t\tgetKey,\n\t\tsyncResult,\n\t\tonInsert: config.debug\n\t\t\t? async (params) => {\n\t\t\t\t\tconsole.log(\"onInsert\", params);\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: onInsert is always defined in createSyncFunction\n\t\t\t\t\tawait syncResult.onInsert!(params);\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tonUpdate: config.debug\n\t\t\t? async (params) => {\n\t\t\t\t\tconsole.log(\"onUpdate\", params);\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: onUpdate is always defined in createSyncFunction\n\t\t\t\t\tawait syncResult.onUpdate!(params);\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tonDelete: config.debug\n\t\t\t? async (params) => {\n\t\t\t\t\tconsole.log(\"onDelete\", params);\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: onDelete is always defined in createSyncFunction\n\t\t\t\t\tawait syncResult.onDelete!(params);\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tsyncMode: config.syncMode,\n\t});\n\n\treturn collectionConfig;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/drizzle/worker.ts"],"names":["drizzleSqliteProxy"],"mappings":"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","file":"chunk-FRONXNEA.js","sourcesContent":["import type { DrizzleConfig } from \"drizzle-orm\";\nimport { drizzle as drizzleSqliteProxy } from \"drizzle-orm/sqlite-proxy\";\nimport type { ISqliteWorkerClient } from \"../worker/client\";\nimport type {\n\tSQLInterceptor,\n\tSQLOperation,\n} from \"../collections/sqlite-collection\";\n\nexport const drizzleSqliteWasmWorker = <\n\tTSchema extends Record<string, unknown> = Record<string, never>,\n>(\n\tclient: ISqliteWorkerClient,\n\tconfig: DrizzleConfig<TSchema> = {},\n) => {\n\treturn drizzleSqliteProxy<TSchema>(async (sql, params, method) => {\n\t\treturn new Promise<{ rows: unknown[] }>((resolve, reject) => {\n\t\t\tclient.performRemoteCallback(\n\t\t\t\t{\n\t\t\t\t\tsql,\n\t\t\t\t\tparams,\n\t\t\t\t\tmethod,\n\t\t\t\t},\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t);\n\t\t});\n\t}, config);\n};\n\n/**\n * Creates an instrumented Drizzle instance that logs all SQL queries.\n * This wraps the standard drizzleSqliteWasmWorker to intercept every query.\n */\nexport const createInstrumentedDrizzle = <\n\tTSchema extends Record<string, unknown> = Record<string, never>,\n>(\n\tclient: ISqliteWorkerClient,\n\tconfig: DrizzleConfig<TSchema> = {},\n\tinterceptor?: SQLInterceptor,\n) => {\n\treturn drizzleSqliteProxy<TSchema>(async (sql, params, method) => {\n\t\tconst startTime = Date.now();\n\n\t\tconst result = await new Promise<{ rows: unknown[] }>((resolve, reject) => {\n\t\t\tclient.performRemoteCallback(\n\t\t\t\t{\n\t\t\t\t\tsql,\n\t\t\t\t\tparams,\n\t\t\t\t\tmethod,\n\t\t\t\t},\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t);\n\t\t});\n\n\t\t// Log the operation if interceptor is provided\n\t\tif (interceptor?.onOperation) {\n\t\t\t// Parse SQL to determine context\n\t\t\tconst sqlLower = sql.toLowerCase().trim();\n\t\t\tlet context = \"Direct Drizzle query\";\n\n\t\t\tif (sqlLower.startsWith(\"select\")) {\n\t\t\t\t// Extract table name from SELECT query\n\t\t\t\tconst fromMatch = sql.match(/from\\s+[\"']?(\\w+)[\"']?/i);\n\t\t\t\tconst tableName = fromMatch?.[1] || \"unknown\";\n\n\t\t\t\t// Check for LIMIT/OFFSET - handle both literal values and ? placeholders\n\t\t\t\t// Drizzle uses parameterized queries, so we need to check for `limit ?` style\n\t\t\t\tconst hasLimit = /limit\\s+(\\d+|\\?|\\$\\d+)/i.test(sql);\n\t\t\t\tconst hasOffset = /offset\\s+(\\d+|\\?|\\$\\d+)/i.test(sql);\n\t\t\t\tconst hasOrderBy = /order\\s+by/i.test(sql);\n\n\t\t\t\tif (hasLimit || hasOffset) {\n\t\t\t\t\t// Extract actual values from params if using placeholders\n\t\t\t\t\t// Drizzle typically puts LIMIT as second-to-last param, OFFSET as last\n\t\t\t\t\tlet limitVal = \"?\";\n\t\t\t\t\tlet offsetVal = \"0\";\n\n\t\t\t\t\t// Try to extract literal values first\n\t\t\t\t\tconst literalLimit = sql.match(/limit\\s+(\\d+)/i);\n\t\t\t\t\tconst literalOffset = sql.match(/offset\\s+(\\d+)/i);\n\n\t\t\t\t\tif (literalLimit) {\n\t\t\t\t\t\tlimitVal = literalLimit[1];\n\t\t\t\t\t} else if (params && params.length > 0) {\n\t\t\t\t\t\t// For parameterized queries, try to infer from params\n\t\t\t\t\t\t// LIMIT/OFFSET are usually at the end\n\t\t\t\t\t\tif (hasLimit && hasOffset && params.length >= 2) {\n\t\t\t\t\t\t\tlimitVal = String(params[params.length - 2]);\n\t\t\t\t\t\t\toffsetVal = String(params[params.length - 1]);\n\t\t\t\t\t\t} else if (hasLimit && params.length >= 1) {\n\t\t\t\t\t\t\tlimitVal = String(params[params.length - 1]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (literalOffset) {\n\t\t\t\t\t\toffsetVal = literalOffset[1];\n\t\t\t\t\t}\n\n\t\t\t\t\tcontext = `SELECT with LIMIT ${limitVal} OFFSET ${offsetVal}`;\n\t\t\t\t} else if (hasOrderBy) {\n\t\t\t\t\tcontext = `SELECT all from ${tableName} (ordered)`;\n\t\t\t\t} else {\n\t\t\t\t\tcontext = `SELECT all from ${tableName}`;\n\t\t\t\t}\n\n\t\t\t\tconst operation: SQLOperation = {\n\t\t\t\t\ttype: \"raw-query\",\n\t\t\t\t\tsql,\n\t\t\t\t\tparams: params as unknown[],\n\t\t\t\t\tmethod,\n\t\t\t\t\trowCount: result.rows?.length ?? 0,\n\t\t\t\t\tcontext,\n\t\t\t\t\ttimestamp: startTime,\n\t\t\t\t};\n\t\t\t\tinterceptor.onOperation(operation);\n\t\t\t} else if (sqlLower.startsWith(\"insert\")) {\n\t\t\t\tconst intoMatch = sql.match(/into\\s+[\"']?(\\w+)[\"']?/i);\n\t\t\t\tcontext = `INSERT into ${intoMatch?.[1] || \"unknown\"}`;\n\n\t\t\t\tconst operation: SQLOperation = {\n\t\t\t\t\ttype: \"raw-query\",\n\t\t\t\t\tsql,\n\t\t\t\t\tparams: params as unknown[],\n\t\t\t\t\tmethod,\n\t\t\t\t\trowCount: 0,\n\t\t\t\t\tcontext,\n\t\t\t\t\ttimestamp: startTime,\n\t\t\t\t};\n\t\t\t\tinterceptor.onOperation(operation);\n\t\t\t} else if (sqlLower.startsWith(\"update\")) {\n\t\t\t\tconst tableMatch = sql.match(/update\\s+[\"']?(\\w+)[\"']?/i);\n\t\t\t\tcontext = `UPDATE ${tableMatch?.[1] || \"unknown\"}`;\n\n\t\t\t\tconst operation: SQLOperation = {\n\t\t\t\t\ttype: \"raw-query\",\n\t\t\t\t\tsql,\n\t\t\t\t\tparams: params as unknown[],\n\t\t\t\t\tmethod,\n\t\t\t\t\trowCount: 0,\n\t\t\t\t\tcontext,\n\t\t\t\t\ttimestamp: startTime,\n\t\t\t\t};\n\t\t\t\tinterceptor.onOperation(operation);\n\t\t\t} else if (sqlLower.startsWith(\"delete\")) {\n\t\t\t\tconst fromMatch = sql.match(/from\\s+[\"']?(\\w+)[\"']?/i);\n\t\t\t\tcontext = `DELETE from ${fromMatch?.[1] || \"unknown\"}`;\n\n\t\t\t\tconst operation: SQLOperation = {\n\t\t\t\t\ttype: \"raw-query\",\n\t\t\t\t\tsql,\n\t\t\t\t\tparams: params as unknown[],\n\t\t\t\t\tmethod,\n\t\t\t\t\trowCount: 0,\n\t\t\t\t\tcontext,\n\t\t\t\t\ttimestamp: startTime,\n\t\t\t\t};\n\t\t\t\tinterceptor.onOperation(operation);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}, config);\n};\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useDrizzleSqliteDb.ts"],"names":[],"mappings":"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","file":"chunk-WFFFP6DB.js","sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n\tcustomSqliteMigrate,\n\ttype DurableSqliteMigrationConfig,\n} from \"../migration/migrator\";\nimport {\n\tdrizzleSqliteWasmWorker,\n\tcreateInstrumentedDrizzle,\n} from \"../drizzle/worker\";\nimport type { ISqliteWorkerClient } from \"../worker/manager\";\nimport {\n\tinitializeSqliteWorker,\n\tisSqliteWorkerInitialized,\n} from \"../worker/global-manager\";\nimport type { SQLInterceptor } from \"../collections/sqlite-collection\";\nimport type { SqliteWasmWorkerOpenOptions } from \"../worker/sqlite-open-options\";\n\nexport const useDrizzleSqliteDb = <TSchema extends Record<string, unknown>>(\n\tWorkerConstructor: new () => Worker,\n\tdbName: string,\n\tschema: TSchema,\n\tmigrations: DurableSqliteMigrationConfig,\n\tdebug?: boolean,\n\t/** Optional interceptor to log ALL SQL queries (including direct Drizzle queries) */\n\tinterceptor?: SQLInterceptor,\n\t/**\n\t * Pragmas applied when the worker first opens this `dbName` in the session.\n\t * Ignored if that database was already started (same global worker + dbName).\n\t */\n\tworkerOpenOptions?: SqliteWasmWorkerOpenOptions,\n) => {\n\tconst resolveRef = useRef<null | (() => void)>(null);\n\tconst rejectRef = useRef<null | ((error: unknown) => void)>(null);\n\tconst [sqliteClient, setSqliteClient] = useState<ISqliteWorkerClient | null>(\n\t\tnull,\n\t);\n\tconst sqliteClientRef = useRef<ISqliteWorkerClient | null>(null);\n\n\tconst readyPromise = useMemo(() => {\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tresolveRef.current = resolve;\n\t\t\trejectRef.current = reject;\n\t\t});\n\t}, []);\n\n\t// Initialize the global manager and get db instance\n\tuseEffect(() => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\t// SSR stub\n\t\t\tsetSqliteClient({\n\t\t\t\tperformRemoteCallback: () => {},\n\t\t\t\tcheckpoint: () => Promise.resolve(),\n\t\t\t\tonStarted: () => {},\n\t\t\t\tterminate: () => {},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tlet mounted = true;\n\n\t\tconst init = async () => {\n\t\t\t// Initialize manager if not already initialized\n\t\t\tif (!isSqliteWorkerInitialized()) {\n\t\t\t\tawait initializeSqliteWorker(WorkerConstructor);\n\t\t\t}\n\n\t\t\t// Get manager and create db instance\n\t\t\tconst { getSqliteWorkerManager } = await import(\n\t\t\t\t\"../worker/global-manager\"\n\t\t\t);\n\t\t\tconst manager = getSqliteWorkerManager();\n\t\t\tconst instance = await manager.getDbInstance(dbName, workerOpenOptions);\n\n\t\t\tif (mounted) {\n\t\t\t\tsqliteClientRef.current = instance;\n\t\t\t\tsetSqliteClient(instance);\n\t\t\t}\n\t\t};\n\n\t\tinit();\n\n\t\treturn () => {\n\t\t\tmounted = false;\n\t\t};\n\t}, [dbName, WorkerConstructor, workerOpenOptions]);\n\n\t// Store interceptor in a ref to avoid recreating drizzle on interceptor changes\n\tconst interceptorRef = useRef(interceptor);\n\tinterceptorRef.current = interceptor;\n\n\t// Create drizzle instance with a callback-based approach that waits for the client\n\t// Use instrumented version if interceptor is provided to log ALL queries\n\tconst drizzle = useMemo(() => {\n\t\tif (debug) {\n\t\t\tconsole.log(`[DEBUG] ${dbName} - creating drizzle proxy wrapper`);\n\t\t}\n\n\t\tconst client: ISqliteWorkerClient = {\n\t\t\tperformRemoteCallback: (data, resolve, reject) => {\n\t\t\t\tconst actualClient = sqliteClientRef.current;\n\t\t\t\tif (!actualClient) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`[DEBUG] ${dbName} - performRemoteCallback called but no sqliteClient yet`,\n\t\t\t\t\t);\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(`Database ${dbName} not ready yet - still initializing`),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactualClient.performRemoteCallback(data, resolve, reject);\n\t\t\t},\n\t\t\tonStarted: (callback) => {\n\t\t\t\tconst actualClient = sqliteClientRef.current;\n\t\t\t\tif (!actualClient) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[DEBUG] ${dbName} - onStarted called but no sqliteClient yet`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tactualClient.onStarted(callback);\n\t\t\t},\n\t\t\tterminate: () => {\n\t\t\t\tsqliteClientRef.current?.terminate();\n\t\t\t},\n\t\t\tcheckpoint: () => {\n\t\t\t\treturn sqliteClientRef.current?.checkpoint() ?? Promise.resolve();\n\t\t\t},\n\t\t};\n\n\t\t// Use instrumented version if interceptor is provided\n\t\t// Use a wrapper that accesses the ref so interceptor changes don't recreate drizzle\n\t\tconst interceptorWrapper: SQLInterceptor = {\n\t\t\tonOperation: (op) => interceptorRef.current?.onOperation?.(op),\n\t\t};\n\n\t\t// Always use instrumented if initial interceptor was provided\n\t\tif (interceptor) {\n\t\t\treturn createInstrumentedDrizzle<TSchema>(\n\t\t\t\tclient,\n\t\t\t\t{ schema },\n\t\t\t\tinterceptorWrapper,\n\t\t\t);\n\t\t}\n\n\t\treturn drizzleSqliteWasmWorker<TSchema>(client, { schema });\n\t}, [schema, dbName, !!interceptor]); // Only recreate if interceptor presence changes, not on every render\n\n\tuseEffect(() => {\n\t\tif (!sqliteClient) {\n\t\t\tif (debug) {\n\t\t\t\tconsole.log(`[DEBUG] ${dbName} - waiting for sqliteClient...`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tsqliteClient.onStarted(async () => {\n\t\t\ttry {\n\t\t\t\tawait customSqliteMigrate(drizzle, migrations);\n\t\t\t\tresolveRef.current?.();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`Migration error for ${dbName}:`, error);\n\t\t\t\trejectRef.current?.(error);\n\t\t\t}\n\t\t});\n\n\t\treturn () => {\n\t\t\tsqliteClient.terminate();\n\t\t};\n\t}, [sqliteClient, drizzle, migrations, dbName]);\n\n\treturn { drizzle, readyPromise, sqliteClient };\n};\n"]}
|