trellis 3.1.6 → 3.1.7

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 (56) hide show
  1. package/README.md +1 -0
  2. package/bin/trellis.mjs +68 -2
  3. package/dist/better-sqlite-backend-ahx5p0br.js +147 -0
  4. package/dist/cli/index.js +116 -45
  5. package/dist/client/index.js +5 -4
  6. package/dist/cms/client.d.ts +2 -1
  7. package/dist/cms/client.d.ts.map +1 -1
  8. package/dist/cms/index.js +4 -0
  9. package/dist/cms/types.d.ts +1 -1
  10. package/dist/cms/types.d.ts.map +1 -1
  11. package/dist/core/index.d.ts +4 -0
  12. package/dist/core/index.d.ts.map +1 -1
  13. package/dist/core/index.js +14 -4
  14. package/dist/core/persist/factory.d.ts +28 -0
  15. package/dist/core/persist/factory.d.ts.map +1 -0
  16. package/dist/core/persist/factory.js +8 -0
  17. package/dist/core/persist/sqlite-backend.d.ts.map +1 -1
  18. package/dist/core/persist/sqljs-backend.d.ts +60 -0
  19. package/dist/core/persist/sqljs-backend.d.ts.map +1 -0
  20. package/dist/core/persist/sqljs-backend.js +8 -0
  21. package/dist/db/index.js +11 -10
  22. package/dist/embeddings/index.js +1 -1
  23. package/dist/embeddings/store.d.ts.map +1 -1
  24. package/dist/{index-0zk3fx2s.js → index-4wxa8xz4.js} +4 -237
  25. package/dist/{index-6n5dcebj.js → index-53f3b8p8.js} +84 -30
  26. package/dist/{index-y3d71wzd.js → index-7pjz3tsy.js} +36 -6
  27. package/dist/{index-0q7wbasy.js → index-a2a394zz.js} +7 -3
  28. package/dist/index-h32txmxe.js +42 -0
  29. package/dist/index-h7zxhhhh.js +252 -0
  30. package/dist/index-h9e2efx4.js +251 -0
  31. package/dist/{index-2917tjd8.js → index-hr9qvv77.js} +15 -3
  32. package/dist/{index-hmdbnd4n.js → index-hy73j9z8.js} +1 -1
  33. package/dist/{index-q31hfjja.js → index-jgda3xyv.js} +1 -1
  34. package/dist/{index-7e27kvvj.js → index-wncptktd.js} +1 -1
  35. package/dist/index.js +8 -6
  36. package/dist/react/index.js +5 -4
  37. package/dist/{sdk-snn5gad3.js → sdk-bepky0xs.js} +5 -4
  38. package/dist/server/index.d.ts +2 -2
  39. package/dist/server/index.d.ts.map +1 -1
  40. package/dist/server/index.js +27 -24
  41. package/dist/server/node-adapter.d.ts +38 -0
  42. package/dist/server/node-adapter.d.ts.map +1 -0
  43. package/dist/server/node-adapter.js +108 -0
  44. package/dist/server/server-shared.d.ts +21 -0
  45. package/dist/server/server-shared.d.ts.map +1 -0
  46. package/dist/server/server.d.ts +19 -2
  47. package/dist/server/server.d.ts.map +1 -1
  48. package/dist/server/tenancy.d.ts +28 -2
  49. package/dist/server/tenancy.d.ts.map +1 -1
  50. package/dist/{server-mrctdwzr.js → server-szdjx0nt.js} +5 -3
  51. package/dist/sqlite-backend-0vsmc6qj.js +8 -0
  52. package/dist/{tenancy-7d1g4ayp.js → tenancy-pjm32b4v.js} +4 -3
  53. package/dist/vcs/blob-store.d.ts +2 -1
  54. package/dist/vcs/blob-store.d.ts.map +1 -1
  55. package/dist/vcs/index.js +2 -2
  56. package/package.json +16 -3
