flatsql 3.11.1 → 3.12.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.
Files changed (181) hide show
  1. package/README.md +61 -795
  2. package/bin/flatsql.mjs +76 -0
  3. package/cpp/README.md +18 -0
  4. package/cpp/include/flatsql/flatsql.h +162 -0
  5. package/cpp/include/flatsql/flatsql_io.h +159 -0
  6. package/docs/API-3.12.md +126 -0
  7. package/package.json +28 -123
  8. package/wasm/flatsql.wasm +0 -0
  9. package/wasm/index.d.ts +61 -548
  10. package/wasm/index.js +280 -1281
  11. package/wasm/integrity.json +6 -26
  12. package/wasm/runtime/LICENSE.sdk.txt +190 -0
  13. package/wasm/runtime/NOTICE.txt +2 -0
  14. package/wasm/runtime/browser-guest.mjs +1 -0
  15. package/wasm/runtime/browser-host.mjs +1 -0
  16. package/wasm/runtime/node-guest.mjs +2 -0
  17. package/wasm/runtime/node-host.mjs +5 -0
  18. package/wasm/runtime/opfsIoWorker.mjs +1 -0
  19. package/wasm/runtime/wasiThreadBrowserWorker.mjs +1 -0
  20. package/dist/artifacts/index.d.ts +0 -3
  21. package/dist/artifacts/index.d.ts.map +0 -1
  22. package/dist/artifacts/index.js +0 -3
  23. package/dist/artifacts/index.js.map +0 -1
  24. package/dist/artifacts/transport.d.ts +0 -5
  25. package/dist/artifacts/transport.d.ts.map +0 -1
  26. package/dist/artifacts/transport.js +0 -45
  27. package/dist/artifacts/transport.js.map +0 -1
  28. package/dist/artifacts/types.d.ts +0 -34
  29. package/dist/artifacts/types.d.ts.map +0 -1
  30. package/dist/artifacts/types.js +0 -2
  31. package/dist/artifacts/types.js.map +0 -1
  32. package/dist/btree/btree.d.ts +0 -34
  33. package/dist/btree/btree.d.ts.map +0 -1
  34. package/dist/btree/btree.js +0 -234
  35. package/dist/btree/btree.js.map +0 -1
  36. package/dist/btree/index.d.ts +0 -3
  37. package/dist/btree/index.d.ts.map +0 -1
  38. package/dist/btree/index.js +0 -3
  39. package/dist/btree/index.js.map +0 -1
  40. package/dist/btree/types.d.ts +0 -36
  41. package/dist/btree/types.d.ts.map +0 -1
  42. package/dist/btree/types.js +0 -55
  43. package/dist/btree/types.js.map +0 -1
  44. package/dist/cluster/index.d.ts +0 -11
  45. package/dist/cluster/index.d.ts.map +0 -1
  46. package/dist/cluster/index.js +0 -59
  47. package/dist/cluster/index.js.map +0 -1
  48. package/dist/response/artifact.d.ts +0 -4
  49. package/dist/response/artifact.d.ts.map +0 -1
  50. package/dist/response/artifact.js +0 -102
  51. package/dist/response/artifact.js.map +0 -1
  52. package/dist/response/cache-key.d.ts +0 -6
  53. package/dist/response/cache-key.d.ts.map +0 -1
  54. package/dist/response/cache-key.js +0 -114
  55. package/dist/response/cache-key.js.map +0 -1
  56. package/dist/response/index.d.ts +0 -5
  57. package/dist/response/index.d.ts.map +0 -1
  58. package/dist/response/index.js +0 -5
  59. package/dist/response/index.js.map +0 -1
  60. package/dist/response/memory-cache.d.ts +0 -17
  61. package/dist/response/memory-cache.d.ts.map +0 -1
  62. package/dist/response/memory-cache.js +0 -76
  63. package/dist/response/memory-cache.js.map +0 -1
  64. package/dist/response/types.d.ts +0 -57
  65. package/dist/response/types.d.ts.map +0 -1
  66. package/dist/response/types.js +0 -2
  67. package/dist/response/types.js.map +0 -1
  68. package/dist/schema/index.d.ts +0 -3
  69. package/dist/schema/index.d.ts.map +0 -1
  70. package/dist/schema/index.js +0 -3
  71. package/dist/schema/index.js.map +0 -1
  72. package/dist/schema/parser.d.ts +0 -25
  73. package/dist/schema/parser.d.ts.map +0 -1
  74. package/dist/schema/parser.js +0 -474
  75. package/dist/schema/parser.js.map +0 -1
  76. package/dist/schema/types.d.ts +0 -33
  77. package/dist/schema/types.d.ts.map +0 -1
  78. package/dist/schema/types.js +0 -29
  79. package/dist/schema/types.js.map +0 -1
  80. package/dist/standalone/index.d.ts +0 -3
  81. package/dist/standalone/index.d.ts.map +0 -1
  82. package/dist/standalone/index.js +0 -3
  83. package/dist/standalone/index.js.map +0 -1
  84. package/dist/standalone/process-client.d.ts +0 -85
  85. package/dist/standalone/process-client.d.ts.map +0 -1
  86. package/dist/standalone/process-client.js +0 -537
  87. package/dist/standalone/process-client.js.map +0 -1
  88. package/dist/standalone/wasmedge-runner.d.ts +0 -19
  89. package/dist/standalone/wasmedge-runner.d.ts.map +0 -1
  90. package/dist/standalone/wasmedge-runner.js +0 -108
  91. package/dist/standalone/wasmedge-runner.js.map +0 -1
  92. package/dist/storage/index.d.ts +0 -3
  93. package/dist/storage/index.d.ts.map +0 -1
  94. package/dist/storage/index.js +0 -3
  95. package/dist/storage/index.js.map +0 -1
  96. package/dist/storage/stacked-flatbuffers.d.ts +0 -38
  97. package/dist/storage/stacked-flatbuffers.d.ts.map +0 -1
  98. package/dist/storage/stacked-flatbuffers.js +0 -253
  99. package/dist/storage/stacked-flatbuffers.js.map +0 -1
  100. package/dist/storage/types.d.ts +0 -23
  101. package/dist/storage/types.d.ts.map +0 -1
  102. package/dist/storage/types.js +0 -27
  103. package/dist/storage/types.js.map +0 -1
  104. package/dist/stress/aggregate.d.ts +0 -3
  105. package/dist/stress/aggregate.d.ts.map +0 -1
  106. package/dist/stress/aggregate.js +0 -61
  107. package/dist/stress/aggregate.js.map +0 -1
  108. package/dist/stress/docker-compose.d.ts +0 -17
  109. package/dist/stress/docker-compose.d.ts.map +0 -1
  110. package/dist/stress/docker-compose.js +0 -156
  111. package/dist/stress/docker-compose.js.map +0 -1
  112. package/dist/stress/index.d.ts +0 -10
  113. package/dist/stress/index.d.ts.map +0 -1
  114. package/dist/stress/index.js +0 -10
  115. package/dist/stress/index.js.map +0 -1
  116. package/dist/stress/metrics.d.ts +0 -3
  117. package/dist/stress/metrics.d.ts.map +0 -1
  118. package/dist/stress/metrics.js +0 -83
  119. package/dist/stress/metrics.js.map +0 -1
  120. package/dist/stress/native-publish-event-workload.d.ts +0 -3
  121. package/dist/stress/native-publish-event-workload.d.ts.map +0 -1
  122. package/dist/stress/native-publish-event-workload.js +0 -465
  123. package/dist/stress/native-publish-event-workload.js.map +0 -1
  124. package/dist/stress/production-gate.d.ts +0 -4
  125. package/dist/stress/production-gate.d.ts.map +0 -1
  126. package/dist/stress/production-gate.js +0 -12
  127. package/dist/stress/production-gate.js.map +0 -1
  128. package/dist/stress/report.d.ts +0 -3
  129. package/dist/stress/report.d.ts.map +0 -1
  130. package/dist/stress/report.js +0 -174
  131. package/dist/stress/report.js.map +0 -1
  132. package/dist/stress/sds-discovery.d.ts +0 -4
  133. package/dist/stress/sds-discovery.d.ts.map +0 -1
  134. package/dist/stress/sds-discovery.js +0 -40
  135. package/dist/stress/sds-discovery.js.map +0 -1
  136. package/dist/stress/smoke-runner.d.ts +0 -3
  137. package/dist/stress/smoke-runner.d.ts.map +0 -1
  138. package/dist/stress/smoke-runner.js +0 -64
  139. package/dist/stress/smoke-runner.js.map +0 -1
  140. package/dist/stress/types.d.ts +0 -219
  141. package/dist/stress/types.d.ts.map +0 -1
  142. package/dist/stress/types.js +0 -2
  143. package/dist/stress/types.js.map +0 -1
  144. package/dist/stress/workload.d.ts +0 -6
  145. package/dist/stress/workload.d.ts.map +0 -1
  146. package/dist/stress/workload.js +0 -144
  147. package/dist/stress/workload.js.map +0 -1
  148. package/docs/PARTITION-STORE-WASM.md +0 -338
  149. package/docs/PARTITION-STORE.md +0 -2380
  150. package/docs/agents/response-artifacts.md +0 -65
  151. package/docs/response-artifacts.md +0 -86
  152. package/scripts/stress-docker.sh +0 -279
  153. package/sdm/flatsql-spatial.wasm +0 -0
  154. package/sdm/index.d.ts +0 -88
  155. package/sdm/index.js +0 -253
  156. package/sdm/manifest.json +0 -402
  157. package/stress/docker/Dockerfile +0 -11
  158. package/stress/docker/docker-compose.yml +0 -51
  159. package/stress/sds/aggregate.mjs +0 -97
  160. package/stress/sds/run.mjs +0 -105
  161. package/stress/sds/write-compose.mjs +0 -96
  162. package/wasm/flatsql-client.js +0 -280
  163. package/wasm/flatsql-io.d.ts +0 -97
  164. package/wasm/flatsql-io.js +0 -625
  165. package/wasm/flatsql-p4-threads.wasm +0 -0
  166. package/wasm/flatsql-ps-threads.wasm +0 -0
  167. package/wasm/flatsql-wasi-noeh.wasm +0 -0
  168. package/wasm/flatsql-wasi.wasm +0 -0
  169. package/wasm/flatsql.js +0 -2
  170. package/wasm/flatsql.worker.js +0 -209
  171. package/wasm/native/flatsql_wasmedge_runner.cpp +0 -858
  172. package/wasm/ps-node-fault.d.mts +0 -23
  173. package/wasm/ps-node-fault.mjs +0 -381
  174. package/wasm/ps-node-guest.mjs +0 -173
  175. package/wasm/ps-node-host.d.mts +0 -95
  176. package/wasm/ps-node-host.mjs +0 -476
  177. package/wasm/ps-node-imports.mjs +0 -847
  178. package/wasm/ps.d.ts +0 -21
  179. package/wasm/ps.js +0 -75
  180. package/wasm/wasi.d.ts +0 -11
  181. package/wasm/wasi.js +0 -51
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ // Binary streams only. Schema/text conversion is a separate program.
3
+ import fs from 'node:fs/promises';
4
+ import { once } from 'node:events';
5
+ import { FlatSQL } from '../wasm/index.js';
6
+
7
+ const help = `Usage:
8
+ flatsql ingest --root DIR --schema FILE.bfbs --type NAME --id '$FID' < records.fb > receipts.fb
9
+ flatsql query --root DIR [--records] [--request FILE.fb] > results.fb
10
+
11
+ Ingest reads concatenated size-prefixed FlatBuffers from stdin.
12
+ Query reads one SDS QRP FlatBuffer request from stdin or --request.
13
+ Results are size-prefixed SDS QRP pages, or unchanged record frames with --records.
14
+ Optional ingest metadata: --provider NAME --source NAME --producer NAME --batch NAME.
15
+ Use a separate converter such as flatc-wasm for text input and output.
16
+ `;
17
+ async function main() {
18
+ const [command,...args]=process.argv.slice(2), options={};
19
+ if (!command || command==='--help' || command==='-h') { process.stdout.write(help); return; }
20
+ const allowed=new Set(['root','schema','type','id','request','provider','source','producer','batch']);
21
+ for (let i=0;i<args.length;i++) {
22
+ const key=args[i].slice(2);
23
+ if (args[i]==='--records') { options.records=true; continue; }
24
+ if (!args[i].startsWith('--') || !allowed.has(key) || !args[i+1] || args[i+1].startsWith('--'))
25
+ throw new Error(`Unknown or incomplete option: ${args[i]}`);
26
+ options[key]=args[++i];
27
+ }
28
+ if (!options.root || !['ingest','query'].includes(command)) throw new Error(help);
29
+ if (command==='ingest' && (!options.schema || !options.type || !options.id)) throw new Error(help);
30
+ const signal=new AbortController();
31
+ const interrupt=()=>signal.abort();
32
+ process.once('SIGINT',interrupt); process.once('SIGTERM',interrupt);
33
+ const write=async data=>{ if (!process.stdout.write(data)) await once(process.stdout,'drain'); };
34
+ const db=await FlatSQL.open({root:options.root});
35
+ try {
36
+ if (command==='query') {
37
+ let request;
38
+ if (options.request) {
39
+ if ((await fs.stat(options.request)).size>8*1024*1024) throw new Error('QRP request exceeds 8 MiB');
40
+ request=await fs.readFile(options.request);
41
+ } else {
42
+ const parts=[];let size=0;
43
+ for await (const chunk of process.stdin) {
44
+ size+=chunk.length;if(size>8*1024*1024)throw new Error('QRP request exceeds 8 MiB');parts.push(chunk);
45
+ }
46
+ request=Buffer.concat(parts);
47
+ }
48
+ for await (const chunk of db.query(request,{records:options.records,signal:signal.signal})) await write(chunk);
49
+ } else {
50
+ await db.registerSchema({name:options.type,fileIdentifier:options.id,bfbs:await fs.readFile(options.schema)});
51
+ const limit=4*1024*1024;
52
+ let pending=Buffer.alloc(0),batch=[],size=0;
53
+ const flush=async()=>{
54
+ if(!size)return;
55
+ await write(await db.ingest(options.type,Buffer.concat(batch,size),{...options,signal:signal.signal}));
56
+ batch=[];size=0;
57
+ };
58
+ for await(const chunk of process.stdin) {
59
+ pending=Buffer.concat([pending,chunk]);let at=0;
60
+ while(pending.length-at>=4) {
61
+ const n=pending.readUInt32LE(at)+4;
62
+ if(n<12 || n>limit)throw new Error('Record frame must be between 12 bytes and 4 MiB');
63
+ if(pending.length-at<n)break;
64
+ if(size+n>limit)await flush();
65
+ batch.push(Buffer.from(pending.subarray(at,at+n)));size+=n;at+=n;
66
+ }
67
+ pending=Buffer.from(pending.subarray(at));
68
+ }
69
+ if(pending.length)throw new Error('Truncated FlatBuffer record frame');
70
+ await flush();
71
+ }
72
+ } finally {
73
+ await db.close();process.removeListener('SIGINT',interrupt);process.removeListener('SIGTERM',interrupt);
74
+ }
75
+ }
76
+ main().catch(error=>{process.stderr.write(`flatsql: ${error.message}\n`);process.exitCode=1;});
package/cpp/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # FlatSQL native engine
2
+
3
+ FlatSQL 3.12 has one public C ABI: `include/flatsql/flatsql.h`.
4
+ Build the `flatsql` static library with CMake and the pinned DigitalArsenal
5
+ FlatBuffers checkout at `8af3053eb8400de4a0a654805b8257e93fae3a8e`.
6
+
7
+ ```sh
8
+ cmake -S cpp -B cpp/build -DFLATBUFFERS_DIR=/path/to/flatbuffers -DCMAKE_BUILD_TYPE=Release
9
+ cmake --build cpp/build --target flatsql
10
+ ```
11
+
12
+ The same engine builds as `wasm/flatsql.wasm` using wasi-sdk 30.
13
+ Native hosts provide the seven filesystem imports described in the ABI header.
14
+ Public SQL requests/results use SDS QRP; records are size-prefixed FlatBuffers.
15
+ See `docs/API-3.12.md` for the binary and geospatial contracts.
16
+
17
+ The private source directory names `p4` and `p4sql` identify the storage
18
+ implementation. They are not alternate engines or public entry points.
@@ -0,0 +1,162 @@
1
+ /* FlatSQL: one engine and one ABI for binary records and SQL.
2
+ * SQL input is SDS QRP; all projected results are size-prefixed SDS QRP.
3
+ * Record streams contain unchanged size-prefixed FlatBuffers. Configuration,
4
+ * registration and storage metadata use the documented packed control layout;
5
+ * they never parse or render record text. Mailboxes keep queries off the host
6
+ * executor thread and retain independent cancellation and resource budgets.
7
+ */
8
+ #ifndef FLATSQL_H
9
+ #define FLATSQL_H
10
+
11
+ #include <stdint.h>
12
+
13
+ #if defined(__wasm__)
14
+ # define FLATSQL_EXPORT(name) __attribute__((export_name(name)))
15
+ #else
16
+ # define FLATSQL_EXPORT(name)
17
+ #endif
18
+
19
+ #ifdef __cplusplus
20
+ extern "C" {
21
+ #endif
22
+
23
+ /* ---- §3.2 Status and reject codes ------------------------------------- */
24
+
25
+ #define FLATSQL_OK 0
26
+ #define FLATSQL_E_ARG -1 /* malformed request or config */
27
+ #define FLATSQL_E_NOMEM -2
28
+ #define FLATSQL_E_IO -3
29
+ #define FLATSQL_E_CORRUPT -4 /* the file is quarantined, never rewritten; reads elsewhere continue */
30
+ #define FLATSQL_E_FORMAT -5 /* unsupported store/file format or layout; marker/state mismatch; C-5 rule change */
31
+ #define FLATSQL_E_BUSY -6 /* a queue or partition credit is full: nothing was done, retry; reader paths never wait */
32
+ #define FLATSQL_E_CANCELLED -7
33
+ #define FLATSQL_E_BUDGET -8 /* rows-examined, bytes-read, result rows/bytes, work or heap cap */
34
+ #define FLATSQL_E_UNSUPPORTED -9
35
+ #define FLATSQL_E_NOTYPE -10 /* type not registered */
36
+ #define FLATSQL_E_STOPPED -11 /* stop word set, or the instance is stopping */
37
+ #define FLATSQL_E_NOSPACE -12 /* quota or device full: writes refuse, reads continue */
38
+ #define FLATSQL_E_SQL -13 /* SQL error; the text is in the slot's err */
39
+ #define FLATSQL_E_INTERNAL -14
40
+
41
+ /* Per-record rejects (PUT rows, `reject` column). -100..-109 are
42
+ * ps::RejectCode from flatsql/typecfg/extract.h, unchanged. */
43
+ #define FLATSQL_REJ_BAD_ENTRY -100
44
+ #define FLATSQL_REJ_FRAME_SIZE -101
45
+ #define FLATSQL_REJ_FID -102
46
+ #define FLATSQL_REJ_VERIFY -103
47
+ #define FLATSQL_REJ_CID -104
48
+ #define FLATSQL_REJ_SEALED -105
49
+ #define FLATSQL_REJ_ATTR -106
50
+ #define FLATSQL_REJ_QUARANTINED -107
51
+ #define FLATSQL_REJ_NO_TYPE -108
52
+ #define FLATSQL_REJ_TXN_TOO_LARGE -109
53
+ #define FLATSQL_REJ_CID_FORM -110 /* the CID is not a CIDv1 raw sha2-256 (bafkrei...) */
54
+ #define FLATSQL_REJ_SEQ -111 /* a migrate-mode seq is missing, <= 0, or held by a different CID */
55
+ #define FLATSQL_REJ_TOO_LARGE -112 /* above the type's max frame, or above the write pool's request area (C-6) */
56
+ #define FLATSQL_REJ_TAG -113 /* a tag without provider or source, a tag index out of range, or a record
57
+ PEER whose token differs from the call peer's */
58
+
59
+ /* ---- §3.5 Ops, classes, slot states -------------------------------------- */
60
+
61
+ enum {
62
+ FLATSQL_OPC_PUT = 1, FLATSQL_OPC_SUPERSEDE = 2, FLATSQL_OPC_DELETE = 3, FLATSQL_OPC_QUOTA_GC = 4, FLATSQL_OPC_REBUILD = 5,
63
+ FLATSQL_OPC_GET = 10, FLATSQL_OPC_TAGS = 11, FLATSQL_OPC_SCAN = 12, FLATSQL_OPC_HEAD = 13, FLATSQL_OPC_WINDOW = 14,
64
+ FLATSQL_OPC_INDEX_PAGE = 15, FLATSQL_OPC_EPOCH = 16, FLATSQL_OPC_SUMMARY = 17,
65
+ FLATSQL_OPC_RANGES = 18, FLATSQL_OPC_FEED_ROOT = 19, FLATSQL_OPC_DROPS = 20,
66
+ FLATSQL_OPC_EXPOSURE = 21, FLATSQL_OPC_RELEASE = 22,
67
+ FLATSQL_OPC_SQL = 30, FLATSQL_OPC_SURFACE = 31
68
+ };
69
+ /* IPFS ops: tag 1 type; tags 3/4 provider/source (both omitted = every feed,
70
+ * both empty = local). Tag 80 u64: inclusive from-commit for RANGES/DROPS,
71
+ * through-commit for RELEASE. Tag 81 u8: EXPOSURE (0 default, 1 on).
72
+ * Tag 82 u32: RELEASE generation (default current); offsets are generation-local.
73
+ * RELEASE of a generation older than the current one releases that whole
74
+ * (immutable) generation; tag 80 is ignored. RELEASE of the current generation
75
+ * releases every older one once tag 80 reaches its compaction checkpoint (the
76
+ * first FCK after genesis), and is a no-op before that.
77
+ * RANGES: path,offset,length,cid,kind,unit,block,provider,source,generation.
78
+ * Paths are relative to config root; inline block bytes only for dag-pb nodes.
79
+ * LINK unit is its publication/change commit, including rewrites of old units.
80
+ * FEED_ROOT: provider,source,cid,unit,generation,blocked_generations.
81
+ * DROPS: cid,unit,provider,source,generation. Includes removed records, large
82
+ * roots/leaves and obsolete raw metadata. Derived LINK blocks are reclaimed
83
+ * by pin-update/GC. Unit names the removal or replacement checkpoint.
84
+ * RANGES is the live closure in the current generation, filtered by unit.
85
+ * Reset the cursor when FEED_ROOT reports a changed generation.
86
+ * Exposure is runtime policy: the node must reapply it after opening a store
87
+ * before the 30-second retired-reader window expires.
88
+ * EXPOSURE/RELEASE return no rows. These run on a read lane; exposure/release
89
+ * change only the node's generation-release bookkeeping, never stream bytes.
90
+ */
91
+ enum { FLATSQL_RANGE_RECORD=1, FLATSQL_RANGE_LARGE_LEAF=2, FLATSQL_RANGE_LARGE_ROOT=3,
92
+ FLATSQL_RANGE_FMB=4, FLATSQL_RANGE_FCK=5, FLATSQL_RANGE_FSG=6, FLATSQL_RANGE_LINK=7 };
93
+ enum { FLATSQL_CLASS_WRITE = 1, FLATSQL_CLASS_INTERACTIVE = 2, FLATSQL_CLASS_BULK = 3, FLATSQL_CLASS_SANDBOX = 4,
94
+ FLATSQL_CLASS_MAINTENANCE = 5 };
95
+ enum { FLATSQL_SLOT_FREE = 0, FLATSQL_SLOT_CLAIMED = 1, FLATSQL_SLOT_QUEUED = 2, FLATSQL_SLOT_RUNNING = 3, FLATSQL_SLOT_DONE = 5 };
96
+ enum { FLATSQL_ACT_REJECTED = 0, FLATSQL_ACT_NEW = 1, FLATSQL_ACT_COPY = 2, FLATSQL_ACT_RETAG = 3, FLATSQL_ACT_DUP = 4,
97
+ FLATSQL_ACT_IDENT_DUP = 5, FLATSQL_ACT_MIGRATED = 6 };
98
+
99
+ /* ---- §3.4 The mailbox ------------------------------------------------------ */
100
+
101
+ #define FLATSQL_LAYOUT_VERSION 1
102
+ #define FLATSQL_SLOT_HEADER 448
103
+ typedef struct FlatSQLLayout {
104
+ uint32_t version; /* 0: 1 */
105
+ uint32_t size; /* 4: 640 */
106
+ uint32_t headerSize; /* 8: 448 */
107
+ uint32_t stopWord; /* 12: address of the u32 stop word */
108
+ uint32_t nSlots[2]; /* 16: [0] write pool, [1] read pool */
109
+ uint32_t slotBase[2]; /* 24 */
110
+ uint32_t slotStride[2]; /* 32: headerSize + reqBytes + ringBytes, 64-aligned */
111
+ uint32_t reqBytes[2]; /* 40 */
112
+ uint32_t ringBytes[2]; /* 48: powers of two */
113
+ uint32_t queueCells[4]; /* 56: per class, index = class-1 */
114
+ uint32_t queueMask[4]; /* 72 */
115
+ uint32_t queueEnq[4]; /* 88: address of the u64 enqueue counter */
116
+ uint32_t queueDeq[4]; /* 104: address of the u64 dequeue counter */
117
+ uint32_t nThreads; /* 120: service threads (writers, lanes, maintenance), <= 64 */
118
+ uint32_t rsv; /* 124: 0 */
119
+ uint32_t threadClass[64]; /* 128: 1 write, 2 interactive, 3 bulk, 4 sandbox, 5 maintenance */
120
+ uint32_t doorbell[64]; /* 384: address of the thread's doorbell u32; its state u32 is at doorbell+4
121
+ (0 idle, 1 busy, 2 stopped) */
122
+ } FlatSQLLayout;
123
+
124
+ /* Slot header byte offsets (version 1). */
125
+ enum {
126
+ FLATSQL_SLOT_OFF_STATE = 0, FLATSQL_SLOT_OFF_CANCEL = 4, FLATSQL_SLOT_OFF_OUTSEQ = 8, FLATSQL_SLOT_OFF_SPACESEQ = 12,
127
+ FLATSQL_SLOT_OFF_OP = 16, FLATSQL_SLOT_OFF_CLASS = 20, FLATSQL_SLOT_OFF_FLAGS = 24, FLATSQL_SLOT_OFF_REQLEN = 28,
128
+ FLATSQL_SLOT_OFF_REQID = 32, FLATSQL_SLOT_OFF_MAX_ROWS_EXAMINED = 40, FLATSQL_SLOT_OFF_MAX_BYTES_READ = 48,
129
+ FLATSQL_SLOT_OFF_MAX_RESULT_ROWS = 56, FLATSQL_SLOT_OFF_MAX_RESULT_BYTES = 64, FLATSQL_SLOT_OFF_RING_HEAD = 72,
130
+ FLATSQL_SLOT_OFF_RING_TAIL = 80, FLATSQL_SLOT_OFF_STATUS = 88, FLATSQL_SLOT_OFF_ERRLEN = 92, FLATSQL_SLOT_OFF_ROWS_OUT = 96,
131
+ FLATSQL_SLOT_OFF_ROWS_EXAMINED = 104, FLATSQL_SLOT_OFF_BYTES_READ = 112, FLATSQL_SLOT_OFF_SUBMIT_NS = 120,
132
+ FLATSQL_SLOT_OFF_START_NS = 128, FLATSQL_SLOT_OFF_END_NS = 136, FLATSQL_SLOT_OFF_ERR = 144, FLATSQL_SLOT_ERR_CAP = 256,
133
+ FLATSQL_SLOT_OFF_THREAD = 400
134
+ };
135
+
136
+ /* ---- §3.3 Exports (exact) ------------------------------------------------ */
137
+
138
+ FLATSQL_EXPORT("flatsql_init") int32_t flatsql_init(const uint8_t* cfg, int32_t cfgLen);
139
+ FLATSQL_EXPORT("flatsql_start") int32_t flatsql_start(void); /* >= 0: threads started */
140
+ FLATSQL_EXPORT("flatsql_layout") int32_t flatsql_layout(FlatSQLLayout* out); /* bytes written = 640 */
141
+ FLATSQL_EXPORT("flatsql_wake") int32_t flatsql_wake(uint32_t* addr, int32_t n); /* memory.atomic.notify; woken count */
142
+ FLATSQL_EXPORT("flatsql_register_type") int32_t flatsql_register_type(const uint8_t* spec, int32_t specLen);
143
+ FLATSQL_EXPORT("flatsql_set_quota") int32_t flatsql_set_quota(double bytes); /* 0 = none */
144
+ FLATSQL_EXPORT("flatsql_activate") int32_t flatsql_activate(void); /* create mode 2 only */
145
+ FLATSQL_EXPORT("flatsql_stats") int32_t flatsql_stats(uint8_t* out, int32_t cap); /* bytes written; u64 LE array §3.10 */
146
+ FLATSQL_EXPORT("flatsql_stop") int32_t flatsql_stop(double deadlineMs); /* FLATSQL_OK, or FLATSQL_E_BUSY at the deadline */
147
+ FLATSQL_EXPORT("flatsql_alloc") void* flatsql_alloc(int32_t n); /* wasm only */
148
+ FLATSQL_EXPORT("flatsql_free") void flatsql_free(void* p); /* wasm only */
149
+
150
+ /* Prepare a PUT or DELETE mailbox request from an unchanged stream of size-prefixed
151
+ * records. Metadata is the control TLV (type, producer, source tags, timestamp;
152
+ * tag 55: u32 signature count, then u16 length + bytes per PUT record).
153
+ * CID computation stays in the guest. Returns status and an allocated buffer.
154
+ * Caller frees *output with flatsql_free. */
155
+ FLATSQL_EXPORT("flatsql_record_request") int32_t flatsql_record_request(
156
+ int32_t opcode, const uint8_t* frames, int32_t size, const uint8_t* metadata, int32_t metadataSize, uint8_t** output, uint32_t* outLen);
157
+
158
+ #ifdef __cplusplus
159
+ }
160
+ #endif
161
+
162
+ #endif
@@ -0,0 +1,159 @@
1
+ #ifndef FLATSQL_IO_H
2
+ #define FLATSQL_IO_H
3
+
4
+ /*
5
+ * FlatSQL host I/O contract — SEVEN imports, one contract, every host.
6
+ * =====================================================================
7
+ *
8
+ * FlatSQL does not use emscripten's filesystem and does not use WASI file
9
+ * descriptors. It registers its OWN sqlite3_vfs ("flatsql_io") whose methods
10
+ * call out through the seven functions declared below. Every host — the
11
+ * browser JS shim, the standalone WASI shim, WasmEdge/wazero in the Go node —
12
+ * satisfies the SAME seven names with the SAME signatures. There is no runtime
13
+ * detection anywhere in module code; the difference between a browser
14
+ * key->bytes store and a real POSIX file lives entirely in the host shim.
15
+ * See docs/STORAGE-DURABILITY.md §3.5.
16
+ *
17
+ * WHY NOT WASI path_open: MEASURED (§3.5). `-s WASMFS=1` routes file I/O to an
18
+ * in-memory backend that looks durable and is not; `-s FORCE_FILESYSTEM=1`
19
+ * emits ten emscripten `__syscall_*` imports that no host satisfies and still
20
+ * never emits path_open. Both were reverted.
21
+ *
22
+ * SIGNATURE LAW — i32 and f64 ONLY.
23
+ * Offsets and sizes are `double`, never `int64_t`. Emscripten legalizes i64 at
24
+ * the JS boundary for the browser target (splitting one i64 parameter into two
25
+ * i32s) but NOT for STANDALONE_WASM. An i64 in this contract would therefore
26
+ * give the two lanes genuinely different wasm signatures for the same function
27
+ * name — the exact divergence class this design exists to prevent. f64 is
28
+ * exact to 2^53 (9 PB), passes through JS unmodified, and is identical in
29
+ * every lane.
30
+ *
31
+ * ERROR LAW: errors are return values, never traps. The -fignore-exceptions
32
+ * WASI artifact turns any throw into a guest-poisoning `unreachable`
33
+ * (commit b26ed45), so nothing below may throw.
34
+ */
35
+
36
+ #include <stdint.h>
37
+
38
+ /* ---- open flags ------------------------------------------------------- */
39
+ #define FLATSQL_IO_READ 0x0001
40
+ #define FLATSQL_IO_WRITE 0x0002
41
+ #define FLATSQL_IO_CREATE 0x0004
42
+ #define FLATSQL_IO_EXCL 0x0008
43
+ #define FLATSQL_IO_TRUNC 0x0010
44
+ /* Advisory: the host may drop the file when the handle is closed. */
45
+ #define FLATSQL_IO_DELETE_ON_CLOSE 0x0020
46
+
47
+ /* Namespace operations. These are carried on `open` rather than spent as two
48
+ * more imports: a VFS needs xAccess and xDelete, and both are pure
49
+ * path->status questions that allocate no handle. With either bit set,
50
+ * flatsql_io_open returns a STATUS (0 = success/exists, negative = error or
51
+ * absent) and no handle is created. Hosts must not allocate for them. */
52
+ #define FLATSQL_IO_PROBE 0x0040 /* xAccess: does the path exist? */
53
+ #define FLATSQL_IO_UNLINK 0x0080 /* xDelete: remove the path */
54
+
55
+ /* Partition store flags (docs/PARTITION-STORE.md §5.4, design A12/A38).
56
+ * They are flags, not imports: the import set stays seven. The values are the
57
+ * ones every space-data-module-sdk host implements (module-sdk 0.8.22,
58
+ * docs/isomorphic-pthreads.md "Flags and statuses"); they must not diverge.
59
+ *
60
+ * CREATE_PARENTS: create every missing parent directory (fsyncing the parent
61
+ * of each one created) and, when the file itself is newly created, fsync its
62
+ * parent directory before returning. Best effort on OPFS.
63
+ * UNLINK_IF_UNUSED: unlink, or FLATSQL_IO_ERR_BUSY while any handle names the
64
+ * path. After a successful unlink a POSIX host fsyncs the parent directory.
65
+ * (A plain UNLINK of an open path is BUSY on OPFS and allowed on POSIX: the
66
+ * engine never unlinks a path it holds open.)
67
+ * OPEN_DEFERRED: return a handle before the open finishes; the first use
68
+ * waits, or fails with the open's status. Synchronous hosts treat it as a
69
+ * plain open. */
70
+ #define FLATSQL_IO_CREATE_PARENTS 0x0100
71
+ #define FLATSQL_IO_UNLINK_IF_UNUSED 0x0200
72
+ #define FLATSQL_IO_OPEN_DEFERRED 0x0400
73
+
74
+ /* ---- status codes (all negative; every call may return any of them) ---- */
75
+ #define FLATSQL_IO_ERR_GENERIC (-1)
76
+ #define FLATSQL_IO_ERR_NOENT (-2)
77
+ #define FLATSQL_IO_ERR_ACCESS (-3)
78
+ #define FLATSQL_IO_ERR_IO (-4)
79
+ #define FLATSQL_IO_ERR_NOSPACE (-5)
80
+ #define FLATSQL_IO_ERR_BADHANDLE (-6)
81
+ #define FLATSQL_IO_ERR_BUSY (-7) /* path in use, or its lock held elsewhere */
82
+ /* EEXIST (CREATE|EXCL on an existing path) maps to GENERIC on every host. */
83
+
84
+ #if defined(__wasm__)
85
+ # define FLATSQL_IO_IMPORT(name) \
86
+ __attribute__((import_module("env"), import_name(name)))
87
+ #else
88
+ # define FLATSQL_IO_IMPORT(name)
89
+ #endif
90
+
91
+ #ifdef __cplusplus
92
+ extern "C" {
93
+ #endif
94
+
95
+ /* Open (or probe/unlink) `path`. Returns a non-negative opaque handle, or a
96
+ * negative status. `pathLen` is explicit: hosts never scan for NUL. */
97
+ FLATSQL_IO_IMPORT("flatsql_io_open")
98
+ int32_t flatsql_io_open(const char* path, int32_t pathLen, int32_t flags);
99
+
100
+ /* Offset-addressed read. Returns bytes actually read (may be < len at EOF), or
101
+ * a negative status. Never moves an implicit cursor — there isn't one. */
102
+ FLATSQL_IO_IMPORT("flatsql_io_read")
103
+ int32_t flatsql_io_read(int32_t handle, void* dst, int32_t len, double offset);
104
+
105
+ /* Offset-addressed write. Writing past EOF extends the file (the gap reads as
106
+ * zeroes). Returns bytes written or a negative status. */
107
+ FLATSQL_IO_IMPORT("flatsql_io_write")
108
+ int32_t flatsql_io_write(int32_t handle, const void* src, int32_t len,
109
+ double offset);
110
+
111
+ /* Set the file length exactly (grow or shrink). */
112
+ FLATSQL_IO_IMPORT("flatsql_io_truncate")
113
+ int32_t flatsql_io_truncate(int32_t handle, double size);
114
+
115
+ /* Durability barrier. Returns 0 only when prior writes are durable. */
116
+ FLATSQL_IO_IMPORT("flatsql_io_sync")
117
+ int32_t flatsql_io_sync(int32_t handle);
118
+
119
+ /* Current length in bytes, or a negative status. */
120
+ FLATSQL_IO_IMPORT("flatsql_io_size")
121
+ double flatsql_io_size(int32_t handle);
122
+
123
+ /* Release the handle. */
124
+ FLATSQL_IO_IMPORT("flatsql_io_close")
125
+ int32_t flatsql_io_close(int32_t handle);
126
+
127
+ #ifdef __cplusplus
128
+ } /* extern "C" */
129
+
130
+ namespace flatsql {
131
+
132
+ /* Name of the VFS registered over the seven imports above. */
133
+ extern const char* const kFlatSqlVfsName; /* "flatsql_io" */
134
+
135
+ /* Idempotent. Registers the VFS with SQLite. `makeDefault` decides whether an
136
+ * open with a NULL vfs name lands here. Returns SQLITE_OK on success. Never
137
+ * throws. */
138
+ int registerFlatSqlIoVfs(bool makeDefault);
139
+
140
+ /* Connections opened with the URI parameter ra=1 read ahead sequentially:
141
+ * up to `streams` streams per connection (1..8, default 2), `bytes` per
142
+ * read-ahead (default 1 MiB). Applies to reads after the call. */
143
+ void setFlatSqlIoReadahead(int streams, int bytes);
144
+
145
+ /* Process-wide VFS counters. */
146
+ struct FlatSqlIoVfsStats {
147
+ int64_t walIndexBytes; /* heap WAL-index regions mapped now */
148
+ int64_t walIndexBytesPeak;
149
+ int64_t readaheadReads; /* host reads issued by readahead */
150
+ int64_t readaheadHits; /* SQLite reads served from readahead buffers */
151
+ int64_t readaheadBytes;
152
+ int64_t nodes; /* paths with an open database file */
153
+ };
154
+ FlatSqlIoVfsStats flatSqlIoVfsStats();
155
+
156
+ } /* namespace flatsql */
157
+ #endif /* __cplusplus */
158
+
159
+ #endif /* FLATSQL_IO_H */
@@ -0,0 +1,126 @@
1
+ # FlatSQL 3.12 binary API
2
+
3
+ FlatSQL has one public JavaScript entry point, `flatsql`, exporting `FlatSQL`
4
+ and `FlatSQLError`, and one native ABI, `cpp/include/flatsql/flatsql.h`.
5
+ `flatsql/flatsql.wasm` identifies the same WASI threads artifact on every host.
6
+ There are no PS/P4 selectors, old engine aliases, or compatibility modes.
7
+
8
+ ## Schemas, records, and queries
9
+
10
+ - `FlatSQL.open(options)` opens persistent host storage. Node `root` is a
11
+ filesystem directory; browser `root` is an OPFS directory. Node without a
12
+ root creates a temporary store. `close()` drains/cancels operations and stops
13
+ the engine. Close an instance before opening the same directory again.
14
+ - `registerSchema({name, fileIdentifier, bfbs, ...})` registers a binary
15
+ reflection schema. Type names are SQL identifiers, up to 64 characters; the
16
+ file identifier is four bytes. Indexed extraction rules and full-text
17
+ indexing are schema configuration, executed inside the guest.
18
+ - `ingest(type, records, metadata)` accepts concatenated frames:
19
+ `[u32 little-endian payload length][FlatBuffer payload]`. The guest validates
20
+ records, computes identities, persists streams and updates indexes. Provider,
21
+ source, producer, batch and timestamp metadata are optional. `signatures`
22
+ supplies one opaque byte array per record, retained in `_signature`.
23
+ - `remove(type, records)` deletes those original binary payloads and returns a
24
+ QRP receipt. Record hashing and deletion stay inside the engine.
25
+ - `query(request, options)` returns an async stream of byte chunks; `execute`
26
+ collects it within a byte budget. Requests are canonical SDS QRP buffers,
27
+ optionally size-prefixed, with `KIND=Request` and `REPRESENTATION=FlatBuffer`
28
+ (or their schema defaults). `SQL` and `PARAMETERS` drive the query. Express
29
+ filters, sort, selection, and paging in SQL; unrelated QRP selection fields
30
+ are rejected instead of silently ignored.
31
+ - Projection output is a stream of size-prefixed SDS QRP pages: column names,
32
+ typed rows, and a final summary containing counts, status and truncation.
33
+ Chunk boundaries need not coincide with frame boundaries. QRP null, integer,
34
+ float, text and bytes preserve SQLite values; boolean parameters bind as
35
+ SQLite integers 0/1. Integers remain signed 64-bit values.
36
+ - `SELECT _data` with `{records:true}` streams original record frames unchanged.
37
+ IDs, properties, altitude, null geometry and bounding boxes are preserved
38
+ byte for byte. Derived geometry has the separate semantics below.
39
+ - With `registerSchema({..., fullText:true})`, SQL `_search MATCH ?1` uses the
40
+ engine's FTS5 index over the record's text fields, including nested text.
41
+ The engine returns `BUSY` while its background index catches up; retry the
42
+ query, and never treat that condition as zero matches.
43
+ - Hidden metadata columns `_cid`, `_seq`, `_ts`, `_epoch`, `_producer`, `_peer`
44
+ and `_signature` are available alongside `_source`, `_rowid` and `_data`.
45
+ - `flatsql_provenance(type, cid)` is a SQL table-valued function returning every
46
+ persisted copy and source tag for that content record. Both arguments are
47
+ required; `cid` is the `_cid` text from the record relation. Join it to the
48
+ record relation to preserve provider, source, batch, producer, original peer,
49
+ timestamp and signature when copying records. Its columns are `cid`, `seq`,
50
+ `producer`, `peer`, `ts`, `sig`, `provider`, `source`, `source_url`, `batch`,
51
+ `content_key_id`, `producer_peer`, `producer_pubkey` and `at`. Untagged copies
52
+ have NULL tag columns. Use distinct CIDs when joining the ordinary record
53
+ relation: a CID can occur in several feeds, and `_source` alone does not
54
+ enumerate every membership. Results use the same
55
+ typed QRP pages and query budgets as other SQL queries.
56
+ The function name is reserved and cannot be registered as a schema name.
57
+ - Root scalar/string/byte-vector fields are exposed by BFBS reflection.
58
+ Complex/nested fields remain in `_data`. Unsigned integers above the SQLite
59
+ signed 64-bit range produce an error; retrieve `_data` to preserve them.
60
+ - `surface()` returns the SQL catalog in QRP pages. `setQuota(bytes)` changes the
61
+ disk budget; zero removes that budget. Low-level mailbox maintenance and
62
+ storage controls are documented in the C header, behind the same engine.
63
+
64
+ `QueryOptions` provides cancellation (`AbortSignal`), elapsed timeout,
65
+ rows/result bytes, rows examined, bytes read, and bulk/sandbox lane selection.
66
+ QRP `MAX_ROWS`, `LIMIT`, `MAX_BYTES`, and `MAX_ELAPSED_MS` are enforced by the
67
+ engine. Breaking a stream cancels and drains its lane before its slot is reused.
68
+ `execute` defaults to a 16 MiB collected result budget, with bounded room for
69
+ terminal framing. A budget failure throws `FlatSQLError`; already streamed
70
+ chunks are partial, never a successful complete answer.
71
+
72
+ The data boundary accepts `Uint8Array`, not JavaScript rows or SQL strings.
73
+ The package does not parse or render JSON, GeoJSON or WKT, compile schema text,
74
+ or provide the SQLite JSON extension. Manifest JSON is tooling metadata.
75
+ Convert separately with flatc-wasm or generated SDS bindings. Private packed
76
+ control messages configure memory and files; they do not carry a second public
77
+ record or SQL result format.
78
+
79
+ ## Geometry
80
+
81
+ Geometry arguments are canonical SDS GJN (`$GJN`, root `GJN`) FlatBuffers,
82
+ provided as a payload or one size-prefixed frame. Results are GJN payloads in
83
+ QRP `Bytes` values. Every result verifies against the same SDS schema. No
84
+ custom geometry blob or JSON parser exists inside the engine.
85
+
86
+ All seven GJN geometry kinds are decoded, including multi-geometries and
87
+ collections. Multiple features are evaluated as a collection; null feature
88
+ geometries contribute no points. SQL NULL propagates. Malformed buffers,
89
+ non-finite positions, open polygon rings, and unsupported combinations produce
90
+ SQL errors. Properties remain opaque, including SDS `JSON_VALUE` strings.
91
+
92
+ | Function | Behavior |
93
+ | --- | --- |
94
+ | `geo_distance`, `geo_within_radius`, `geo_bearing` | Spherical calculations; distances/radii in kilometers, coordinates in latitude/longitude order. |
95
+ | `geo_bbox_contains`, `geo_area_bbox` | Scalar bounding-box predicates and spherical area. |
96
+ | `geo_contains(g,lat,lon)` | Point/polygon membership, including polygon holes and collection members. |
97
+ | `geo_area_geom(g)` | Sum of planar polygon areas minus holes, in square degrees. Non-area members contribute zero. |
98
+ | `geo_length_geom(g)` | Haversine line length in kilometers; collection members contribute their lengths. |
99
+ | `geo_envelope(g)`, `geo_convex_hull(g)` | Two-dimensional envelope/hull over every member's coordinates. |
100
+ | `geo_centroid(g)` | Planar centroid, weighted by polygon area minus holes, then line length, then point count. Highest-dimensional members contribute; empty/degenerate input returns NULL. |
101
+ | `geo_intersection`, `geo_union`, `geo_difference`, `geo_sym_difference` | Convex, hole-free polygon operands, either winding. Exact clipped pieces; concave or holed operands are rejected. Results may contain multiple polygon pieces with touching boundaries. |
102
+ | `geo_buffer(g,d)` | Point buffer with positive distance in degrees, approximated by a 16-segment circle. Other geometry kinds are rejected. |
103
+ | `geo_voronoi`, `geo_delaunay` | Point/multipoint sites in the longitude/latitude plane. Voronoi bounds must be a convex, hole-free polygon. |
104
+ | `geo_destination`, `geo_midpoint` | GJN point results from spherical calculations. |
105
+ | `geo_to_ecef_x/y/z(lat,lon,alt)` | Separate numeric Cartesian components in meters; altitude input is meters. |
106
+ | `geo_from_ecef(x,y,z)` | GJN point with WGS84 longitude, latitude and altitude in meters. |
107
+
108
+ Derived map geometry is explicitly 2D: it contains newly computed coordinates
109
+ and no feature IDs, properties, source bbox or altitude. `geo_from_ecef` computes
110
+ altitude. Scalar map measurements ignore altitude. Original record queries
111
+ preserve the complete original 3D record. Geometry computations are planar
112
+ unless explicitly described as spherical; they do not unwrap antimeridian
113
+ crossings or act as a global spherical topology engine.
114
+
115
+ ## Integrity and hosts
116
+
117
+ Default loads verify the adjacent `integrity.json`: browser Fetch SRI and Node
118
+ SHA-256. Supplying `wasmBytes` requires a verification callback, allowing a host
119
+ to enforce its signed artifact policy before instantiation. Generic adapters
120
+ provide threads, memory, filesystem I/O and transport; query, geometry, indexing,
121
+ and record identity logic stay inside C++/WASM.
122
+
123
+ Browser hosting requires shared memory and cross-origin isolation. Worker URLs
124
+ can be supplied explicitly for bundlers. The distributed private runtime
125
+ adapters bundle only the necessary published SDK host code and its license;
126
+ they do not bring the SDK's legacy FlatSQL dependency into the package.