@rotorsoft/act-sqlite 2.0.2 → 2.1.1

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/dist/index.js CHANGED
@@ -2,57 +2,26 @@
2
2
  import {
3
3
  createClient
4
4
  } from "@libsql/client";
5
+ import { ConcurrencyError, StoreError, ValidationError as ValidationError2 } from "@rotorsoft/act";
5
6
  import {
6
- ConcurrencyError,
7
- check_appends,
8
- concurrency_error,
9
- DEFAULT_QUERY_STREAMS_LIMIT,
10
- fair_slots,
11
- is_literal_source,
12
- StoreError,
13
- seed_event,
14
- throw_if_stale,
15
- ValidationError
16
- } from "@rotorsoft/act";
7
+ checkAppends,
8
+ checkVersion,
9
+ concurrencyError,
10
+ fairSlots,
11
+ isStreamName,
12
+ seedEvent
13
+ } from "@rotorsoft/act/adapter";
14
+ import { DEFAULT_QUERY_STREAMS_LIMIT } from "@rotorsoft/act/types";
17
15
  import {
18
16
  decrypt,
19
17
  encrypt,
20
18
  makeKeyResolver
21
19
  } from "@rotorsoft/act-crypto";
22
- var SHARED_MEMORY_URL = "file::memory:?cache=shared";
23
- var is_in_memory_url = (url) => url === ":memory:" || url === "file::memory:" || url.startsWith("file::memory:?");
24
- var resolve_url = (url) => {
25
- if (typeof url !== "string" || url.trim().length === 0)
26
- throw new ValidationError(
27
- 'SqliteStore config \u2014 "url" is required and has no default. Use a file database ("file:myapp.db"), a remote libSQL server ("libsql://\u2026" plus authToken), or ":memory:" for a process-wide shared in-memory database. For isolated throwaway state, prefer InMemoryStore from @rotorsoft/act',
28
- { url },
29
- "missing url"
30
- );
31
- if (url.startsWith("file::memory:?") && url.includes("cache=private"))
32
- throw new ValidationError(
33
- 'SqliteStore config \u2014 a private in-memory database ("cache=private") cannot back a store: libSQL gives each connection its own database, so writes are accepted and then lost on the next statement. Use ":memory:" for the shared-cache database, a "file:" path, or InMemoryStore from @rotorsoft/act',
34
- { url },
35
- "private in-memory url"
36
- );
37
- return is_in_memory_url(url) ? SHARED_MEMORY_URL : url;
38
- };
39
- var parse_json = (raw) => JSON.parse(raw);
40
- var to_committed = (row, prefix = "") => ({
41
- id: Number(row[`${prefix}id`]),
42
- stream: row[`${prefix}stream`],
43
- version: Number(row[`${prefix}version`]),
44
- created: new Date(row[`${prefix}created`]),
45
- name: row[`${prefix}name`],
46
- data: parse_json(row[`${prefix}data`]),
47
- meta: parse_json(row[`${prefix}meta`])
48
- });
49
- var SQLITE_CONSTRAINT_UNIQUE = 2067;
50
- var is_unique_violation = (e) => {
51
- const err = e;
52
- return err?.rawCode === SQLITE_CONSTRAINT_UNIQUE || typeof err?.message === "string" && err.message.includes("UNIQUE constraint failed");
53
- };
20
+
21
+ // src/stream-glob.ts
22
+ import { ValidationError } from "@rotorsoft/act";
54
23
  var PORTABLE_BODY = /^(?:\.\*|\.|[^\\^$.()[\]{}|+?*])*$/;