@@ -5,10 +5,14 @@ import {
5
5
  import {
6
6
  QueryEngine
7
7
  } from "./index-yp88he8n.js";
8
+ import {
9
+ __require
10
+ } from "./index-a76rekgs.js";
8
11
 
9
12
  // src/server/server.ts
10
13
  import { existsSync, readFileSync } from "fs";
11
- import { join } from "path";
14
+ import { dirname, join } from "path";
15
+ import { fileURLToPath } from "url";
12
16
 
13
17
  // src/server/auth.ts
14
18
  var ANONYMOUS = {
@@ -415,7 +419,22 @@ function computeDiff(prev, next) {
415
419
  }
416
420
 
417
421
  // src/server/server.ts
422
+ var __moduleDir = import.meta.dir ?? dirname(fileURLToPath(import.meta.url));
418
423
  function startServer(opts) {
424
+ return startServerBun(opts);
425
+ }
426
+ async function startServerCrossRuntime(opts) {
427
+ if (typeof globalThis.Bun !== "undefined") {
428
+ const bunServer = startServerBun(opts);
429
+ return {
430
+ port: bunServer.port ?? opts.port ?? opts.config.port ?? 3000,
431
+ hostname: bunServer.hostname,
432
+ stop: (closeActive) => bunServer.stop(closeActive)
433
+ };
434
+ }
435
+ return startServerNode(opts);
436
+ }
437
+ function buildServerContext(opts) {
419
438
  const { pool, permissions, config } = opts;
420
439
  const port = opts.port ?? config.port ?? 3000;
421
440
  const authConfig = {
@@ -424,35 +443,42 @@ function startServer(opts) {
424
443
  allowPublic: true
425
444
  };
426
445
  const subs = new SubscriptionManager(pool, permissions ?? null);
427
- const server = Bun.serve({
446
+ const handleHttp = async (req) => {
447
+ const url = new URL(req.url);
448
+ const path = url.pathname;
449
+ const auth = await resolveAuth(req.headers.get("authorization"), authConfig);
450
+ const tenantId = auth.tenantId ?? url.searchParams.get("tenantId") ?? null;
451
+ try {
452
+ return await route(req, url, path, auth, tenantId, {
453
+ pool,
454
+ permissions: permissions ?? null,
455
+ subs,
456
+ authConfig,
457
+ config,
458
+ oauthProviders: opts.oauthProviders ?? {}
459
+ });
460
+ } catch (err) {
461
+ if (err instanceof PermissionError) {
462
+ return json(err.toResponse(), 403);
463
+ }
464
+ const msg = err instanceof Error ? err.message : String(err);
465
+ return json({ error: "Internal Server Error", message: msg }, 500);
466
+ }
467
+ };
468
+ return { port, authConfig, subs, handleHttp };
469
+ }
470
+ function startServerBun(opts) {
471
+ const { port, subs, handleHttp } = buildServerContext(opts);
472
+ return Bun.serve({
428
473
  port,
429
- async fetch(req, server2) {
430
- const url = new URL(req.url);
431
- const path = url.pathname;
474
+ async fetch(req, server) {
432
475
  if (req.headers.get("upgrade") === "websocket") {
433
- const upgraded = server2.upgrade(req);
476
+ const upgraded = server.upgrade(req, { data: undefined });
434
477
  if (upgraded)
435
478
  return;
436
479
  return new Response("WebSocket upgrade failed", { status: 400 });
437
480
  }
438
- const auth = await resolveAuth(req.headers.get("authorization"), authConfig);
439
- const tenantId = auth.tenantId ?? url.searchParams.get("tenantId") ?? null;
440
- try {
441
- return await route(req, url, path, auth, tenantId, {
442
- pool,
443
- permissions: permissions ?? null,
444
- subs,
445
- authConfig,
446
- config,
447
- oauthProviders: opts.oauthProviders ?? {}
448
- });
449
- } catch (err) {
450
- if (err instanceof PermissionError) {
451
- return json(err.toResponse(), 403);
452
- }
453
- const msg = err instanceof Error ? err.message : String(err);
454
- return json({ error: "Internal Server Error", message: msg }, 500);
455
- }
481
+ return handleHttp(req);
456
482
  },
457
483
  websocket: {
458
484
  async open(ws) {
@@ -476,14 +502,42 @@ function startServer(opts) {
476
502
  }
477
503
  }
478
504
  });
479
- return server;
505
+ }
506
+ async function startServerNode(opts) {
507
+ const { port, subs, handleHttp } = buildServerContext(opts);
508
+ const { startNodeServer } = await import("./server/node-adapter.js");
509
+ return startNodeServer({
510
+ port,
511
+ fetch: handleHttp,
512
+ websocket: {
513
+ open(ws) {
514
+ const id = crypto.randomUUID();
515
+ ws.__clientId = id;
516
+ subs.addClient(id, ws, {
517
+ userId: null,
518
+ tenantId: null,
519
+ roles: [],
520
+ claims: {},
521
+ authenticated: false
522
+ }, null);
523
+ },
524
+ async message(ws, raw) {
525
+ const id = ws.__clientId;
526
+ await subs.handleMessage(id, typeof raw === "string" ? raw : raw.toString());
527
+ },
528
+ close(ws) {
529
+ const id = ws.__clientId;
530
+ subs.removeClient(id);
531
+ }
532
+ }
533
+ });
480
534
  }
481
535
  async function route(req, url, path, auth, tenantId, ctx) {
482
536
  const method = req.method.toUpperCase();
483
537
  if (method === "GET" && path === "/__trellis/inspector.js") {
484
538
  const candidates = [
485
- join(import.meta.dir, "db", "inspector.js"),
486
- join(import.meta.dir, "inspector.js")
539
+ join(__moduleDir, "db", "inspector.js"),
540
+ join(__moduleDir, "inspector.js")
487
541
  ];
488
542
  for (const p of candidates) {
489
543
  if (existsSync(p)) {
@@ -498,8 +552,8 @@ async function route(req, url, path, auth, tenantId, ctx) {
498
552
  }
499
553
  if (method === "GET" && path === "/__trellis/trellis.css") {
500
554
  const candidates = [
501
- join(import.meta.dir, "db", "trellis.css"),
502
- join(import.meta.dir, "trellis.css")
555
+ join(__moduleDir, "db", "trellis.css"),
556
+ join(__moduleDir, "trellis.css")
503
557
  ];
504
558
  for (const p of candidates) {
505
559
  if (existsSync(p)) {
@@ -844,4 +898,4 @@ function json(data, status = 200) {
844
898
  });
845
899
  }
846
900
 
847
- export { ANONYMOUS, signJwt, verifyJwt, resolveAuth, GOOGLE_PROVIDER, GITHUB_PROVIDER, buildOAuthUrl, exchangeOAuthCode, PermissionRegistry, PermissionError, PUBLIC_READ, FULLY_PUBLIC, OWNER_ONLY, ADMIN_ONLY, SubscriptionManager, startServer };
901
+ export { ANONYMOUS, signJwt, verifyJwt, resolveAuth, GOOGLE_PROVIDER, GITHUB_PROVIDER, buildOAuthUrl, exchangeOAuthCode, PermissionRegistry, PermissionError, PUBLIC_READ, FULLY_PUBLIC, OWNER_ONLY, ADMIN_ONLY, SubscriptionManager, startServer, startServerCrossRuntime };
@@ -1,8 +1,13 @@
1
1
  // @bun
2
2
  import {
3
- SqliteKernelBackend,
4
3
  TrellisKernel
5
- } from "./index-0zk3fx2s.js";
4
+ } from "./index-4wxa8xz4.js";
5
+ import {
6
+ SqliteKernelBackend
7
+ } from "./index-h7zxhhhh.js";
8
+ import {
9
+ __require
10
+ } from "./index-a76rekgs.js";
6
11
 
7
12
  // src/server/tenancy.ts
8
13
  import { existsSync, mkdirSync } from "fs";
@@ -14,18 +19,34 @@ class TenantPool {
14
19
  pool = new Map;
15
20
  dbPath;
16
21
  agentId;
17
- constructor(dbPath, agentId = "trellis-db") {
22
+ backendOpts;
23
+ constructor(dbPath, agentIdOrOpts = "trellis-db") {
18
24
  this.dbPath = resolve(dbPath);
19
- this.agentId = agentId;
25
+ if (typeof agentIdOrOpts === "string") {
26
+ this.agentId = agentIdOrOpts;
27
+ this.backendOpts = undefined;
28
+ } else {
29
+ this.agentId = agentIdOrOpts.agentId ?? "trellis-db";
30
+ this.backendOpts = agentIdOrOpts.backend;
31
+ }
20
32
  this._ensureDirs();
21
33
  }
22
34
  get(tenantId) {
23
35
  const id = tenantId ?? DEFAULT_TENANT;
24
36
  if (!this.pool.has(id)) {
25
- this.pool.set(id, this._createKernel(id));
37
+ this.pool.set(id, this._createKernelSync(id));
26
38
  }
27
39
  return this.pool.get(id);
28
40
  }
41
+ async preload(tenantId) {
42
+ const id = tenantId ?? DEFAULT_TENANT;
43
+ const cached = this.pool.get(id);
44
+ if (cached)
45
+ return cached;
46
+ const kernel = await this._createKernelAsync(id);
47
+ this.pool.set(id, kernel);
48
+ return kernel;
49
+ }
29
50
  has(tenantId) {
30
51
  return this.pool.has(tenantId);
31
52
  }
@@ -52,9 +73,18 @@ class TenantPool {
52
73
  }
53
74
  return join(this.dbPath, TENANTS_DIR, `${id}.sqlite`);
54
75
  }
55
- _createKernel(tenantId) {
76
+ _createKernelSync(tenantId) {
56
77
  const sqlitePath = this.dbFilePath(tenantId);
57
78
  const backend = new SqliteKernelBackend(sqlitePath);
79
+ return this._wrapKernel(backend);
80
+ }
81
+ async _createKernelAsync(tenantId) {
82
+ const sqlitePath = this.dbFilePath(tenantId);
83
+ const { createKernelBackend } = await import("./core/persist/factory.js");
84
+ const backend = await createKernelBackend(sqlitePath, this.backendOpts);
85
+ return this._wrapKernel(backend);
86
+ }
87
+ _wrapKernel(backend) {
58
88
  const kernel = new TrellisKernel({
59
89
  backend,
60
90
  agentId: this.agentId,
@@ -434,9 +434,13 @@ class BlobStore {
434
434
  return this.hexFromBuffer(hashBuffer);
435
435
  }
436
436
  hashSync(content) {
437
- const hasher = new Bun.CryptoHasher("sha256");
438
- hasher.update(content);
439
- return hasher.digest("hex");
437
+ if (typeof globalThis.Bun !== "undefined") {
438
+ const hasher = new globalThis.Bun.CryptoHasher("sha256");
439
+ hasher.update(content);
440
+ return hasher.digest("hex");
441
+ }
442
+ const { createHash } = __require("crypto");
443
+ return createHash("sha256").update(content).digest("hex");
440
444
  }
441
445
  count() {
442
446
  try {
@@ -0,0 +1,42 @@
1
+ // @bun
2
+ import {
3
+ __require
4
+ } from "./index-a76rekgs.js";
5
+
6
+ // src/core/persist/factory.ts
7
+ async function createKernelBackend(dbPath, opts = {}) {
8
+ const choice = opts.backend ?? detectBackend();
9
+ if (choice === "bun") {
10
+ const { SqliteKernelBackend } = await import("./sqlite-backend-0vsmc6qj.js");
11
+ const backend2 = new SqliteKernelBackend(dbPath);
12
+ backend2.init();
13
+ return backend2;
14
+ }
15
+ if (choice === "better-sqlite") {
16
+ const { BetterSqliteKernelBackend } = await import("./better-sqlite-backend-ahx5p0br.js");
17
+ const backend2 = new BetterSqliteKernelBackend(dbPath);
18
+ backend2.init();
19
+ return backend2;
20
+ }
21
+ const { SqlJsKernelBackend } = await import("./core/persist/sqljs-backend.js");
22
+ const backend = await SqlJsKernelBackend.create({
23
+ dbPath,
24
+ autoFlushEvery: opts.sqljs?.autoFlushEvery
25
+ });
26
+ backend.init();
27
+ return backend;
28
+ }
29
+ function detectBackend() {
30
+ if (typeof globalThis.Bun !== "undefined")
31
+ return "bun";
32
+ try {
33
+ const { createRequire } = __require("module");
34
+ const req = createRequire(import.meta.url);
35
+ req.resolve("better-sqlite3");
36
+ return "better-sqlite";
37
+ } catch {
38
+ return "sqljs";
39
+ }
40
+ }
41
+
42
+ export { createKernelBackend };
@@ -0,0 +1,252 @@
1
+ // @bun
2
+ import {
3
+ __require
4
+ } from "./index-a76rekgs.js";
5
+
6
+ // src/core/persist/sqlite-backend.ts
7
+ var _DatabaseCtor = null;
8
+ function loadDatabaseCtor() {
9
+ if (_DatabaseCtor)
10
+ return _DatabaseCtor;
11
+ try {
12
+ const { createRequire } = __require("module");
13
+ const requireCJS = createRequire(import.meta.url);
14
+ _DatabaseCtor = requireCJS("bun:sqlite").Database;
15
+ return _DatabaseCtor;
16
+ } catch {
17
+ throw new Error("SqliteKernelBackend requires the Bun runtime (built-in `bun:sqlite`). " + "In Node / WebContainer use `createKernelBackend()` from " + "`trellis/core` \u2014 it auto-selects better-sqlite3 or sql.js.");
18
+ }
19
+ }
20
+ var SCHEMA_SQL = `
21
+ CREATE TABLE IF NOT EXISTS ops (
22
+ hash TEXT PRIMARY KEY,
23
+ kind TEXT NOT NULL,
24
+ timestamp TEXT NOT NULL,
25
+ agent_id TEXT NOT NULL,
26
+ previous_hash TEXT,
27
+ payload TEXT NOT NULL
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS snapshots (
31
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
32
+ last_op_hash TEXT NOT NULL,
33
+ data TEXT NOT NULL,
34
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
35
+ );
36
+
37
+ CREATE TABLE IF NOT EXISTS blobs (
38
+ hash TEXT PRIMARY KEY,
39
+ content BLOB NOT NULL
40
+ );
41
+
42
+ CREATE INDEX IF NOT EXISTS idx_ops_kind ON ops(kind);
43
+ CREATE INDEX IF NOT EXISTS idx_ops_timestamp ON ops(timestamp);
44
+ CREATE INDEX IF NOT EXISTS idx_ops_agent ON ops(agent_id);
45
+ CREATE INDEX IF NOT EXISTS idx_ops_previous ON ops(previous_hash);
46
+ CREATE INDEX IF NOT EXISTS idx_snapshots_op ON snapshots(last_op_hash);
47
+ `;
48
+
49
+ class SqliteKernelBackend {
50
+ dbPath;
51
+ db;
52
+ _stmts = null;
53
+ constructor(dbPath) {
54
+ this.dbPath = dbPath;
55
+ const DatabaseCtor = loadDatabaseCtor();
56
+ this.db = new DatabaseCtor(dbPath);
57
+ }
58
+ init() {
59
+ this.db.exec("PRAGMA journal_mode=WAL;");
60
+ this.db.exec("PRAGMA foreign_keys=ON;");
61
+ this.db.exec("PRAGMA synchronous=NORMAL;");
62
+ this.db.exec(SCHEMA_SQL);
63
+ this._prepareStatements();
64
+ }
65
+ _prepareStatements() {
66
+ this._stmts = {
67
+ insert: this.db.prepare(`
68
+ INSERT OR IGNORE INTO ops (hash, kind, timestamp, agent_id, previous_hash, payload)
69
+ VALUES ($hash, $kind, $timestamp, $agentId, $previousHash, $payload)
70
+ `),
71
+ readAll: this.db.prepare(`
72
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
73
+ FROM ops ORDER BY rowid ASC
74
+ `),
75
+ readUntil: this.db.prepare(`
76
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
77
+ FROM ops WHERE rowid <= (SELECT rowid FROM ops WHERE hash = $hash)
78
+ ORDER BY rowid ASC
79
+ `),
80
+ readAfter: this.db.prepare(`
81
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
82
+ FROM ops WHERE rowid > (SELECT rowid FROM ops WHERE hash = $hash)
83
+ ORDER BY rowid ASC
84
+ `),
85
+ getByHash: this.db.prepare(`
86
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
87
+ FROM ops WHERE hash = $hash
88
+ `),
89
+ getLast: this.db.prepare(`
90
+ SELECT hash, kind, timestamp, agent_id, previous_hash, payload
91
+ FROM ops ORDER BY rowid DESC LIMIT 1
92
+ `),
93
+ count: this.db.prepare("SELECT COUNT(*) as cnt FROM ops"),
94
+ saveSnapshot: this.db.prepare(`
95
+ INSERT INTO snapshots (last_op_hash, data)
96
+ VALUES ($lastOpHash, $data)
97
+ `),
98
+ loadSnapshot: this.db.prepare(`
99
+ SELECT last_op_hash, data FROM snapshots
100
+ ORDER BY id DESC LIMIT 1
101
+ `),
102
+ putBlob: this.db.prepare(`
103
+ INSERT OR IGNORE INTO blobs (hash, content) VALUES ($hash, $content)
104
+ `),
105
+ getBlob: this.db.prepare(`
106
+ SELECT content FROM blobs WHERE hash = $hash
107
+ `),
108
+ hasBlob: this.db.prepare(`
109
+ SELECT 1 FROM blobs WHERE hash = $hash
110
+ `)
111
+ };
112
+ }
113
+ append(op) {
114
+ const payload = JSON.stringify({
115
+ facts: op.facts,
116
+ links: op.links,
117
+ ...op.deleteFacts?.length ? { deleteFacts: op.deleteFacts } : {},
118
+ ...op.deleteLinks?.length ? { deleteLinks: op.deleteLinks } : {},
119
+ ...op.vcs ? { vcs: op.vcs } : {},
120
+ ...op.signature ? { signature: op.signature } : {}
121
+ });
122
+ this._stmts.insert.run({
123
+ $hash: op.hash,
124
+ $kind: op.kind,
125
+ $timestamp: op.timestamp,
126
+ $agentId: op.agentId,
127
+ $previousHash: op.previousHash ?? null,
128
+ $payload: payload
129
+ });
130
+ }
131
+ appendBatch(ops) {
132
+ if (ops.length === 0)
133
+ return;
134
+ this.db.transaction(() => {
135
+ for (const op of ops) {
136
+ this.append(op);
137
+ }
138
+ })();
139
+ }
140
+ readAll() {
141
+ const rows = this._stmts.readAll.all();
142
+ return rows.map(rowToOp);
143
+ }
144
+ readUntil(hash) {
145
+ const rows = this._stmts.readUntil.all({ $hash: hash });
146
+ return rows.map(rowToOp);
147
+ }
148
+ readAfter(hash) {
149
+ const rows = this._stmts.readAfter.all({ $hash: hash });
150
+ return rows.map(rowToOp);
151
+ }
152
+ readUntilTimestamp(isoTimestamp) {
153
+ const rows = this.db.prepare(`SELECT hash, kind, timestamp, agent_id, previous_hash, payload
154
+ FROM ops WHERE timestamp <= $ts ORDER BY rowid ASC`).all({ $ts: isoTimestamp });
155
+ return rows.map(rowToOp);
156
+ }
157
+ getLastOp() {
158
+ const row = this._stmts.getLast.get();
159
+ return row ? rowToOp(row) : undefined;
160
+ }
161
+ getByHash(hash) {
162
+ return this.getOpByHash(hash);
163
+ }
164
+ getOpCount() {
165
+ return this.count();
166
+ }
167
+ getOpByHash(hash) {
168
+ const row = this._stmts.getByHash.get({ $hash: hash });
169
+ return row ? rowToOp(row) : undefined;
170
+ }
171
+ count() {
172
+ const row = this._stmts.count.get();
173
+ return row?.cnt ?? 0;
174
+ }
175
+ findCommonAncestor(hashA, hashB) {
176
+ const ancestorsA = new Set;
177
+ let cursor = hashA;
178
+ while (cursor) {
179
+ ancestorsA.add(cursor);
180
+ const op = this.getOpByHash(cursor);
181
+ cursor = op?.previousHash;
182
+ }
183
+ cursor = hashB;
184
+ while (cursor) {
185
+ if (ancestorsA.has(cursor)) {
186
+ return this.getOpByHash(cursor);
187
+ }
188
+ const op = this.getOpByHash(cursor);
189
+ cursor = op?.previousHash;
190
+ }
191
+ return;
192
+ }
193
+ saveSnapshot(lastOpHash, data) {
194
+ this._stmts.saveSnapshot.run({
195
+ $lastOpHash: lastOpHash,
196
+ $data: JSON.stringify(data)
197
+ });
198
+ }
199
+ loadLatestSnapshot() {
200
+ const row = this._stmts.loadSnapshot.get();
201
+ if (!row)
202
+ return;
203
+ return {
204
+ lastOpHash: row.last_op_hash,
205
+ data: JSON.parse(row.data)
206
+ };
207
+ }
208
+ putBlob(hash, content) {
209
+ this._stmts.putBlob.run({
210
+ $hash: hash,
211
+ $content: Buffer.from(content)
212
+ });
213
+ }
214
+ getBlob(hash) {
215
+ const row = this._stmts.getBlob.get({ $hash: hash });
216
+ if (!row)
217
+ return;
218
+ return new Uint8Array(row.content);
219
+ }
220
+ hasBlob(hash) {
221
+ return !!this._stmts.hasBlob.get({ $hash: hash });
222
+ }
223
+ close() {
224
+ this.db.close();
225
+ }
226
+ }
227
+ function rowToOp(row) {
228
+ const payload = JSON.parse(row.payload);
229
+ const op = {
230
+ hash: row.hash,
231
+ kind: row.kind,
232
+ timestamp: row.timestamp,
233
+ agentId: row.agent_id
234
+ };
235
+ if (row.previous_hash)
236
+ op.previousHash = row.previous_hash;
237
+ if (payload.facts)
238
+ op.facts = payload.facts;
239
+ if (payload.links)
240
+ op.links = payload.links;
241
+ if (payload.deleteFacts)
242
+ op.deleteFacts = payload.deleteFacts;
243
+ if (payload.deleteLinks)
244
+ op.deleteLinks = payload.deleteLinks;
245
+ if (payload.vcs)
246
+ op.vcs = payload.vcs;
247
+ if (payload.signature)
248
+ op.signature = payload.signature;
249
+ return op;
250
+ }
251
+
252
+ export { SqliteKernelBackend };