@aiao/rxdb-adapter-electron 0.0.26 → 0.0.28

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.
Files changed (59) hide show
  1. package/README.md +122 -21
  2. package/dist/RxDBAdapterElectron.d.ts +27 -1
  3. package/dist/RxDBAdapterElectron.d.ts.map +1 -1
  4. package/dist/electron-sqlite-host.d.ts.map +1 -1
  5. package/dist/host.d.ts +1 -1
  6. package/dist/host.d.ts.map +1 -1
  7. package/dist/host.js +46 -40
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +20 -6
  11. package/dist/node-sqlite-engine.d.ts +10 -0
  12. package/dist/node-sqlite-engine.d.ts.map +1 -1
  13. package/dist/pglite/RxDBAdapterElectronPGlite.d.ts +53 -1
  14. package/dist/pglite/RxDBAdapterElectronPGlite.d.ts.map +1 -1
  15. package/dist/pglite/desktop-pglite-client.d.ts +27 -1
  16. package/dist/pglite/desktop-pglite-client.d.ts.map +1 -1
  17. package/dist/pglite/desktop-pglite-results.d.ts +14 -0
  18. package/dist/pglite/desktop-pglite-results.d.ts.map +1 -0
  19. package/dist/pglite/electron-pglite-backup-error.d.ts +32 -0
  20. package/dist/pglite/electron-pglite-backup-error.d.ts.map +1 -0
  21. package/dist/pglite/pglite-adapter.interface.d.ts +12 -0
  22. package/dist/pglite/pglite-adapter.interface.d.ts.map +1 -1
  23. package/dist/pglite/restore-electron-pglite-database.d.ts +68 -0
  24. package/dist/pglite/restore-electron-pglite-database.d.ts.map +1 -0
  25. package/dist/pglite-host/electron-pglite-host.d.ts +47 -32
  26. package/dist/pglite-host/electron-pglite-host.d.ts.map +1 -1
  27. package/dist/pglite-host/pglite-host-data-dir.d.ts +75 -0
  28. package/dist/pglite-host/pglite-host-data-dir.d.ts.map +1 -0
  29. package/dist/pglite-host/pglite-host-lock.d.ts +48 -0
  30. package/dist/pglite-host/pglite-host-lock.d.ts.map +1 -0
  31. package/dist/pglite-host/pglite-host-restore.d.ts +38 -0
  32. package/dist/pglite-host/pglite-host-restore.d.ts.map +1 -0
  33. package/dist/pglite-host/pglite-host-runtime.d.ts +90 -0
  34. package/dist/pglite-host/pglite-host-runtime.d.ts.map +1 -0
  35. package/dist/pglite-host.d.ts +2 -2
  36. package/dist/pglite-host.d.ts.map +1 -1
  37. package/dist/pglite-host.js +643 -120
  38. package/dist/pglite.d.ts +2 -0
  39. package/dist/pglite.d.ts.map +1 -1
  40. package/dist/pglite.js +341 -65
  41. package/package.json +13 -10
  42. package/src/RxDBAdapterElectron.ts +40 -1
  43. package/src/electron-sqlite-host.ts +3 -0
  44. package/src/host.ts +1 -0
  45. package/src/index.ts +1 -0
  46. package/src/node-sqlite-engine.ts +20 -1
  47. package/src/pglite/RxDBAdapterElectronPGlite.ts +80 -5
  48. package/src/pglite/desktop-pglite-client.ts +111 -17
  49. package/src/pglite/desktop-pglite-results.ts +24 -0
  50. package/src/pglite/electron-pglite-backup-error.ts +128 -0
  51. package/src/pglite/pglite-adapter.interface.ts +14 -0
  52. package/src/pglite/restore-electron-pglite-database.ts +429 -0
  53. package/src/pglite-host/electron-pglite-host.ts +409 -160
  54. package/src/pglite-host/pglite-host-data-dir.ts +224 -0
  55. package/src/pglite-host/pglite-host-lock.ts +154 -0
  56. package/src/pglite-host/pglite-host-restore.ts +460 -0
  57. package/src/pglite-host/pglite-host-runtime.ts +166 -0
  58. package/src/pglite-host.ts +7 -0
  59. package/src/pglite.ts +9 -0