55
- function streamPatternToGlob(input) {
24
+ function stream_glob(input) {
56
25
  let s = input;
57
26
  const start = s.startsWith("^");
58
27
  const end = s.endsWith("$");
@@ -85,6 +54,40 @@ function streamPatternToGlob(input) {
85
54
  }
86
55
  return out;
87
56
  }
57
+
58
+ // src/sqlite-store.ts
59
+ var SHARED_MEMORY_URL = "file::memory:?cache=shared";
60
+ var is_in_memory_url = (url) => url === ":memory:" || url === "file::memory:" || url.startsWith("file::memory:?");
61
+ var resolve_url = (url) => {
62
+ if (typeof url !== "string" || url.trim().length === 0)
63
+ throw new ValidationError2(
64
+ 'SqliteStore config \u2014 "url" is required and has no default. Use a file database ("file:myapp.db"), a remote libSQL server ("libsql://\u2026" plus authToken), or ":memory:" for a process-wide shared in-memory database. For isolated throwaway state, prefer InMemoryStore from @rotorsoft/act',
65
+ { url },
66
+ "missing url"
67
+ );
68
+ if (url.startsWith("file::memory:?") && url.includes("cache=private"))
69
+ throw new ValidationError2(
70
+ 'SqliteStore config \u2014 a private in-memory database ("cache=private") cannot back a store: libSQL gives each connection its own database, so writes are accepted and then lost on the next statement. Use ":memory:" for the shared-cache database, a "file:" path, or InMemoryStore from @rotorsoft/act',
71
+ { url },
72
+ "private in-memory url"
73
+ );
74
+ return is_in_memory_url(url) ? SHARED_MEMORY_URL : url;
75
+ };
76
+ var parse_json = (raw) => JSON.parse(raw);
77
+ var to_committed = (row, prefix = "") => ({
78
+ id: Number(row[`${prefix}id`]),
79
+ stream: row[`${prefix}stream`],
80
+ version: Number(row[`${prefix}version`]),
81
+ created: new Date(row[`${prefix}created`]),
82
+ name: row[`${prefix}name`],
83
+ data: parse_json(row[`${prefix}data`]),
84
+ meta: parse_json(row[`${prefix}meta`])
85
+ });
86
+ var SQLITE_CONSTRAINT_UNIQUE = 2067;
87
+ var is_unique_violation = (e) => {
88
+ const err = e;
89
+ return err?.rawCode === SQLITE_CONSTRAINT_UNIQUE || typeof err?.message === "string" && err.message.includes("UNIQUE constraint failed");
90
+ };
88
91
  var SqliteStore = class {
89
92
  client;
90
93
  // Memoized key resolver for the optional `pii_encryption` envelope.
@@ -285,7 +288,7 @@ var SqliteStore = class {
285
288
  }
286
289
  // --- commit: one transaction across every append ---
287
290
  async commit(appends, meta) {
288
- check_appends(appends);
291
+ checkAppends(appends);
289
292
  if (!appends.length) return [];
290
293
  return this._serial(async () => {
291
294
  const tx = await this._begin("commit");
@@ -299,7 +302,7 @@ var SqliteStore = class {
299
302
  args: [append.stream]
300
303
  });
301
304
  const current = Number(row.rows[0].v);
302
- throw_if_stale(append, current);
305
+ checkVersion(append, current);
303
306
  heads.set(append.stream, current);
304
307
  }
305
308
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -340,7 +343,7 @@ var SqliteStore = class {
340
343
  } catch (e) {
341
344
  await tx.rollback();
342
345
  if (e instanceof ConcurrencyError) throw e;
343
- if (is_unique_violation(e)) throw concurrency_error(appending, head);
346
+ if (is_unique_violation(e)) throw concurrencyError(appending, head);
344
347
  throw new StoreError("commit", { cause: e });
345
348
  }
346
349
  });
@@ -355,7 +358,7 @@ var SqliteStore = class {
355
358
  args.push(query.stream);
356
359
  } else {
357
360
  sql += " AND stream GLOB ?";
358
- args.push(streamPatternToGlob(query.stream));
361
+ args.push(stream_glob(query.stream));
359
362
  }
360
363
  }
361
364
  if (query?.names !== void 0) {
@@ -413,8 +416,8 @@ var SqliteStore = class {
413
416
  // through `prioritize()` instead.
414
417
  async subscribe(streams, correlated_at, correlator) {
415
418
  for (const { stream, source } of streams) {
416
- if (source !== void 0 && !is_literal_source(source, stream))
417
- streamPatternToGlob(source);
419
+ if (source !== void 0 && !isStreamName(source, stream))
420
+ stream_glob(source);
418
421
  }
419
422
  return this._tx("subscribe", async (tx) => {
420
423
  let subscribed = 0;
@@ -547,7 +550,7 @@ var SqliteStore = class {
547
550
  priority: Number(row.priority),
548
551
  lane: row.lane
549
552
  })).sort((a, b) => b.priority - a.priority || a.at - b.at);
550
- const fair = fair_slots(lagging);
553
+ const fair = fairSlots(lagging);
551
554
  const priority_slice = candidates.slice(0, lagging - fair);
552
555
  const picked = new Set(priority_slice.map((c) => c.stream));
553
556
  const fair_slice = [...candidates].sort((a, b) => a.at - b.at).filter((c) => !picked.has(c.stream)).slice(0, fair);
@@ -705,7 +708,7 @@ var SqliteStore = class {
705
708
  args.push(filter.stream);
706
709
  } else {
707
710
  conditions.push("stream GLOB ?");
708
- args.push(streamPatternToGlob(filter.stream));
711
+ args.push(stream_glob(filter.stream));
709
712
  }
710
713
  }
711
714
  if (filter.source !== void 0) {
@@ -715,7 +718,7 @@ var SqliteStore = class {
715
718
  args.push(filter.source);
716
719
  } else {
717
720
  conditions.push("source GLOB ?");
718
- args.push(streamPatternToGlob(filter.source));
721
+ args.push(stream_glob(filter.source));
719
722
  }
720
723
  }
721
724
  if (filter.blocked !== void 0) {
@@ -838,7 +841,7 @@ var SqliteStore = class {
838
841
  args.push(input.stream);
839
842
  } else {
840
843
  where.push(`e.stream GLOB ?`);
841
- args.push(streamPatternToGlob(input.stream));
844
+ args.push(stream_glob(input.stream));
842
845
  }
843
846
  }
844
847
  if (exclude.length) {
@@ -1029,7 +1032,7 @@ var SqliteStore = class {
1029
1032
  sql: "DELETE FROM events WHERE stream = ?",
1030
1033
  args: [stream]
1031
1034
  });
1032
- const seed = seed_event(snapshot, meta);
1035
+ const seed = seedEvent(snapshot, meta);
1033
1036
  const now = (/* @__PURE__ */ new Date()).toISOString();
1034
1037
  const ins = await tx.execute({
1035
1038
  sql: "INSERT INTO events (stream, version, name, data, meta, created) VALUES (?, 0, ?, ?, ?, ?)",
@@ -1125,7 +1128,6 @@ var SqliteStore = class {
1125
1128
  }
1126
1129
  };
1127
1130
  export {
1128
- SqliteStore,
1129
- streamPatternToGlob
1131
+ SqliteStore
1130
1132
  };
1131
1133
  //# sourceMappingURL=index.js.map