space-data-module-sdk 0.5.19 → 0.5.21
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/README.md +52 -7
- package/package.json +5 -1
- package/src/AGENTS.md +33 -0
- package/src/auth/AGENTS.md +25 -0
- package/src/browser.js +2 -0
- package/src/bundle/AGENTS.md +21 -0
- package/src/compiler/AGENTS.md +35 -0
- package/src/compliance/AGENTS.md +18 -0
- package/src/host/AGENTS.md +39 -0
- package/src/host/isomorphicLoader.js +133 -0
- package/src/host/wasiShim.js +12 -1
- package/src/index.d.ts +100 -0
- package/src/manifest/AGENTS.md +18 -0
- package/src/runtime-host/AGENTS.md +32 -0
- package/src/runtime-host/flatbufferStreamIngestor.js +181 -0
- package/src/runtime-host/flatsqlRuntimeStore.js +120 -49
- package/src/runtime-host/index.js +2 -0
- package/src/testing/AGENTS.md +33 -0
- package/src/testing/index.js +1 -0
- package/src/testing/moduleFlatbufferStreamPump.js +255 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# AGENTS
|
|
2
|
+
|
|
3
|
+
Apply the root and `src/AGENTS.md` files first.
|
|
4
|
+
|
|
5
|
+
## Area Ownership
|
|
6
|
+
|
|
7
|
+
This directory owns the canonical runtime-host storage model: row handles,
|
|
8
|
+
region handles, FlatSQL-backed storage, and binary FlatBuffer ingest on the host
|
|
9
|
+
side.
|
|
10
|
+
|
|
11
|
+
## Storage And Streaming Rules
|
|
12
|
+
|
|
13
|
+
- Keep durable row identity host-owned as `(schemaFileId, rowId)`.
|
|
14
|
+
- Keep runtime aligned-binary identity host-owned as `(regionId, recordIndex)`.
|
|
15
|
+
- The canonical ingest path is binary FlatBuffer bytes, not JSON.
|
|
16
|
+
- Use size-prefixed FlatBuffer frames for streaming transport.
|
|
17
|
+
- Do not coerce row payloads through JSON serialization.
|
|
18
|
+
- If the host owns persistence, use runtime-host ingest helpers.
|
|
19
|
+
- If a resident module owns state, keep the stream binary and push into the
|
|
20
|
+
module through the harness/pump path rather than inventing JSON wrappers.
|
|
21
|
+
|
|
22
|
+
## Key Files
|
|
23
|
+
|
|
24
|
+
- `flatbufferStreamIngestor.js`
|
|
25
|
+
- `flatsqlRuntimeStore.js`
|
|
26
|
+
- `index.js`
|
|
27
|
+
|
|
28
|
+
## Verification
|
|
29
|
+
|
|
30
|
+
- `npm run test:stream-ingest`
|
|
31
|
+
- `node --test test/flatsql-local-node.test.js`
|
|
32
|
+
- `npm run benchmark:stream-1gib` for large-stream changes
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createFlatSqlRuntimeStore } from "./flatsqlRuntimeStore.js";
|
|
2
|
+
|
|
3
|
+
function toUint8Array(data) {
|
|
4
|
+
if (data instanceof Uint8Array) {
|
|
5
|
+
return data;
|
|
6
|
+
}
|
|
7
|
+
if (data instanceof ArrayBuffer) {
|
|
8
|
+
return new Uint8Array(data);
|
|
9
|
+
}
|
|
10
|
+
if (ArrayBuffer.isView(data)) {
|
|
11
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
12
|
+
}
|
|
13
|
+
throw new TypeError(
|
|
14
|
+
"FlatBuffer stream ingestor expects Uint8Array, ArrayBuffer, or ArrayBufferView chunks.",
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function concatUint8Arrays(chunks) {
|
|
19
|
+
let totalLength = 0;
|
|
20
|
+
for (let index = 0; index < chunks.length; index += 1) {
|
|
21
|
+
totalLength += chunks[index].byteLength;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const combined = new Uint8Array(totalLength);
|
|
25
|
+
let offset = 0;
|
|
26
|
+
for (let index = 0; index < chunks.length; index += 1) {
|
|
27
|
+
combined.set(chunks[index], offset);
|
|
28
|
+
offset += chunks[index].byteLength;
|
|
29
|
+
}
|
|
30
|
+
return combined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function readFrameSize(bytes, offset) {
|
|
34
|
+
return (
|
|
35
|
+
bytes[offset] |
|
|
36
|
+
(bytes[offset + 1] << 8) |
|
|
37
|
+
(bytes[offset + 2] << 16) |
|
|
38
|
+
((bytes[offset + 3] << 24) >>> 0)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readFileIdentifier(payload) {
|
|
43
|
+
if (!(payload instanceof Uint8Array) || payload.byteLength < 8) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return String.fromCharCode(payload[4], payload[5], payload[6], payload[7]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function normalizeSchemaFileId(fileIdentifier) {
|
|
50
|
+
if (typeof fileIdentifier !== "string") {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const normalized = fileIdentifier.trim();
|
|
54
|
+
return normalized.length > 0 ? normalized : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function resolveRouteHandler(frameRouter, rawFileIdentifier, schemaFileId) {
|
|
58
|
+
if (typeof frameRouter === "function") {
|
|
59
|
+
return frameRouter;
|
|
60
|
+
}
|
|
61
|
+
if (!frameRouter || typeof frameRouter !== "object") {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (typeof frameRouter[schemaFileId] === "function") {
|
|
65
|
+
return frameRouter[schemaFileId];
|
|
66
|
+
}
|
|
67
|
+
if (typeof frameRouter[rawFileIdentifier] === "function") {
|
|
68
|
+
return frameRouter[rawFileIdentifier];
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function createFlatBufferStreamIngestor(options = {}) {
|
|
74
|
+
const rows = options.rows ?? createFlatSqlRuntimeStore();
|
|
75
|
+
const frameRouter = options.frameRouter ?? null;
|
|
76
|
+
const appendFrame =
|
|
77
|
+
typeof options.appendFrame === "function" ? options.appendFrame : null;
|
|
78
|
+
|
|
79
|
+
const stats = {
|
|
80
|
+
bytesReceived: 0,
|
|
81
|
+
chunksReceived: 0,
|
|
82
|
+
framesDecoded: 0,
|
|
83
|
+
framesAppended: 0,
|
|
84
|
+
framesRouted: 0,
|
|
85
|
+
parseErrors: 0,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
let pending = new Uint8Array(0);
|
|
89
|
+
|
|
90
|
+
function appendDecodedFrame(payload, context) {
|
|
91
|
+
if (appendFrame) {
|
|
92
|
+
appendFrame(payload, context);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
rows.appendRow({
|
|
96
|
+
schemaFileId: context.schemaFileId,
|
|
97
|
+
payload,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function pushBytes(data) {
|
|
102
|
+
const bytes = toUint8Array(data);
|
|
103
|
+
stats.bytesReceived += bytes.byteLength;
|
|
104
|
+
stats.chunksReceived += 1;
|
|
105
|
+
|
|
106
|
+
const combined =
|
|
107
|
+
pending.byteLength > 0 ? concatUint8Arrays([pending, bytes]) : bytes;
|
|
108
|
+
|
|
109
|
+
let offset = 0;
|
|
110
|
+
let appendedCount = 0;
|
|
111
|
+
|
|
112
|
+
while (offset + 4 <= combined.byteLength) {
|
|
113
|
+
const frameSize = readFrameSize(combined, offset);
|
|
114
|
+
if (frameSize <= 0) {
|
|
115
|
+
stats.parseErrors += 1;
|
|
116
|
+
throw new Error("Invalid FlatBuffer stream frame size.");
|
|
117
|
+
}
|
|
118
|
+
if (offset + 4 + frameSize > combined.byteLength) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const payload = combined.subarray(offset + 4, offset + 4 + frameSize);
|
|
123
|
+
const rawFileIdentifier = readFileIdentifier(payload);
|
|
124
|
+
const schemaFileId = normalizeSchemaFileId(rawFileIdentifier);
|
|
125
|
+
if (!schemaFileId) {
|
|
126
|
+
stats.parseErrors += 1;
|
|
127
|
+
throw new Error(
|
|
128
|
+
"FlatBuffer stream frame is missing a readable file identifier.",
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const context = {
|
|
133
|
+
rawFileIdentifier,
|
|
134
|
+
schemaFileId,
|
|
135
|
+
rows,
|
|
136
|
+
stats,
|
|
137
|
+
};
|
|
138
|
+
const routeHandler = resolveRouteHandler(
|
|
139
|
+
frameRouter,
|
|
140
|
+
rawFileIdentifier,
|
|
141
|
+
schemaFileId,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
stats.framesDecoded += 1;
|
|
145
|
+
if (routeHandler) {
|
|
146
|
+
const routeResult = routeHandler(payload, context);
|
|
147
|
+
if (routeResult !== false) {
|
|
148
|
+
stats.framesRouted += 1;
|
|
149
|
+
offset += 4 + frameSize;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
appendDecodedFrame(payload, context);
|
|
155
|
+
stats.framesAppended += 1;
|
|
156
|
+
appendedCount += 1;
|
|
157
|
+
offset += 4 + frameSize;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
pending =
|
|
161
|
+
offset < combined.byteLength
|
|
162
|
+
? combined.slice(offset)
|
|
163
|
+
: new Uint8Array(0);
|
|
164
|
+
|
|
165
|
+
return appendedCount;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function finish() {
|
|
169
|
+
if (pending.byteLength > 0) {
|
|
170
|
+
throw new Error("FlatBuffer stream ended with a partial frame.");
|
|
171
|
+
}
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
rows,
|
|
177
|
+
stats,
|
|
178
|
+
pushBytes,
|
|
179
|
+
finish,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -5,7 +5,6 @@ const RUNTIME_ROW_SCHEMA = `
|
|
|
5
5
|
table RuntimeHostRow {
|
|
6
6
|
schemaFileId: string;
|
|
7
7
|
rowId: ulong;
|
|
8
|
-
payloadJson: string;
|
|
9
8
|
}
|
|
10
9
|
`;
|
|
11
10
|
|
|
@@ -19,14 +18,85 @@ function clonePayload(payload) {
|
|
|
19
18
|
if (typeof structuredClone === "function") {
|
|
20
19
|
return structuredClone(payload);
|
|
21
20
|
}
|
|
21
|
+
return clonePayloadFallback(payload, new WeakMap());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function clonePayloadFallback(payload, seen) {
|
|
25
|
+
if (payload instanceof Date) {
|
|
26
|
+
return new Date(payload.getTime());
|
|
27
|
+
}
|
|
28
|
+
if (payload instanceof RegExp) {
|
|
29
|
+
return new RegExp(payload.source, payload.flags);
|
|
30
|
+
}
|
|
31
|
+
if (payload instanceof Map) {
|
|
32
|
+
if (seen.has(payload)) {
|
|
33
|
+
return seen.get(payload);
|
|
34
|
+
}
|
|
35
|
+
const cloned = new Map();
|
|
36
|
+
seen.set(payload, cloned);
|
|
37
|
+
for (const [key, value] of payload.entries()) {
|
|
38
|
+
cloned.set(clonePayloadFallback(key, seen), clonePayloadFallback(value, seen));
|
|
39
|
+
}
|
|
40
|
+
return cloned;
|
|
41
|
+
}
|
|
42
|
+
if (payload instanceof Set) {
|
|
43
|
+
if (seen.has(payload)) {
|
|
44
|
+
return seen.get(payload);
|
|
45
|
+
}
|
|
46
|
+
const cloned = new Set();
|
|
47
|
+
seen.set(payload, cloned);
|
|
48
|
+
for (const value of payload.values()) {
|
|
49
|
+
cloned.add(clonePayloadFallback(value, seen));
|
|
50
|
+
}
|
|
51
|
+
return cloned;
|
|
52
|
+
}
|
|
22
53
|
if (ArrayBuffer.isView(payload)) {
|
|
23
|
-
|
|
54
|
+
if (payload instanceof DataView) {
|
|
55
|
+
return new DataView(
|
|
56
|
+
payload.buffer.slice(
|
|
57
|
+
payload.byteOffset,
|
|
58
|
+
payload.byteOffset + payload.byteLength,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const clonedBuffer = payload.buffer.slice(
|
|
63
|
+
payload.byteOffset,
|
|
64
|
+
payload.byteOffset + payload.byteLength,
|
|
65
|
+
);
|
|
66
|
+
return new payload.constructor(clonedBuffer, 0, payload.length);
|
|
24
67
|
}
|
|
25
68
|
if (payload instanceof ArrayBuffer) {
|
|
26
69
|
return payload.slice(0);
|
|
27
70
|
}
|
|
71
|
+
if (Array.isArray(payload)) {
|
|
72
|
+
if (seen.has(payload)) {
|
|
73
|
+
return seen.get(payload);
|
|
74
|
+
}
|
|
75
|
+
const cloned = [];
|
|
76
|
+
seen.set(payload, cloned);
|
|
77
|
+
for (const value of payload) {
|
|
78
|
+
cloned.push(clonePayloadFallback(value, seen));
|
|
79
|
+
}
|
|
80
|
+
return cloned;
|
|
81
|
+
}
|
|
28
82
|
if (typeof payload === "object") {
|
|
29
|
-
|
|
83
|
+
if (seen.has(payload)) {
|
|
84
|
+
return seen.get(payload);
|
|
85
|
+
}
|
|
86
|
+
const prototype = Object.getPrototypeOf(payload);
|
|
87
|
+
const cloned = Object.create(prototype ?? Object.prototype);
|
|
88
|
+
seen.set(payload, cloned);
|
|
89
|
+
for (const key of Reflect.ownKeys(payload)) {
|
|
90
|
+
const descriptor = Object.getOwnPropertyDescriptor(payload, key);
|
|
91
|
+
if (!descriptor) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if ("value" in descriptor) {
|
|
95
|
+
descriptor.value = clonePayloadFallback(descriptor.value, seen);
|
|
96
|
+
}
|
|
97
|
+
Object.defineProperty(cloned, key, descriptor);
|
|
98
|
+
}
|
|
99
|
+
return cloned;
|
|
30
100
|
}
|
|
31
101
|
return payload;
|
|
32
102
|
}
|
|
@@ -54,48 +124,46 @@ function escapeSqlStringLiteral(value) {
|
|
|
54
124
|
return String(value).replaceAll("'", "''");
|
|
55
125
|
}
|
|
56
126
|
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
127
|
+
function encodeRuntimeRowMetadata({ schemaFileId, rowId }) {
|
|
128
|
+
const schemaBytes = encoder.encode(normalizeSchemaFileId(schemaFileId));
|
|
129
|
+
const encoded = new Uint8Array(4 + schemaBytes.byteLength + 8);
|
|
130
|
+
const view = new DataView(encoded.buffer);
|
|
131
|
+
view.setUint32(0, schemaBytes.byteLength, true);
|
|
132
|
+
encoded.set(schemaBytes, 4);
|
|
133
|
+
view.setBigUint64(4 + schemaBytes.byteLength, BigInt(rowId), true);
|
|
134
|
+
return encoded;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function decodeRuntimeRowMetadata(data) {
|
|
138
|
+
const bytes =
|
|
139
|
+
data instanceof Uint8Array
|
|
140
|
+
? data
|
|
141
|
+
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
142
|
+
if (bytes.byteLength < 12) {
|
|
143
|
+
throw new Error("Invalid runtime row metadata buffer.");
|
|
71
144
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
145
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
146
|
+
const schemaLength = view.getUint32(0, true);
|
|
147
|
+
const schemaStart = 4;
|
|
148
|
+
const schemaEnd = schemaStart + schemaLength;
|
|
149
|
+
const rowIdOffset = schemaEnd;
|
|
150
|
+
if (schemaEnd + 8 > bytes.byteLength) {
|
|
151
|
+
throw new Error("Invalid runtime row metadata layout.");
|
|
77
152
|
}
|
|
78
153
|
return {
|
|
79
|
-
|
|
80
|
-
|
|
154
|
+
schemaFileId: decoder.decode(bytes.subarray(schemaStart, schemaEnd)),
|
|
155
|
+
rowId: Number(view.getBigUint64(rowIdOffset, true)),
|
|
81
156
|
};
|
|
82
157
|
}
|
|
83
158
|
|
|
84
|
-
function
|
|
85
|
-
|
|
86
|
-
if (payload?.kind === "bytes") {
|
|
87
|
-
return Uint8Array.from(payload.bytes ?? []);
|
|
88
|
-
}
|
|
89
|
-
if (payload?.kind === "json") {
|
|
90
|
-
return clonePayload(payload.value);
|
|
91
|
-
}
|
|
92
|
-
return clonePayload(payload);
|
|
159
|
+
function buildRowKey(schemaFileId, rowId) {
|
|
160
|
+
return `${normalizeSchemaFileId(schemaFileId)}:${Number(rowId)}`;
|
|
93
161
|
}
|
|
94
162
|
|
|
95
163
|
function createRuntimeRowAccessor() {
|
|
96
164
|
const accessor = new DirectAccessor();
|
|
97
165
|
accessor.registerAccessor(RUNTIME_ROW_TABLE, (data, path) => {
|
|
98
|
-
const row =
|
|
166
|
+
const row = decodeRuntimeRowMetadata(data);
|
|
99
167
|
let current = row;
|
|
100
168
|
for (const segment of Array.isArray(path) ? path : []) {
|
|
101
169
|
if (current === null || current === undefined) {
|
|
@@ -106,13 +174,10 @@ function createRuntimeRowAccessor() {
|
|
|
106
174
|
return current ?? null;
|
|
107
175
|
});
|
|
108
176
|
accessor.registerBuilder(RUNTIME_ROW_TABLE, (fields) =>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
payloadJson: String(fields.payloadJson ?? "null"),
|
|
114
|
-
}),
|
|
115
|
-
),
|
|
177
|
+
encodeRuntimeRowMetadata({
|
|
178
|
+
schemaFileId: fields.schemaFileId,
|
|
179
|
+
rowId: Number(fields.rowId),
|
|
180
|
+
}),
|
|
116
181
|
);
|
|
117
182
|
return accessor;
|
|
118
183
|
}
|
|
@@ -127,18 +192,21 @@ function cloneQueryResult(result) {
|
|
|
127
192
|
};
|
|
128
193
|
}
|
|
129
194
|
|
|
130
|
-
function rowViewFromQueryRow(row) {
|
|
195
|
+
function rowViewFromQueryRow(row, payloadStore) {
|
|
196
|
+
const schemaFileId = String(row[0]);
|
|
197
|
+
const rowId = Number(row[1]);
|
|
131
198
|
return {
|
|
132
199
|
handle: {
|
|
133
|
-
schemaFileId
|
|
134
|
-
rowId
|
|
200
|
+
schemaFileId,
|
|
201
|
+
rowId,
|
|
135
202
|
},
|
|
136
|
-
payload:
|
|
203
|
+
payload: clonePayload(payloadStore.get(buildRowKey(schemaFileId, rowId))),
|
|
137
204
|
};
|
|
138
205
|
}
|
|
139
206
|
|
|
140
207
|
export function createFlatSqlRuntimeStore(options = {}) {
|
|
141
208
|
const accessor = options.accessor ?? createRuntimeRowAccessor();
|
|
209
|
+
const payloadStore = options.payloadStore ?? new Map();
|
|
142
210
|
const database =
|
|
143
211
|
options.database ??
|
|
144
212
|
FlatSQLDatabase.fromSchema(
|
|
@@ -168,8 +236,11 @@ export function createFlatSqlRuntimeStore(options = {}) {
|
|
|
168
236
|
database.insert(RUNTIME_ROW_TABLE, {
|
|
169
237
|
schemaFileId: normalizedSchemaFileId,
|
|
170
238
|
rowId: nextRowId,
|
|
171
|
-
payloadJson: JSON.stringify(serializePayload(payload)),
|
|
172
239
|
});
|
|
240
|
+
payloadStore.set(
|
|
241
|
+
buildRowKey(normalizedSchemaFileId, nextRowId),
|
|
242
|
+
clonePayload(payload),
|
|
243
|
+
);
|
|
173
244
|
return {
|
|
174
245
|
schemaFileId: normalizedSchemaFileId,
|
|
175
246
|
rowId: nextRowId,
|
|
@@ -193,12 +264,12 @@ export function createFlatSqlRuntimeStore(options = {}) {
|
|
|
193
264
|
const result =
|
|
194
265
|
normalizedSchemaFileId === null
|
|
195
266
|
? database.query(
|
|
196
|
-
`SELECT schemaFileId, rowId
|
|
267
|
+
`SELECT schemaFileId, rowId FROM ${RUNTIME_ROW_TABLE} ORDER BY schemaFileId, rowId`,
|
|
197
268
|
)
|
|
198
269
|
: database.query(
|
|
199
|
-
`SELECT schemaFileId, rowId
|
|
270
|
+
`SELECT schemaFileId, rowId FROM ${RUNTIME_ROW_TABLE} WHERE schemaFileId = '${escapeSqlStringLiteral(normalizedSchemaFileId)}' ORDER BY rowId`,
|
|
200
271
|
);
|
|
201
|
-
return (result.rows ?? []).map(rowViewFromQueryRow);
|
|
272
|
+
return (result.rows ?? []).map((row) => rowViewFromQueryRow(row, payloadStore));
|
|
202
273
|
}
|
|
203
274
|
|
|
204
275
|
function query(sql) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createFlatSqlRuntimeStore } from "./flatsqlRuntimeStore.js";
|
|
2
|
+
import { createFlatBufferStreamIngestor } from "./flatbufferStreamIngestor.js";
|
|
2
3
|
import { createRuntimeRegionStore } from "./runtimeRegionStore.js";
|
|
3
4
|
import { createModuleRegistry } from "./moduleRegistry.js";
|
|
4
5
|
|
|
@@ -15,6 +16,7 @@ export function createRuntimeHost(options = {}) {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export {
|
|
19
|
+
createFlatBufferStreamIngestor,
|
|
18
20
|
createFlatSqlRuntimeStore,
|
|
19
21
|
createModuleRegistry,
|
|
20
22
|
createRuntimeRegionStore,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# AGENTS
|
|
2
|
+
|
|
3
|
+
Apply the root and `src/AGENTS.md` files first.
|
|
4
|
+
|
|
5
|
+
## Area Ownership
|
|
6
|
+
|
|
7
|
+
This directory owns SDK test harnesses and runtime-facing helper surfaces used
|
|
8
|
+
by examples and downstream consumers: browser harnesses, generic process invoke
|
|
9
|
+
clients, runtime-matrix helpers, and resident-module FlatBuffer pumps.
|
|
10
|
+
|
|
11
|
+
## Harness Rules
|
|
12
|
+
|
|
13
|
+
- Keep browser harness behavior aligned with the same standalone artifacts that
|
|
14
|
+
WasmEdge runs.
|
|
15
|
+
- Prefer portable invoke envelopes and portable WASI behavior over runtime-
|
|
16
|
+
specific shortcuts.
|
|
17
|
+
- `createModuleFlatBufferStreamPump(...)` is the canonical no-JSON path for
|
|
18
|
+
feeding binary FlatBuffer streams into a resident module instance.
|
|
19
|
+
- Avoid hiding stateful behavior inside one-off demos; if a harness contract is
|
|
20
|
+
real, test it here.
|
|
21
|
+
|
|
22
|
+
## Key Files
|
|
23
|
+
|
|
24
|
+
- `browserModuleHarness.js`
|
|
25
|
+
- `moduleFlatbufferStreamPump.js`
|
|
26
|
+
- `processInvoke.js`
|
|
27
|
+
|
|
28
|
+
## Verification
|
|
29
|
+
|
|
30
|
+
- `node --test test/browser-harness.test.js`
|
|
31
|
+
- `node --test test/isomorphic-loader.test.js`
|
|
32
|
+
- `npm run test:module-stream`
|
|
33
|
+
- `node --test test/process-invoke.test.js`
|
package/src/testing/index.js
CHANGED
|
@@ -26,6 +26,7 @@ export {
|
|
|
26
26
|
createModuleHarness,
|
|
27
27
|
resolveModuleHarnessLaunchPlan,
|
|
28
28
|
} from "./moduleHarness.js";
|
|
29
|
+
export { createModuleFlatBufferStreamPump } from "./moduleFlatbufferStreamPump.js";
|
|
29
30
|
|
|
30
31
|
const CapabilitySurfaceMatrix = Object.freeze({
|
|
31
32
|
logging: Object.freeze({
|