flatsql 0.2.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.
Files changed (65) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +489 -0
  3. package/dist/btree/btree.d.ts +34 -0
  4. package/dist/btree/btree.d.ts.map +1 -0
  5. package/dist/btree/btree.js +235 -0
  6. package/dist/btree/btree.js.map +1 -0
  7. package/dist/btree/index.d.ts +3 -0
  8. package/dist/btree/index.d.ts.map +1 -0
  9. package/dist/btree/index.js +3 -0
  10. package/dist/btree/index.js.map +1 -0
  11. package/dist/btree/types.d.ts +36 -0
  12. package/dist/btree/types.d.ts.map +1 -0
  13. package/dist/btree/types.js +55 -0
  14. package/dist/btree/types.js.map +1 -0
  15. package/dist/core/database.d.ts +45 -0
  16. package/dist/core/database.d.ts.map +1 -0
  17. package/dist/core/database.js +248 -0
  18. package/dist/core/database.js.map +1 -0
  19. package/dist/core/index.d.ts +3 -0
  20. package/dist/core/index.d.ts.map +1 -0
  21. package/dist/core/index.js +3 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/core/table-store.d.ts +28 -0
  24. package/dist/core/table-store.d.ts.map +1 -0
  25. package/dist/core/table-store.js +153 -0
  26. package/dist/core/table-store.js.map +1 -0
  27. package/dist/flatbuffer-accessor.d.ts +35 -0
  28. package/dist/flatbuffer-accessor.d.ts.map +1 -0
  29. package/dist/flatbuffer-accessor.js +114 -0
  30. package/dist/flatbuffer-accessor.js.map +1 -0
  31. package/dist/index.d.ts +12 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +15 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/schema/index.d.ts +3 -0
  36. package/dist/schema/index.d.ts.map +1 -0
  37. package/dist/schema/index.js +3 -0
  38. package/dist/schema/index.js.map +1 -0
  39. package/dist/schema/parser.d.ts +25 -0
  40. package/dist/schema/parser.d.ts.map +1 -0
  41. package/dist/schema/parser.js +394 -0
  42. package/dist/schema/parser.js.map +1 -0
  43. package/dist/schema/types.d.ts +33 -0
  44. package/dist/schema/types.d.ts.map +1 -0
  45. package/dist/schema/types.js +29 -0
  46. package/dist/schema/types.js.map +1 -0
  47. package/dist/storage/index.d.ts +3 -0
  48. package/dist/storage/index.d.ts.map +1 -0
  49. package/dist/storage/index.js +3 -0
  50. package/dist/storage/index.js.map +1 -0
  51. package/dist/storage/stacked-flatbuffers.d.ts +38 -0
  52. package/dist/storage/stacked-flatbuffers.d.ts.map +1 -0
  53. package/dist/storage/stacked-flatbuffers.js +253 -0
  54. package/dist/storage/stacked-flatbuffers.js.map +1 -0
  55. package/dist/storage/types.d.ts +23 -0
  56. package/dist/storage/types.d.ts.map +1 -0
  57. package/dist/storage/types.js +27 -0
  58. package/dist/storage/types.js.map +1 -0
  59. package/package.json +79 -0
  60. package/wasm/flatsql-client.js +280 -0
  61. package/wasm/flatsql.js +2 -0
  62. package/wasm/flatsql.wasm +0 -0
  63. package/wasm/flatsql.worker.js +209 -0
  64. package/wasm/index.d.ts +234 -0
  65. package/wasm/index.js +463 -0
