@haverstack/record-adapter-sqljs 0.6.0

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/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
2
+
3
+ To the extent possible under law, the Haverstack contributors have waived all
4
+ copyright and related or neighboring rights to Haverstack. This work is
5
+ published from the United States.
6
+
7
+ https://creativecommons.org/publicdomain/zero/1.0/
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Haverstack — SQLite Record Adapter
3
+ * -------------------------------------------------------
4
+ * Implements StackRecordAdapter using sql.js (SQLite compiled
5
+ * to WebAssembly). Runs in Node, browsers, and other runtimes
6
+ * without native compilation.
7
+ *
8
+ * The database is held in memory and flushed to disk on every
9
+ * write. Stack config (ownerEntityId, timezone) is stored as
10
+ * a singleton _config@1 record with id='_config' in the
11
+ * records table.
12
+ *
13
+ * Also exposes token management methods (createToken,
14
+ * lookupToken, listTokens, revokeToken) used by server
15
+ * implementations to issue and validate bearer tokens.
16
+ */
17
+ import type { StackRecordAdapter, StackRecord, StackType, TypeId, RecordVersion, StackQuery, QueryResult, Association, AdapterCapabilities } from '@haverstack/core';
18
+ export type SQLiteRecordInitializeOptions = {
19
+ /** Absolute path to the .db file. Must not already exist. */
20
+ path: string;
21
+ /** IANA timezone string e.g. "America/New_York". */
22
+ timezone: string;
23
+ /** Entity ID of the stack owner. */
24
+ entityId: string;
25
+ };
26
+ export type SQLiteRecordOpenOptions = {
27
+ /** Absolute path to an existing .db file. */
28
+ path: string;
29
+ };
30
+ export type TokenInfo = {
31
+ id: string;
32
+ entityId: string;
33
+ label?: string;
34
+ createdAt: Date;
35
+ expiresAt?: Date;
36
+ };
37
+ export declare class SQLiteRecordAdapter implements StackRecordAdapter {
38
+ private readonly SQL;
39
+ private readonly path;
40
+ readonly capabilities: AdapterCapabilities;
41
+ ownerEntityId: string;
42
+ timezone: string;
43
+ private db;
44
+ private constructor();
45
+ /**
46
+ * Initialize a new stack database. Fails if the file already exists —
47
+ * use open() for existing databases.
48
+ */
49
+ static initialize(opts: SQLiteRecordInitializeOptions): Promise<SQLiteRecordAdapter>;
50
+ /**
51
+ * Open an existing stack database. Fails if the file does not exist —
52
+ * use initialize() for new databases.
53
+ */
54
+ static open(opts: SQLiteRecordOpenOptions): Promise<SQLiteRecordAdapter>;
55
+ /** Flush the in-memory database to disk. Called after every write. */
56
+ private persist;
57
+ private readConfig;
58
+ createRecord(record: StackRecord): Promise<StackRecord>;
59
+ getRecord(id: string): Promise<StackRecord | null>;
60
+ updateRecord(id: string, changes: Partial<StackRecord>): Promise<StackRecord>;
61
+ deleteRecord(id: string, opts?: {
62
+ hard?: boolean;
63
+ }): Promise<void>;
64
+ queryRecords(query: StackQuery): Promise<QueryResult>;
65
+ getVersions(id: string): Promise<RecordVersion[]>;
66
+ getVersion(id: string, version: number): Promise<RecordVersion | null>;
67
+ saveVersion(id: string, version: RecordVersion): Promise<void>;
68
+ saveType(type: StackType): Promise<void>;
69
+ getType(id: TypeId): Promise<StackType | null>;
70
+ listTypes(): Promise<StackType[]>;
71
+ createToken(entityId: string, opts?: {
72
+ label?: string;
73
+ expiresAt?: Date;
74
+ }): Promise<{
75
+ id: string;
76
+ token: string;
77
+ }>;
78
+ lookupToken(token: string): Promise<{
79
+ entityId: string;
80
+ } | null>;
81
+ listTokens(): Promise<TokenInfo[]>;
82
+ revokeToken(id: string): Promise<void>;
83
+ associate(recordId: string, association: Association): Promise<void>;
84
+ dissociate(recordId: string, association: Association): Promise<void>;
85
+ private insertAssociations;
86
+ private getAssociationsForRecord;
87
+ private updateFts;
88
+ private execQuery;
89
+ flush(): Promise<void>;
90
+ close(): Promise<void>;
91
+ }
92
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,705 @@
1
+ /**
2
+ * Haverstack — SQLite Record Adapter
3
+ * -------------------------------------------------------
4
+ * Implements StackRecordAdapter using sql.js (SQLite compiled
5
+ * to WebAssembly). Runs in Node, browsers, and other runtimes
6
+ * without native compilation.
7
+ *
8
+ * The database is held in memory and flushed to disk on every
9
+ * write. Stack config (ownerEntityId, timezone) is stored as
10
+ * a singleton _config@1 record with id='_config' in the
11
+ * records table.
12
+ *
13
+ * Also exposes token management methods (createToken,
14
+ * lookupToken, listTokens, revokeToken) used by server
15
+ * implementations to issue and validate bearer tokens.
16
+ */
17
+ import initSqlJs from 'sql.js';
18
+ import { createHash, randomBytes } from 'node:crypto';
19
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
20
+ // -------------------------------------------------------
21
+ // SQL — schema
22
+ // -------------------------------------------------------
23
+ const SCHEMA_SQL = `
24
+ CREATE TABLE IF NOT EXISTS records (
25
+ id TEXT PRIMARY KEY,
26
+ type_id TEXT NOT NULL,
27
+ created_at INTEGER NOT NULL,
28
+ updated_at INTEGER NOT NULL,
29
+ content TEXT NOT NULL CHECK (json_valid(content)),
30
+ version INTEGER NOT NULL DEFAULT 1,
31
+ parent_id TEXT,
32
+ entity_id TEXT,
33
+ app_id TEXT,
34
+ deleted_at INTEGER,
35
+ permissions TEXT CHECK (permissions IS NULL OR json_valid(permissions))
36
+ ) STRICT;
37
+
38
+ CREATE TABLE IF NOT EXISTS associations (
39
+ record_id TEXT NOT NULL REFERENCES records(id),
40
+ kind TEXT NOT NULL CHECK (kind IN ('tag', 'attachment', 'relationship')),
41
+ label TEXT NOT NULL,
42
+ file_id TEXT NOT NULL DEFAULT '',
43
+ mime_type TEXT,
44
+ related_id TEXT NOT NULL DEFAULT '',
45
+ PRIMARY KEY (record_id, kind, label, file_id, related_id)
46
+ ) STRICT;
47
+
48
+ CREATE TABLE IF NOT EXISTS versions (
49
+ record_id TEXT NOT NULL REFERENCES records(id),
50
+ version INTEGER NOT NULL,
51
+ content TEXT NOT NULL CHECK (json_valid(content)),
52
+ updated_at INTEGER NOT NULL,
53
+ entity_id TEXT,
54
+ PRIMARY KEY (record_id, version)
55
+ ) STRICT;
56
+
57
+ CREATE TABLE IF NOT EXISTS types (
58
+ id TEXT PRIMARY KEY,
59
+ base_id TEXT NOT NULL,
60
+ version INTEGER NOT NULL,
61
+ name TEXT NOT NULL,
62
+ schema TEXT NOT NULL CHECK (json_valid(schema)),
63
+ schema_hash TEXT NOT NULL,
64
+ migrates_from TEXT,
65
+ created_at INTEGER NOT NULL
66
+ ) STRICT;
67
+
68
+ CREATE TABLE IF NOT EXISTS tokens (
69
+ id TEXT PRIMARY KEY,
70
+ token_hash TEXT NOT NULL UNIQUE,
71
+ entity_id TEXT NOT NULL,
72
+ label TEXT,
73
+ created_at INTEGER NOT NULL,
74
+ expires_at INTEGER
75
+ ) STRICT;
76
+
77
+ -- Indexes
78
+ CREATE INDEX IF NOT EXISTS idx_records_type_id ON records(type_id);
79
+ CREATE INDEX IF NOT EXISTS idx_records_parent_id ON records(parent_id);
80
+ CREATE INDEX IF NOT EXISTS idx_records_entity_id ON records(entity_id);
81
+ CREATE INDEX IF NOT EXISTS idx_records_app_id ON records(app_id);
82
+ CREATE INDEX IF NOT EXISTS idx_records_deleted_at ON records(deleted_at);
83
+ CREATE INDEX IF NOT EXISTS idx_records_created_at ON records(created_at);
84
+ CREATE INDEX IF NOT EXISTS idx_records_updated_at ON records(updated_at);
85
+ CREATE INDEX IF NOT EXISTS idx_assoc_record_id ON associations(record_id);
86
+ CREATE INDEX IF NOT EXISTS idx_assoc_kind_label ON associations(kind, label);
87
+ CREATE INDEX IF NOT EXISTS idx_assoc_kind_file_id ON associations(kind, file_id);
88
+ CREATE INDEX IF NOT EXISTS idx_types_base_id ON types(base_id);
89
+ CREATE INDEX IF NOT EXISTS idx_tokens_hash ON tokens(token_hash);
90
+
91
+ -- Full-text search (FTS4 — compatible with sql.js)
92
+ CREATE VIRTUAL TABLE IF NOT EXISTS records_fts USING fts4(
93
+ content,
94
+ content='records'
95
+ );
96
+ `;
97
+ // -------------------------------------------------------
98
+ // Helpers
99
+ // -------------------------------------------------------
100
+ const toMs = (d) => d.getTime();
101
+ const fromMs = (ms) => new Date(ms);
102
+ const rowToRecord = (row, associations) => {
103
+ const record = {
104
+ id: row.id,
105
+ typeId: row.type_id,
106
+ createdAt: fromMs(row.created_at),
107
+ updatedAt: fromMs(row.updated_at),
108
+ content: JSON.parse(row.content),
109
+ version: row.version,
110
+ };
111
+ if (row.parent_id)
112
+ record.parentId = row.parent_id;
113
+ if (row.entity_id)
114
+ record.entityId = row.entity_id;
115
+ if (row.app_id)
116
+ record.appId = row.app_id;
117
+ if (row.deleted_at)
118
+ record.deletedAt = fromMs(row.deleted_at);
119
+ if (row.permissions)
120
+ record.permissions = JSON.parse(row.permissions);
121
+ if (associations.length)
122
+ record.associations = associations;
123
+ return record;
124
+ };
125
+ const rowToAssociation = (row) => {
126
+ if (row.kind === 'tag') {
127
+ return { kind: 'tag', label: row.label };
128
+ }
129
+ if (row.kind === 'attachment') {
130
+ return {
131
+ kind: 'attachment',
132
+ label: row.label,
133
+ fileId: row.file_id,
134
+ mimeType: row.mime_type,
135
+ };
136
+ }
137
+ // relationship
138
+ return {
139
+ kind: 'relationship',
140
+ label: row.label,
141
+ recordId: row.related_id,
142
+ };
143
+ };
144
+ const rowToType = (row) => {
145
+ const t = {
146
+ id: row.id,
147
+ baseId: row.base_id,
148
+ version: row.version,
149
+ name: row.name,
150
+ schema: JSON.parse(row.schema),
151
+ schemaHash: row.schema_hash,
152
+ createdAt: fromMs(row.created_at),
153
+ };
154
+ if (row.migrates_from)
155
+ t.migratesFrom = row.migrates_from;
156
+ return t;
157
+ };
158
+ const rowToVersion = (row) => {
159
+ const v = {
160
+ version: row.version,
161
+ content: JSON.parse(row.content),
162
+ updatedAt: fromMs(row.updated_at),
163
+ };
164
+ if (row.entity_id)
165
+ v.entityId = row.entity_id;
166
+ return v;
167
+ };
168
+ // -------------------------------------------------------
169
+ // FTS4 query sanitization
170
+ // -------------------------------------------------------
171
+ /**
172
+ * Sanitizes user input for safe use in an FTS4 MATCH clause.
173
+ *
174
+ * FTS4's query language supports operators (AND/OR/NOT, phrases, NEAR, wildcards)
175
+ * that can be expensive or cause parse errors with untrusted input.
176
+ * This function removes the dangerous operators while preserving useful ones:
177
+ * kept: AND/OR/NOT (with a left operand), phrase queries ("…"), implicit AND
178
+ * removed: wildcards (*), NEAR/N, bare NOT (no left operand)
179
+ * capped: parenthesis nesting depth (default: 2)
180
+ *
181
+ * A query timeout is not implementable here: sql.js runs SQLite as synchronous
182
+ * WASM that blocks the JS event loop, and db.interrupt() is not exposed. Moving
183
+ * sql.js into a Worker thread would enable a timeout via interrupt() but is out
184
+ * of scope for this change.
185
+ */
186
+ const sanitizeFts4Query = (query, maxDepth = 2) => {
187
+ if (!query)
188
+ return '';
189
+ // Remove wildcards
190
+ let clean = query.replace(/\*/g, '');
191
+ // Remove NEAR operator (handles NEAR and NEAR/N variants)
192
+ clean = clean.replace(/\bNEAR(?:\/\d+)?\b/gi, '');
193
+ // Strip bare NOT with no left operand — FTS4 requires "term NOT term", not "NOT term"
194
+ clean = clean.replace(/(?:^|\(\s*)NOT\s+/gi, (m) => m.replace(/NOT\s+/i, ''));
195
+ // Enforce max nesting depth; replace excess ( with a space and discard unmatched )
196
+ let currentDepth = 0;
197
+ let result = '';
198
+ for (const char of clean) {
199
+ if (char === '(') {
200
+ if (currentDepth < maxDepth) {
201
+ currentDepth++;
202
+ result += char;
203
+ }
204
+ else
205
+ result += ' ';
206
+ }
207
+ else if (char === ')') {
208
+ if (currentDepth > 0) {
209
+ currentDepth--;
210
+ result += char;
211
+ }
212
+ else
213
+ result += ' ';
214
+ }
215
+ else {
216
+ result += char;
217
+ }
218
+ }
219
+ // Auto-close any unclosed parens
220
+ if (currentDepth > 0)
221
+ result += ')'.repeat(currentDepth);
222
+ // Iteratively remove empty paren pairs left behind by NEAR/NOT stripping
223
+ let prev;
224
+ do {
225
+ prev = result;
226
+ result = result.replace(/\(\s*\)/g, ' ');
227
+ } while (result !== prev);
228
+ return result.replace(/\s+/g, ' ').replace(/\(\s+/g, '(').replace(/\s+\)/g, ')').trim();
229
+ };
230
+ const getSortField = (query) => query.sort?.field ?? 'createdAt';
231
+ const getSortColumn = (field) => field === 'createdAt' ? 'created_at' : field === 'updatedAt' ? 'updated_at' : 'version';
232
+ const buildWhereClause = (query) => {
233
+ const conditions = ["r.id != '_config'"];
234
+ const params = [];
235
+ const f = query.filter ?? {};
236
+ if (!f.includeDeleted) {
237
+ conditions.push('r.deleted_at IS NULL');
238
+ }
239
+ if (f.typeId !== undefined) {
240
+ const ids = Array.isArray(f.typeId) ? f.typeId : [f.typeId];
241
+ conditions.push(`r.type_id IN (${ids.map(() => '?').join(',')})`);
242
+ params.push(...ids);
243
+ }
244
+ if (f.parentId !== undefined) {
245
+ if (f.parentId === null) {
246
+ conditions.push('r.parent_id IS NULL');
247
+ }
248
+ else {
249
+ conditions.push('r.parent_id = ?');
250
+ params.push(f.parentId);
251
+ }
252
+ }
253
+ if (f.appId !== undefined) {
254
+ const ids = Array.isArray(f.appId) ? f.appId : [f.appId];
255
+ conditions.push(`r.app_id IN (${ids.map(() => '?').join(',')})`);
256
+ params.push(...ids);
257
+ }
258
+ if (f.entityId !== undefined) {
259
+ const ids = Array.isArray(f.entityId) ? f.entityId : [f.entityId];
260
+ conditions.push(`r.entity_id IN (${ids.map(() => '?').join(',')})`);
261
+ params.push(...ids);
262
+ }
263
+ if (f.createdAt?.after) {
264
+ conditions.push('r.created_at > ?');
265
+ params.push(toMs(f.createdAt.after));
266
+ }
267
+ if (f.createdAt?.before) {
268
+ conditions.push('r.created_at < ?');
269
+ params.push(toMs(f.createdAt.before));
270
+ }
271
+ if (f.updatedAt?.after) {
272
+ conditions.push('r.updated_at > ?');
273
+ params.push(toMs(f.updatedAt.after));
274
+ }
275
+ if (f.updatedAt?.before) {
276
+ conditions.push('r.updated_at < ?');
277
+ params.push(toMs(f.updatedAt.before));
278
+ }
279
+ // Tag filter — record must have ALL specified tags
280
+ if (f.tags?.length) {
281
+ for (const tag of f.tags) {
282
+ conditions.push(`EXISTS (SELECT 1 FROM associations a WHERE a.record_id = r.id AND a.kind = 'tag' AND a.label = ?)`);
283
+ params.push(tag);
284
+ }
285
+ }
286
+ // Attachment label filter
287
+ if (f.hasAttachment) {
288
+ conditions.push(`EXISTS (SELECT 1 FROM associations a WHERE a.record_id = r.id AND a.kind = 'attachment' AND a.label = ?)`);
289
+ params.push(f.hasAttachment);
290
+ }
291
+ // Attachment file ID filter — find records that reference a specific file
292
+ if (f.attachmentFileId) {
293
+ conditions.push(`EXISTS (SELECT 1 FROM associations a WHERE a.record_id = r.id AND a.kind = 'attachment' AND a.file_id = ?)`);
294
+ params.push(f.attachmentFileId);
295
+ }
296
+ // Relationship filter
297
+ if (f.relatedTo) {
298
+ conditions.push(`EXISTS (SELECT 1 FROM associations a WHERE a.record_id = r.id AND a.kind = 'relationship' AND a.related_id = ?` +
299
+ (f.relatedTo.label ? ` AND a.label = ?` : '') +
300
+ `)`);
301
+ params.push(f.relatedTo.recordId);
302
+ if (f.relatedTo.label)
303
+ params.push(f.relatedTo.label);
304
+ }
305
+ // Content field filters (top-level scalar exact match)
306
+ if (f.content) {
307
+ for (const [key, value] of Object.entries(f.content)) {
308
+ conditions.push(`json_extract(r.content, ?) = ?`);
309
+ params.push(`$.${key}`, value);
310
+ }
311
+ }
312
+ if (f.search) {
313
+ const sanitized = sanitizeFts4Query(f.search);
314
+ if (sanitized) {
315
+ conditions.push(`r.rowid IN (SELECT rowid FROM records_fts WHERE records_fts MATCH ?)`);
316
+ params.push(sanitized);
317
+ }
318
+ }
319
+ // Cursor (sort-field value + id for stable pagination)
320
+ if (query.cursor) {
321
+ const parts = Buffer.from(query.cursor, 'base64').toString().split('|');
322
+ // New format: field|value|id (3 parts). Legacy format: value|id (2 parts, implies createdAt).
323
+ const [cursorField, cursorValue, cursorId] = parts.length === 3
324
+ ? parts
325
+ : ['createdAt', parts[0], parts[1]];
326
+ const validSortFields = ['createdAt', 'updatedAt', 'version'];
327
+ if (!validSortFields.includes(cursorField)) {
328
+ throw new Error(`Invalid cursor: unknown sort field "${cursorField}"`);
329
+ }
330
+ const numericValue = Number(cursorValue);
331
+ if (!isFinite(numericValue)) {
332
+ throw new Error(`Invalid cursor: non-numeric sort value`);
333
+ }
334
+ const col = getSortColumn(cursorField);
335
+ const sortDir = query.sort?.direction ?? 'desc';
336
+ const op = sortDir === 'asc' ? '>' : '<';
337
+ conditions.push(`(r.${col} ${op} ? OR (r.${col} = ? AND r.id ${op} ?))`);
338
+ params.push(numericValue, numericValue, cursorId);
339
+ }
340
+ return {
341
+ sql: conditions.length ? `WHERE ${conditions.join(' AND ')}` : '',
342
+ params,
343
+ };
344
+ };
345
+ const buildOrderClause = (query) => {
346
+ const field = getSortField(query);
347
+ const dir = (query.sort?.direction ?? 'desc').toUpperCase();
348
+ return `ORDER BY r.${getSortColumn(field)} ${dir}, r.id ${dir}`;
349
+ };
350
+ const makeCursor = (record, field) => {
351
+ const value = field === 'updatedAt'
352
+ ? toMs(record.updatedAt)
353
+ : field === 'version'
354
+ ? record.version
355
+ : toMs(record.createdAt);
356
+ return Buffer.from(`${field}|${value}|${record.id}`).toString('base64');
357
+ };
358
+ // -------------------------------------------------------
359
+ // SQLiteRecordAdapter
360
+ // -------------------------------------------------------
361
+ export class SQLiteRecordAdapter {
362
+ SQL;
363
+ path;
364
+ capabilities = {
365
+ fullTextSearch: true,
366
+ contentFieldQuery: true,
367
+ sortableFields: ['createdAt', 'updatedAt', 'version'],
368
+ };
369
+ ownerEntityId;
370
+ timezone;
371
+ db;
372
+ constructor(SQL, path) {
373
+ this.SQL = SQL;
374
+ this.path = path;
375
+ }
376
+ /**
377
+ * Initialize a new stack database. Fails if the file already exists —
378
+ * use open() for existing databases.
379
+ */
380
+ static async initialize(opts) {
381
+ if (existsSync(opts.path)) {
382
+ throw new Error(`Cannot initialize: database already exists at "${opts.path}". ` +
383
+ `Use SQLiteRecordAdapter.open() instead.`);
384
+ }
385
+ const SQL = await initSqlJs();
386
+ const adapter = new SQLiteRecordAdapter(SQL, opts.path);
387
+ adapter.db = new SQL.Database();
388
+ adapter.db.run(SCHEMA_SQL);
389
+ const now = Date.now();
390
+ adapter.db.run(`INSERT INTO records (id, type_id, created_at, updated_at, content, version)
391
+ VALUES ('_config', '_config@1', ?, ?, ?, 1)`, [now, now, JSON.stringify({ entityId: opts.entityId, timezone: opts.timezone })]);
392
+ adapter.ownerEntityId = opts.entityId;
393
+ adapter.timezone = opts.timezone;
394
+ adapter.persist();
395
+ return adapter;
396
+ }
397
+ /**
398
+ * Open an existing stack database. Fails if the file does not exist —
399
+ * use initialize() for new databases.
400
+ */
401
+ static async open(opts) {
402
+ if (!existsSync(opts.path)) {
403
+ throw new Error(`Cannot open: no database found at "${opts.path}". ` +
404
+ `Use SQLiteRecordAdapter.initialize() to create one.`);
405
+ }
406
+ const SQL = await initSqlJs();
407
+ const adapter = new SQLiteRecordAdapter(SQL, opts.path);
408
+ const fileBuffer = readFileSync(opts.path);
409
+ adapter.db = new SQL.Database(fileBuffer);
410
+ adapter.db.run(SCHEMA_SQL);
411
+ adapter.readConfig();
412
+ return adapter;
413
+ }
414
+ // -------------------------------------------------------
415
+ // Persistence
416
+ // -------------------------------------------------------
417
+ /** Flush the in-memory database to disk. Called after every write. */
418
+ persist() {
419
+ const data = this.db.export();
420
+ writeFileSync(this.path, Buffer.from(data));
421
+ }
422
+ readConfig() {
423
+ const rows = this.execQuery(`SELECT content FROM records WHERE id = '_config'`);
424
+ if (!rows.length)
425
+ throw new Error('Stack database is missing its config record.');
426
+ const content = JSON.parse(rows[0].content);
427
+ this.ownerEntityId = content.entityId;
428
+ this.timezone = content.timezone ?? 'UTC';
429
+ }
430
+ // -------------------------------------------------------
431
+ // Records
432
+ // -------------------------------------------------------
433
+ async createRecord(record) {
434
+ this.db.run(`INSERT INTO records
435
+ (id, type_id, created_at, updated_at, content, version,
436
+ parent_id, entity_id, app_id, deleted_at, permissions)
437
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
438
+ record.id,
439
+ record.typeId,
440
+ toMs(record.createdAt),
441
+ toMs(record.updatedAt),
442
+ JSON.stringify(record.content),
443
+ record.version,
444
+ record.parentId ?? null,
445
+ record.entityId ?? null,
446
+ record.appId ?? null,
447
+ record.deletedAt ? toMs(record.deletedAt) : null,
448
+ record.permissions ? JSON.stringify(record.permissions) : null,
449
+ ]);
450
+ if (record.associations?.length) {
451
+ this.insertAssociations(record.id, record.associations);
452
+ }
453
+ this.updateFts(record.id, JSON.stringify(record.content));
454
+ this.persist();
455
+ return record;
456
+ }
457
+ async getRecord(id) {
458
+ const stmt = this.db.prepare('SELECT * FROM records r WHERE r.id = ?');
459
+ stmt.bind([id]);
460
+ if (!stmt.step()) {
461
+ stmt.free();
462
+ return null;
463
+ }
464
+ const row = stmt.getAsObject();
465
+ stmt.free();
466
+ const associations = this.getAssociationsForRecord(id);
467
+ return rowToRecord(row, associations);
468
+ }
469
+ async updateRecord(id, changes) {
470
+ const setClauses = [];
471
+ const params = [];
472
+ if (changes.content !== undefined) {
473
+ setClauses.push('content = ?');
474
+ params.push(JSON.stringify(changes.content));
475
+ }
476
+ if (changes.typeId !== undefined) {
477
+ setClauses.push('type_id = ?');
478
+ params.push(changes.typeId);
479
+ }
480
+ if (changes.updatedAt !== undefined) {
481
+ setClauses.push('updated_at = ?');
482
+ params.push(toMs(changes.updatedAt));
483
+ }
484
+ if (changes.version !== undefined) {
485
+ setClauses.push('version = ?');
486
+ params.push(changes.version);
487
+ }
488
+ if (changes.deletedAt !== undefined) {
489
+ setClauses.push('deleted_at = ?');
490
+ params.push(toMs(changes.deletedAt));
491
+ }
492
+ if (changes.permissions !== undefined) {
493
+ setClauses.push('permissions = ?');
494
+ params.push(changes.permissions.length ? JSON.stringify(changes.permissions) : null);
495
+ }
496
+ if (setClauses.length) {
497
+ params.push(id);
498
+ this.db.run(`UPDATE records SET ${setClauses.join(', ')} WHERE id = ?`, params);
499
+ }
500
+ // Replace associations if provided
501
+ if (changes.associations !== undefined) {
502
+ this.db.run('DELETE FROM associations WHERE record_id = ?', [id]);
503
+ if (changes.associations.length) {
504
+ this.insertAssociations(id, changes.associations);
505
+ }
506
+ }
507
+ if (changes.content !== undefined) {
508
+ this.updateFts(id, JSON.stringify(changes.content));
509
+ }
510
+ this.persist();
511
+ const updated = await this.getRecord(id);
512
+ if (!updated)
513
+ throw new Error(`Record not found after update: "${id}"`);
514
+ return updated;
515
+ }
516
+ async deleteRecord(id, opts = {}) {
517
+ if (opts.hard) {
518
+ this.db.run('DELETE FROM associations WHERE record_id = ?', [id]);
519
+ this.db.run('DELETE FROM versions WHERE record_id = ?', [id]);
520
+ this.db.run(`DELETE FROM records_fts WHERE docid = (SELECT rowid FROM records WHERE id = ?)`, [id]);
521
+ this.db.run('DELETE FROM records WHERE id = ?', [id]);
522
+ }
523
+ else {
524
+ this.db.run('UPDATE records SET deleted_at = ? WHERE id = ?', [toMs(new Date()), id]);
525
+ }
526
+ this.persist();
527
+ }
528
+ async queryRecords(query) {
529
+ const { sql: where, params } = buildWhereClause(query);
530
+ const order = buildOrderClause(query);
531
+ const limit = query.limit ?? 50;
532
+ // Fetch one extra to determine if there's a next page
533
+ const rows = this.execQuery(`SELECT r.* FROM records r ${where} ${order} LIMIT ?`, [...params, limit + 1]);
534
+ const hasMore = rows.length > limit;
535
+ const page = hasMore ? rows.slice(0, limit) : rows;
536
+ const records = page.map((row) => {
537
+ const associations = this.getAssociationsForRecord(row.id);
538
+ return rowToRecord(row, associations);
539
+ });
540
+ // Total count (without pagination)
541
+ const countRows = this.execQuery(`SELECT COUNT(*) as total FROM records r ${where}`, params);
542
+ const total = countRows[0]?.total ?? 0;
543
+ const lastRecord = records[records.length - 1];
544
+ const cursor = hasMore && lastRecord ? makeCursor(lastRecord, getSortField(query)) : null;
545
+ return { records, cursor, total };
546
+ }
547
+ // -------------------------------------------------------
548
+ // Versions
549
+ // -------------------------------------------------------
550
+ async getVersions(id) {
551
+ const rows = this.execQuery('SELECT * FROM versions WHERE record_id = ? ORDER BY version DESC', [id]);
552
+ return rows.map(rowToVersion);
553
+ }
554
+ async getVersion(id, version) {
555
+ const rows = this.execQuery('SELECT * FROM versions WHERE record_id = ? AND version = ?', [id, version]);
556
+ return rows.length ? rowToVersion(rows[0]) : null;
557
+ }
558
+ async saveVersion(id, version) {
559
+ this.db.run(`INSERT OR IGNORE INTO versions (record_id, version, content, updated_at, entity_id)
560
+ VALUES (?, ?, ?, ?, ?)`, [
561
+ id,
562
+ version.version,
563
+ JSON.stringify(version.content),
564
+ toMs(version.updatedAt),
565
+ version.entityId ?? null,
566
+ ]);
567
+ this.persist();
568
+ }
569
+ // -------------------------------------------------------
570
+ // Types
571
+ // -------------------------------------------------------
572
+ async saveType(type) {
573
+ this.db.run(`INSERT OR REPLACE INTO types
574
+ (id, base_id, version, name, schema, schema_hash, migrates_from, created_at)
575
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
576
+ type.id,
577
+ type.baseId,
578
+ type.version,
579
+ type.name,
580
+ JSON.stringify(type.schema),
581
+ type.schemaHash,
582
+ type.migratesFrom ?? null,
583
+ toMs(type.createdAt),
584
+ ]);
585
+ this.persist();
586
+ }
587
+ async getType(id) {
588
+ const rows = this.execQuery('SELECT * FROM types WHERE id = ?', [id]);
589
+ return rows.length ? rowToType(rows[0]) : null;
590
+ }
591
+ async listTypes() {
592
+ const rows = this.execQuery('SELECT * FROM types ORDER BY base_id, version');
593
+ return rows.map(rowToType);
594
+ }
595
+ // -------------------------------------------------------
596
+ // Tokens
597
+ // -------------------------------------------------------
598
+ async createToken(entityId, opts = {}) {
599
+ const id = randomBytes(8).toString('hex');
600
+ const token = randomBytes(32).toString('hex');
601
+ const tokenHash = createHash('sha256').update(token).digest('hex');
602
+ this.db.run('INSERT INTO tokens (id, token_hash, entity_id, label, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?)', [
603
+ id,
604
+ tokenHash,
605
+ entityId,
606
+ opts.label ?? null,
607
+ toMs(new Date()),
608
+ opts.expiresAt ? toMs(opts.expiresAt) : null,
609
+ ]);
610
+ this.persist();
611
+ return { id, token };
612
+ }
613
+ async lookupToken(token) {
614
+ const hash = createHash('sha256').update(token).digest('hex');
615
+ const rows = this.execQuery('SELECT entity_id, expires_at FROM tokens WHERE token_hash = ?', [hash]);
616
+ if (!rows.length)
617
+ return null;
618
+ const row = rows[0];
619
+ if (row.expires_at !== null && Date.now() > row.expires_at)
620
+ return null;
621
+ return { entityId: row.entity_id };
622
+ }
623
+ async listTokens() {
624
+ const rows = this.execQuery('SELECT id, entity_id, label, created_at, expires_at FROM tokens ORDER BY created_at DESC');
625
+ return rows.map((row) => ({
626
+ id: row.id,
627
+ entityId: row.entity_id,
628
+ ...(row.label && { label: row.label }),
629
+ createdAt: fromMs(row.created_at),
630
+ ...(row.expires_at !== null && { expiresAt: fromMs(row.expires_at) }),
631
+ }));
632
+ }
633
+ async revokeToken(id) {
634
+ this.db.run('DELETE FROM tokens WHERE id = ?', [id]);
635
+ this.persist();
636
+ }
637
+ // -------------------------------------------------------
638
+ // Associations
639
+ // -------------------------------------------------------
640
+ async associate(recordId, association) {
641
+ this.insertAssociations(recordId, [association]);
642
+ this.persist();
643
+ }
644
+ async dissociate(recordId, association) {
645
+ this.db.run(`DELETE FROM associations
646
+ WHERE record_id = ?
647
+ AND kind = ?
648
+ AND label = ?
649
+ AND file_id = ?
650
+ AND related_id = ?`, [
651
+ recordId,
652
+ association.kind,
653
+ association.label,
654
+ association.kind === 'attachment' ? association.fileId : '',
655
+ association.kind === 'relationship' ? association.recordId : '',
656
+ ]);
657
+ this.persist();
658
+ }
659
+ insertAssociations(recordId, associations) {
660
+ for (const assoc of associations) {
661
+ this.db.run(`INSERT OR IGNORE INTO associations
662
+ (record_id, kind, label, file_id, mime_type, related_id)
663
+ VALUES (?, ?, ?, ?, ?, ?)`, [
664
+ recordId,
665
+ assoc.kind,
666
+ assoc.label,
667
+ assoc.kind === 'attachment' ? assoc.fileId : '',
668
+ assoc.kind === 'attachment' ? assoc.mimeType : null,
669
+ assoc.kind === 'relationship' ? assoc.recordId : '',
670
+ ]);
671
+ }
672
+ }
673
+ getAssociationsForRecord(recordId) {
674
+ const rows = this.execQuery('SELECT * FROM associations WHERE record_id = ?', [recordId]);
675
+ return rows.map(rowToAssociation);
676
+ }
677
+ updateFts(recordId, content) {
678
+ // FTS4 content table — delete old entry then insert new one
679
+ this.db.run(`DELETE FROM records_fts WHERE docid = (SELECT rowid FROM records WHERE id = ?)`, [
680
+ recordId,
681
+ ]);
682
+ this.db.run(`INSERT INTO records_fts(docid, content)
683
+ SELECT rowid, ? FROM records WHERE id = ?`, [content, recordId]);
684
+ }
685
+ execQuery(sql, params = []) {
686
+ const stmt = this.db.prepare(sql);
687
+ stmt.bind(params);
688
+ const results = [];
689
+ while (stmt.step()) {
690
+ results.push(stmt.getAsObject());
691
+ }
692
+ stmt.free();
693
+ return results;
694
+ }
695
+ // -------------------------------------------------------
696
+ // Lifecycle
697
+ // -------------------------------------------------------
698
+ async flush() {
699
+ this.persist();
700
+ }
701
+ async close() {
702
+ this.db.close();
703
+ }
704
+ }
705
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@haverstack/record-adapter-sqljs",
3
+ "version": "0.6.0",
4
+ "description": "sql.js record adapter for Haverstack",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.js",
9
+ "types": "./dist/index.d.ts"
10
+ }
11
+ },
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/haverstack/core",
20
+ "directory": "packages/record-adapter-sqljs"
21
+ },
22
+ "license": "CC0-1.0",
23
+ "keywords": [
24
+ "haverstack",
25
+ "sqljs",
26
+ "sql.js",
27
+ "sqlite",
28
+ "record",
29
+ "adapter",
30
+ "personal data",
31
+ "storage"
32
+ ],
33
+ "dependencies": {
34
+ "sql.js": "^1.14.0",
35
+ "@haverstack/core": "0.6.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^22.0.0",
39
+ "@types/sql.js": "^1.4.9",
40
+ "typescript": "^5.5.0",
41
+ "vitest": "^2.0.0"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.build.json",
45
+ "test": "vitest run",
46
+ "typecheck": "tsc --noEmit",
47
+ "lint": "eslint src tests"
48
+ }
49
+ }