@rocicorp/zero 1.6.0-canary.5 → 1.6.0-canary.6
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/out/replicache/src/kv/expo-sqlite/store.d.ts +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js +6 -7
- package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js +6 -6
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.d.ts +6 -6
- package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +104 -22
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/kv/throw-if-closed.d.ts +1 -0
- package/out/replicache/src/kv/throw-if-closed.d.ts.map +1 -1
- package/out/replicache/src/kv/throw-if-closed.js +1 -4
- package/out/replicache/src/kv/throw-if-closed.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +6 -3
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/reaper.js +2 -2
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +4 -4
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +4 -4
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +5 -0
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/configuration-error.d.ts +4 -0
- package/out/zero-cache/src/types/configuration-error.d.ts.map +1 -0
- package/out/zero-cache/src/types/configuration-error.js +11 -0
- package/out/zero-cache/src/types/configuration-error.js.map +1 -0
- package/out/zero-cache/src/types/pg.d.ts +2 -0
- package/out/zero-cache/src/types/pg.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg.js +34 -1
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +3 -1
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SQLiteStoreOptions } from '../sqlite-store.ts';
|
|
2
2
|
import type { StoreProvider } from '../store.ts';
|
|
3
3
|
export type ExpoSQLiteStoreOptions = SQLiteStoreOptions;
|
|
4
|
-
export declare function dropExpoSQLiteStore(name: string): Promise<void>;
|
|
4
|
+
export declare function dropExpoSQLiteStore(name: string, opts?: ExpoSQLiteStoreOptions): Promise<void>;
|
|
5
5
|
/**
|
|
6
6
|
* Creates a StoreProvider for SQLite-based stores using expo-sqlite.
|
|
7
7
|
* Supports shared connections between multiple store instances with the same name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../../replicache/src/kv/expo-sqlite/store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAExD,wBAAgB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../../replicache/src/kv/expo-sqlite/store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAExD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,CAAC,EAAE,sBAAsB,GAC5B,aAAa,CAMf"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SQLiteStore, dropStore } from "../sqlite-store.js";
|
|
2
2
|
import { deleteDatabaseSync, openDatabaseSync } from "expo-sqlite";
|
|
3
3
|
//#region ../replicache/src/kv/expo-sqlite/store.ts
|
|
4
|
-
function dropExpoSQLiteStore(name) {
|
|
5
|
-
return dropStore(name, (filename) => new ExpoSQLiteDatabase(filename));
|
|
4
|
+
function dropExpoSQLiteStore(name, opts) {
|
|
5
|
+
return dropStore(name, (filename) => new ExpoSQLiteDatabase(filename), opts);
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Creates a StoreProvider for SQLite-based stores using expo-sqlite.
|
|
@@ -12,7 +12,7 @@ function dropExpoSQLiteStore(name) {
|
|
|
12
12
|
function expoSQLiteStoreProvider(opts) {
|
|
13
13
|
return {
|
|
14
14
|
create: (name) => new SQLiteStore(name, (name) => new ExpoSQLiteDatabase(name), opts),
|
|
15
|
-
drop: dropExpoSQLiteStore
|
|
15
|
+
drop: (name) => dropExpoSQLiteStore(name, opts)
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
var ExpoSQLitePreparedStatement = class {
|
|
@@ -20,13 +20,12 @@ var ExpoSQLitePreparedStatement = class {
|
|
|
20
20
|
constructor(statement) {
|
|
21
21
|
this.#statement = statement;
|
|
22
22
|
}
|
|
23
|
-
async firstValue(params) {
|
|
24
|
-
const row = await (await this.#statement.executeForRawResultAsync(params)).getFirstAsync();
|
|
25
|
-
return row === null ? void 0 : row[0];
|
|
26
|
-
}
|
|
27
23
|
async exec(params) {
|
|
28
24
|
await this.#statement.executeForRawResultAsync(params);
|
|
29
25
|
}
|
|
26
|
+
async all(params) {
|
|
27
|
+
return (await this.#statement.executeForRawResultAsync(params)).getAllAsync();
|
|
28
|
+
}
|
|
30
29
|
};
|
|
31
30
|
var ExpoSQLiteDatabase = class {
|
|
32
31
|
#db;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","names":["#statement","#db","#filename","#statements"],"sources":["../../../../../../replicache/src/kv/expo-sqlite/store.ts"],"sourcesContent":["import {\n deleteDatabaseSync,\n openDatabaseSync,\n type SQLiteDatabase as DB,\n type SQLiteStatement,\n} from 'expo-sqlite';\nimport type {\n PreparedStatement,\n SQLiteDatabase,\n SQLiteStoreOptions,\n} from '../sqlite-store.ts';\nimport {dropStore, SQLiteStore} from '../sqlite-store.ts';\nimport type {StoreProvider} from '../store.ts';\n\nexport type ExpoSQLiteStoreOptions = SQLiteStoreOptions;\n\nexport function dropExpoSQLiteStore(name: string): Promise<void> {\n return dropStore(name, filename => new ExpoSQLiteDatabase(filename));\n}\n\n/**\n * Creates a StoreProvider for SQLite-based stores using expo-sqlite.\n * Supports shared connections between multiple store instances with the same name,\n * providing efficient resource utilization and proper transaction isolation.\n */\nexport function expoSQLiteStoreProvider(\n opts?: ExpoSQLiteStoreOptions,\n): StoreProvider {\n return {\n create: name =>\n new SQLiteStore(name, name => new ExpoSQLiteDatabase(name), opts),\n drop: dropExpoSQLiteStore,\n };\n}\n\nclass ExpoSQLitePreparedStatement implements PreparedStatement {\n readonly #statement: SQLiteStatement;\n\n constructor(statement: SQLiteStatement) {\n this.#statement = statement;\n }\n\n async
|
|
1
|
+
{"version":3,"file":"store.js","names":["#statement","#db","#filename","#statements"],"sources":["../../../../../../replicache/src/kv/expo-sqlite/store.ts"],"sourcesContent":["import {\n deleteDatabaseSync,\n openDatabaseSync,\n type SQLiteDatabase as DB,\n type SQLiteStatement,\n} from 'expo-sqlite';\nimport type {\n PreparedStatement,\n SQLiteDatabase,\n SQLiteStoreOptions,\n} from '../sqlite-store.ts';\nimport {dropStore, SQLiteStore} from '../sqlite-store.ts';\nimport type {StoreProvider} from '../store.ts';\n\nexport type ExpoSQLiteStoreOptions = SQLiteStoreOptions;\n\nexport function dropExpoSQLiteStore(\n name: string,\n opts?: ExpoSQLiteStoreOptions,\n): Promise<void> {\n return dropStore(name, filename => new ExpoSQLiteDatabase(filename), opts);\n}\n\n/**\n * Creates a StoreProvider for SQLite-based stores using expo-sqlite.\n * Supports shared connections between multiple store instances with the same name,\n * providing efficient resource utilization and proper transaction isolation.\n */\nexport function expoSQLiteStoreProvider(\n opts?: ExpoSQLiteStoreOptions,\n): StoreProvider {\n return {\n create: name =>\n new SQLiteStore(name, name => new ExpoSQLiteDatabase(name), opts),\n drop: name => dropExpoSQLiteStore(name, opts),\n };\n}\n\nclass ExpoSQLitePreparedStatement implements PreparedStatement {\n readonly #statement: SQLiteStatement;\n\n constructor(statement: SQLiteStatement) {\n this.#statement = statement;\n }\n\n async exec(params: string[]): Promise<void> {\n await this.#statement.executeForRawResultAsync(params);\n }\n\n async all(params: string[]): Promise<unknown[][]> {\n const result = await this.#statement.executeForRawResultAsync(params);\n return result.getAllAsync() as Promise<unknown[][]>;\n }\n}\n\nclass ExpoSQLiteDatabase implements SQLiteDatabase {\n readonly #db: DB;\n readonly #filename: string;\n readonly #statements: Set<SQLiteStatement> = new Set();\n\n constructor(filename: string) {\n this.#filename = filename;\n this.#db = openDatabaseSync(filename);\n }\n\n close(): void {\n for (const stmt of this.#statements) {\n stmt.finalizeSync();\n }\n this.#db.closeSync();\n }\n\n destroy(): void {\n deleteDatabaseSync(this.#filename);\n }\n\n prepare(sql: string): PreparedStatement {\n const statement = this.#db.prepareSync(sql);\n this.#statements.add(statement);\n return new ExpoSQLitePreparedStatement(statement);\n }\n\n execSync(sql: string): void {\n this.#db.execSync(sql);\n }\n}\n"],"mappings":";;;AAgBA,SAAgB,oBACd,MACA,MACe;AACf,QAAO,UAAU,OAAM,aAAY,IAAI,mBAAmB,SAAS,EAAE,KAAK;;;;;;;AAQ5E,SAAgB,wBACd,MACe;AACf,QAAO;EACL,SAAQ,SACN,IAAI,YAAY,OAAM,SAAQ,IAAI,mBAAmB,KAAK,EAAE,KAAK;EACnE,OAAM,SAAQ,oBAAoB,MAAM,KAAK;EAC9C;;AAGH,IAAM,8BAAN,MAA+D;CAC7D;CAEA,YAAY,WAA4B;AACtC,QAAA,YAAkB;;CAGpB,MAAM,KAAK,QAAiC;AAC1C,QAAM,MAAA,UAAgB,yBAAyB,OAAO;;CAGxD,MAAM,IAAI,QAAwC;AAEhD,UADe,MAAM,MAAA,UAAgB,yBAAyB,OAAO,EACvD,aAAa;;;AAI/B,IAAM,qBAAN,MAAmD;CACjD;CACA;CACA,8BAA6C,IAAI,KAAK;CAEtD,YAAY,UAAkB;AAC5B,QAAA,WAAiB;AACjB,QAAA,KAAW,iBAAiB,SAAS;;CAGvC,QAAc;AACZ,OAAK,MAAM,QAAQ,MAAA,WACjB,MAAK,cAAc;AAErB,QAAA,GAAS,WAAW;;CAGtB,UAAgB;AACd,qBAAmB,MAAA,SAAe;;CAGpC,QAAQ,KAAgC;EACtC,MAAM,YAAY,MAAA,GAAS,YAAY,IAAI;AAC3C,QAAA,WAAiB,IAAI,UAAU;AAC/B,SAAO,IAAI,4BAA4B,UAAU;;CAGnD,SAAS,KAAmB;AAC1B,QAAA,GAAS,SAAS,IAAI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../../replicache/src/kv/op-sqlite/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAG/C,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,GAAG;IAEtD,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../../replicache/src/kv/op-sqlite/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAG/C,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,GAAG;IAEtD,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAaF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,CAAC,EAAE,oBAAoB,GAC1B,aAAa,CAUf"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SQLiteStore, dropStore } from "../sqlite-store.js";
|
|
2
2
|
import { open } from "./types.js";
|
|
3
3
|
//#region ../replicache/src/kv/op-sqlite/store.ts
|
|
4
|
-
function dropOpSQLiteStore(name) {
|
|
5
|
-
return dropStore(name, (filename,
|
|
4
|
+
function dropOpSQLiteStore(name, opts) {
|
|
5
|
+
return dropStore(name, (filename, options) => new OpSQLiteDatabase(filename, options), opts);
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Creates a StoreProvider for SQLite-based stores using @op-engineering/op-sqlite.
|
|
@@ -13,7 +13,7 @@ function dropOpSQLiteStore(name) {
|
|
|
13
13
|
function opSQLiteStoreProvider(opts) {
|
|
14
14
|
return {
|
|
15
15
|
create: (name) => new SQLiteStore(name, (name, options) => new OpSQLiteDatabase(name, options), opts),
|
|
16
|
-
drop: dropOpSQLiteStore
|
|
16
|
+
drop: (name) => dropOpSQLiteStore(name, opts)
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
var OpSQLitePreparedStatement = class {
|
|
@@ -23,12 +23,12 @@ var OpSQLitePreparedStatement = class {
|
|
|
23
23
|
this.#db = db;
|
|
24
24
|
this.#sql = sql;
|
|
25
25
|
}
|
|
26
|
-
async firstValue(params) {
|
|
27
|
-
return (await this.#db.executeRaw(this.#sql, params))[0]?.[0];
|
|
28
|
-
}
|
|
29
26
|
async exec(params) {
|
|
30
27
|
await this.#db.executeRaw(this.#sql, params);
|
|
31
28
|
}
|
|
29
|
+
all(params) {
|
|
30
|
+
return this.#db.executeRaw(this.#sql, params);
|
|
31
|
+
}
|
|
32
32
|
};
|
|
33
33
|
var OpSQLiteDatabase = class {
|
|
34
34
|
#db;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","names":["#db","#sql","#filename"],"sources":["../../../../../../replicache/src/kv/op-sqlite/store.ts"],"sourcesContent":["import type {\n PreparedStatement,\n SQLiteDatabase,\n SQLiteStoreOptions,\n} from '../sqlite-store.ts';\nimport {dropStore, SQLiteStore} from '../sqlite-store.ts';\nimport type {StoreProvider} from '../store.ts';\nimport {open, type DB} from './types.ts';\n\nexport type OpSQLiteStoreOptions = SQLiteStoreOptions & {\n // OpSQLite-specific options\n location?: 'default' | 'Library' | 'Documents' | 'Temporary';\n encryptionKey?: string;\n};\n\nfunction dropOpSQLiteStore(name: string): Promise<void> {\n return dropStore(\n name,\n (filename,
|
|
1
|
+
{"version":3,"file":"store.js","names":["#db","#sql","#filename"],"sources":["../../../../../../replicache/src/kv/op-sqlite/store.ts"],"sourcesContent":["import type {\n PreparedStatement,\n SQLiteDatabase,\n SQLiteStoreOptions,\n} from '../sqlite-store.ts';\nimport {dropStore, SQLiteStore} from '../sqlite-store.ts';\nimport type {StoreProvider} from '../store.ts';\nimport {open, type DB} from './types.ts';\n\nexport type OpSQLiteStoreOptions = SQLiteStoreOptions & {\n // OpSQLite-specific options\n location?: 'default' | 'Library' | 'Documents' | 'Temporary';\n encryptionKey?: string;\n};\n\nfunction dropOpSQLiteStore(\n name: string,\n opts?: OpSQLiteStoreOptions,\n): Promise<void> {\n return dropStore(\n name,\n (filename, options) => new OpSQLiteDatabase(filename, options),\n opts,\n );\n}\n\n/**\n * Creates a StoreProvider for SQLite-based stores using @op-engineering/op-sqlite.\n * Supports shared connections between multiple store instances with the same name,\n * providing efficient resource utilization and proper transaction isolation.\n * Uses parameterized queries for safety and performance.\n */\nexport function opSQLiteStoreProvider(\n opts?: OpSQLiteStoreOptions,\n): StoreProvider {\n return {\n create: name =>\n new SQLiteStore(\n name,\n (name, options) => new OpSQLiteDatabase(name, options),\n opts,\n ),\n drop: name => dropOpSQLiteStore(name, opts),\n };\n}\n\nclass OpSQLitePreparedStatement implements PreparedStatement {\n readonly #db: DB;\n readonly #sql: string;\n\n constructor(db: DB, sql: string) {\n this.#db = db;\n this.#sql = sql;\n }\n\n async exec(params: string[]): Promise<void> {\n await this.#db.executeRaw(this.#sql, params);\n }\n\n all(params: string[]): Promise<unknown[][]> {\n return this.#db.executeRaw(this.#sql, params);\n }\n}\n\nclass OpSQLiteDatabase implements SQLiteDatabase {\n readonly #db: DB;\n readonly #filename: string;\n\n constructor(filename: string, opts?: OpSQLiteStoreOptions) {\n this.#filename = filename;\n const openOpts: {\n name: string;\n location?: string;\n encryptionKey?: string;\n } = {name: filename};\n\n if (opts?.location) {\n openOpts.location = opts.location;\n }\n if (opts?.encryptionKey) {\n openOpts.encryptionKey = opts.encryptionKey;\n }\n\n this.#db = open(openOpts);\n }\n\n close(): void {\n this.#db.close();\n }\n\n destroy(): void {\n // OpSQLite uses delete method on the database instance\n // We need to create a temporary connection to delete the database\n try {\n const tempDb = open({name: this.#filename});\n tempDb.delete();\n tempDb.close();\n } catch (_error) {\n // Database might not exist, which is fine\n }\n }\n\n prepare(sql: string): PreparedStatement {\n return new OpSQLitePreparedStatement(this.#db, sql);\n }\n\n execSync(sql: string): void {\n this.#db.executeRawSync(sql, []);\n }\n}\n"],"mappings":";;;AAeA,SAAS,kBACP,MACA,MACe;AACf,QAAO,UACL,OACC,UAAU,YAAY,IAAI,iBAAiB,UAAU,QAAQ,EAC9D,KACD;;;;;;;;AASH,SAAgB,sBACd,MACe;AACf,QAAO;EACL,SAAQ,SACN,IAAI,YACF,OACC,MAAM,YAAY,IAAI,iBAAiB,MAAM,QAAQ,EACtD,KACD;EACH,OAAM,SAAQ,kBAAkB,MAAM,KAAK;EAC5C;;AAGH,IAAM,4BAAN,MAA6D;CAC3D;CACA;CAEA,YAAY,IAAQ,KAAa;AAC/B,QAAA,KAAW;AACX,QAAA,MAAY;;CAGd,MAAM,KAAK,QAAiC;AAC1C,QAAM,MAAA,GAAS,WAAW,MAAA,KAAW,OAAO;;CAG9C,IAAI,QAAwC;AAC1C,SAAO,MAAA,GAAS,WAAW,MAAA,KAAW,OAAO;;;AAIjD,IAAM,mBAAN,MAAiD;CAC/C;CACA;CAEA,YAAY,UAAkB,MAA6B;AACzD,QAAA,WAAiB;EACjB,MAAM,WAIF,EAAC,MAAM,UAAS;AAEpB,MAAI,MAAM,SACR,UAAS,WAAW,KAAK;AAE3B,MAAI,MAAM,cACR,UAAS,gBAAgB,KAAK;AAGhC,QAAA,KAAW,KAAK,SAAS;;CAG3B,QAAc;AACZ,QAAA,GAAS,OAAO;;CAGlB,UAAgB;AAGd,MAAI;GACF,MAAM,SAAS,KAAK,EAAC,MAAM,MAAA,UAAe,CAAC;AAC3C,UAAO,QAAQ;AACf,UAAO,OAAO;WACP,QAAQ;;CAKnB,QAAQ,KAAgC;AACtC,SAAO,IAAI,0BAA0B,MAAA,IAAU,IAAI;;CAGrD,SAAS,KAAmB;AAC1B,QAAA,GAAS,eAAe,KAAK,EAAE,CAAC"}
|
|
@@ -3,14 +3,10 @@ import type { Read, Store, Write } from './store.ts';
|
|
|
3
3
|
import { WriteImplBase } from './write-impl-base.ts';
|
|
4
4
|
/**
|
|
5
5
|
* A SQLite prepared statement.
|
|
6
|
-
*
|
|
7
|
-
* `run` executes the statement with optional parameters.
|
|
8
|
-
* `all` executes the statement and returns the result rows.
|
|
9
|
-
* `finalize` releases the statement.
|
|
10
6
|
*/
|
|
11
7
|
export interface PreparedStatement {
|
|
12
|
-
firstValue(params: string[]): Promise<unknown>;
|
|
13
8
|
exec(params: string[]): Promise<void>;
|
|
9
|
+
all(params: string[]): Promise<unknown[][]>;
|
|
14
10
|
}
|
|
15
11
|
export interface SQLiteDatabase {
|
|
16
12
|
/**
|
|
@@ -47,6 +43,8 @@ export declare function safeFilename(name: string): string;
|
|
|
47
43
|
export type PreparedStatements = {
|
|
48
44
|
has: PreparedStatement;
|
|
49
45
|
get: PreparedStatement;
|
|
46
|
+
hasMany: PreparedStatement;
|
|
47
|
+
getMany: PreparedStatement;
|
|
50
48
|
put: PreparedStatement;
|
|
51
49
|
del: PreparedStatement;
|
|
52
50
|
};
|
|
@@ -55,6 +53,8 @@ export interface SQLiteStoreOptions {
|
|
|
55
53
|
journalMode?: 'WAL' | 'DELETE';
|
|
56
54
|
synchronous?: 'NORMAL' | 'FULL';
|
|
57
55
|
readUncommitted?: boolean;
|
|
56
|
+
/** Directory in which to create the SQLite file. Defaults to the process CWD. */
|
|
57
|
+
directory?: string | undefined;
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
60
|
* Common database setup logic shared between expo-sqlite and op-sqlite implementations.
|
|
@@ -77,5 +77,5 @@ export declare class SQLiteWrite extends WriteImplBase implements Write {
|
|
|
77
77
|
get closed(): boolean;
|
|
78
78
|
}
|
|
79
79
|
export declare function clearAllNamedStoresForTesting(): void;
|
|
80
|
-
export declare function dropStore(name: string, createDelegate: (filename: string, opts?: SQLiteStoreOptions) => SQLiteDatabase): Promise<void>;
|
|
80
|
+
export declare function dropStore(name: string, createDelegate: (filename: string, opts?: SQLiteStoreOptions) => SQLiteDatabase, opts?: SQLiteStoreOptions): Promise<void>;
|
|
81
81
|
//# sourceMappingURL=sqlite-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/sqlite-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,YAAY,CAAC;AAMnD,OAAO,EAAiB,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAEnE
|
|
1
|
+
{"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/sqlite-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { deepFreeze } from "../frozen-json.js";
|
|
2
|
-
import {
|
|
2
|
+
import { maybeTransactionIsClosedRejection, throwIfStoreClosed, transactionError } from "./throw-if-closed.js";
|
|
3
3
|
import { WriteImplBase, deleteSentinel } from "./write-impl-base.js";
|
|
4
4
|
import { RWLock } from "@rocicorp/lock";
|
|
5
5
|
//#region ../replicache/src/kv/sqlite-store.ts
|
|
@@ -14,8 +14,8 @@ var SQLiteStore = class {
|
|
|
14
14
|
#entry;
|
|
15
15
|
#closed = false;
|
|
16
16
|
constructor(name, create, opts) {
|
|
17
|
-
this.#filename =
|
|
18
|
-
this.#entry = getOrCreateEntry(
|
|
17
|
+
this.#filename = resolveFilename(name, opts);
|
|
18
|
+
this.#entry = getOrCreateEntry(this.#filename, create, opts);
|
|
19
19
|
}
|
|
20
20
|
async read() {
|
|
21
21
|
throwIfStoreClosed(this);
|
|
@@ -52,6 +52,11 @@ var SQLiteStore = class {
|
|
|
52
52
|
function safeFilename(name) {
|
|
53
53
|
return name.replace(/[^a-zA-Z0-9]/g, "_");
|
|
54
54
|
}
|
|
55
|
+
function resolveFilename(name, opts) {
|
|
56
|
+
const safe = safeFilename(name);
|
|
57
|
+
const dir = opts?.directory;
|
|
58
|
+
return dir ? `${dir}/${safe}` : safe;
|
|
59
|
+
}
|
|
55
60
|
/**
|
|
56
61
|
* Common database setup logic shared between expo-sqlite and op-sqlite implementations.
|
|
57
62
|
* Configures SQLite pragmas, creates the entry table, and prepares common statements.
|
|
@@ -70,28 +75,107 @@ function setupDatabase(delegate, opts) {
|
|
|
70
75
|
return {
|
|
71
76
|
has: delegate.prepare(`SELECT 1 FROM entry WHERE key = ? LIMIT 1`),
|
|
72
77
|
get: delegate.prepare("SELECT value FROM entry WHERE key = ?"),
|
|
78
|
+
hasMany: delegate.prepare(`SELECT key FROM entry WHERE key IN (SELECT value FROM json_each(?))`),
|
|
79
|
+
getMany: delegate.prepare(`SELECT key, value FROM entry WHERE key IN (SELECT value FROM json_each(?))`),
|
|
73
80
|
put: delegate.prepare(`INSERT OR REPLACE INTO entry (key, value)
|
|
74
81
|
SELECT e.value->>0, e.value->1 FROM json_each(?) e`),
|
|
75
82
|
del: delegate.prepare(`DELETE FROM entry WHERE key IN (SELECT value FROM json_each(?))`)
|
|
76
83
|
};
|
|
77
84
|
}
|
|
85
|
+
var CB_STRIDE = 2;
|
|
86
|
+
var CB_RESOLVE = 0;
|
|
87
|
+
var CB_REJECT = 1;
|
|
88
|
+
function rejectAll(callbacks, e) {
|
|
89
|
+
for (let i = CB_REJECT; i < callbacks.length; i += CB_STRIDE) callbacks[i](e);
|
|
90
|
+
}
|
|
91
|
+
function resolveGet(resolve, reject, raw) {
|
|
92
|
+
try {
|
|
93
|
+
resolve(raw === void 0 ? void 0 : deepFreeze(JSON.parse(raw)));
|
|
94
|
+
} catch (e) {
|
|
95
|
+
reject(e);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function flushGets(keys, callbacks, ps) {
|
|
99
|
+
let rows;
|
|
100
|
+
try {
|
|
101
|
+
rows = keys.length === 1 ? await ps.get.all([keys[0]]) : await ps.getMany.all([JSON.stringify(keys)]);
|
|
102
|
+
} catch (e) {
|
|
103
|
+
rejectAll(callbacks, e);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (keys.length === 1) {
|
|
107
|
+
resolveGet(callbacks[CB_RESOLVE], callbacks[CB_REJECT], rows[0]?.[0]);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const resultMap = new Map(rows);
|
|
111
|
+
for (let i = 0; i < keys.length; i++) resolveGet(callbacks[i * CB_STRIDE + CB_RESOLVE], callbacks[i * CB_STRIDE + CB_REJECT], resultMap.get(keys[i]));
|
|
112
|
+
}
|
|
113
|
+
async function flushHas(keys, callbacks, ps) {
|
|
114
|
+
let rows;
|
|
115
|
+
try {
|
|
116
|
+
rows = keys.length === 1 ? await ps.has.all([keys[0]]) : await ps.hasMany.all([JSON.stringify(keys)]);
|
|
117
|
+
} catch (e) {
|
|
118
|
+
rejectAll(callbacks, e);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (keys.length === 1) {
|
|
122
|
+
callbacks[CB_RESOLVE](rows.length > 0);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const existingKeys = new Set(rows.map((row) => row[0]));
|
|
126
|
+
for (let i = 0; i < keys.length; i++) callbacks[i * CB_STRIDE + CB_RESOLVE](existingKeys.has(keys[i]));
|
|
127
|
+
}
|
|
78
128
|
var SQLiteStoreRead = class {
|
|
79
129
|
#release;
|
|
80
|
-
#closed = false;
|
|
81
130
|
#preparedStatements;
|
|
131
|
+
#closed = false;
|
|
132
|
+
#pendingGetKeys = [];
|
|
133
|
+
#pendingGetCallbacks = [];
|
|
134
|
+
#pendingHasKeys = [];
|
|
135
|
+
#pendingHasCallbacks = [];
|
|
136
|
+
#scheduled = false;
|
|
82
137
|
constructor(release, preparedStatements) {
|
|
83
138
|
this.#release = release;
|
|
84
139
|
this.#preparedStatements = preparedStatements;
|
|
85
140
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
141
|
+
has(key) {
|
|
142
|
+
return maybeTransactionIsClosedRejection(this) ?? new Promise((resolve, reject) => {
|
|
143
|
+
this.#pendingHasKeys.push(key);
|
|
144
|
+
this.#pendingHasCallbacks.push(resolve, reject);
|
|
145
|
+
this.#scheduleLookup();
|
|
146
|
+
});
|
|
89
147
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
148
|
+
get(key) {
|
|
149
|
+
return maybeTransactionIsClosedRejection(this) ?? new Promise((resolve, reject) => {
|
|
150
|
+
this.#pendingGetKeys.push(key);
|
|
151
|
+
this.#pendingGetCallbacks.push(resolve, reject);
|
|
152
|
+
this.#scheduleLookup();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
#scheduleLookup() {
|
|
156
|
+
if (!this.#scheduled) {
|
|
157
|
+
this.#scheduled = true;
|
|
158
|
+
queueMicrotask(() => {
|
|
159
|
+
this.#scheduled = false;
|
|
160
|
+
const ps = this.#preparedStatements;
|
|
161
|
+
const getKeys = this.#pendingGetKeys;
|
|
162
|
+
this.#pendingGetKeys = [];
|
|
163
|
+
const getCallbacks = this.#pendingGetCallbacks;
|
|
164
|
+
this.#pendingGetCallbacks = [];
|
|
165
|
+
const hasKeys = this.#pendingHasKeys;
|
|
166
|
+
this.#pendingHasKeys = [];
|
|
167
|
+
const hasCallbacks = this.#pendingHasCallbacks;
|
|
168
|
+
this.#pendingHasCallbacks = [];
|
|
169
|
+
if (this.#closed) {
|
|
170
|
+
const e = transactionError();
|
|
171
|
+
rejectAll(getCallbacks, e);
|
|
172
|
+
rejectAll(hasCallbacks, e);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (getKeys.length > 0) flushGets(getKeys, getCallbacks, ps);
|
|
176
|
+
if (hasKeys.length > 0) flushHas(hasKeys, hasCallbacks, ps);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
95
179
|
}
|
|
96
180
|
release() {
|
|
97
181
|
if (!this.#closed) {
|
|
@@ -116,17 +200,16 @@ var SQLiteWrite = class extends WriteImplBase {
|
|
|
116
200
|
this.#preparedStatements = preparedStatements;
|
|
117
201
|
}
|
|
118
202
|
async commit() {
|
|
119
|
-
if (this.#closed)
|
|
203
|
+
if (this.#closed) throw transactionError();
|
|
120
204
|
const deleteKeys = [];
|
|
121
205
|
for (const entry of this._pending) if (entry[1] === deleteSentinel) {
|
|
122
206
|
deleteKeys.push(entry[0]);
|
|
123
207
|
this._pending.delete(entry[0]);
|
|
124
208
|
}
|
|
125
209
|
const delP = deleteKeys.length > 0 ? this.#preparedStatements.del.exec([JSON.stringify(deleteKeys)]) : void 0;
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
else if (upP) await upP;
|
|
210
|
+
const putP = this._pending.size > 0 ? this.#preparedStatements.put.exec([JSON.stringify([...this._pending])]) : void 0;
|
|
211
|
+
if (putP) await putP;
|
|
212
|
+
if (delP) await delP;
|
|
130
213
|
this.#dbDelegate.execSync("COMMIT");
|
|
131
214
|
this._pending.clear();
|
|
132
215
|
this.#committed = true;
|
|
@@ -155,8 +238,7 @@ var stores = /* @__PURE__ */ new Map();
|
|
|
155
238
|
* This implements the shared connection pattern where multiple stores with the same
|
|
156
239
|
* name share the same database connection, lock, and delegate.
|
|
157
240
|
*/
|
|
158
|
-
function getOrCreateEntry(
|
|
159
|
-
const filename = safeFilename(name);
|
|
241
|
+
function getOrCreateEntry(filename, create, opts) {
|
|
160
242
|
const entry = stores.get(filename);
|
|
161
243
|
if (entry) {
|
|
162
244
|
entry.refCount++;
|
|
@@ -192,8 +274,8 @@ function clearAllNamedStoresForTesting() {
|
|
|
192
274
|
for (const entry of stores.values()) entry.db.close();
|
|
193
275
|
stores.clear();
|
|
194
276
|
}
|
|
195
|
-
function dropStore(name, createDelegate) {
|
|
196
|
-
const filename =
|
|
277
|
+
function dropStore(name, createDelegate, opts) {
|
|
278
|
+
const filename = resolveFilename(name, opts);
|
|
197
279
|
const entry = stores.get(filename);
|
|
198
280
|
if (entry) {
|
|
199
281
|
try {
|
|
@@ -201,7 +283,7 @@ function dropStore(name, createDelegate) {
|
|
|
201
283
|
} catch {}
|
|
202
284
|
stores.delete(filename);
|
|
203
285
|
}
|
|
204
|
-
const tempDelegate = createDelegate(filename);
|
|
286
|
+
const tempDelegate = createDelegate(filename, opts);
|
|
205
287
|
try {
|
|
206
288
|
tempDelegate.close();
|
|
207
289
|
} catch {}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-store.js","names":["#filename","#entry","#closed","#release","#preparedStatements","#dbDelegate","#committed"],"sources":["../../../../../replicache/src/kv/sqlite-store.ts"],"sourcesContent":["import {RWLock} from '@rocicorp/lock';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {deepFreeze} from '../frozen-json.ts';\nimport type {Read, Store, Write} from './store.ts';\nimport {\n throwIfStoreClosed,\n throwIfTransactionClosed,\n transactionIsClosedRejection,\n} from './throw-if-closed.ts';\nimport {deleteSentinel, WriteImplBase} from './write-impl-base.ts';\n\n/**\n * A SQLite prepared statement.\n *\n * `run` executes the statement with optional parameters.\n * `all` executes the statement and returns the result rows.\n * `finalize` releases the statement.\n */\nexport interface PreparedStatement {\n firstValue(params: string[]): Promise<unknown>;\n exec(params: string[]): Promise<void>;\n}\n\nexport interface SQLiteDatabase {\n /**\n * Close the database connection.\n */\n close(): void;\n\n /**\n * Destroy or delete the database (e.g. delete file).\n */\n destroy(): void;\n\n /**\n * Prepare a SQL string, returning a statement you can execute.\n * E.g. `const stmt = db.prepare(\"SELECT * FROM todos WHERE id=?\");`\n */\n prepare(sql: string): PreparedStatement;\n\n // for PRAGMA statements, schema creation and transaction control.\n execSync(sql: string): void;\n}\n\nexport type CreateSQLiteDatabase = (\n filename: string,\n opts?: SQLiteStoreOptions,\n) => SQLiteDatabase;\n\n/**\n * SQLite-based implementation of the Store interface using a configurable delegate.\n * Supports shared connections between multiple store instances with the same name,\n * providing efficient resource utilization and proper transaction isolation.\n * Uses parameterized queries for safety and performance.\n */\nexport class SQLiteStore implements Store {\n readonly #filename: string;\n readonly #entry: StoreEntry;\n\n #closed = false;\n\n constructor(\n name: string,\n create: CreateSQLiteDatabase,\n opts?: SQLiteStoreOptions,\n ) {\n this.#filename = safeFilename(name);\n this.#entry = getOrCreateEntry(name, create, opts);\n }\n\n async read(): Promise<Read> {\n throwIfStoreClosed(this);\n\n const entry = this.#entry;\n const {db, lock, preparedStatements} = entry;\n const release = await lock.read();\n\n // Start shared read transaction if this is the first reader\n // This ensures consistent reads across all concurrent readers\n if (entry.activeReaders === 0) {\n db.execSync('BEGIN');\n }\n entry.activeReaders++;\n\n return new SQLiteStoreRead(() => {\n entry.activeReaders--;\n // Commit shared read transaction when last reader finishes\n if (entry.activeReaders === 0) {\n db.execSync('COMMIT');\n }\n release();\n }, preparedStatements);\n }\n\n async write(): Promise<Write> {\n throwIfStoreClosed(this);\n\n const {lock, db, preparedStatements} = this.#entry;\n const release = await lock.write();\n\n // At this point, RWLock guarantees no active readers\n // The last reader would have already committed the shared transaction\n\n db.execSync('BEGIN IMMEDIATE');\n\n return new SQLiteWrite(release, db, preparedStatements);\n }\n\n async close(): Promise<void> {\n if (this.#closed) {\n return;\n }\n\n const {lock, db} = this.#entry;\n // Wait for all readers and writers to finish.\n const writeRelease = await lock.write();\n\n // Handle reference counting for shared stores - only close database\n // when this is the last store instance using it\n decrementStoreRefCount(this.#filename, db);\n\n this.#closed = true;\n writeRelease();\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nexport function safeFilename(name: string): string {\n return name.replace(/[^a-zA-Z0-9]/g, '_');\n}\n\nexport type PreparedStatements = {\n has: PreparedStatement;\n get: PreparedStatement;\n put: PreparedStatement;\n del: PreparedStatement;\n};\n\nexport interface SQLiteStoreOptions {\n // Common options\n busyTimeout?: number;\n journalMode?: 'WAL' | 'DELETE';\n synchronous?: 'NORMAL' | 'FULL';\n readUncommitted?: boolean;\n}\n\n/**\n * Common database setup logic shared between expo-sqlite and op-sqlite implementations.\n * Configures SQLite pragmas, creates the entry table, and prepares common statements.\n */\n\nexport function setupDatabase(\n delegate: SQLiteDatabase,\n opts?: SQLiteStoreOptions,\n): PreparedStatements {\n // Configure SQLite pragmas for optimal performance\n delegate.execSync(`PRAGMA busy_timeout = ${opts?.busyTimeout ?? 200}`);\n delegate.execSync(`PRAGMA journal_mode = '${opts?.journalMode ?? 'WAL'}'`);\n delegate.execSync(`PRAGMA synchronous = '${opts?.synchronous ?? 'NORMAL'}'`);\n delegate.execSync(\n `PRAGMA read_uncommitted = ${Boolean(opts?.readUncommitted)}`,\n );\n\n // Create the entry table\n delegate.execSync(`\n CREATE TABLE IF NOT EXISTS entry (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n ) WITHOUT ROWID\n `);\n\n // Prepare common statements\n return {\n has: delegate.prepare(`SELECT 1 FROM entry WHERE key = ? LIMIT 1`),\n get: delegate.prepare('SELECT value FROM entry WHERE key = ?'),\n put: delegate.prepare(\n `INSERT OR REPLACE INTO entry (key, value)\n SELECT e.value->>0, e.value->1 FROM json_each(?) e`,\n ),\n del: delegate.prepare(\n `DELETE FROM entry WHERE key IN (SELECT value FROM json_each(?))`,\n ),\n };\n}\n\nexport class SQLiteStoreRead implements Read {\n #release: () => void;\n #closed = false;\n #preparedStatements: PreparedStatements;\n\n constructor(release: () => void, preparedStatements: PreparedStatements) {\n this.#release = release;\n this.#preparedStatements = preparedStatements;\n }\n\n async has(key: string): Promise<boolean> {\n throwIfTransactionClosed(this);\n const value = await this.#preparedStatements.has.firstValue([key]);\n return value !== undefined;\n }\n\n async get(key: string): Promise<ReadonlyJSONValue | undefined> {\n throwIfTransactionClosed(this);\n const value = await this.#preparedStatements.get.firstValue([key]);\n if (!value) {\n return undefined;\n }\n\n const parsedValue = JSON.parse(value as string) as ReadonlyJSONValue;\n return deepFreeze(parsedValue);\n }\n\n release(): void {\n if (!this.#closed) {\n this.#closed = true;\n this.#release();\n }\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nexport class SQLiteWrite extends WriteImplBase implements Write {\n readonly #release: () => void;\n readonly #dbDelegate: SQLiteDatabase;\n readonly #preparedStatements: PreparedStatements;\n #committed = false;\n #closed = false;\n\n constructor(\n release: () => void,\n dbDelegate: SQLiteDatabase,\n preparedStatements: PreparedStatements,\n ) {\n super(new SQLiteStoreRead(() => undefined, preparedStatements));\n this.#release = release;\n this.#dbDelegate = dbDelegate;\n this.#preparedStatements = preparedStatements;\n }\n\n async commit(): Promise<void> {\n if (this.#closed) {\n return transactionIsClosedRejection();\n }\n\n const deleteKeys: string[] = [];\n for (const entry of this._pending) {\n if (entry[1] === deleteSentinel) {\n deleteKeys.push(entry[0]);\n this._pending.delete(entry[0]);\n }\n }\n\n const delP =\n deleteKeys.length > 0\n ? this.#preparedStatements.del.exec([JSON.stringify(deleteKeys)])\n : undefined;\n const upP =\n this._pending.size > 0\n ? this.#preparedStatements.put.exec([\n JSON.stringify([...this._pending]),\n ])\n : undefined;\n\n if (delP && upP) {\n await Promise.all([delP, upP]);\n } else if (delP) {\n await delP;\n } else if (upP) {\n await upP;\n }\n\n this.#dbDelegate.execSync('COMMIT');\n this._pending.clear();\n this.#committed = true;\n }\n\n release(): void {\n if (!this.#closed) {\n this.#closed = true;\n super.release();\n let rollbackError: unknown;\n if (!this.#committed) {\n try {\n this.#dbDelegate.execSync('ROLLBACK');\n } catch (e) {\n rollbackError = e;\n }\n }\n\n this.#release();\n if (rollbackError !== undefined) {\n throw rollbackError;\n }\n }\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\ntype StoreEntry = {\n readonly lock: RWLock;\n readonly db: SQLiteDatabase;\n refCount: number;\n activeReaders: number;\n preparedStatements: PreparedStatements;\n};\n\n// Global map to share database connections between multiple store instances with the same name\nconst stores = new Map<string, StoreEntry>();\n\n/**\n * Gets an existing store entry or creates a new one if it doesn't exist.\n * This implements the shared connection pattern where multiple stores with the same\n * name share the same database connection, lock, and delegate.\n */\nfunction getOrCreateEntry(\n name: string,\n create: (filename: string, opts?: SQLiteStoreOptions) => SQLiteDatabase,\n opts?: SQLiteStoreOptions,\n): StoreEntry {\n const filename = safeFilename(name);\n const entry = stores.get(filename);\n\n if (entry) {\n entry.refCount++;\n return entry;\n }\n\n const dbDelegate = create(filename, opts);\n const preparedStatements = setupDatabase(dbDelegate, opts);\n\n const lock = new RWLock();\n\n const newEntry: StoreEntry = {\n lock,\n db: dbDelegate,\n refCount: 1,\n activeReaders: 0,\n preparedStatements,\n };\n stores.set(filename, newEntry);\n return newEntry;\n}\n\n/**\n * Decrements the reference count for a shared store and cleans up resources\n * when the last reference is released.\n */\n\nfunction decrementStoreRefCount(\n filename: string,\n dbDelegate: SQLiteDatabase,\n): void {\n const entry = stores.get(filename);\n if (entry) {\n entry.refCount--;\n if (entry.refCount <= 0) {\n dbDelegate.close();\n stores.delete(filename);\n }\n }\n}\nexport function clearAllNamedStoresForTesting(): void {\n for (const entry of stores.values()) {\n entry.db.close();\n }\n stores.clear();\n}\n\nexport function dropStore(\n name: string,\n createDelegate: (\n filename: string,\n opts?: SQLiteStoreOptions,\n ) => SQLiteDatabase,\n): Promise<void> {\n const filename = safeFilename(name);\n const entry = stores.get(filename);\n if (entry) {\n try {\n entry.db.close();\n } catch {\n // Ignore close errors\n }\n stores.delete(filename);\n }\n\n // Create a temporary delegate to handle database deletion\n const tempDelegate = createDelegate(filename);\n try {\n // we close the db before destroying it - this\n // caused an issue with expo-sqlite since it requires this\n tempDelegate.close();\n } catch {\n // Ignore close errors\n }\n try {\n tempDelegate.destroy();\n } catch {\n // Destroy errors shouldn't be fatal; the file may already be gone or locked\n }\n\n return Promise.resolve();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sqlite-store.js","names":["#filename","#entry","#closed","#release","#preparedStatements","#pendingHasKeys","#pendingHasCallbacks","#scheduleLookup","#pendingGetKeys","#pendingGetCallbacks","#scheduled","#dbDelegate","#committed"],"sources":["../../../../../replicache/src/kv/sqlite-store.ts"],"sourcesContent":["import {RWLock} from '@rocicorp/lock';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {deepFreeze} from '../frozen-json.ts';\nimport type {Read, Store, Write} from './store.ts';\nimport {\n maybeTransactionIsClosedRejection,\n throwIfStoreClosed,\n transactionError,\n} from './throw-if-closed.ts';\nimport {deleteSentinel, WriteImplBase} from './write-impl-base.ts';\n\n/**\n * A SQLite prepared statement.\n */\nexport interface PreparedStatement {\n exec(params: string[]): Promise<void>;\n all(params: string[]): Promise<unknown[][]>;\n}\n\nexport interface SQLiteDatabase {\n /**\n * Close the database connection.\n */\n close(): void;\n\n /**\n * Destroy or delete the database (e.g. delete file).\n */\n destroy(): void;\n\n /**\n * Prepare a SQL string, returning a statement you can execute.\n * E.g. `const stmt = db.prepare(\"SELECT * FROM todos WHERE id=?\");`\n */\n prepare(sql: string): PreparedStatement;\n\n // for PRAGMA statements, schema creation and transaction control.\n execSync(sql: string): void;\n}\n\nexport type CreateSQLiteDatabase = (\n filename: string,\n opts?: SQLiteStoreOptions,\n) => SQLiteDatabase;\n\n/**\n * SQLite-based implementation of the Store interface using a configurable delegate.\n * Supports shared connections between multiple store instances with the same name,\n * providing efficient resource utilization and proper transaction isolation.\n * Uses parameterized queries for safety and performance.\n */\nexport class SQLiteStore implements Store {\n readonly #filename: string;\n readonly #entry: StoreEntry;\n\n #closed = false;\n\n constructor(\n name: string,\n create: CreateSQLiteDatabase,\n opts?: SQLiteStoreOptions,\n ) {\n this.#filename = resolveFilename(name, opts);\n this.#entry = getOrCreateEntry(this.#filename, create, opts);\n }\n\n async read(): Promise<Read> {\n throwIfStoreClosed(this);\n\n const entry = this.#entry;\n const {db, lock, preparedStatements} = entry;\n const release = await lock.read();\n\n // Start shared read transaction if this is the first reader\n // This ensures consistent reads across all concurrent readers\n if (entry.activeReaders === 0) {\n db.execSync('BEGIN');\n }\n entry.activeReaders++;\n\n return new SQLiteStoreRead(() => {\n entry.activeReaders--;\n // Commit shared read transaction when last reader finishes\n if (entry.activeReaders === 0) {\n db.execSync('COMMIT');\n }\n release();\n }, preparedStatements);\n }\n\n async write(): Promise<Write> {\n throwIfStoreClosed(this);\n\n const {lock, db, preparedStatements} = this.#entry;\n const release = await lock.write();\n\n // At this point, RWLock guarantees no active readers\n // The last reader would have already committed the shared transaction\n\n db.execSync('BEGIN IMMEDIATE');\n\n return new SQLiteWrite(release, db, preparedStatements);\n }\n\n async close(): Promise<void> {\n if (this.#closed) {\n return;\n }\n\n const {lock, db} = this.#entry;\n // Wait for all readers and writers to finish.\n const writeRelease = await lock.write();\n\n // Handle reference counting for shared stores - only close database\n // when this is the last store instance using it\n decrementStoreRefCount(this.#filename, db);\n\n this.#closed = true;\n writeRelease();\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nexport function safeFilename(name: string): string {\n return name.replace(/[^a-zA-Z0-9]/g, '_');\n}\n\nfunction resolveFilename(name: string, opts?: SQLiteStoreOptions): string {\n const safe = safeFilename(name);\n const dir = opts?.directory;\n return dir ? `${dir}/${safe}` : safe;\n}\n\nexport type PreparedStatements = {\n has: PreparedStatement;\n get: PreparedStatement;\n hasMany: PreparedStatement;\n getMany: PreparedStatement;\n put: PreparedStatement;\n del: PreparedStatement;\n};\n\nexport interface SQLiteStoreOptions {\n // Common options\n busyTimeout?: number;\n journalMode?: 'WAL' | 'DELETE';\n synchronous?: 'NORMAL' | 'FULL';\n readUncommitted?: boolean;\n /** Directory in which to create the SQLite file. Defaults to the process CWD. */\n directory?: string | undefined;\n}\n\n/**\n * Common database setup logic shared between expo-sqlite and op-sqlite implementations.\n * Configures SQLite pragmas, creates the entry table, and prepares common statements.\n */\n\nexport function setupDatabase(\n delegate: SQLiteDatabase,\n opts?: SQLiteStoreOptions,\n): PreparedStatements {\n // Configure SQLite pragmas for optimal performance\n delegate.execSync(`PRAGMA busy_timeout = ${opts?.busyTimeout ?? 200}`);\n delegate.execSync(`PRAGMA journal_mode = '${opts?.journalMode ?? 'WAL'}'`);\n delegate.execSync(`PRAGMA synchronous = '${opts?.synchronous ?? 'NORMAL'}'`);\n delegate.execSync(\n `PRAGMA read_uncommitted = ${Boolean(opts?.readUncommitted)}`,\n );\n\n // Create the entry table\n delegate.execSync(`\n CREATE TABLE IF NOT EXISTS entry (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n ) WITHOUT ROWID\n `);\n\n // Prepare common statements\n return {\n has: delegate.prepare(`SELECT 1 FROM entry WHERE key = ? LIMIT 1`),\n get: delegate.prepare('SELECT value FROM entry WHERE key = ?'),\n hasMany: delegate.prepare(\n `SELECT key FROM entry WHERE key IN (SELECT value FROM json_each(?))`,\n ),\n getMany: delegate.prepare(\n `SELECT key, value FROM entry WHERE key IN (SELECT value FROM json_each(?))`,\n ),\n put: delegate.prepare(\n `INSERT OR REPLACE INTO entry (key, value)\n SELECT e.value->>0, e.value->1 FROM json_each(?) e`,\n ),\n del: delegate.prepare(\n `DELETE FROM entry WHERE key IN (SELECT value FROM json_each(?))`,\n ),\n };\n}\n\n// Callbacks are stored as striped pairs: [resolve, reject, resolve, reject, ...]\nconst CB_STRIDE = 2;\nconst CB_RESOLVE = 0;\nconst CB_REJECT = 1;\n\ntype GetResolve = (v: ReadonlyJSONValue | undefined) => void;\ntype HasResolve = (v: boolean) => void;\ntype Reject = (e: unknown) => void;\n\nfunction rejectAll(callbacks: unknown[], e: unknown): void {\n for (let i = CB_REJECT; i < callbacks.length; i += CB_STRIDE) {\n (callbacks[i] as Reject)(e);\n }\n}\n\nfunction resolveGet(\n resolve: GetResolve,\n reject: Reject,\n raw: string | undefined,\n): void {\n try {\n resolve(\n raw === undefined\n ? undefined\n : deepFreeze(JSON.parse(raw) as ReadonlyJSONValue),\n );\n } catch (e) {\n reject(e);\n }\n}\n\nasync function flushGets(\n keys: string[],\n callbacks: unknown[],\n ps: PreparedStatements,\n): Promise<void> {\n let rows: unknown[][];\n try {\n rows =\n keys.length === 1\n ? await ps.get.all([keys[0]])\n : await ps.getMany.all([JSON.stringify(keys)]);\n } catch (e) {\n rejectAll(callbacks, e);\n return;\n }\n if (keys.length === 1) {\n resolveGet(\n callbacks[CB_RESOLVE] as GetResolve,\n callbacks[CB_REJECT] as Reject,\n rows[0]?.[0] as string | undefined,\n );\n return;\n }\n const resultMap = new Map(rows as [string, string][]);\n for (let i = 0; i < keys.length; i++) {\n resolveGet(\n callbacks[i * CB_STRIDE + CB_RESOLVE] as GetResolve,\n callbacks[i * CB_STRIDE + CB_REJECT] as Reject,\n resultMap.get(keys[i]),\n );\n }\n}\n\nasync function flushHas(\n keys: string[],\n callbacks: unknown[],\n ps: PreparedStatements,\n): Promise<void> {\n let rows: unknown[][];\n try {\n rows =\n keys.length === 1\n ? await ps.has.all([keys[0]])\n : await ps.hasMany.all([JSON.stringify(keys)]);\n } catch (e) {\n rejectAll(callbacks, e);\n return;\n }\n if (keys.length === 1) {\n (callbacks[CB_RESOLVE] as HasResolve)(rows.length > 0);\n return;\n }\n const existingKeys = new Set(rows.map(row => row[0] as string));\n for (let i = 0; i < keys.length; i++) {\n (callbacks[i * CB_STRIDE + CB_RESOLVE] as HasResolve)(\n existingKeys.has(keys[i]),\n );\n }\n}\n\nexport class SQLiteStoreRead implements Read {\n readonly #release: () => void;\n readonly #preparedStatements: PreparedStatements;\n #closed = false;\n #pendingGetKeys: string[] = [];\n #pendingGetCallbacks: unknown[] = [];\n #pendingHasKeys: string[] = [];\n #pendingHasCallbacks: unknown[] = [];\n #scheduled = false;\n\n constructor(release: () => void, preparedStatements: PreparedStatements) {\n this.#release = release;\n this.#preparedStatements = preparedStatements;\n }\n\n has(key: string): Promise<boolean> {\n return (\n maybeTransactionIsClosedRejection(this) ??\n new Promise((resolve, reject) => {\n this.#pendingHasKeys.push(key);\n this.#pendingHasCallbacks.push(resolve, reject);\n this.#scheduleLookup();\n })\n );\n }\n\n get(key: string): Promise<ReadonlyJSONValue | undefined> {\n return (\n maybeTransactionIsClosedRejection(this) ??\n new Promise((resolve, reject) => {\n this.#pendingGetKeys.push(key);\n this.#pendingGetCallbacks.push(resolve, reject);\n this.#scheduleLookup();\n })\n );\n }\n\n #scheduleLookup(): void {\n if (!this.#scheduled) {\n this.#scheduled = true;\n queueMicrotask(() => {\n this.#scheduled = false;\n\n const ps = this.#preparedStatements;\n const getKeys = this.#pendingGetKeys;\n this.#pendingGetKeys = [];\n const getCallbacks = this.#pendingGetCallbacks;\n this.#pendingGetCallbacks = [];\n const hasKeys = this.#pendingHasKeys;\n this.#pendingHasKeys = [];\n const hasCallbacks = this.#pendingHasCallbacks;\n this.#pendingHasCallbacks = [];\n\n if (this.#closed) {\n const e = transactionError();\n rejectAll(getCallbacks, e);\n rejectAll(hasCallbacks, e);\n return;\n }\n\n if (getKeys.length > 0) {\n void flushGets(getKeys, getCallbacks, ps);\n }\n if (hasKeys.length > 0) {\n void flushHas(hasKeys, hasCallbacks, ps);\n }\n });\n }\n }\n\n release(): void {\n if (!this.#closed) {\n this.#closed = true;\n this.#release();\n }\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nexport class SQLiteWrite extends WriteImplBase implements Write {\n readonly #release: () => void;\n readonly #dbDelegate: SQLiteDatabase;\n readonly #preparedStatements: PreparedStatements;\n #committed = false;\n #closed = false;\n\n constructor(\n release: () => void,\n dbDelegate: SQLiteDatabase,\n preparedStatements: PreparedStatements,\n ) {\n super(new SQLiteStoreRead(() => undefined, preparedStatements));\n this.#release = release;\n this.#dbDelegate = dbDelegate;\n this.#preparedStatements = preparedStatements;\n }\n\n async commit(): Promise<void> {\n if (this.#closed) {\n throw transactionError();\n }\n\n const deleteKeys: string[] = [];\n for (const entry of this._pending) {\n if (entry[1] === deleteSentinel) {\n deleteKeys.push(entry[0]);\n this._pending.delete(entry[0]);\n }\n }\n\n const delP =\n deleteKeys.length > 0\n ? this.#preparedStatements.del.exec([JSON.stringify(deleteKeys)])\n : undefined;\n const putP =\n this._pending.size > 0\n ? this.#preparedStatements.put.exec([\n JSON.stringify([...this._pending]),\n ])\n : undefined;\n\n if (putP) await putP;\n if (delP) await delP;\n\n this.#dbDelegate.execSync('COMMIT');\n this._pending.clear();\n this.#committed = true;\n }\n\n release(): void {\n if (!this.#closed) {\n this.#closed = true;\n super.release();\n let rollbackError: unknown;\n if (!this.#committed) {\n try {\n this.#dbDelegate.execSync('ROLLBACK');\n } catch (e) {\n rollbackError = e;\n }\n }\n this.#release();\n if (rollbackError !== undefined) {\n throw rollbackError;\n }\n }\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\ntype StoreEntry = {\n readonly lock: RWLock;\n readonly db: SQLiteDatabase;\n refCount: number;\n activeReaders: number;\n preparedStatements: PreparedStatements;\n};\n\n// Global map to share database connections between multiple store instances with the same name\nconst stores = new Map<string, StoreEntry>();\n\n/**\n * Gets an existing store entry or creates a new one if it doesn't exist.\n * This implements the shared connection pattern where multiple stores with the same\n * name share the same database connection, lock, and delegate.\n */\nfunction getOrCreateEntry(\n filename: string,\n create: (filename: string, opts?: SQLiteStoreOptions) => SQLiteDatabase,\n opts?: SQLiteStoreOptions,\n): StoreEntry {\n const entry = stores.get(filename);\n\n if (entry) {\n entry.refCount++;\n return entry;\n }\n\n const dbDelegate = create(filename, opts);\n const preparedStatements = setupDatabase(dbDelegate, opts);\n\n const lock = new RWLock();\n\n const newEntry: StoreEntry = {\n lock,\n db: dbDelegate,\n refCount: 1,\n activeReaders: 0,\n preparedStatements,\n };\n stores.set(filename, newEntry);\n return newEntry;\n}\n\n/**\n * Decrements the reference count for a shared store and cleans up resources\n * when the last reference is released.\n */\n\nfunction decrementStoreRefCount(\n filename: string,\n dbDelegate: SQLiteDatabase,\n): void {\n const entry = stores.get(filename);\n if (entry) {\n entry.refCount--;\n if (entry.refCount <= 0) {\n dbDelegate.close();\n stores.delete(filename);\n }\n }\n}\nexport function clearAllNamedStoresForTesting(): void {\n for (const entry of stores.values()) {\n entry.db.close();\n }\n stores.clear();\n}\n\nexport function dropStore(\n name: string,\n createDelegate: (\n filename: string,\n opts?: SQLiteStoreOptions,\n ) => SQLiteDatabase,\n opts?: SQLiteStoreOptions,\n): Promise<void> {\n const filename = resolveFilename(name, opts);\n const entry = stores.get(filename);\n if (entry) {\n try {\n entry.db.close();\n } catch {\n // Ignore close errors\n }\n stores.delete(filename);\n }\n\n // Create a temporary delegate to handle database deletion\n const tempDelegate = createDelegate(filename, opts);\n try {\n // we close the db before destroying it - this\n // caused an issue with expo-sqlite since it requires this\n tempDelegate.close();\n } catch {\n // Ignore close errors\n }\n try {\n tempDelegate.destroy();\n } catch {\n // Destroy errors shouldn't be fatal; the file may already be gone or locked\n }\n\n return Promise.resolve();\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throw-if-closed.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/throw-if-closed.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"throw-if-closed.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/kv/throw-if-closed.ts"],"names":[],"mappings":"AAIA,wBAAgB,gBAAgB,IAAI,KAAK,CAExC;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAC,GAAG,IAAI,CAI1E;AAED,wBAAgB,wBAAwB,CAAC,WAAW,EAAE;IACpD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,GAAG,IAAI,CAIP;AAED,wBAAgB,4BAA4B,mBAE3C;AAED,wBAAgB,iCAAiC,CAAC,WAAW,EAAE;IAC7D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,CAE7B;AAED,wBAAgB,sBAAsB,mBAErC"}
|
|
@@ -8,9 +8,6 @@ function transactionError() {
|
|
|
8
8
|
function throwIfStoreClosed(store) {
|
|
9
9
|
if (store.closed) throw storeError();
|
|
10
10
|
}
|
|
11
|
-
function throwIfTransactionClosed(transaction) {
|
|
12
|
-
if (transaction.closed) throw transactionError();
|
|
13
|
-
}
|
|
14
11
|
function transactionIsClosedRejection() {
|
|
15
12
|
return Promise.reject(transactionError());
|
|
16
13
|
}
|
|
@@ -21,6 +18,6 @@ function storeIsClosedRejection() {
|
|
|
21
18
|
return Promise.reject(storeError());
|
|
22
19
|
}
|
|
23
20
|
//#endregion
|
|
24
|
-
export { maybeTransactionIsClosedRejection, storeIsClosedRejection, throwIfStoreClosed,
|
|
21
|
+
export { maybeTransactionIsClosedRejection, storeIsClosedRejection, throwIfStoreClosed, transactionError, transactionIsClosedRejection };
|
|
25
22
|
|
|
26
23
|
//# sourceMappingURL=throw-if-closed.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throw-if-closed.js","names":[],"sources":["../../../../../replicache/src/kv/throw-if-closed.ts"],"sourcesContent":["function storeError(): Error {\n return new Error('Store is closed');\n}\n\
|
|
1
|
+
{"version":3,"file":"throw-if-closed.js","names":[],"sources":["../../../../../replicache/src/kv/throw-if-closed.ts"],"sourcesContent":["function storeError(): Error {\n return new Error('Store is closed');\n}\n\nexport function transactionError(): Error {\n return new Error('Transaction is closed');\n}\n\nexport function throwIfStoreClosed(store: {readonly closed: boolean}): void {\n if (store.closed) {\n throw storeError();\n }\n}\n\nexport function throwIfTransactionClosed(transaction: {\n readonly closed: boolean;\n}): void {\n if (transaction.closed) {\n throw transactionError();\n }\n}\n\nexport function transactionIsClosedRejection() {\n return Promise.reject(transactionError());\n}\n\nexport function maybeTransactionIsClosedRejection(transaction: {\n readonly closed: boolean;\n}): Promise<never> | undefined {\n return transaction.closed ? transactionIsClosedRejection() : undefined;\n}\n\nexport function storeIsClosedRejection() {\n return Promise.reject(storeError());\n}\n"],"mappings":";AAAA,SAAS,aAAoB;AAC3B,wBAAO,IAAI,MAAM,kBAAkB;;AAGrC,SAAgB,mBAA0B;AACxC,wBAAO,IAAI,MAAM,wBAAwB;;AAG3C,SAAgB,mBAAmB,OAAyC;AAC1E,KAAI,MAAM,OACR,OAAM,YAAY;;AAYtB,SAAgB,+BAA+B;AAC7C,QAAO,QAAQ,OAAO,kBAAkB,CAAC;;AAG3C,SAAgB,kCAAkC,aAEnB;AAC7B,QAAO,YAAY,SAAS,8BAA8B,GAAG,KAAA;;AAG/D,SAAgB,yBAAyB;AACvC,QAAO,QAAQ,OAAO,YAAY,CAAC"}
|
package/out/zero/package.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var package_default = {
|
|
2
2
|
name: "@rocicorp/zero",
|
|
3
|
-
version: "1.6.0-canary.
|
|
3
|
+
version: "1.6.0-canary.6",
|
|
4
4
|
description: "Zero is a web framework for serverless web development.",
|
|
5
5
|
homepage: "https://zero.rocicorp.dev",
|
|
6
6
|
bugs: { "url": "https://bugs.rocicorp.dev" },
|
package/out/zero/package.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.6.0-canary.
|
|
1
|
+
{"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.6.0-canary.6\",\n \"description\": \"Zero is a web framework for serverless web development.\",\n \"homepage\": \"https://zero.rocicorp.dev\",\n \"bugs\": {\n \"url\": \"https://bugs.rocicorp.dev\"\n },\n \"license\": \"Apache-2.0\",\n \"author\": \"Rocicorp, Inc.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rocicorp/mono.git\",\n \"directory\": \"packages/zero\"\n },\n \"bin\": {\n \"analyze-query\": \"./out/zero/src/analyze-query.js\",\n \"ast-to-zql\": \"./out/zero/src/ast-to-zql.js\",\n \"transform-query\": \"./out/zero/src/transform-query.js\",\n \"zero-build-schema\": \"./out/zero/src/build-schema.js\",\n \"zero-cache\": \"./out/zero/src/cli.js\",\n \"zero-cache-dev\": \"./out/zero/src/zero-cache-dev.js\",\n \"zero-deploy-permissions\": \"./out/zero/src/deploy-permissions.js\",\n \"zero-out\": \"./out/zero/src/zero-out.js\"\n },\n \"files\": [\n \"out\",\n \"!*.tsbuildinfo\"\n ],\n \"type\": \"module\",\n \"main\": \"out/zero/src/zero.js\",\n \"module\": \"out/zero/src/zero.js\",\n \"types\": \"out/zero/src/zero.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./out/zero/src/zero.d.ts\",\n \"default\": \"./out/zero/src/zero.js\"\n },\n \"./analyze\": {\n \"types\": \"./out/zero/src/analyze.d.ts\",\n \"default\": \"./out/zero/src/analyze.js\"\n },\n \"./bindings\": {\n \"types\": \"./out/zero/src/bindings.d.ts\",\n \"default\": \"./out/zero/src/bindings.js\"\n },\n \"./change-protocol/v0\": {\n \"types\": \"./out/zero/src/change-protocol/v0.d.ts\",\n \"default\": \"./out/zero/src/change-protocol/v0.js\"\n },\n \"./expo-sqlite\": {\n \"types\": \"./out/zero/src/expo-sqlite.d.ts\",\n \"default\": \"./out/zero/src/expo-sqlite.js\"\n },\n \"./op-sqlite\": {\n \"types\": \"./out/zero/src/op-sqlite.d.ts\",\n \"default\": \"./out/zero/src/op-sqlite.js\"\n },\n \"./pg\": {\n \"types\": \"./out/zero/src/pg.d.ts\",\n \"default\": \"./out/zero/src/pg.js\"\n },\n \"./react\": {\n \"types\": \"./out/zero/src/react.d.ts\",\n \"default\": \"./out/zero/src/react.js\"\n },\n \"./react-native\": {\n \"types\": \"./out/zero/src/react-native.d.ts\",\n \"default\": \"./out/zero/src/react-native.js\"\n },\n \"./server\": {\n \"types\": \"./out/zero/src/server.d.ts\",\n \"default\": \"./out/zero/src/server.js\"\n },\n \"./server/adapters/drizzle\": {\n \"types\": \"./out/zero/src/adapters/drizzle.d.ts\",\n \"default\": \"./out/zero/src/adapters/drizzle.js\"\n },\n \"./server/adapters/kysely\": {\n \"types\": \"./out/zero/src/adapters/kysely.d.ts\",\n \"default\": \"./out/zero/src/adapters/kysely.js\"\n },\n \"./server/adapters/prisma\": {\n \"types\": \"./out/zero/src/adapters/prisma.d.ts\",\n \"default\": \"./out/zero/src/adapters/prisma.js\"\n },\n \"./server/adapters/pg\": {\n \"types\": \"./out/zero/src/adapters/pg.d.ts\",\n \"default\": \"./out/zero/src/adapters/pg.js\"\n },\n \"./server/adapters/postgresjs\": {\n \"types\": \"./out/zero/src/adapters/postgresjs.d.ts\",\n \"default\": \"./out/zero/src/adapters/postgresjs.js\"\n },\n \"./solid\": {\n \"types\": \"./out/zero/src/solid.d.ts\",\n \"default\": \"./out/zero/src/solid.js\"\n },\n \"./sqlite\": {\n \"types\": \"./out/zero/src/sqlite.d.ts\",\n \"default\": \"./out/zero/src/sqlite.js\"\n },\n \"./zqlite\": {\n \"types\": \"./out/zero/src/zqlite.d.ts\",\n \"default\": \"./out/zero/src/zqlite.js\"\n }\n },\n \"scripts\": {\n \"build\": \"node --experimental-strip-types --no-warnings tool/build.ts\",\n \"build:watch\": \"node --experimental-strip-types --no-warnings tool/build.ts --watch\",\n \"check-types\": \"tsc -p tsconfig.client.json && tsc -p tsconfig.server.json\",\n \"check-types:client:watch\": \"tsc -p tsconfig.client.json --watch\",\n \"check-types:server:watch\": \"tsc -p tsconfig.server.json --watch\",\n \"format\": \"oxfmt .\",\n \"check-format\": \"oxfmt --check .\",\n \"lint\": \"oxlint --quiet --config ../../oxlint.config.ts src/\",\n \"docs\": \"node --experimental-strip-types --no-warnings tool/generate-docs.ts\",\n \"docs:server\": \"node --watch --experimental-strip-types --no-warnings tool/generate-docs.ts --server\",\n \"fmt\": \"oxfmt .\",\n \"check-fmt\": \"oxfmt --check .\"\n },\n \"dependencies\": {\n \"@badrap/valita\": \"0.3.11\",\n \"@databases/escape-identifier\": \"^1.0.3\",\n \"@databases/sql\": \"^3.3.0\",\n \"@dotenvx/dotenvx\": \"^1.39.0\",\n \"@drdgvhbh/postgres-error-codes\": \"^0.0.6\",\n \"@fastify/cors\": \"^10.0.0\",\n \"@fastify/websocket\": \"^11.0.0\",\n \"@google-cloud/precise-date\": \"^4.0.0\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/api-logs\": \"^0.203.0\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.62.0\",\n \"@opentelemetry/exporter-metrics-otlp-http\": \"^0.203.0\",\n \"@opentelemetry/resources\": \"^2.0.1\",\n \"@opentelemetry/sdk-metrics\": \"^2.0.1\",\n \"@opentelemetry/sdk-node\": \"^0.203.0\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@postgresql-typed/oids\": \"^0.2.0\",\n \"@rocicorp/lock\": \"^1.0.4\",\n \"@rocicorp/logger\": \"^5.4.0\",\n \"@rocicorp/resolver\": \"^1.0.2\",\n \"@rocicorp/zero-sqlite3\": \"^1.0.18\",\n \"@standard-schema/spec\": \"^1.0.0\",\n \"@types/basic-auth\": \"^1.1.8\",\n \"@types/ws\": \"^8.5.12\",\n \"basic-auth\": \"^2.0.1\",\n \"chalk-template\": \"^1.1.0\",\n \"chokidar\": \"^4.0.1\",\n \"cloudevents\": \"^10.0.0\",\n \"command-line-args\": \"^6.0.1\",\n \"command-line-usage\": \"^7.0.3\",\n \"compare-utf8\": \"^0.2.0\",\n \"defu\": \"^6.1.4\",\n \"eventemitter3\": \"^5.0.1\",\n \"fastify\": \"^5.0.0\",\n \"is-in-subnet\": \"^4.0.1\",\n \"jose\": \"^5.9.3\",\n \"js-xxhash\": \"^4.0.0\",\n \"json-custom-numbers\": \"^3.1.1\",\n \"kasi\": \"^1.1.0\",\n \"nanoid\": \"^5.1.2\",\n \"oxfmt\": \"^0.45.0\",\n \"parse-prometheus-text-format\": \"^1.1.1\",\n \"pg-format\": \"npm:pg-format-fix@^1.0.5\",\n \"postgres\": \"3.4.7\",\n \"semver\": \"^7.5.4\",\n \"tsx\": \"^4.21.0\",\n \"url-pattern\": \"^1.0.3\",\n \"urlpattern-polyfill\": \"^10.1.0\",\n \"ws\": \"^8.18.1\"\n },\n \"devDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"@vitest/runner\": \"^4.1.5\",\n \"analyze-query\": \"0.0.0\",\n \"ast-to-zql\": \"0.0.0\",\n \"expo-sqlite\": \">=15\",\n \"replicache\": \"15.2.1\",\n \"shared\": \"0.0.0\",\n \"syncpack\": \"^14.3.0\",\n \"typedoc\": \"^0.28.17\",\n \"typedoc-plugin-markdown\": \"^4.10.0\",\n \"typescript\": \"~6.0.2\",\n \"vite\": \"8.0.3\",\n \"vitest\": \"^4.1.5\",\n \"zero-cache\": \"0.0.0\",\n \"zero-client\": \"0.0.0\",\n \"zero-pg\": \"0.0.0\",\n \"zero-react\": \"0.0.0\",\n \"zero-server\": \"0.0.0\",\n \"zero-solid\": \"0.0.0\",\n \"zqlite\": \"0.0.0\"\n },\n \"peerDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"expo-sqlite\": \">=15\",\n \"kysely\": \"^0.28.16\"\n },\n \"peerDependenciesMeta\": {\n \"kysely\": {\n \"optional\": true\n },\n \"expo-sqlite\": {\n \"optional\": true\n },\n \"@op-engineering/op-sqlite\": {\n \"optional\": true\n }\n },\n \"engines\": {\n \"node\": \">=22\"\n }\n}"],"mappings":""}
|
|
@@ -4,7 +4,7 @@ import { parentWorker, singleProcessMode } from "../types/processes.js";
|
|
|
4
4
|
import { getShardConfig } from "../types/shards.js";
|
|
5
5
|
import { getNormalizedZeroConfig } from "../config/zero-config.js";
|
|
6
6
|
import { DatabaseInitError } from "../../../zqlite/src/db.js";
|
|
7
|
-
import {
|
|
7
|
+
import { connectPgClient } from "../types/pg.js";
|
|
8
8
|
import { exitAfter, runUntilKilled } from "../services/life-cycle.js";
|
|
9
9
|
import { createLogContext } from "./logging.js";
|
|
10
10
|
import { getServerContext } from "../config/server-context.js";
|
|
@@ -37,7 +37,7 @@ async function runWorker(parent, env, ...argv) {
|
|
|
37
37
|
startOtelAuto(createLogContext(config, "change-streamer", 0, false), "change-streamer", 0);
|
|
38
38
|
lc = createLogContext(config, "change-streamer");
|
|
39
39
|
initEventSink(lc, config);
|
|
40
|
-
const changeDB =
|
|
40
|
+
const changeDB = await connectPgClient(lc, change.db, "change-streamer", { max: change.maxConns }, { sendStringAsJson: true });
|
|
41
41
|
warmupConnections(lc, changeDB, "change").catch(() => {});
|
|
42
42
|
const { autoReset, replicationLag } = config;
|
|
43
43
|
const shard = getShardConfig(config);
|
|
@@ -88,7 +88,10 @@ async function runWorker(parent, env, ...argv) {
|
|
|
88
88
|
parent.send(["ready", { ready: true }]);
|
|
89
89
|
return runUntilKilled(lc, parent, changeStreamerWebServer, monitor);
|
|
90
90
|
}
|
|
91
|
-
if (!singleProcessMode()) exitAfter(lc, () => runWorker(must(parentWorker), process.env, ...process.argv.slice(2)).catch((e) =>
|
|
91
|
+
if (!singleProcessMode()) exitAfter(lc, () => runWorker(must(parentWorker), process.env, ...process.argv.slice(2)).catch(async (e) => {
|
|
92
|
+
await publishCriticalEvent(lc, replicationStatusError(lc, "Initializing", e));
|
|
93
|
+
throw e;
|
|
94
|
+
}));
|
|
92
95
|
//#endregion
|
|
93
96
|
export { runWorker as default };
|
|
94
97
|
|