@aiao/rxdb-adapter-electron 0.0.0-stage → 0.0.26

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +293 -2
  3. package/dist/RxDBAdapterElectron.d.ts +35 -0
  4. package/dist/RxDBAdapterElectron.d.ts.map +1 -0
  5. package/dist/electron-adapter.interface.d.ts +23 -0
  6. package/dist/electron-adapter.interface.d.ts.map +1 -0
  7. package/dist/electron-file-host.d.ts +52 -0
  8. package/dist/electron-file-host.d.ts.map +1 -0
  9. package/dist/electron-sqlite-host.d.ts +65 -0
  10. package/dist/electron-sqlite-host.d.ts.map +1 -0
  11. package/dist/host.d.ts +19 -0
  12. package/dist/host.d.ts.map +1 -0
  13. package/dist/host.js +762 -0
  14. package/dist/index.d.ts +22 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +22 -0
  17. package/dist/node-sqlite-engine.d.ts +87 -0
  18. package/dist/node-sqlite-engine.d.ts.map +1 -0
  19. package/dist/pglite/RxDBAdapterElectronPGlite.d.ts +44 -0
  20. package/dist/pglite/RxDBAdapterElectronPGlite.d.ts.map +1 -0
  21. package/dist/pglite/desktop-pglite-client.d.ts +118 -0
  22. package/dist/pglite/desktop-pglite-client.d.ts.map +1 -0
  23. package/dist/pglite/pglite-adapter.interface.d.ts +56 -0
  24. package/dist/pglite/pglite-adapter.interface.d.ts.map +1 -0
  25. package/dist/pglite-host/electron-pglite-host.d.ts +114 -0
  26. package/dist/pglite-host/electron-pglite-host.d.ts.map +1 -0
  27. package/dist/pglite-host.d.ts +17 -0
  28. package/dist/pglite-host.d.ts.map +1 -0
  29. package/dist/pglite-host.js +215 -0
  30. package/dist/pglite.d.ts +20 -0
  31. package/dist/pglite.d.ts.map +1 -0
  32. package/dist/pglite.js +217 -0
  33. package/dist/sqlite-script.d.ts +26 -0
  34. package/dist/sqlite-script.d.ts.map +1 -0
  35. package/package.json +91 -3
  36. package/src/RxDBAdapterElectron.ts +66 -0
  37. package/src/electron-adapter.interface.ts +25 -0
  38. package/src/electron-file-host.ts +758 -0
  39. package/src/electron-sqlite-host.ts +298 -0
  40. package/src/host.ts +63 -0
  41. package/src/index.ts +70 -0
  42. package/src/node-sqlite-engine.ts +612 -0
  43. package/src/pglite/RxDBAdapterElectronPGlite.ts +77 -0
  44. package/src/pglite/desktop-pglite-client.ts +520 -0
  45. package/src/pglite/pglite-adapter.interface.ts +64 -0
  46. package/src/pglite-host/electron-pglite-host.ts +580 -0
  47. package/src/pglite-host.ts +43 -0
  48. package/src/pglite.ts +42 -0
  49. package/src/sqlite-script.ts +134 -0