@@ -1,27 +1,416 @@
1
- import { DESKTOP_PGLITE_DEFAULT_BEGIN_TIMEOUT_MS as e, DESKTOP_PGLITE_MAX_BEGIN_TIMEOUT_MS as t, DESKTOP_PGLITE_PROTOCOL_VERSION as n, DESKTOP_PGLITE_PROTOCOL_VERSION as r, RxDBAdapterDesktopError as i, RxDBAdapterDesktopError as a, assertValidDesktopDatabaseName as o, isDesktopPgliteRequestKind as s, parseDesktopPgliteRequest as c, parseDesktopPgliteRequest as l } from "@aiao/rxdb-adapter-sqlite-core/desktop-host";
2
- import { randomUUID as u } from "node:crypto";
3
- //#region src/pglite-host/electron-pglite-host.ts
4
- var d = "desktop-pglite://app-scope", f = Object.freeze([
5
- "rxdb_change_notify",
6
- "rxdb_branch_notify",
7
- "rxdb_migration_notify"
8
- ]), p = Symbol("pg.begin timed out"), m = async (e, t) => {
9
- let n;
1
+ import { DESKTOP_PGLITE_DEFAULT_BEGIN_TIMEOUT_MS as e, DESKTOP_PGLITE_EXCLUDED_FILES as t, DESKTOP_PGLITE_EXCLUDED_FILES as n, DESKTOP_PGLITE_MAX_BEGIN_TIMEOUT_MS as r, DESKTOP_PGLITE_MAX_DATA_CHUNK_BYTES as i, DESKTOP_PGLITE_MAX_DATA_CHUNK_BYTES as a, DESKTOP_PGLITE_PROTOCOL_VERSION as o, DESKTOP_PGLITE_PROTOCOL_VERSION as s, RxDBAdapterDesktopError as c, RxDBAdapterDesktopError as l, assertValidDesktopDatabaseName as u, isDesktopPgliteRequestKind as d, parseDesktopPgliteRequest as f, parseDesktopPgliteRequest as p } from "@aiao/rxdb-adapter-sqlite-core/desktop-host";
2
+ import { randomUUID as m } from "node:crypto";
3
+ import { DatabaseSync as h } from "node:sqlite";
4
+ import { lstat as g, mkdir as _, open as v, readdir as y, rm as b } from "node:fs/promises";
5
+ import { basename as x, dirname as S, join as C } from "node:path";
6
+ import { mkdirSync as w } from "node:fs";
7
+ //#region src/pglite-host/pglite-host-data-dir.ts
8
+ var T = /* @__PURE__ */ new Map([
9
+ ["ENOSPC", "disk_full"],
10
+ ["EDQUOT", "disk_full"],
11
+ ["EACCES", "permission_denied"],
12
+ ["EPERM", "permission_denied"],
13
+ ["EROFS", "permission_denied"],
14
+ ["ENOENT", "file_not_found"]
15
+ ]), E = (e) => {
16
+ let t = e?.code;
17
+ return typeof t == "string" ? t : void 0;
18
+ }, D = (e, t) => {
19
+ if (e instanceof l) return e;
20
+ let n = T.get(E(e) ?? "") ?? "host_internal_error";
21
+ return new l(n, t, { cause: e });
22
+ }, O = async (e) => (await y(e)).filter((e) => !n.has(e)).sort();
23
+ async function* k(e, t, n) {
24
+ let r = await v(e, "r");
10
25
  try {
11
- return await Promise.race([e, new Promise((e) => {
12
- n = setTimeout(() => e(p), t);
13
- })]);
26
+ let e = 0;
27
+ for (; e < t;) {
28
+ let i = new Uint8Array(Math.min(a, t - e)), { bytesRead: o } = await r.read(i, 0, i.length, e);
29
+ if (o <= 0) throw new l("host_internal_error", `data file shrank while being read: ${n}`);
30
+ yield {
31
+ type: "data",
32
+ bytes: o === i.length ? i : i.slice(0, o)
33
+ }, e += o;
34
+ }
14
35
  } finally {
15
- clearTimeout(n);
36
+ await r.close();
37
+ }
38
+ }
39
+ async function* A(e, t) {
40
+ for (let n of await O(e)) {
41
+ let r = C(e, n), i = t === "" ? n : `${t}/${n}`, a = await g(r);
42
+ if (a.isDirectory()) {
43
+ yield {
44
+ type: "entry",
45
+ header: {
46
+ path: i,
47
+ kind: "directory",
48
+ size: 0
49
+ }
50
+ }, yield* A(r, i);
51
+ continue;
52
+ }
53
+ if (!a.isFile()) throw new l("host_internal_error", `unsupported file type in the data directory: ${i}`);
54
+ yield {
55
+ type: "entry",
56
+ header: {
57
+ path: i,
58
+ kind: "file",
59
+ size: a.size
60
+ }
61
+ }, yield* k(r, a.size, i);
16
62
  }
17
- }, h = (e) => ({
63
+ }
64
+ async function* ee(e) {
65
+ try {
66
+ yield* A(e, "");
67
+ } catch (e) {
68
+ throw D(e, "failed to read the PGlite data directory");
69
+ }
70
+ }
71
+ var j = async (e) => {
72
+ try {
73
+ return (await y(e)).length === 0;
74
+ } catch (e) {
75
+ let t = E(e);
76
+ if (t === "ENOENT") return !0;
77
+ if (t === "ENOTDIR") return !1;
78
+ throw D(e, "failed to inspect the restore target");
79
+ }
80
+ }, M = async (e) => {
81
+ try {
82
+ return (await g(C(e, "PG_VERSION"))).isFile();
83
+ } catch (e) {
84
+ if (E(e) === "ENOENT") return !1;
85
+ throw D(e, "failed to inspect the PGlite data directory");
86
+ }
87
+ }, N = async (e, t) => {
88
+ let n = await v(e, t);
89
+ try {
90
+ await n.sync();
91
+ } finally {
92
+ await n.close();
93
+ }
94
+ }, P = async (e) => {
95
+ process.platform !== "win32" && await N(e, "r");
96
+ }, F = async (e) => {
97
+ for (let t of await y(e)) {
98
+ let n = C(e, t);
99
+ (await g(n)).isDirectory() ? await F(n) : await N(n, "r+");
100
+ }
101
+ await P(e);
102
+ }, I = async (e) => {
103
+ try {
104
+ await F(e), await P(S(e));
105
+ } catch (e) {
106
+ throw D(e, "failed to persist the restored PGlite data directory");
107
+ }
108
+ }, L = async (e) => {
109
+ try {
110
+ await b(e, {
111
+ recursive: !0,
112
+ force: !0,
113
+ maxRetries: 3
114
+ });
115
+ } catch (e) {
116
+ throw D(e, "failed to remove the PGlite data directory");
117
+ }
118
+ }, R = (e) => C(S(e), `.${x(e)}.rxdb-lock`), z = "\n PRAGMA busy_timeout = 0;\n PRAGMA locking_mode = EXCLUSIVE;\n PRAGMA journal_mode = DELETE;\n PRAGMA synchronous = FULL;\n BEGIN EXCLUSIVE;\n CREATE TABLE IF NOT EXISTS holder (id INTEGER PRIMARY KEY, pid INTEGER NOT NULL);\n CREATE TABLE IF NOT EXISTS restore_marker (id INTEGER PRIMARY KEY, created_at TEXT NOT NULL);\n", B = /* @__PURE__ */ new Map([
119
+ [3, "permission_denied"],
120
+ [5, "database_busy"],
121
+ [6, "database_busy"],
122
+ [8, "permission_denied"],
123
+ [13, "disk_full"],
124
+ [23, "permission_denied"]
125
+ ]), V = (e, t, n) => {
126
+ let r = e?.errcode, i = typeof r == "number" ? B.get(r & 255) : void 0;
127
+ return new l(i ?? t, n, { cause: e });
128
+ }, H = (e, t) => {
129
+ try {
130
+ w(S(e), {
131
+ recursive: !0,
132
+ mode: 448
133
+ });
134
+ } catch (e) {
135
+ throw D(e, "failed to create the parent of the PGlite data directory");
136
+ }
137
+ try {
138
+ return new h(e);
139
+ } catch (e) {
140
+ throw V(e, "open_failed", `failed to open the lock of PGlite data directory "${x(t)}"`);
141
+ }
142
+ }, U = (e) => {
143
+ let t = H(R(e), e);
144
+ try {
145
+ t.exec(z), t.prepare("INSERT OR REPLACE INTO holder (id, pid) VALUES (1, ?)").run(process.pid), t.exec("COMMIT");
146
+ } catch (n) {
147
+ throw t.close(), V(n, "open_failed", `failed to lock PGlite data directory "${x(e)}"`);
148
+ }
149
+ let n = !1, r = (e, t) => {
150
+ try {
151
+ return e();
152
+ } catch (e) {
153
+ throw V(e, "host_internal_error", t);
154
+ }
155
+ };
156
+ return {
157
+ hasMarker: () => r(() => t.prepare("SELECT 1 FROM restore_marker LIMIT 1").get() !== void 0, "failed to read the restore marker"),
158
+ markRestoring: () => r(() => {
159
+ t.prepare("INSERT OR REPLACE INTO restore_marker (id, created_at) VALUES (1, ?)").run((/* @__PURE__ */ new Date()).toISOString());
160
+ }, "failed to persist the restore marker"),
161
+ clearRestoring: () => r(() => {
162
+ t.exec("DELETE FROM restore_marker");
163
+ }, "failed to remove the restore marker"),
164
+ release: () => {
165
+ n || (n = !0, t.close());
166
+ }
167
+ };
168
+ }, W = (e) => ({
18
169
  rows: e.rows,
19
170
  fields: e.fields.map((e) => ({
20
171
  name: e.name,
21
172
  dataTypeID: e.dataTypeID
22
173
  })),
23
174
  affectedRows: e.affectedRows
24
- }), g = (e) => e instanceof a ? {
175
+ }), G = async (e) => {
176
+ try {
177
+ return await e();
178
+ } catch (e) {
179
+ throw e instanceof l ? e : new l("statement_failed", e instanceof Error ? e.message : String(e), { cause: e });
180
+ }
181
+ }, K = Symbol("transaction begin timed out"), q = async (e, t) => {
182
+ let n;
183
+ try {
184
+ return await Promise.race([e, new Promise((e) => {
185
+ n = setTimeout(() => e(K), t);
186
+ })]);
187
+ } finally {
188
+ clearTimeout(n);
189
+ }
190
+ }, J = async (e, t) => {
191
+ let n, r = new Promise((e, t) => {
192
+ n = {
193
+ resolve: e,
194
+ reject: t
195
+ };
196
+ });
197
+ r.catch(() => void 0);
198
+ let i, a = new Promise((e) => {
199
+ i = e;
200
+ }), o = e.transaction(async (e) => {
201
+ i(e), await r;
202
+ });
203
+ o.catch(() => void 0);
204
+ let s = await q(a, t);
205
+ if (s === K) throw n.reject(new l("transaction_unavailable", "the begin that opened this transaction timed out")), new l("transaction_unavailable", `waited ${t}ms for the PGlite connection but another transaction still holds it`);
206
+ return {
207
+ tx: s,
208
+ settle: n,
209
+ finished: o
210
+ };
211
+ }, Y = /* @__PURE__ */ new Set([
212
+ "EEXIST",
213
+ "ENOENT",
214
+ "ENOTDIR"
215
+ ]), X = (e, t) => new l("database_corrupted", e, t), te = (e) => e instanceof l ? e : Y.has(E(e) ?? "") ? X("the archive does not describe a valid directory tree", { cause: e }) : D(e, "failed to write the restored PGlite data directory"), Z = (e, t) => new l("protocol_violation", `${t} is not allowed while the restore is ${e.stage}`), Q = (e, t, n) => {
216
+ if (e.stage !== t) throw Z(e, n);
217
+ }, ne = async (e, t) => {
218
+ let n = e.file;
219
+ if (n === void 0) throw X("a data chunk arrived without a file entry");
220
+ if (n.written + t.byteLength > n.size) throw X(`the data of "${n.path}" exceeds its declared size`);
221
+ await n.handle.writeFile(t), n.written += t.byteLength, !(n.written < n.size) && (e.file = void 0, await n.handle.close());
222
+ }, re = async (e, t) => {
223
+ if (e.file !== void 0) throw X(`the data of "${e.file.path}" is incomplete`);
224
+ let n = C(e.directory, ...t.path.split("/"));
225
+ if (t.kind === "directory") {
226
+ await _(n, { mode: 448 });
227
+ return;
228
+ }
229
+ let r = await v(n, "wx", 384);
230
+ if (t.size === 0) {
231
+ await r.close();
232
+ return;
233
+ }
234
+ e.file = {
235
+ handle: r,
236
+ path: t.path,
237
+ size: t.size,
238
+ written: 0
239
+ };
240
+ }, ie = (e) => {
241
+ let t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map(), r = async (n, r) => {
242
+ if (await e.isInUse(n) || t.has(n)) throw new l("database_busy", `"${n}" is open or being restored in this host`);
243
+ t.add(n);
244
+ try {
245
+ return U(r);
246
+ } catch (e) {
247
+ throw t.delete(n), e;
248
+ }
249
+ }, i = (e, n) => {
250
+ t.delete(e), n.release();
251
+ }, a = async (e, t, n) => {
252
+ try {
253
+ await L(t), n.clearRestoring();
254
+ } catch (t) {
255
+ throw new l("cleanup_pending", `the incomplete restore of "${e}" could not be removed; run pg.restore.cleanup to retry`, { cause: t });
256
+ }
257
+ }, o = async (t, a) => {
258
+ let o = t.storage.dataDirectoryName, s = e.resolveDataDirectory(o), c = await r(o, s);
259
+ try {
260
+ if (c.hasMarker()) throw new l("restore_incomplete", `a restore of "${o}" did not finish; run pg.restore.cleanup first`);
261
+ if (!await j(s)) throw new l("target_not_empty", `"${o}" already holds data`);
262
+ } catch (e) {
263
+ throw i(o, c), e;
264
+ }
265
+ let u = m();
266
+ return n.set(u, {
267
+ id: u,
268
+ owner: a,
269
+ dataDirectoryName: o,
270
+ directory: s,
271
+ lock: c,
272
+ stage: "begun",
273
+ marked: !1,
274
+ file: void 0,
275
+ runtime: void 0,
276
+ tail: Promise.resolve(),
277
+ finished: !1
278
+ }), {
279
+ kind: "pg.restore.begin",
280
+ result: { restoreId: u }
281
+ };
282
+ }, s = async (t) => {
283
+ let n = t.storage.dataDirectoryName, o = e.resolveDataDirectory(n), s = await r(n, o);
284
+ try {
285
+ return s.hasMarker() ? (await a(n, o, s), {
286
+ kind: "pg.restore.cleanup",
287
+ result: { cleaned: !0 }
288
+ }) : {
289
+ kind: "pg.restore.cleanup",
290
+ result: { cleaned: !1 }
291
+ };
292
+ } finally {
293
+ i(n, s);
294
+ }
295
+ }, c = (e, t) => {
296
+ let r = n.get(e);
297
+ if (r === void 0) throw new l("transaction_not_found", `restore ${e} is unknown or already finished`);
298
+ if (r.owner !== t) throw new l("permission_denied", `restore ${e} belongs to another window`);
299
+ return r;
300
+ }, u = (e, t) => {
301
+ let n = e.tail.then(() => {
302
+ if (e.finished) throw new l("transaction_not_found", `restore ${e.id} is already finished`);
303
+ return t();
304
+ });
305
+ return e.tail = n.then(() => void 0, () => void 0), n;
306
+ }, d = async (e) => {
307
+ let { file: t, runtime: n } = e;
308
+ e.file = void 0, e.runtime = void 0, await t?.handle.close().catch(() => void 0), await n?.close().catch(() => void 0);
309
+ }, f = async (e, t) => {
310
+ try {
311
+ await t();
312
+ } catch (t) {
313
+ throw t instanceof l && t.code === "protocol_violation" || (e.stage = "failed", await d(e)), t;
314
+ }
315
+ }, p = (e) => {
316
+ e.finished = !0, n.delete(e.id), i(e.dataDirectoryName, e.lock);
317
+ }, h = async (e) => {
318
+ Q(e, "begun", "pg.restore.prepare"), e.lock.markRestoring(), e.marked = !0;
319
+ try {
320
+ await _(e.directory, {
321
+ recursive: !0,
322
+ mode: 448
323
+ });
324
+ } catch (e) {
325
+ throw D(e, "failed to create the restore target");
326
+ }
327
+ e.stage = "prepared";
328
+ }, g = async (e, t) => {
329
+ Q(e, "prepared", "pg.restore.write");
330
+ try {
331
+ await (t.type === "data" ? ne(e, t.bytes) : re(e, t.header));
332
+ } catch (e) {
333
+ throw te(e);
334
+ }
335
+ }, v = async (t) => {
336
+ let n;
337
+ try {
338
+ return n = await e.createRuntime(t), await n.query("SELECT 1"), n;
339
+ } catch (e) {
340
+ throw await n?.close().catch(() => void 0), X("the restored data directory cannot be opened", { cause: e });
341
+ }
342
+ }, y = async (e) => {
343
+ if (Q(e, "prepared", "pg.restore.open"), e.file !== void 0) throw X(`the data of "${e.file.path}" is incomplete`);
344
+ if (!await M(e.directory)) throw X("the archive has no PG_VERSION");
345
+ e.runtime = await v(e.dataDirectoryName), e.stage = "opened";
346
+ }, b = (e, t) => {
347
+ let n = e.runtime;
348
+ if (n === void 0) throw Z(e, t);
349
+ return n;
350
+ }, x = async (e, t) => {
351
+ let n = b(e, t.kind);
352
+ return W(await G(() => n.query(t.sql, [...t.params])));
353
+ }, S = async (e) => {
354
+ let t = b(e, "pg.restore.persist");
355
+ e.runtime = void 0;
356
+ try {
357
+ await t.close();
358
+ } catch (e) {
359
+ throw D(e, "failed to close the restored PGlite instance");
360
+ }
361
+ await I(e.directory), e.stage = "persisted";
362
+ }, C = (e) => {
363
+ Q(e, "persisted", "pg.restore.commit"), e.lock.clearRestoring(), p(e);
364
+ }, w = async (e) => {
365
+ try {
366
+ await d(e), e.marked && await a(e.dataDirectoryName, e.directory, e.lock);
367
+ } finally {
368
+ p(e);
369
+ }
370
+ }, T = (e) => u(e, async () => {
371
+ await d(e), p(e);
372
+ }).catch(() => void 0), E = async (e, t) => {
373
+ switch (t.kind) {
374
+ case "pg.restore.prepare": return await f(e, () => h(e)), { kind: "pg.restore.prepare" };
375
+ case "pg.restore.write": return await f(e, () => g(e, t.item)), { kind: "pg.restore.write" };
376
+ case "pg.restore.open": return await f(e, () => y(e)), { kind: "pg.restore.open" };
377
+ case "pg.restore.query": return {
378
+ kind: "pg.restore.query",
379
+ result: await x(e, t)
380
+ };
381
+ case "pg.restore.persist": return await f(e, () => S(e)), { kind: "pg.restore.persist" };
382
+ case "pg.restore.commit": return await f(e, async () => C(e)), { kind: "pg.restore.commit" };
383
+ case "pg.restore.abort": return await w(e), { kind: "pg.restore.abort" };
384
+ default: throw new l("protocol_violation", `unsupported restore request kind: ${String(t.kind)}`);
385
+ }
386
+ }, O = async (e, t) => {
387
+ let n = c(e.restoreId, t);
388
+ return u(n, () => E(n, e));
389
+ };
390
+ return {
391
+ get openCount() {
392
+ return n.size;
393
+ },
394
+ isReserved: (e) => t.has(e),
395
+ handle: async (e, t) => {
396
+ switch (e.kind) {
397
+ case "pg.restore.begin": return o(e, t);
398
+ case "pg.restore.cleanup": return s(e);
399
+ default: return O(e, t);
400
+ }
401
+ },
402
+ releaseOwner: async (e) => {
403
+ await Promise.all([...n.values()].filter((t) => t.owner === e).map(T));
404
+ },
405
+ closeAll: async () => {
406
+ await Promise.all([...n.values()].map(T));
407
+ }
408
+ };
409
+ }, ae = "desktop-pglite://app-scope", $ = Object.freeze([
410
+ "rxdb_change_notify",
411
+ "rxdb_branch_notify",
412
+ "rxdb_migration_notify"
413
+ ]), oe = (e) => e instanceof l ? {
25
414
  kind: "error",
26
415
  code: e.code,
27
416
  message: e.detail
@@ -29,15 +418,20 @@ var d = "desktop-pglite://app-scope", f = Object.freeze([
29
418
  kind: "error",
30
419
  code: "host_internal_error",
31
420
  message: e instanceof Error ? e.message : String(e)
32
- }, _ = async (e) => {
33
- try {
34
- return await e();
35
- } catch (e) {
36
- throw e instanceof a ? e : new a("statement_failed", e instanceof Error ? e.message : String(e), { cause: e });
37
- }
38
- };
39
- function v(e) {
40
- let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), o = (t, n, r) => {
421
+ }, se = (e, t) => new l("open_failed", `the application could not open a PGlite runtime for ${e}`, { cause: t });
422
+ function ce(e) {
423
+ let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o, c = async (e) => {
424
+ for (; a.has(e);) await a.get(e);
425
+ return t.has(e);
426
+ }, u = e.backup, d = u === void 0 ? void 0 : {
427
+ options: u,
428
+ extensions: [...new Set(u.extensions)].sort(),
429
+ restores: ie({
430
+ createRuntime: (t) => e.createRuntime(t),
431
+ resolveDataDirectory: (e) => u.resolveDataDirectory(e),
432
+ isInUse: c
433
+ })
434
+ }, f = (t, n, r) => {
41
435
  try {
42
436
  e.postNotify({
43
437
  kind: "pg.notify",
@@ -48,148 +442,270 @@ function v(e) {
48
442
  } catch (t) {
49
443
  e.onDeliveryError?.(t);
50
444
  }
51
- }, s = (t) => {
52
- let n = /* @__PURE__ */ new Set();
445
+ }, h = (e) => {
446
+ if (d === void 0) return;
447
+ let t = U(d.options.resolveDataDirectory(e)), n;
448
+ try {
449
+ n = t.hasMarker();
450
+ } catch (e) {
451
+ throw t.release(), e;
452
+ }
453
+ if (!n) return t;
454
+ throw t.release(), new l("restore_incomplete", `a restore of "${e}" did not finish; run pg.restore.cleanup before connecting`);
455
+ }, g = async (e, t) => {
456
+ for (let n of $) await e.listen(n, (e) => {
457
+ for (let r of t) f(r, n, e);
458
+ });
459
+ }, _ = async (t, n) => {
460
+ let r;
461
+ try {
462
+ r = await e.createRuntime(t);
463
+ } catch (e) {
464
+ throw se(t, e);
465
+ }
466
+ try {
467
+ await g(r, n);
468
+ } catch (e) {
469
+ throw await r.close().catch(() => void 0), se(t, e);
470
+ }
471
+ return r;
472
+ }, v = async (e, t) => {
473
+ let n = h(e);
474
+ try {
475
+ return {
476
+ runtime: await _(e, t),
477
+ lock: n
478
+ };
479
+ } catch (e) {
480
+ throw n?.release(), e;
481
+ }
482
+ }, y = (e) => {
483
+ let t = /* @__PURE__ */ new Set();
53
484
  return {
54
- sessions: n,
55
- ready: (async () => {
56
- let r = await e.createRuntime(t);
57
- for (let e of f) await r.listen(e, (t) => {
58
- for (let r of n) o(r, e, t);
59
- });
60
- return r;
61
- })()
485
+ sessions: t,
486
+ pending: 0,
487
+ ready: v(e, t)
62
488
  };
63
- }, c = (e, t) => {
489
+ }, b = async (e) => {
490
+ let { runtime: t, lock: n } = await e.ready;
491
+ try {
492
+ await t.close();
493
+ } finally {
494
+ n?.release();
495
+ }
496
+ }, x = async (e, n) => {
497
+ t.delete(e);
498
+ let r = b(n), i = r.then(() => void 0, () => void 0);
499
+ a.set(e, i);
500
+ try {
501
+ await r;
502
+ } finally {
503
+ a.get(e) === i && a.delete(e);
504
+ }
505
+ }, S = (e, t) => {
64
506
  let r = n.get(e);
65
- if (!r) throw new a("session_closed", `session ${e} is not open on this host`);
66
- if (r.owner !== t) throw new a("permission_denied", `session ${e} belongs to another window`);
507
+ if (!r) throw new l("session_closed", `session ${e} is not open on this host`);
508
+ if (r.owner !== t) throw new l("permission_denied", `session ${e} belongs to another window`);
67
509
  return r;
68
- }, v = async (e) => {
510
+ }, C = async (e) => {
69
511
  let n = t.get(e.dataDirectoryName);
70
- if (!n) throw new a("host_internal_error", `session references a released instance for ${e.dataDirectoryName}`);
71
- return n.ready;
72
- }, y = (e, t) => {
73
- let n = i.get(e);
74
- if (!n || n.sessionId !== t) throw new a("transaction_not_found", `transaction ${e} is unknown, already finished, or not owned by session ${t}`);
512
+ if (!n) throw new l("host_internal_error", `session references a released instance for ${e.dataDirectoryName}`);
513
+ return (await n.ready).runtime;
514
+ }, w = (e, t) => {
515
+ let n = r.get(e);
516
+ if (!n || n.sessionId !== t) throw new l("transaction_not_found", `transaction ${e} is unknown, already finished, or not owned by session ${t}`);
75
517
  return n;
76
- }, b = async (e, t) => {
77
- let n = i.get(e);
518
+ }, T = async (e, t) => {
519
+ let n = r.get(e);
78
520
  if (!n) return;
79
- i.delete(e), t ? n.settle.reject(t) : n.settle.resolve();
80
- let r = await n.finished.then(() => void 0, (e) => e);
81
- if (!(t || r === void 0)) return r instanceof a ? r : new a("statement_failed", r instanceof Error ? r.message : String(r), { cause: r });
82
- }, x = async (e, i) => {
83
- let { dataDirectoryName: o } = e.storage, c = t.get(o) ?? s(o);
84
- t.set(o, c);
85
- try {
86
- await c.ready;
521
+ r.delete(e), t ? n.settle.reject(t) : n.settle.resolve();
522
+ let i = await n.finished.then(() => void 0, (e) => e);
523
+ if (!(t || i === void 0)) return i instanceof l ? i : new l("statement_failed", i instanceof Error ? i.message : String(i), { cause: i });
524
+ }, E = async (e, r) => {
525
+ let { dataDirectoryName: i } = e.storage;
526
+ for (; a.has(i);) await a.get(i);
527
+ if (d?.restores.isReserved(i)) throw new l("restore_in_progress", `"${i}" is being restored`);
528
+ let o = t.get(i) ?? y(i);
529
+ t.set(i, o), o.pending += 1;
530
+ try {
531
+ await o.ready;
87
532
  } catch (e) {
88
- throw c.sessions.size === 0 && t.delete(o), new a("open_failed", `the application could not open a PGlite runtime for ${o}`, { cause: e });
533
+ throw t.get(i) === o && t.delete(i), e;
534
+ } finally {
535
+ --o.pending;
89
536
  }
90
- let l = u();
91
- return c.sessions.add(l), n.set(l, {
92
- dataDirectoryName: o,
93
- owner: i
537
+ let c = m();
538
+ return o.sessions.add(c), n.set(c, {
539
+ dataDirectoryName: i,
540
+ owner: r
94
541
  }), {
95
542
  kind: "pg.open",
96
543
  result: {
97
- sessionId: l,
98
- resolvedLocation: `${d}/${o}`,
99
- protocolVersion: r
544
+ sessionId: c,
545
+ resolvedLocation: `${ae}/${i}`,
546
+ protocolVersion: s
100
547
  }
101
548
  };
102
- }, S = async (e) => {
549
+ }, D = async (e) => {
103
550
  let r = n.get(e);
104
551
  if (!r) return;
105
552
  n.delete(e);
106
553
  let i = t.get(r.dataDirectoryName);
107
- i && (i.sessions.delete(e), !(i.sessions.size > 0) && (t.delete(r.dataDirectoryName), await (await i.ready.catch(() => void 0))?.close()));
108
- }, C = async (e, t) => {
109
- let n = [...i.entries()].filter(([, t]) => t.sessionId === e).map(([e]) => e);
110
- for (let e of n) await b(e, new a("transaction_not_found", t));
554
+ i && (i.sessions.delete(e), !(i.sessions.size > 0 || i.pending > 0) && await x(r.dataDirectoryName, i));
555
+ }, O = async (e, t) => {
556
+ let n = [...r.entries()].filter(([, t]) => t.sessionId === e).map(([e]) => e);
557
+ for (let e of n) await T(e, new l("transaction_not_found", t));
111
558
  return n.length;
112
- }, w = async (e, t) => {
113
- let n = await v(c(e.sessionId, t)), r, o = new Promise((e, t) => {
114
- r = {
115
- resolve: e,
116
- reject: t
117
- };
118
- });
119
- o.catch(() => void 0);
120
- let s, l = new Promise((e) => {
121
- s = e;
122
- }), d = n.transaction(async (e) => {
123
- s(e), await o;
124
- });
125
- d.catch(() => void 0);
126
- let f = await m(l, e.timeout);
127
- if (f === p) throw r.reject(new a("transaction_unavailable", "the begin that opened this transaction timed out")), new a("transaction_unavailable", `waited ${e.timeout}ms for the PGlite connection but another transaction still holds it`);
128
- let h = u();
129
- return i.set(h, {
130
- sessionId: e.sessionId,
131
- tx: f,
132
- settle: r,
133
- finished: d
559
+ }, k = async (e, t) => {
560
+ let n = await J(await C(S(e.sessionId, t)), e.timeout), i = m();
561
+ return r.set(i, {
562
+ ...n,
563
+ sessionId: e.sessionId
134
564
  }), {
135
565
  kind: "pg.begin",
136
- result: { transactionId: h }
566
+ result: { transactionId: i }
137
567
  };
138
- }, T = async (e, t) => {
139
- let n = c(e.sessionId, t), r = [...e.params];
568
+ }, A = async (e, t) => {
569
+ let n = S(e.sessionId, t), r = [...e.params];
140
570
  if (e.transactionId !== void 0) {
141
- let t = y(e.transactionId, e.sessionId);
571
+ let t = w(e.transactionId, e.sessionId);
142
572
  return {
143
573
  kind: "pg.query",
144
- result: h(await _(() => t.tx.query(e.sql, r)))
574
+ result: W(await G(() => t.tx.query(e.sql, r)))
145
575
  };
146
576
  }
147
- let i = await v(n);
577
+ let i = await C(n);
148
578
  return {
149
579
  kind: "pg.query",
150
- result: h(await _(() => i.query(e.sql, r)))
580
+ result: W(await G(() => i.query(e.sql, r)))
151
581
  };
152
- }, E = async (e, t) => {
153
- let n = c(e.sessionId, t), r = e.transactionId === void 0 ? await v(n) : y(e.transactionId, e.sessionId).tx;
582
+ }, j = async (e, t) => {
583
+ let n = S(e.sessionId, t), r = e.transactionId === void 0 ? await C(n) : w(e.transactionId, e.sessionId).tx;
154
584
  return {
155
585
  kind: "pg.exec",
156
- result: (await _(() => r.exec(e.sql))).map(h)
586
+ result: (await G(() => r.exec(e.sql))).map(W)
157
587
  };
158
- }, D = async (e, t) => {
159
- c(e.sessionId, t), y(e.transactionId, e.sessionId);
160
- let n = e.kind === "pg.rollback" ? new a("write_aborted", "rollback requested") : null, r = await b(e.transactionId, n);
588
+ }, N = async (e, t) => {
589
+ S(e.sessionId, t), w(e.transactionId, e.sessionId);
590
+ let n = e.kind === "pg.rollback" ? new l("write_aborted", "rollback requested") : null, r = await T(e.transactionId, n);
161
591
  if (r) throw r;
162
592
  return { kind: e.kind };
163
- }, O = async (e, t) => {
164
- let n = await v(c(e.sessionId, t)), r = (await _(() => n.query("SELECT version() AS version"))).rows[0]?.version;
165
- if (typeof r != "string") throw new a("host_internal_error", "PostgreSQL did not report a version string");
593
+ }, P = async (e, t) => {
594
+ let n = await C(S(e.sessionId, t)), r = (await G(() => n.query("SELECT version() AS version"))).rows[0]?.version;
595
+ if (typeof r != "string") throw new l("host_internal_error", "PostgreSQL did not report a version string");
166
596
  return {
167
597
  kind: "pg.version",
168
598
  result: r
169
599
  };
170
- }, k = async (e, t) => (c(e.sessionId, t), await C(e.sessionId, `session ${e.sessionId} was closed`), await S(e.sessionId), { kind: "pg.close" }), A = (e, t) => {
600
+ }, F = () => {
601
+ if (d === void 0) throw new l("unsupported_operation", "this host was created without backup support");
602
+ return d;
603
+ }, I = async (e) => {
604
+ let t;
605
+ try {
606
+ t = await e.options.createProbeRuntime();
607
+ } catch (e) {
608
+ throw new l("open_failed", "the application could not start the PGlite probe runtime", { cause: e });
609
+ }
610
+ try {
611
+ let n = (await G(() => t.query("SHOW server_version"))).rows[0]?.server_version;
612
+ if (typeof n != "string" || n === "") throw new l("host_internal_error", "PostgreSQL did not report server_version");
613
+ return {
614
+ serverVersion: n,
615
+ extensions: e.extensions
616
+ };
617
+ } finally {
618
+ await t.close().catch(() => void 0);
619
+ }
620
+ }, L = async (e) => {
621
+ let t = o ??= I(e);
622
+ try {
623
+ return {
624
+ kind: "pg.engine",
625
+ result: await t
626
+ };
627
+ } catch (e) {
628
+ throw o === t && (o = void 0), e;
629
+ }
630
+ }, R = async (e, t, n) => {
631
+ let r = S(t.sessionId, n), a = e.options.resolveDataDirectory(r.dataDirectoryName), o = await J(await C(r), t.timeout);
632
+ try {
633
+ if (await G(() => o.tx.query("CHECKPOINT")), !await M(a)) throw new l("host_internal_error", `resolveDataDirectory does not point at the data directory of "${r.dataDirectoryName}"`);
634
+ } catch (e) {
635
+ throw o.settle.reject(new l("write_aborted", "the snapshot was aborted")), await o.finished.catch(() => void 0), e;
636
+ }
637
+ let s = m();
638
+ return i.set(s, {
639
+ sessionId: t.sessionId,
640
+ iterator: ee(a),
641
+ held: o
642
+ }), {
643
+ kind: "pg.backup.begin",
644
+ result: { backupId: s }
645
+ };
646
+ }, z = (e, t) => {
647
+ let n = i.get(e);
648
+ if (!n || n.sessionId !== t) throw new l("transaction_not_found", `backup ${e} is unknown, already finished, or not owned by session ${t}`);
649
+ return n;
650
+ }, B = async (e) => {
651
+ let t = i.get(e);
652
+ if (t) {
653
+ i.delete(e);
654
+ try {
655
+ await t.iterator.return(void 0);
656
+ } finally {
657
+ t.held.settle.resolve(), await t.held.finished.catch(() => void 0);
658
+ }
659
+ }
660
+ }, V = async (e, t) => {
661
+ S(e.sessionId, t);
662
+ let n = z(e.backupId, e.sessionId), r;
663
+ try {
664
+ r = await n.iterator.next();
665
+ } catch (t) {
666
+ throw await B(e.backupId), t;
667
+ }
668
+ return {
669
+ kind: "pg.backup.next",
670
+ result: r.done ? { type: "end" } : r.value
671
+ };
672
+ }, H = async (e, t) => (S(e.sessionId, t), z(e.backupId, e.sessionId), await B(e.backupId), { kind: "pg.backup.end" }), K = async (e, t) => {
673
+ let n = F();
674
+ switch (e.kind) {
675
+ case "pg.engine": return L(n);
676
+ case "pg.backup.begin": return R(n, e, t);
677
+ case "pg.backup.next": return V(e, t);
678
+ case "pg.backup.end": return H(e, t);
679
+ default: return n.restores.handle(e, t);
680
+ }
681
+ }, q = async (e, t) => {
682
+ let n = [...i.entries()].filter(([, t]) => t.sessionId === e).map(([e]) => e);
683
+ for (let e of n) await B(e).catch(() => void 0);
684
+ let r = await O(e, t);
685
+ return await D(e), r;
686
+ }, Y = async (e, t) => (S(e.sessionId, t), await q(e.sessionId, `session ${e.sessionId} was closed`), { kind: "pg.close" }), X = (e, t) => {
171
687
  switch (e.kind) {
172
688
  case "pg.handshake": return Promise.resolve({
173
689
  kind: "pg.handshake",
174
- result: { protocolVersion: r }
690
+ result: { protocolVersion: s }
175
691
  });
176
- case "pg.open": return x(e, t);
177
- case "pg.query": return T(e, t);
178
- case "pg.exec": return E(e, t);
179
- case "pg.begin": return w(e, t);
692
+ case "pg.open": return E(e, t);
693
+ case "pg.query": return A(e, t);
694
+ case "pg.exec": return j(e, t);
695
+ case "pg.begin": return k(e, t);
180
696
  case "pg.commit":
181
- case "pg.rollback": return D(e, t);
182
- case "pg.version": return O(e, t);
183
- case "pg.close": return k(e, t);
184
- default: throw new a("protocol_violation", `unsupported pglite request kind: ${String(e.kind)}`);
697
+ case "pg.rollback": return N(e, t);
698
+ case "pg.version": return P(e, t);
699
+ case "pg.close": return Y(e, t);
700
+ default: return K(e, t);
185
701
  }
186
702
  };
187
703
  return {
188
704
  handle: async (e, t) => {
189
705
  try {
190
- return await A(l(e), t);
706
+ return await X(p(e), t);
191
707
  } catch (e) {
192
- return g(e);
708
+ return oe(e);
193
709
  }
194
710
  },
195
711
  get openSessionCount() {
@@ -199,17 +715,24 @@ function v(e) {
199
715
  return t.size;
200
716
  },
201
717
  get openTransactionCount() {
718
+ return r.size;
719
+ },
720
+ get openBackupCount() {
202
721
  return i.size;
203
722
  },
723
+ get openRestoreCount() {
724
+ return d === void 0 ? 0 : d.restores.openCount;
725
+ },
204
726
  releaseOwner: async (e) => {
205
727
  let t = [...n.entries()].filter(([, t]) => t.owner === e).map(([e]) => e), r = 0;
206
- for (let n of t) r += await C(n, `owner ${e} is gone`), await S(n);
207
- return r;
728
+ for (let n of t) r += await q(n, `owner ${e} is gone`);
729
+ return await d?.restores.releaseOwner(e), r;
208
730
  },
209
731
  closeAll: async () => {
210
- for (let e of [...n.keys()]) await C(e, "the host is shutting down"), await S(e);
732
+ for (let e of [...n.keys()]) await q(e, "the host is shutting down");
733
+ await d?.restores.closeAll();
211
734
  }
212
735
  };
213
736
  }
214
737
  //#endregion
215
- export { e as DESKTOP_PGLITE_DEFAULT_BEGIN_TIMEOUT_MS, t as DESKTOP_PGLITE_MAX_BEGIN_TIMEOUT_MS, n as DESKTOP_PGLITE_PROTOCOL_VERSION, f as DESKTOP_PGLITE_WATCH_CHANNELS, i as RxDBAdapterDesktopError, o as assertValidDesktopDatabaseName, v as createElectronPgliteHost, s as isDesktopPgliteRequestKind, c as parseDesktopPgliteRequest };
738
+ export { e as DESKTOP_PGLITE_DEFAULT_BEGIN_TIMEOUT_MS, t as DESKTOP_PGLITE_EXCLUDED_FILES, r as DESKTOP_PGLITE_MAX_BEGIN_TIMEOUT_MS, i as DESKTOP_PGLITE_MAX_DATA_CHUNK_BYTES, o as DESKTOP_PGLITE_PROTOCOL_VERSION, $ as DESKTOP_PGLITE_WATCH_CHANNELS, c as RxDBAdapterDesktopError, u as assertValidDesktopDatabaseName, ce as createElectronPgliteHost, d as isDesktopPgliteRequestKind, f as parseDesktopPgliteRequest };