@@ -0,0 +1,253 @@
1
+ // Stacked FlatBuffers storage implementation
2
+ // Files are append-only sequences of FlatBuffer records with headers
3
+ // Fully readable by standard FlatBuffer tools
4
+ import { MAGIC, VERSION, crc32 } from './types.js';
5
+ // Header sizes (fixed layout for easy seeking)
6
+ const FILE_HEADER_SIZE = 64; // Padded for alignment
7
+ const RECORD_HEADER_SIZE = 48; // Fixed size record header
8
+ // Security: Default maximum storage size (1GB)
9
+ const DEFAULT_MAX_STORAGE_SIZE = 1024 * 1024 * 1024;
10
+ // Security: Warning threshold (80% of max)
11
+ const WARNING_THRESHOLD = 0.8;
12
+ export class StackedFlatBufferStore {
13
+ data;
14
+ dataView;
15
+ writeOffset;
16
+ recordCount = 0n;
17
+ sequence = 0n;
18
+ schemaName;
19
+ // Index of records by offset for quick lookup
20
+ recordIndex = new Map();
21
+ // Security: Storage limits
22
+ maxSize;
23
+ warningEmitted = false;
24
+ onStorageWarning;
25
+ constructor(schemaName, options = {}) {
26
+ // Support legacy signature: constructor(schemaName, initialCapacity)
27
+ const opts = typeof options === 'number'
28
+ ? { initialCapacity: options }
29
+ : options;
30
+ this.schemaName = schemaName;
31
+ this.maxSize = opts.maxSize ?? DEFAULT_MAX_STORAGE_SIZE;
32
+ this.onStorageWarning = opts.onStorageWarning;
33
+ const initialCapacity = opts.initialCapacity ?? 1024 * 1024;
34
+ this.data = new Uint8Array(initialCapacity);
35
+ this.dataView = new DataView(this.data.buffer);
36
+ this.writeOffset = BigInt(FILE_HEADER_SIZE);
37
+ this.writeFileHeader();
38
+ }
39
+ writeFileHeader() {
40
+ const view = this.dataView;
41
+ // Magic number
42
+ view.setUint32(0, MAGIC, true);
43
+ // Version
44
+ view.setUint32(4, VERSION, true);
45
+ // Data start offset
46
+ view.setBigUint64(8, BigInt(FILE_HEADER_SIZE), true);
47
+ // Record count (updated on each append)
48
+ view.setBigUint64(16, 0n, true);
49
+ // Schema name (up to 40 bytes, null-terminated)
50
+ const nameBytes = new TextEncoder().encode(this.schemaName);
51
+ const nameLen = Math.min(nameBytes.length, 39);
52
+ this.data.set(nameBytes.slice(0, nameLen), 24);
53
+ this.data[24 + nameLen] = 0;
54
+ }
55
+ updateFileHeader() {
56
+ this.dataView.setBigUint64(16, this.recordCount, true);
57
+ }
58
+ ensureCapacity(needed) {
59
+ const totalNeeded = Number(this.writeOffset) + needed;
60
+ if (totalNeeded <= this.data.length)
61
+ return;
62
+ // Security: Check if we would exceed max size
63
+ if (this.maxSize > 0 && totalNeeded > this.maxSize) {
64
+ throw new Error(`Storage size limit exceeded: requested ${totalNeeded} bytes, ` +
65
+ `maximum is ${this.maxSize} bytes`);
66
+ }
67
+ // Grow by doubling
68
+ let newSize = this.data.length * 2;
69
+ while (newSize < totalNeeded) {
70
+ newSize *= 2;
71
+ }
72
+ // Security: Cap at max size
73
+ if (this.maxSize > 0 && newSize > this.maxSize) {
74
+ newSize = this.maxSize;
75
+ }
76
+ // Security: Emit warning when approaching limit
77
+ if (this.maxSize > 0 && !this.warningEmitted) {
78
+ const threshold = this.maxSize * WARNING_THRESHOLD;
79
+ if (newSize >= threshold) {
80
+ this.warningEmitted = true;
81
+ if (this.onStorageWarning) {
82
+ this.onStorageWarning(newSize, this.maxSize);
83
+ }
84
+ }
85
+ }
86
+ const newData = new Uint8Array(newSize);
87
+ newData.set(this.data);
88
+ this.data = newData;
89
+ this.dataView = new DataView(this.data.buffer);
90
+ }
91
+ // Append a FlatBuffer record
92
+ // Returns the offset where the record was stored
93
+ append(tableName, flatbufferData) {
94
+ const checksum = crc32(flatbufferData);
95
+ const timestamp = BigInt(Date.now());
96
+ const seq = this.sequence++;
97
+ const header = {
98
+ sequence: seq,
99
+ tableName,
100
+ timestamp,
101
+ dataLength: flatbufferData.length,
102
+ checksum,
103
+ };
104
+ const totalSize = RECORD_HEADER_SIZE + flatbufferData.length;
105
+ this.ensureCapacity(totalSize);
106
+ const recordOffset = this.writeOffset;
107
+ // Write record header
108
+ const offset = Number(this.writeOffset);
109
+ this.dataView.setBigUint64(offset, seq, true);
110
+ // Table name (16 bytes, null-padded)
111
+ const tableBytes = new TextEncoder().encode(tableName);
112
+ const tableLen = Math.min(tableBytes.length, 15);
113
+ this.data.set(tableBytes.slice(0, tableLen), offset + 8);
114
+ this.data[offset + 8 + tableLen] = 0;
115
+ this.dataView.setBigUint64(offset + 24, timestamp, true);
116
+ this.dataView.setUint32(offset + 32, flatbufferData.length, true);
117
+ this.dataView.setUint32(offset + 36, checksum, true);
118
+ // Reserved bytes 40-47
119
+ // Write FlatBuffer data
120
+ this.data.set(flatbufferData, offset + RECORD_HEADER_SIZE);
121
+ this.writeOffset += BigInt(totalSize);
122
+ this.recordCount++;
123
+ this.recordIndex.set(recordOffset, header);
124
+ this.updateFileHeader();
125
+ return recordOffset;
126
+ }
127
+ // Read a record at a given offset
128
+ readRecord(offset) {
129
+ const off = Number(offset);
130
+ // Read header
131
+ const sequence = this.dataView.getBigUint64(off, true);
132
+ const tableNameBytes = this.data.slice(off + 8, off + 24);
133
+ const nullIdx = tableNameBytes.indexOf(0);
134
+ const tableName = new TextDecoder().decode(tableNameBytes.slice(0, nullIdx >= 0 ? nullIdx : tableNameBytes.length));
135
+ const timestamp = this.dataView.getBigUint64(off + 24, true);
136
+ const dataLength = this.dataView.getUint32(off + 32, true);
137
+ const checksum = this.dataView.getUint32(off + 36, true);
138
+ // Read data
139
+ const dataStart = off + RECORD_HEADER_SIZE;
140
+ const data = this.data.slice(dataStart, dataStart + dataLength);
141
+ // Verify checksum
142
+ const computedChecksum = crc32(data);
143
+ if (computedChecksum !== checksum) {
144
+ throw new Error(`Checksum mismatch at offset ${offset}: expected ${checksum}, got ${computedChecksum}`);
145
+ }
146
+ return {
147
+ header: {
148
+ sequence,
149
+ tableName,
150
+ timestamp,
151
+ dataLength,
152
+ checksum,
153
+ },
154
+ offset,
155
+ data,
156
+ };
157
+ }
158
+ // Iterate all records
159
+ *iterateRecords() {
160
+ let offset = BigInt(FILE_HEADER_SIZE);
161
+ const end = this.writeOffset;
162
+ while (offset < end) {
163
+ const record = this.readRecord(offset);
164
+ yield record;
165
+ offset += BigInt(RECORD_HEADER_SIZE + record.header.dataLength);
166
+ }
167
+ }
168
+ // Get records for a specific table
169
+ *iterateTableRecords(tableName) {
170
+ for (const record of this.iterateRecords()) {
171
+ if (record.header.tableName === tableName) {
172
+ yield record;
173
+ }
174
+ }
175
+ }
176
+ // Get the raw data (for export/persistence)
177
+ getData() {
178
+ return this.data.slice(0, Number(this.writeOffset));
179
+ }
180
+ // Load from existing data
181
+ static fromData(data, options = {}) {
182
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
183
+ // Verify magic
184
+ const magic = view.getUint32(0, true);
185
+ if (magic !== MAGIC) {
186
+ throw new Error(`Invalid file magic: expected ${MAGIC.toString(16)}, got ${magic.toString(16)}`);
187
+ }
188
+ const version = view.getUint32(4, true);
189
+ if (version !== VERSION) {
190
+ throw new Error(`Unsupported version: ${version}`);
191
+ }
192
+ // Read schema name
193
+ const nameBytes = data.slice(24, 64);
194
+ const nullIdx = nameBytes.indexOf(0);
195
+ const schemaName = new TextDecoder().decode(nameBytes.slice(0, nullIdx >= 0 ? nullIdx : nameBytes.length));
196
+ const store = new StackedFlatBufferStore(schemaName, {
197
+ ...options,
198
+ initialCapacity: data.length,
199
+ });
200
+ store.data.set(data);
201
+ store.dataView = new DataView(store.data.buffer);
202
+ // Rebuild index by scanning records
203
+ store.writeOffset = BigInt(FILE_HEADER_SIZE);
204
+ store.recordCount = 0n;
205
+ store.sequence = 0n;
206
+ // Find end and rebuild index
207
+ let offset = BigInt(FILE_HEADER_SIZE);
208
+ while (offset < BigInt(data.length)) {
209
+ try {
210
+ const record = store.readRecord(offset);
211
+ store.recordIndex.set(offset, record.header);
212
+ store.recordCount++;
213
+ if (record.header.sequence >= store.sequence) {
214
+ store.sequence = record.header.sequence + 1n;
215
+ }
216
+ offset += BigInt(RECORD_HEADER_SIZE + record.header.dataLength);
217
+ store.writeOffset = offset;
218
+ }
219
+ catch {
220
+ // End of valid data
221
+ break;
222
+ }
223
+ }
224
+ return store;
225
+ }
226
+ getRecordCount() {
227
+ return this.recordCount;
228
+ }
229
+ getSchemaName() {
230
+ return this.schemaName;
231
+ }
232
+ // Security: Get current storage size
233
+ getCurrentSize() {
234
+ return Number(this.writeOffset);
235
+ }
236
+ // Security: Get maximum storage size (0 = unlimited)
237
+ getMaxSize() {
238
+ return this.maxSize;
239
+ }
240
+ // Security: Get storage usage as a percentage (0-100)
241
+ getUsagePercent() {
242
+ if (this.maxSize === 0)
243
+ return 0;
244
+ return (Number(this.writeOffset) / this.maxSize) * 100;
245
+ }
246
+ // Security: Check if storage is near capacity (>80%)
247
+ isNearCapacity() {
248
+ if (this.maxSize === 0)
249
+ return false;
250
+ return Number(this.writeOffset) >= this.maxSize * WARNING_THRESHOLD;
251
+ }
252
+ }
253
+ //# sourceMappingURL=stacked-flatbuffers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stacked-flatbuffers.js","sourceRoot":"","sources":["../../src/storage/stacked-flatbuffers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface RecordHeader {
2
+ sequence: bigint;
3
+ tableName: string;
4
+ timestamp: bigint;
5
+ dataLength: number;
6
+ checksum: number;
7
+ }
8
+ export interface DataFileHeader {
9
+ magic: number;
10
+ version: number;
11
+ dataStartOffset: bigint;
12
+ recordCount: bigint;
13
+ schemaName: string;
14
+ }
15
+ export interface StoredRecord {
16
+ header: RecordHeader;
17
+ offset: bigint;
18
+ data: Uint8Array;
19
+ }
20
+ export declare const MAGIC = 1179407441;
21
+ export declare const VERSION = 1;
22
+ export declare function crc32(data: Uint8Array): number;
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,eAAO,MAAM,KAAK,aAAa,CAAC;AAChC,eAAO,MAAM,OAAO,IAAI,CAAC;AAGzB,wBAAgB,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAS9C"}
@@ -0,0 +1,27 @@
1
+ // Storage types for stacked FlatBuffers
2
+ export const MAGIC = 0x464c5451; // "FLTQ"
3
+ export const VERSION = 1;
4
+ // Simple CRC32 implementation
5
+ export function crc32(data) {
6
+ let crc = 0xffffffff;
7
+ const table = getCRC32Table();
8
+ for (let i = 0; i < data.length; i++) {
9
+ crc = (crc >>> 8) ^ table[(crc ^ data[i]) & 0xff];
10
+ }
11
+ return (crc ^ 0xffffffff) >>> 0;
12
+ }
13
+ let crc32Table = null;
14
+ function getCRC32Table() {
15
+ if (crc32Table)
16
+ return crc32Table;
17
+ crc32Table = new Uint32Array(256);
18
+ for (let i = 0; i < 256; i++) {
19
+ let c = i;
20
+ for (let j = 0; j < 8; j++) {
21
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
22
+ }
23
+ crc32Table[i] = c;
24
+ }
25
+ return crc32Table;
26
+ }
27
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAwBxC,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,SAAS;AAC1C,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AAEzB,8BAA8B;AAC9B,MAAM,UAAU,KAAK,CAAC,IAAgB;IACpC,IAAI,GAAG,GAAG,UAAU,CAAC;IACrB,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,CAAC,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,UAAU,GAAuB,IAAI,CAAC;AAE1C,SAAS,aAAa;IACpB,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAElC,UAAU,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC/C,CAAC;QACD,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "flatsql",
3
+ "version": "0.2.0",
4
+ "description": "SQL queries over raw FlatBuffer storage - zero conversion, real-time indexing, pure streaming",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./wasm": {
14
+ "types": "./wasm/index.d.ts",
15
+ "import": "./wasm/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "wasm/*.js",
21
+ "wasm/*.wasm",
22
+ "wasm/*.d.ts",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "build:wasm": "bash scripts/build-wasm.sh",
29
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
30
+ "test:wasm": "node wasm/test-node.mjs",
31
+ "dev": "tsc --watch",
32
+ "serve": "vite docs --port 8081",
33
+ "prepublishOnly": "npm run build",
34
+ "postinstall": "bash scripts/install-emsdk.sh",
35
+ "emsdk:install": "bash scripts/install-emsdk.sh",
36
+ "emsdk:env": "echo 'Run: source packages/emsdk/emsdk_env.sh'"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/DigitalArsenal/flatsql.git"
41
+ },
42
+ "homepage": "https://digitalarsenal.github.io/flatsql/",
43
+ "bugs": {
44
+ "url": "https://github.com/DigitalArsenal/flatsql/issues"
45
+ },
46
+ "keywords": [
47
+ "flatbuffers",
48
+ "sqlite",
49
+ "sql",
50
+ "database",
51
+ "streaming",
52
+ "binary",
53
+ "zero-copy",
54
+ "wasm",
55
+ "webassembly",
56
+ "query",
57
+ "virtual-table"
58
+ ],
59
+ "author": "Digital Arsenal <tj@digitalarsenal.io>",
60
+ "license": "Apache-2.0",
61
+ "dependencies": {
62
+ "flatc-wasm": "^26.1.14",
63
+ "sql.js": "^1.10.0"
64
+ },
65
+ "devDependencies": {
66
+ "@types/node": "^20.0.0",
67
+ "typescript": "^5.3.0",
68
+ "jest": "^29.7.0",
69
+ "@types/jest": "^29.5.0",
70
+ "ts-jest": "^29.1.0",
71
+ "vite": "^5.0.0"
72
+ },
73
+ "engines": {
74
+ "node": ">=18.0.0"
75
+ },
76
+ "publishConfig": {
77
+ "access": "public"
78
+ }
79
+ }
@@ -0,0 +1,280 @@
1
+ /**
2
+ * FlatSQL Worker Client
3
+ * Provides a clean async API for communicating with the FlatSQL worker.
4
+ * Works in: Browser, Node.js, Deno
5
+ *
6
+ * Usage:
7
+ * import { FlatSQLClient, FlatSQLWorkerDatabase } from './flatsql-client.js';
8
+ *
9
+ * const client = new FlatSQLClient();
10
+ * await client.init();
11
+ *
12
+ * const db = await client.createDatabase(schema, 'mydb');
13
+ * await db.registerFileId('USER', 'User');
14
+ * const result = await db.query('SELECT * FROM User');
15
+ */
16
+
17
+ // Environment detection
18
+ const isBrowser = typeof window !== 'undefined' || (typeof self !== 'undefined' && typeof importScripts === 'undefined');
19
+ const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
20
+ const isDeno = typeof Deno !== 'undefined';
21
+
22
+ /**
23
+ * Create a worker based on the environment
24
+ */
25
+ async function createWorker(workerPath) {
26
+ if (isNode) {
27
+ const { Worker } = await import('worker_threads');
28
+ return new Worker(workerPath);
29
+ } else if (isDeno) {
30
+ return new Worker(new URL(workerPath, import.meta.url), { type: 'module' });
31
+ } else {
32
+ // Browser
33
+ return new Worker(workerPath, { type: 'module' });
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Setup message handlers for the worker
39
+ */
40
+ function setupWorkerHandlers(worker, handlers) {
41
+ if (isNode) {
42
+ worker.on('message', handlers.onMessage);
43
+ worker.on('error', handlers.onError);
44
+ worker.on('exit', handlers.onExit);
45
+ } else {
46
+ worker.onmessage = (e) => handlers.onMessage(e.data);
47
+ worker.onerror = handlers.onError;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * FlatSQL Worker Client
53
+ * Manages communication with the FlatSQL worker.
54
+ */
55
+ export class FlatSQLClient {
56
+ constructor(workerPath = './flatsql.worker.js') {
57
+ this.workerPath = workerPath;
58
+ this.worker = null;
59
+ this.pending = new Map();
60
+ this.nextId = 1;
61
+ this.ready = false;
62
+ this.readyPromise = null;
63
+ this.databases = new Map();
64
+ }
65
+
66
+ /**
67
+ * Initialize the client and worker
68
+ */
69
+ async init() {
70
+ if (this.worker) return this;
71
+
72
+ this.worker = await createWorker(this.workerPath);
73
+
74
+ this.readyPromise = new Promise((resolve, reject) => {
75
+ const timeout = setTimeout(() => {
76
+ reject(new Error('Worker initialization timeout'));
77
+ }, 30000);
78
+
79
+ const handlers = {
80
+ onMessage: (data) => {
81
+ if (data.type === 'ready') {
82
+ clearTimeout(timeout);
83
+ this.ready = true;
84
+ resolve();
85
+ return;
86
+ }
87
+
88
+ const { id, success, result, error } = data;
89
+ const pending = this.pending.get(id);
90
+ if (pending) {
91
+ this.pending.delete(id);
92
+ if (success) {
93
+ pending.resolve(result);
94
+ } else {
95
+ pending.reject(new Error(error));
96
+ }
97
+ }
98
+ },
99
+ onError: (err) => {
100
+ clearTimeout(timeout);
101
+ reject(err);
102
+ },
103
+ onExit: (code) => {
104
+ if (code !== 0) {
105
+ reject(new Error(`Worker exited with code ${code}`));
106
+ }
107
+ }
108
+ };
109
+
110
+ setupWorkerHandlers(this.worker, handlers);
111
+ });
112
+
113
+ await this.readyPromise;
114
+
115
+ // Initialize WASM in worker
116
+ await this.call('init');
117
+
118
+ return this;
119
+ }
120
+
121
+ /**
122
+ * Call a method on the worker
123
+ */
124
+ async call(method, params = {}) {
125
+ if (!this.worker) {
126
+ throw new Error('Client not initialized. Call init() first.');
127
+ }
128
+
129
+ const id = this.nextId++;
130
+
131
+ return new Promise((resolve, reject) => {
132
+ this.pending.set(id, { resolve, reject });
133
+ this.worker.postMessage({ id, method, params });
134
+ });
135
+ }
136
+
137
+ /**
138
+ * Create a new database
139
+ */
140
+ async createDatabase(schema, name = 'default') {
141
+ const dbId = `db_${this.nextId++}`;
142
+ await this.call('createDatabase', { id: dbId, schema, name });
143
+ const db = new FlatSQLWorkerDatabase(this, dbId);
144
+ this.databases.set(dbId, db);
145
+ return db;
146
+ }
147
+
148
+ /**
149
+ * Create a test User FlatBuffer (for demos)
150
+ */
151
+ async createTestUser(id, name, email, age) {
152
+ const result = await this.call('createTestUser', { id, name, email, age });
153
+ return new Uint8Array(result.data);
154
+ }
155
+
156
+ /**
157
+ * Create a test Post FlatBuffer (for demos)
158
+ */
159
+ async createTestPost(id, userId, title) {
160
+ const result = await this.call('createTestPost', { id, userId, title });
161
+ return new Uint8Array(result.data);
162
+ }
163
+
164
+ /**
165
+ * Terminate the worker
166
+ */
167
+ terminate() {
168
+ if (this.worker) {
169
+ if (isNode) {
170
+ this.worker.terminate();
171
+ } else {
172
+ this.worker.terminate();
173
+ }
174
+ this.worker = null;
175
+ this.ready = false;
176
+ }
177
+ }
178
+ }
179
+
180
+ /**
181
+ * FlatSQL Database accessed through a worker
182
+ */
183
+ export class FlatSQLWorkerDatabase {
184
+ constructor(client, dbId) {
185
+ this._client = client;
186
+ this._dbId = dbId;
187
+ }
188
+
189
+ /**
190
+ * Register a file ID for routing FlatBuffers to tables
191
+ */
192
+ async registerFileId(fileId, tableName) {
193
+ await this._client.call('registerFileId', {
194
+ dbId: this._dbId,
195
+ fileId,
196
+ tableName
197
+ });
198
+ }
199
+
200
+ /**
201
+ * Enable built-in demo extractors (User/Post)
202
+ */
203
+ async enableDemoExtractors() {
204
+ await this._client.call('enableDemoExtractors', { dbId: this._dbId });
205
+ }
206
+
207
+ /**
208
+ * Execute a SQL query
209
+ */
210
+ async query(sql) {
211
+ return await this._client.call('query', { dbId: this._dbId, sql });
212
+ }
213
+
214
+ /**
215
+ * Ingest a size-prefixed FlatBuffer stream
216
+ */
217
+ async ingest(data) {
218
+ const result = await this._client.call('ingest', {
219
+ dbId: this._dbId,
220
+ data: Array.from(data)
221
+ });
222
+ return result.bytesConsumed;
223
+ }
224
+
225
+ /**
226
+ * Ingest a single FlatBuffer (without size prefix)
227
+ */
228
+ async ingestOne(data) {
229
+ const result = await this._client.call('ingestOne', {
230
+ dbId: this._dbId,
231
+ data: Array.from(data)
232
+ });
233
+ return result.rowId;
234
+ }
235
+
236
+ /**
237
+ * Ingest multiple FlatBuffers (builds stream internally)
238
+ */
239
+ async ingestStream(buffers) {
240
+ const result = await this._client.call('ingestStream', {
241
+ dbId: this._dbId,
242
+ buffers: buffers.map(b => Array.from(b))
243
+ });
244
+ return result;
245
+ }
246
+
247
+ /**
248
+ * Export database as binary blob
249
+ */
250
+ async exportData() {
251
+ const result = await this._client.call('exportData', { dbId: this._dbId });
252
+ return new Uint8Array(result.data);
253
+ }
254
+
255
+ /**
256
+ * List all tables
257
+ */
258
+ async listTables() {
259
+ const result = await this._client.call('listTables', { dbId: this._dbId });
260
+ return result.tables;
261
+ }
262
+
263
+ /**
264
+ * Get database statistics
265
+ */
266
+ async getStats() {
267
+ const result = await this._client.call('getStats', { dbId: this._dbId });
268
+ return result.stats;
269
+ }
270
+
271
+ /**
272
+ * Delete the database and free resources
273
+ */
274
+ async delete() {
275
+ await this._client.call('deleteDatabase', { dbId: this._dbId });
276
+ this._client.databases.delete(this._dbId);
277
+ }
278
+ }
279
+
280
+ export default FlatSQLClient;