package/dist/host.js ADDED
@@ -0,0 +1,762 @@
1
+ import { DEFAULT_BATCH_TIMEOUT as e, DEFAULT_CACHE_SIZE_KB as t, MAX_BATCH_WAIT_MS as n, SQLiteChangeType as r, WATCH_TABLES as i, get_init_sql as a, isReadOnlyStatement as o, validateSqliteNumericOption as s } from "@aiao/rxdb-adapter-sqlite-core";
2
+ import { DESKTOP_HOST_MAX_BINDINGS as c, DESKTOP_HOST_MAX_BLOB_BYTES as l, DESKTOP_HOST_MAX_FILE_CHUNK_BYTES as u, DESKTOP_HOST_MAX_PENDING_WRITES_PER_SESSION as ee, DESKTOP_HOST_MAX_QUEUED_LOCKS_PER_NAME as d, DESKTOP_HOST_MAX_SQL_LENGTH as f, DESKTOP_HOST_PROTOCOL_VERSION as p, DESKTOP_HOST_PROTOCOL_VERSION as m, RxDBAdapterDesktopError as h, RxDBAdapterDesktopError as g, assertDesktopSqliteStorage as _, assertValidDesktopDatabaseName as v, isDesktopHostFileRequestKind as y, isDesktopPgliteDirectoryStorage as b, isDesktopSqliteFileStorage as te, parseDesktopHostFileRequest as ne, parseDesktopHostFileRequest as re, parseDesktopHostRequest as x, parseDesktopHostRequest as S } from "@aiao/rxdb-adapter-sqlite-core/desktop-host";
3
+ import { randomUUID as C } from "node:crypto";
4
+ import { DatabaseSync as ie, constants as w } from "node:sqlite";
5
+ import { mkdir as T, open as E, readdir as ae, realpath as D, rename as O, rm as k, stat as oe } from "node:fs/promises";
6
+ import { basename as A, dirname as j, join as M, resolve as N, sep as P } from "node:path";
7
+ //#region src/sqlite-script.ts
8
+ var F = 0, I = 1, L = 2, se = 3, ce = 4, R = 5, le = 6, ue = 7, de = 1, fe = [
9
+ [
10
+ 1,
11
+ 0,
12
+ 2,
13
+ 3,
14
+ 4,
15
+ 2,
16
+ 2,
17
+ 2
18
+ ],
19
+ [
20
+ 1,
21
+ 1,
22
+ 2,
23
+ 3,
24
+ 4,
25
+ 2,
26
+ 2,
27
+ 2
28
+ ],
29
+ [
30
+ 1,
31
+ 2,
32
+ 2,
33
+ 2,
34
+ 2,
35
+ 2,
36
+ 2,
37
+ 2
38
+ ],
39
+ [
40
+ 1,
41
+ 3,
42
+ 3,
43
+ 2,
44
+ 4,
45
+ 2,
46
+ 2,
47
+ 2
48
+ ],
49
+ [
50
+ 1,
51
+ 4,
52
+ 2,
53
+ 2,
54
+ 2,
55
+ 4,
56
+ 5,
57
+ 2
58
+ ],
59
+ [
60
+ 6,
61
+ 5,
62
+ 5,
63
+ 5,
64
+ 5,
65
+ 5,
66
+ 5,
67
+ 5
68
+ ],
69
+ [
70
+ 6,
71
+ 6,
72
+ 5,
73
+ 5,
74
+ 5,
75
+ 5,
76
+ 5,
77
+ 7
78
+ ],
79
+ [
80
+ 1,
81
+ 7,
82
+ 5,
83
+ 5,
84
+ 5,
85
+ 5,
86
+ 5,
87
+ 5
88
+ ]
89
+ ], pe = /* @__PURE__ */ new Map([
90
+ ["create", ce],
91
+ ["temp", R],
92
+ ["temporary", R],
93
+ ["trigger", le],
94
+ ["end", ue],
95
+ ["explain", se]
96
+ ]), me = /* @__PURE__ */ new Set([
97
+ " ",
98
+ " ",
99
+ "\n",
100
+ "\r",
101
+ "\f"
102
+ ]), z = /[A-Za-z0-9_$\u0080-\uFFFF]/u, he = (e, t) => {
103
+ let n = e[t];
104
+ if (n === ";") return {
105
+ token: F,
106
+ next: t + 1
107
+ };
108
+ if (me.has(n)) return {
109
+ token: I,
110
+ next: t + 1
111
+ };
112
+ if (n === "/" && e[t + 1] === "*") return {
113
+ token: I,
114
+ next: B(e, t + 2, "*/")
115
+ };
116
+ if (n === "-" && e[t + 1] === "-") return {
117
+ token: I,
118
+ next: B(e, t + 2, "\n")
119
+ };
120
+ if (n === "[") return {
121
+ token: L,
122
+ next: B(e, t + 1, "]")
123
+ };
124
+ if (n === "\"" || n === "'" || n === "`") return {
125
+ token: L,
126
+ next: B(e, t + 1, n)
127
+ };
128
+ if (!z.test(n)) return {
129
+ token: L,
130
+ next: t + 1
131
+ };
132
+ let r = ge(e, t + 1);
133
+ return {
134
+ token: pe.get(e.slice(t, r).toLowerCase()) ?? L,
135
+ next: r
136
+ };
137
+ }, B = (e, t, n) => {
138
+ let r = e.indexOf(n, t);
139
+ return r === -1 ? e.length : r + n.length;
140
+ }, ge = (e, t) => {
141
+ let n = t;
142
+ for (; n < e.length && z.test(e[n]);) n++;
143
+ return n;
144
+ };
145
+ function V(e) {
146
+ let t = [], n = 0, r = 0, i = 0, a = !1;
147
+ for (; i < e.length;) {
148
+ let { token: o, next: s } = he(e, i);
149
+ n = fe[n][o], i = s, o !== I && o !== F && (a = !0), o === F && n === de && (a && t.push(e.slice(r, i)), a = !1, r = i);
150
+ }
151
+ return a && t.push(e.slice(r)), t;
152
+ }
153
+ //#endregion
154
+ //#region src/node-sqlite-engine.ts
155
+ var H = "rxdb_desktop_notify", _e = "rxdb_desktop_notify", ve = [
156
+ {
157
+ type: r.SQLITE_INSERT,
158
+ event: "INSERT",
159
+ row: "NEW"
160
+ },
161
+ {
162
+ type: r.SQLITE_UPDATE,
163
+ event: "UPDATE",
164
+ row: "NEW"
165
+ },
166
+ {
167
+ type: r.SQLITE_DELETE,
168
+ event: "DELETE",
169
+ row: "OLD"
170
+ }
171
+ ], ye = /* @__PURE__ */ new Map([
172
+ [3, "permission_denied"],
173
+ [8, "permission_denied"],
174
+ [23, "permission_denied"],
175
+ [11, "database_corrupted"],
176
+ [26, "database_corrupted"],
177
+ [14, "open_failed"],
178
+ [5, "database_busy"],
179
+ [6, "database_busy"]
180
+ ]), be = /* @__PURE__ */ new Set([w.SQLITE_ATTACH, w.SQLITE_DETACH]), xe = /* @__PURE__ */ new Set(["temp_store_directory", "data_store_directory"]), Se = (e, t) => be.has(e) ? !0 : e === w.SQLITE_PRAGMA && t !== null && xe.has(t.toLowerCase()), Ce = (e) => {
181
+ let t = e.errcode;
182
+ return typeof t == "number" ? t : void 0;
183
+ }, U = (e, t) => {
184
+ let n = Ce(e);
185
+ return n === void 0 ? t : ye.get(n) ?? t;
186
+ }, W = (e) => e instanceof Error ? e.message : String(e), we = (e) => Array.isArray(e) ? Uint8Array.from(e) : e, Te = (e, t, n) => {
187
+ if (typeof e != "bigint" || typeof t != "string" || typeof n != "bigint") throw new g("host_internal_error", `the notify trigger passed (${typeof e}, ${typeof t}, ${typeof n}) instead of (bigint, string, bigint)`);
188
+ return [
189
+ Number(e),
190
+ t,
191
+ n
192
+ ];
193
+ }, Ee = BigInt(-(2 ** 53 - 1)), De = BigInt(2 ** 53 - 1), Oe = (e) => typeof e == "bigint" && e >= Ee && e <= De ? Number(e) : e, ke = (e) => e.map(Oe), G = (e) => {
194
+ let [t] = e.all();
195
+ return Number(t?.[0] ?? 0);
196
+ }, K = (e) => `"${e.replaceAll("\"", "\"\"")}"`, Ae = (e) => `'${e.replaceAll("'", "''")}'`, q = (e, t) => {
197
+ let n = setTimeout(e, t);
198
+ return n.unref?.(), n;
199
+ }, J = class r {
200
+ #e;
201
+ #t;
202
+ #n;
203
+ #r;
204
+ #i = /* @__PURE__ */ new Set();
205
+ #a = /* @__PURE__ */ new Map();
206
+ #o;
207
+ #s;
208
+ #c;
209
+ #l;
210
+ #u = !1;
211
+ constructor(t, n) {
212
+ this.#e = t, this.#t = n.dbName, this.#n = n.onChange, this.#r = s("batchTimeout", n.batchTimeout, e, { allowZero: !0 });
213
+ }
214
+ static open(e) {
215
+ let n;
216
+ try {
217
+ n = new ie(e.filePath);
218
+ } catch (t) {
219
+ throw new g(U(t, "open_failed"), `failed to open desktop database ${e.dbName}: ${W(t)}`, { cause: t });
220
+ }
221
+ try {
222
+ let i = new r(n, e);
223
+ return i.#d(e.cacheSizeKb ?? t), i;
224
+ } catch (t) {
225
+ throw n.close(), new g(U(t, "open_failed"), `failed to initialize desktop database ${e.dbName}: ${W(t)}`, { cause: t });
226
+ }
227
+ }
228
+ execute(e, t = []) {
229
+ this.#f();
230
+ let n = performance.now(), r = V(e);
231
+ if (r.length > 1 && t.length > 0) throw new g("protocol_violation", `multi statement scripts cannot carry bindings, got ${t.length} for SQL "${e}"`);
232
+ this.#T();
233
+ let { results: i, rowsAffected: a } = this.#m(r, t);
234
+ return this.#T(), {
235
+ sql: e,
236
+ rowsAffected: a,
237
+ elapsed: performance.now() - n,
238
+ results: i
239
+ };
240
+ }
241
+ version() {
242
+ this.#f();
243
+ let [e] = this.#p("SELECT sqlite_version()", []);
244
+ return String(e?.rows[0]?.[0]);
245
+ }
246
+ close() {
247
+ if (!this.#u) {
248
+ this.#u = !0, this.#S();
249
+ try {
250
+ this.#O(), this.#e.exec("PRAGMA wal_checkpoint(TRUNCATE)");
251
+ } finally {
252
+ this.#c = void 0, this.#l = void 0, this.#e.close();
253
+ }
254
+ }
255
+ }
256
+ #d(e) {
257
+ this.#e.setAuthorizer((e, t) => Se(e, t) ? w.SQLITE_DENY : w.SQLITE_OK), this.#e.function(H, {
258
+ deterministic: !1,
259
+ directOnly: !1,
260
+ useBigIntArguments: !0,
261
+ varargs: !1
262
+ }, (e, t, n) => (this.#b(...Te(e, t, n)), null)), this.#e.exec(a(e, !0)), this.#T();
263
+ }
264
+ #f() {
265
+ if (this.#u) throw new g("session_closed", `desktop database ${this.#t} is already closed`);
266
+ }
267
+ #p(e, t) {
268
+ try {
269
+ let n = this.#e.prepare(e);
270
+ n.setReturnArrays(!0), n.setReadBigInts(!0);
271
+ let r = n.all(...t.map(we)), i = n.columns().map((e) => e.name);
272
+ return i.length > 0 ? [{
273
+ columns: i,
274
+ rows: r.map(ke)
275
+ }] : [];
276
+ } catch (t) {
277
+ throw this.#g(e, t);
278
+ }
279
+ }
280
+ #m(e, t) {
281
+ let n = [], r = 0;
282
+ for (let i of e) {
283
+ let e = this.#v(), a = this.#p(i, t);
284
+ r += this.#h(i, e), n.length === 0 && n.push(...a);
285
+ }
286
+ return {
287
+ results: n,
288
+ rowsAffected: r
289
+ };
290
+ }
291
+ #h(e, t) {
292
+ return o(e) || this.#v() === t ? 0 : this.#_();
293
+ }
294
+ #g(e, t) {
295
+ return new g(U(t, "statement_failed"), `desktop database ${this.#t} failed for SQL "${e}": ${W(t)}`, { cause: t });
296
+ }
297
+ #_() {
298
+ return this.#c ??= this.#y("SELECT changes()"), G(this.#c);
299
+ }
300
+ #v() {
301
+ return this.#l ??= this.#y("SELECT total_changes()"), G(this.#l);
302
+ }
303
+ #y(e) {
304
+ let t = this.#e.prepare(e);
305
+ return t.setReturnArrays(!0), t;
306
+ }
307
+ #b(e, t, n) {
308
+ let r = `${e} ${t}`, i = this.#a.get(r);
309
+ i ? i.rowIds.push(n) : this.#a.set(r, {
310
+ type: e,
311
+ tableName: t,
312
+ rowIds: [n]
313
+ }), this.#x();
314
+ }
315
+ #x() {
316
+ this.#o && clearTimeout(this.#o), this.#o = q(() => this.#S(), this.#r), this.#s ??= q(() => this.#S(), n);
317
+ }
318
+ #S() {
319
+ this.#C(), this.#w();
320
+ }
321
+ #C() {
322
+ this.#o && clearTimeout(this.#o), this.#s && clearTimeout(this.#s), this.#o = void 0, this.#s = void 0;
323
+ }
324
+ #w() {
325
+ if (this.#a.size === 0) return;
326
+ let e = [...this.#a.values()];
327
+ this.#a.clear();
328
+ let t = /* @__PURE__ */ new Date();
329
+ for (let { type: n, tableName: r, rowIds: i } of e) try {
330
+ this.#n({
331
+ type: n,
332
+ dbName: "main",
333
+ tableName: r,
334
+ rowIds: i,
335
+ recordAt: t
336
+ });
337
+ } catch (e) {
338
+ console.error(`[NodeSqliteEngine] change event listener failed for ${r}:`, e);
339
+ }
340
+ }
341
+ #T() {
342
+ if (this.#i.size === i.size) return;
343
+ let e = [...i], t = e.map(() => "?").join(", "), n = this.#e.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (${t})`);
344
+ n.setReturnArrays(!0);
345
+ let r = n.all(...e);
346
+ for (let [e] of r) this.#i.has(e) || (this.#D(e), this.#E(e));
347
+ }
348
+ #E(e) {
349
+ this.#e.isTransaction || this.#i.add(e);
350
+ }
351
+ #D(e) {
352
+ let t = K(e), n = Ae(e);
353
+ for (let { type: r, event: i, row: a } of ve) {
354
+ let o = K(`${_e}$${e}$${i}`);
355
+ this.#e.exec(`CREATE TEMP TRIGGER IF NOT EXISTS ${o} AFTER ${i} ON ${t} BEGIN SELECT ${H}(${r}, ${n}, ${a}.rowid); END;`);
356
+ }
357
+ }
358
+ #O() {
359
+ this.#e.isTransaction && this.#e.exec("ROLLBACK");
360
+ }
361
+ }, je = "desktop-sqlite://app-scope", Y = "BEGIN IMMEDIATE;", Me = "BEGIN EXCLUSIVE;", Ne = 5e3, Pe = 1, Fe = 100, Ie = (e) => new Promise((t) => {
362
+ setTimeout(t, e);
363
+ }), Le = (e, t) => {
364
+ if (!(e instanceof g) || e.code !== "database_busy") return !1;
365
+ let [n] = V(t);
366
+ return n === Y || n === Me;
367
+ }, Re = (e) => e instanceof g ? {
368
+ kind: "error",
369
+ code: e.code,
370
+ message: e.detail
371
+ } : {
372
+ kind: "error",
373
+ code: "host_internal_error",
374
+ message: e instanceof Error ? e.message : String(e)
375
+ };
376
+ function ze(e) {
377
+ let t = /* @__PURE__ */ new Map(), n = (t, n) => {
378
+ try {
379
+ e.postChange({
380
+ kind: "change",
381
+ sessionId: t,
382
+ event: n
383
+ });
384
+ } catch (t) {
385
+ e.onDeliveryError?.(t);
386
+ }
387
+ }, r = (e) => {
388
+ let n = t.get(e);
389
+ if (!n) throw new g("session_closed", `session ${e} is not open on this host`);
390
+ return n;
391
+ }, i = (t) => {
392
+ try {
393
+ return e.resolveDatabasePath(t);
394
+ } catch (e) {
395
+ throw new g("open_failed", `the application could not resolve a path for ${t}`, { cause: e });
396
+ }
397
+ }, a = (r) => {
398
+ let { databaseName: a } = r.storage, o = C(), s = J.open({
399
+ filePath: i(a),
400
+ dbName: a,
401
+ onChange: (e) => n(o, e),
402
+ cacheSizeKb: e.cacheSizeKb,
403
+ batchTimeout: r.batchTimeout
404
+ });
405
+ return t.set(o, s), {
406
+ kind: "open",
407
+ result: {
408
+ sessionId: o,
409
+ resolvedLocation: `${je}/${a}`,
410
+ protocolVersion: m,
411
+ beginTransactionSql: Y,
412
+ beginSystemMigrationTransactionSql: Me
413
+ }
414
+ };
415
+ }, o = (e) => {
416
+ let n = r(e);
417
+ return t.delete(e), n.close(), { kind: "close" };
418
+ }, s = async (t) => {
419
+ let n = r(t.sessionId), i, a = Pe;
420
+ for (;;) try {
421
+ return {
422
+ kind: "execute",
423
+ result: n.execute(t.sql, t.bindings)
424
+ };
425
+ } catch (n) {
426
+ if (!Le(n, t.sql) || (i ??= performance.now() + (e.busyRetryBudgetMs ?? Ne), performance.now() + a > i)) throw n;
427
+ await Ie(a), a = Math.min(a * 2, Fe);
428
+ }
429
+ }, c = (e) => {
430
+ switch (e.kind) {
431
+ case "handshake": return {
432
+ kind: "handshake",
433
+ result: { protocolVersion: m }
434
+ };
435
+ case "open": return a(e);
436
+ case "close": return o(e.sessionId);
437
+ case "version": return {
438
+ kind: "version",
439
+ result: r(e.sessionId).version()
440
+ };
441
+ case "execute": return s(e);
442
+ default: throw new g("protocol_violation", `unsupported request kind: ${String(e.kind)}`);
443
+ }
444
+ };
445
+ return {
446
+ handle: async (e) => {
447
+ try {
448
+ return await c(S(e));
449
+ } catch (e) {
450
+ return Re(e);
451
+ }
452
+ },
453
+ get openSessionCount() {
454
+ return t.size;
455
+ },
456
+ closeAll: () => {
457
+ for (let e of t.values()) e.close();
458
+ t.clear();
459
+ }
460
+ };
461
+ }
462
+ //#endregion
463
+ //#region src/electron-file-host.ts
464
+ var Be = (e) => e.kind.startsWith("file.write"), Ve = (e) => e.kind.startsWith("file.lock"), He = {
465
+ ENOENT: "file_not_found",
466
+ ENOTDIR: "invalid_file_path",
467
+ EISDIR: "invalid_file_path",
468
+ ENAMETOOLONG: "invalid_file_path",
469
+ EEXIST: "invalid_file_path",
470
+ ELOOP: "invalid_file_path",
471
+ EACCES: "permission_denied",
472
+ EPERM: "permission_denied",
473
+ EROFS: "permission_denied",
474
+ ENOSPC: "disk_full",
475
+ EDQUOT: "disk_full"
476
+ }, X = (e) => {
477
+ if (typeof e != "object" || !e) return;
478
+ let t = e.code;
479
+ return typeof t == "string" ? t : void 0;
480
+ }, Z = (e, t) => {
481
+ if (e instanceof g) return e;
482
+ let n = X(e), r = n === void 0 ? void 0 : He[n];
483
+ return new g(r ?? "host_internal_error", `${n ?? "filesystem failure"} on ${t}`, { cause: e });
484
+ }, Ue = (e) => e instanceof g ? {
485
+ kind: "error",
486
+ code: e.code,
487
+ message: e.detail
488
+ } : {
489
+ kind: "error",
490
+ code: "host_internal_error",
491
+ message: e instanceof Error ? e.message : String(e)
492
+ }, We = (e) => new g("invalid_file_path", `path escapes the storage root: ${e}`), Ge = (e, t) => t === e || t.startsWith(e + P), Ke = (e, t) => {
493
+ let n = t === "" ? e : N(e, t);
494
+ if (!Ge(e, n)) throw We(t);
495
+ return n;
496
+ }, qe = async (e) => {
497
+ let t = [], n = e;
498
+ for (;;) try {
499
+ let e = await D(n);
500
+ return t.length === 0 ? e : M(e, ...t);
501
+ } catch (e) {
502
+ if (X(e) !== "ENOENT") throw e;
503
+ let r = j(n);
504
+ if (r === n) return M(n, ...t);
505
+ t.unshift(A(n)), n = r;
506
+ }
507
+ }, Q = (e) => e ? "directory" : "file", $ = async (e, t, n) => {
508
+ let r;
509
+ try {
510
+ r = (await oe(e)).isDirectory();
511
+ } catch (e) {
512
+ if (X(e) === "ENOENT") return;
513
+ throw Z(e, t);
514
+ }
515
+ if (Q(r) !== n) throw new g("invalid_file_path", `path is not a ${n}: ${t}`);
516
+ };
517
+ function Je(e) {
518
+ let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = (e) => {
519
+ let n = t.get(e);
520
+ if (!n) throw new g("session_closed", `file session ${e} is not open on this host`);
521
+ return n;
522
+ }, i = (e, t) => {
523
+ let n = e.writes.get(t);
524
+ if (!n) throw new g("write_aborted", `write ${t} is no longer pending`);
525
+ return n;
526
+ }, a = () => {
527
+ try {
528
+ return N(e.resolveStorageRoot());
529
+ } catch (e) {
530
+ throw new g("host_internal_error", "the application could not resolve the storage root", { cause: e });
531
+ }
532
+ }, o = async (e) => {
533
+ let t = a(), n = Ke(t, e);
534
+ try {
535
+ let [r, i] = await Promise.all([qe(t), qe(n)]);
536
+ if (!Ge(r, i)) throw We(e);
537
+ return n;
538
+ } catch (t) {
539
+ throw Z(t, e);
540
+ }
541
+ }, s = (e) => {
542
+ let t = n.get(e);
543
+ if (t) return t;
544
+ let r = {
545
+ held: /* @__PURE__ */ new Map(),
546
+ waiting: []
547
+ };
548
+ return n.set(e, r), r;
549
+ }, c = (e, t) => e.held.size === 0 || t.mode !== "exclusive" && [...e.held.values()].every((e) => e === "shared"), l = (e) => {
550
+ let t = n.get(e);
551
+ if (t) {
552
+ for (; t.waiting.length > 0 && c(t, t.waiting[0]);) {
553
+ let e = t.waiting.shift();
554
+ t.held.set(e.lockId, e.mode), e.grant();
555
+ }
556
+ t.held.size === 0 && t.waiting.length === 0 && n.delete(e);
557
+ }
558
+ }, u = (e, t, n) => {
559
+ let i = r(e), a = s(t);
560
+ if (a.waiting.length >= d) throw new g("protocol_violation", `lock ${t} already has ${d} queued waiters`);
561
+ let o = C();
562
+ return new Promise((r, s) => {
563
+ a.waiting.push({
564
+ lockId: o,
565
+ sessionId: e,
566
+ mode: n,
567
+ grant: () => {
568
+ i.lockNames.set(o, t), r(o);
569
+ },
570
+ deny: s
571
+ }), l(t);
572
+ });
573
+ }, f = (e, t) => {
574
+ let r = e.lockNames.get(t);
575
+ if (r === void 0) throw new g("protocol_violation", `lock ${t} is not held by this session`);
576
+ e.lockNames.delete(t), n.get(r)?.held.delete(t), l(r);
577
+ }, p = (e) => {
578
+ for (let [t, r] of n) {
579
+ let n = r.waiting.filter((t) => t.sessionId === e);
580
+ r.waiting = r.waiting.filter((t) => t.sessionId !== e);
581
+ for (let t of n) t.deny(new g("session_closed", `file session ${e} closed while queued`));
582
+ l(t);
583
+ }
584
+ }, h = async (e) => {
585
+ await e.handle.close().catch(() => void 0), await k(e.temporaryPath, { force: !0 }).catch(() => void 0);
586
+ }, _ = async (e) => {
587
+ let r = t.get(e);
588
+ if (r) {
589
+ t.delete(e), r.closed = !0, p(e);
590
+ for (let e of [...r.lockNames.keys()]) {
591
+ let t = r.lockNames.get(e);
592
+ r.lockNames.delete(e), n.get(t)?.held.delete(e), l(t);
593
+ }
594
+ await Promise.all([...r.writes.values()].map(h)), r.writes.clear();
595
+ }
596
+ }, v = async (e) => {
597
+ let t = await o(e);
598
+ try {
599
+ let e = await oe(t);
600
+ return {
601
+ kind: Q(e.isDirectory()),
602
+ size: e.isDirectory() ? 0 : e.size,
603
+ lastModified: e.mtimeMs
604
+ };
605
+ } catch (t) {
606
+ if (X(t) === "ENOENT") return null;
607
+ throw Z(t, e);
608
+ }
609
+ }, y = async (e) => {
610
+ let t = await o(e);
611
+ try {
612
+ return (await ae(t, { withFileTypes: !0 })).map((e) => ({
613
+ name: e.name,
614
+ kind: Q(e.isDirectory())
615
+ }));
616
+ } catch (t) {
617
+ throw Z(t, e);
618
+ }
619
+ }, b = async (e, t) => {
620
+ try {
621
+ await e();
622
+ } catch (e) {
623
+ throw Z(e, t);
624
+ }
625
+ }, te = async (e, t) => {
626
+ let n = await o(e), r = await o(t);
627
+ await b(() => T(j(r), { recursive: !0 }), t), await b(() => O(n, r), e);
628
+ }, ne = async (e, t, n) => {
629
+ let r = await o(e);
630
+ await $(r, e, "file");
631
+ let i;
632
+ try {
633
+ i = await E(r, "r");
634
+ let e = (await i.stat()).size, a = new Uint8Array(Math.max(0, Math.min(n, e - t)));
635
+ return a.byteLength > 0 && await i.read(a, 0, a.byteLength, t), {
636
+ chunk: a,
637
+ eof: t + a.byteLength >= e
638
+ };
639
+ } catch (t) {
640
+ throw Z(t, e);
641
+ } finally {
642
+ await i?.close().catch(() => void 0);
643
+ }
644
+ }, x = async (e, t) => {
645
+ try {
646
+ return await E(e, "wx");
647
+ } catch (e) {
648
+ throw Z(e, t);
649
+ }
650
+ }, S = async (e, t) => {
651
+ let n = C();
652
+ if (e.writes.size + e.reservations.size >= ee) throw new g("protocol_violation", `session already has ${ee} pending writes`);
653
+ e.reservations.add(n);
654
+ try {
655
+ let r = await o(t), i = M(j(r), `.${n}.rxdb-tmp`);
656
+ await b(() => T(j(r), { recursive: !0 }), t);
657
+ let a = {
658
+ logicalPath: t,
659
+ targetPath: r,
660
+ temporaryPath: i,
661
+ handle: await x(i, t)
662
+ };
663
+ if (e.closed) throw await h(a), new g("session_closed", "file session closed while the write was being opened");
664
+ return e.writes.set(n, a), n;
665
+ } finally {
666
+ e.reservations.delete(n);
667
+ }
668
+ }, ie = async (e) => {
669
+ let t;
670
+ try {
671
+ t = await E(e, "r"), await t.sync();
672
+ } catch (e) {
673
+ let t = X(e);
674
+ if (t !== "EISDIR" && t !== "EPERM" && t !== "EACCES") throw e;
675
+ } finally {
676
+ await t?.close().catch(() => void 0);
677
+ }
678
+ }, w = async (e, t) => {
679
+ let n = i(e, t);
680
+ e.writes.delete(t);
681
+ try {
682
+ await n.handle.sync(), await n.handle.close(), await O(n.temporaryPath, n.targetPath), await ie(j(n.targetPath));
683
+ } catch (e) {
684
+ throw await n.handle.close().catch(() => void 0), await k(n.temporaryPath, { force: !0 }).catch(() => void 0), Z(e, n.logicalPath);
685
+ }
686
+ }, D = async (e) => {
687
+ let t = r(e.sessionId);
688
+ if (e.kind === "file.writeBegin") return {
689
+ kind: "file.writeBegin",
690
+ result: { writeId: await S(t, e.path) }
691
+ };
692
+ if (e.kind === "file.writeChunk") {
693
+ let n = i(t, e.writeId);
694
+ try {
695
+ await n.handle.write(e.chunk);
696
+ } catch (e) {
697
+ throw Z(e, n.logicalPath);
698
+ }
699
+ return { kind: "file.writeChunk" };
700
+ }
701
+ if (e.kind === "file.writeCommit") return await w(t, e.writeId), { kind: "file.writeCommit" };
702
+ let n = i(t, e.writeId);
703
+ return t.writes.delete(e.writeId), await h(n), { kind: "file.writeAbort" };
704
+ }, A = async (e) => e.kind === "file.lockAcquire" ? {
705
+ kind: "file.lockAcquire",
706
+ result: { lockId: await u(e.sessionId, e.name, e.mode) }
707
+ } : (f(r(e.sessionId), e.lockId), { kind: "file.lockRelease" }), P = async (e) => {
708
+ if (r(e.sessionId), e.kind === "file.stat") return {
709
+ kind: "file.stat",
710
+ result: await v(e.path)
711
+ };
712
+ if (e.kind === "file.list") return {
713
+ kind: "file.list",
714
+ result: await y(e.path)
715
+ };
716
+ let t = await o(e.path);
717
+ return e.kind === "file.mkdir" ? (await b(() => T(t, { recursive: !0 }), e.path), { kind: "file.mkdir" }) : e.kind === "file.rmdir" ? (await $(t, e.path, "directory"), await b(() => k(t, {
718
+ force: !0,
719
+ recursive: !0
720
+ }), e.path), { kind: "file.rmdir" }) : (await $(t, e.path, "file"), await b(() => k(t, { force: !0 }), e.path), { kind: "file.remove" });
721
+ }, F = async (e) => {
722
+ if (e.kind === "file.open") {
723
+ let e = C();
724
+ return t.set(e, {
725
+ writes: /* @__PURE__ */ new Map(),
726
+ reservations: /* @__PURE__ */ new Set(),
727
+ lockNames: /* @__PURE__ */ new Map(),
728
+ closed: !1
729
+ }), {
730
+ kind: "file.open",
731
+ result: {
732
+ sessionId: e,
733
+ protocolVersion: m
734
+ }
735
+ };
736
+ }
737
+ return e.kind === "file.close" ? (r(e.sessionId), await _(e.sessionId), { kind: "file.close" }) : e.kind === "file.move" ? (r(e.sessionId), await te(e.fromPath, e.toPath), { kind: "file.move" }) : e.kind === "file.read" ? (r(e.sessionId), {
738
+ kind: "file.read",
739
+ result: await ne(e.path, e.offset, e.length)
740
+ }) : Be(e) ? D(e) : Ve(e) ? A(e) : P(e);
741
+ };
742
+ return {
743
+ handle: async (e) => {
744
+ try {
745
+ return await F(re(e));
746
+ } catch (e) {
747
+ return Ue(e);
748
+ }
749
+ },
750
+ get openSessionCount() {
751
+ return t.size;
752
+ },
753
+ get trackedLockNameCount() {
754
+ return n.size;
755
+ },
756
+ closeAll: async () => {
757
+ await Promise.all([...t.keys()].map((e) => _(e)));
758
+ }
759
+ };
760
+ }
761
+ //#endregion
762
+ export { c as DESKTOP_HOST_MAX_BINDINGS, l as DESKTOP_HOST_MAX_BLOB_BYTES, u as DESKTOP_HOST_MAX_FILE_CHUNK_BYTES, f as DESKTOP_HOST_MAX_SQL_LENGTH, p as DESKTOP_HOST_PROTOCOL_VERSION, J as NodeSqliteEngine, h as RxDBAdapterDesktopError, _ as assertDesktopSqliteStorage, v as assertValidDesktopDatabaseName, Je as createElectronFileHost, ze as createElectronSqliteHost, y as isDesktopHostFileRequestKind, b as isDesktopPgliteDirectoryStorage, te as isDesktopSqliteFileStorage, ne as parseDesktopHostFileRequest, x as parseDesktopHostRequest };