@pretable/stream-adapter 0.9.0 → 0.11.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/dist/index.cjs +393 -359
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +54 -42
- package/dist/index.d.cts.map +1 -0
- package/dist/{index.d.ts → index.d.mts} +54 -42
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +392 -357
- package/dist/index.mjs.map +1 -0
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -1,380 +1,414 @@
|
|
|
1
|
-
'
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let _cacheplane_json_stream = require("@cacheplane/json-stream");
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
//#region src/create-batcher.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create a `requestAnimationFrame`-batched mutator that coalesces
|
|
7
|
+
* `add` / `update` / `remove` calls into a single `applyTransaction` per
|
|
8
|
+
* frame. Use this when driving a row model from a stream that emits faster
|
|
9
|
+
* than the browser can render.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const batcher = createBatcher(rowModel);
|
|
14
|
+
* batcher.add([{ id: "1", name: "Ada" }]);
|
|
15
|
+
* batcher.update([{ id: "1", changes: { age: 36 } }]);
|
|
16
|
+
* batcher.flush(); // optional — RAF will flush automatically
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
6
21
|
function createBatcher(rowModel) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (disposed) return;
|
|
118
|
-
disposed = true;
|
|
119
|
-
if (rafId !== null) {
|
|
120
|
-
cancelAnimationFrame(rafId);
|
|
121
|
-
rafId = null;
|
|
122
|
-
}
|
|
123
|
-
addBuffer = [];
|
|
124
|
-
updateBuffer = [];
|
|
125
|
-
removeBuffer = [];
|
|
126
|
-
errorListeners.clear();
|
|
127
|
-
}
|
|
128
|
-
};
|
|
22
|
+
let addBuffer = [];
|
|
23
|
+
let updateBuffer = [];
|
|
24
|
+
let removeBuffer = [];
|
|
25
|
+
let rafId = null;
|
|
26
|
+
let disposed = false;
|
|
27
|
+
let rejectError;
|
|
28
|
+
const errorListeners = /* @__PURE__ */ new Set();
|
|
29
|
+
let failed = false;
|
|
30
|
+
let failure;
|
|
31
|
+
const error = new Promise((_resolve, reject) => {
|
|
32
|
+
rejectError = reject;
|
|
33
|
+
});
|
|
34
|
+
error.catch(() => void 0);
|
|
35
|
+
function fail(error) {
|
|
36
|
+
if (disposed) return;
|
|
37
|
+
disposed = true;
|
|
38
|
+
failed = true;
|
|
39
|
+
failure = error;
|
|
40
|
+
if (rafId !== null) {
|
|
41
|
+
cancelAnimationFrame(rafId);
|
|
42
|
+
rafId = null;
|
|
43
|
+
}
|
|
44
|
+
addBuffer = [];
|
|
45
|
+
updateBuffer = [];
|
|
46
|
+
removeBuffer = [];
|
|
47
|
+
const listeners = [...errorListeners];
|
|
48
|
+
errorListeners.clear();
|
|
49
|
+
for (const listener of listeners) try {
|
|
50
|
+
listener(error);
|
|
51
|
+
} catch (_unused) {}
|
|
52
|
+
rejectError(error);
|
|
53
|
+
}
|
|
54
|
+
function scheduleFlush() {
|
|
55
|
+
if (rafId !== null || disposed) return;
|
|
56
|
+
rafId = requestAnimationFrame(() => {
|
|
57
|
+
rafId = null;
|
|
58
|
+
if (disposed) return;
|
|
59
|
+
try {
|
|
60
|
+
applyBuffered();
|
|
61
|
+
} catch (error) {
|
|
62
|
+
fail(error);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function applyBuffered() {
|
|
67
|
+
if (addBuffer.length === 0 && updateBuffer.length === 0 && removeBuffer.length === 0) return;
|
|
68
|
+
const bufferedAdds = addBuffer;
|
|
69
|
+
const bufferedUpdates = updateBuffer;
|
|
70
|
+
const bufferedRemovals = removeBuffer;
|
|
71
|
+
addBuffer = [];
|
|
72
|
+
updateBuffer = [];
|
|
73
|
+
removeBuffer = [];
|
|
74
|
+
const transaction = {};
|
|
75
|
+
if (bufferedAdds.length > 0) transaction.add = bufferedAdds.map((row) => ({ ...row }));
|
|
76
|
+
if (bufferedUpdates.length > 0) transaction.update = bufferedUpdates.map(({ id, changes }) => ({
|
|
77
|
+
id,
|
|
78
|
+
changes: { ...changes }
|
|
79
|
+
}));
|
|
80
|
+
if (bufferedRemovals.length > 0) transaction.remove = [...bufferedRemovals];
|
|
81
|
+
rowModel.applyTransaction(transaction);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
error,
|
|
85
|
+
subscribeError(listener) {
|
|
86
|
+
if (failed) {
|
|
87
|
+
try {
|
|
88
|
+
listener(failure);
|
|
89
|
+
} catch (_unused2) {}
|
|
90
|
+
return () => void 0;
|
|
91
|
+
}
|
|
92
|
+
if (disposed) return () => void 0;
|
|
93
|
+
errorListeners.add(listener);
|
|
94
|
+
return () => errorListeners.delete(listener);
|
|
95
|
+
},
|
|
96
|
+
add(rows) {
|
|
97
|
+
if (disposed) return;
|
|
98
|
+
addBuffer.push(...rows);
|
|
99
|
+
scheduleFlush();
|
|
100
|
+
},
|
|
101
|
+
update(patches) {
|
|
102
|
+
if (disposed) return;
|
|
103
|
+
updateBuffer.push(...patches);
|
|
104
|
+
scheduleFlush();
|
|
105
|
+
},
|
|
106
|
+
remove(ids) {
|
|
107
|
+
if (disposed) return;
|
|
108
|
+
removeBuffer.push(...ids);
|
|
109
|
+
scheduleFlush();
|
|
110
|
+
},
|
|
111
|
+
flush() {
|
|
112
|
+
if (disposed) return;
|
|
113
|
+
if (rafId !== null) {
|
|
114
|
+
cancelAnimationFrame(rafId);
|
|
115
|
+
rafId = null;
|
|
116
|
+
}
|
|
117
|
+
applyBuffered();
|
|
118
|
+
},
|
|
119
|
+
dispose() {
|
|
120
|
+
if (disposed) return;
|
|
121
|
+
disposed = true;
|
|
122
|
+
if (rafId !== null) {
|
|
123
|
+
cancelAnimationFrame(rafId);
|
|
124
|
+
rafId = null;
|
|
125
|
+
}
|
|
126
|
+
addBuffer = [];
|
|
127
|
+
updateBuffer = [];
|
|
128
|
+
removeBuffer = [];
|
|
129
|
+
errorListeners.clear();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/connect-element-stream.ts
|
|
136
|
+
/**
|
|
137
|
+
* Drive a row model from an `AsyncIterable<TRow>`. Each yielded row is added
|
|
138
|
+
* via a {@link createBatcher | RAF batcher}; the returned
|
|
139
|
+
* {@link StreamConnection} resolves `done` when the stream ends and
|
|
140
|
+
* supports `dispose()` for early cancellation.
|
|
141
|
+
*
|
|
142
|
+
* Pair with {@link parseElementStream} to turn a raw UTF-8 string stream
|
|
143
|
+
* (e.g., from `fetch().body`) into a row stream end-to-end.
|
|
144
|
+
*
|
|
145
|
+
* @public
|
|
146
|
+
*/
|
|
132
147
|
function connectElementStream(rowModel, stream) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
};
|
|
148
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
149
|
+
const batcher = createBatcher(rowModel);
|
|
150
|
+
let disposed = false;
|
|
151
|
+
let sourceClosed = false;
|
|
152
|
+
let resolveDone;
|
|
153
|
+
let rejectDone;
|
|
154
|
+
const done = new Promise((resolve, reject) => {
|
|
155
|
+
resolveDone = resolve;
|
|
156
|
+
rejectDone = reject;
|
|
157
|
+
});
|
|
158
|
+
done.catch(() => void 0);
|
|
159
|
+
const closeSource = () => {
|
|
160
|
+
if (sourceClosed) return;
|
|
161
|
+
sourceClosed = true;
|
|
162
|
+
try {
|
|
163
|
+
var _iterator$return;
|
|
164
|
+
const closing = (_iterator$return = iterator.return) === null || _iterator$return === void 0 ? void 0 : _iterator$return.call(iterator);
|
|
165
|
+
if (closing !== void 0) Promise.resolve(closing).catch(() => void 0);
|
|
166
|
+
} catch (_unused) {}
|
|
167
|
+
};
|
|
168
|
+
let settled = false;
|
|
169
|
+
const settle = (failure, flush = true, close = failure !== void 0) => {
|
|
170
|
+
if (settled) return;
|
|
171
|
+
settled = true;
|
|
172
|
+
disposed = true;
|
|
173
|
+
if (close) closeSource();
|
|
174
|
+
let finalFailure = failure;
|
|
175
|
+
if (flush) try {
|
|
176
|
+
batcher.flush();
|
|
177
|
+
} catch (error) {
|
|
178
|
+
var _finalFailure;
|
|
179
|
+
(_finalFailure = finalFailure) !== null && _finalFailure !== void 0 || (finalFailure = { error });
|
|
180
|
+
}
|
|
181
|
+
batcher.dispose();
|
|
182
|
+
if (finalFailure === void 0) resolveDone();
|
|
183
|
+
else rejectDone(finalFailure.error);
|
|
184
|
+
};
|
|
185
|
+
batcher.subscribeError((error) => {
|
|
186
|
+
settle({ error }, false, true);
|
|
187
|
+
});
|
|
188
|
+
(async () => {
|
|
189
|
+
try {
|
|
190
|
+
while (!disposed) {
|
|
191
|
+
const result = await iterator.next();
|
|
192
|
+
if (disposed) return;
|
|
193
|
+
if (result.done) {
|
|
194
|
+
settle();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
batcher.add([result.value]);
|
|
198
|
+
}
|
|
199
|
+
} catch (err) {
|
|
200
|
+
settle({ error: err }, true, true);
|
|
201
|
+
}
|
|
202
|
+
})().catch((error) => settle({ error }));
|
|
203
|
+
return {
|
|
204
|
+
done,
|
|
205
|
+
dispose() {
|
|
206
|
+
if (disposed) return;
|
|
207
|
+
settle(void 0, true, true);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
197
210
|
}
|
|
198
211
|
|
|
199
|
-
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/connect-partial-stream.ts
|
|
200
214
|
function sameValueZero(left, right) {
|
|
201
|
-
|
|
215
|
+
return left === right || typeof left === "number" && typeof right === "number" && Number.isNaN(left) && Number.isNaN(right);
|
|
202
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Drive a row model from an `AsyncIterable<Partial<TRow>>`. Every yielded
|
|
219
|
+
* partial updates the fixed `options.rowId` via a RAF-batched
|
|
220
|
+
* `{ id, changes }` transaction. A missing target is reported instead of
|
|
221
|
+
* fabricating a row; provide `createRow` when the stream is allowed to add one.
|
|
222
|
+
*
|
|
223
|
+
* Pair with {@link parsePartialStream} for end-to-end partial-update
|
|
224
|
+
* streaming over UTF-8 strings.
|
|
225
|
+
*
|
|
226
|
+
* @public
|
|
227
|
+
*/
|
|
203
228
|
function connectPartialStream(rowModel, stream, options) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
};
|
|
229
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
230
|
+
const batcher = createBatcher({ applyTransaction(transaction) {
|
|
231
|
+
const result = rowModel.applyTransaction(transaction);
|
|
232
|
+
if (result === void 0 || result.issues === void 0) return result;
|
|
233
|
+
let targetMissing = false;
|
|
234
|
+
for (const issue of result.issues) {
|
|
235
|
+
var _options$onIssue;
|
|
236
|
+
if (issue.code !== "unknown-update-id" || issue.rowId === void 0 || !sameValueZero(issue.rowId, options.rowId)) continue;
|
|
237
|
+
targetMissing = true;
|
|
238
|
+
(_options$onIssue = options.onIssue) === null || _options$onIssue === void 0 || _options$onIssue.call(options, {
|
|
239
|
+
code: "unknown-update-id",
|
|
240
|
+
rowId: options.rowId
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (targetMissing && options.createRow !== void 0) {
|
|
244
|
+
var _transaction$update;
|
|
245
|
+
const updates = (_transaction$update = transaction.update) !== null && _transaction$update !== void 0 ? _transaction$update : [];
|
|
246
|
+
const combinedChanges = {};
|
|
247
|
+
let hasTargetUpdate = false;
|
|
248
|
+
for (const update of updates) {
|
|
249
|
+
if (!sameValueZero(update.id, options.rowId)) continue;
|
|
250
|
+
Object.assign(combinedChanges, update.changes);
|
|
251
|
+
hasTargetUpdate = true;
|
|
252
|
+
}
|
|
253
|
+
if (hasTargetUpdate) {
|
|
254
|
+
const row = options.createRow(combinedChanges, options.rowId);
|
|
255
|
+
rowModel.applyTransaction({ add: [row] });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return result;
|
|
259
|
+
} });
|
|
260
|
+
let disposed = false;
|
|
261
|
+
let sourceClosed = false;
|
|
262
|
+
let resolveDone;
|
|
263
|
+
let rejectDone;
|
|
264
|
+
const done = new Promise((resolve, reject) => {
|
|
265
|
+
resolveDone = resolve;
|
|
266
|
+
rejectDone = reject;
|
|
267
|
+
});
|
|
268
|
+
done.catch(() => void 0);
|
|
269
|
+
const closeSource = () => {
|
|
270
|
+
if (sourceClosed) return;
|
|
271
|
+
sourceClosed = true;
|
|
272
|
+
try {
|
|
273
|
+
var _iterator$return;
|
|
274
|
+
const closing = (_iterator$return = iterator.return) === null || _iterator$return === void 0 ? void 0 : _iterator$return.call(iterator);
|
|
275
|
+
if (closing !== void 0) Promise.resolve(closing).catch(() => void 0);
|
|
276
|
+
} catch (_unused) {}
|
|
277
|
+
};
|
|
278
|
+
let settled = false;
|
|
279
|
+
const settle = (failure, flush = true, close = failure !== void 0) => {
|
|
280
|
+
if (settled) return;
|
|
281
|
+
settled = true;
|
|
282
|
+
disposed = true;
|
|
283
|
+
if (close) closeSource();
|
|
284
|
+
let finalFailure = failure;
|
|
285
|
+
if (flush) try {
|
|
286
|
+
batcher.flush();
|
|
287
|
+
} catch (error) {
|
|
288
|
+
var _finalFailure;
|
|
289
|
+
(_finalFailure = finalFailure) !== null && _finalFailure !== void 0 || (finalFailure = { error });
|
|
290
|
+
}
|
|
291
|
+
batcher.dispose();
|
|
292
|
+
if (finalFailure === void 0) resolveDone();
|
|
293
|
+
else rejectDone(finalFailure.error);
|
|
294
|
+
};
|
|
295
|
+
batcher.subscribeError((error) => {
|
|
296
|
+
settle({ error }, false, true);
|
|
297
|
+
});
|
|
298
|
+
(async () => {
|
|
299
|
+
try {
|
|
300
|
+
while (!disposed) {
|
|
301
|
+
const result = await iterator.next();
|
|
302
|
+
if (disposed) return;
|
|
303
|
+
if (result.done) {
|
|
304
|
+
settle();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
batcher.update([{
|
|
308
|
+
id: options.rowId,
|
|
309
|
+
changes: result.value
|
|
310
|
+
}]);
|
|
311
|
+
}
|
|
312
|
+
} catch (err) {
|
|
313
|
+
settle({ error: err }, true, true);
|
|
314
|
+
}
|
|
315
|
+
})().catch((error) => settle({ error }));
|
|
316
|
+
return {
|
|
317
|
+
done,
|
|
318
|
+
dispose() {
|
|
319
|
+
if (disposed) return;
|
|
320
|
+
settle(void 0, true, true);
|
|
321
|
+
}
|
|
322
|
+
};
|
|
300
323
|
}
|
|
324
|
+
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region src/parse-element-stream.ts
|
|
327
|
+
/**
|
|
328
|
+
* Parse a UTF-8 string stream into an `AsyncIterable<TRow>`. Built on
|
|
329
|
+
* `@cacheplane/json-stream`'s incremental JSON parser; emits each
|
|
330
|
+
* complete top-level array element as a typed row.
|
|
331
|
+
*
|
|
332
|
+
* Pair with {@link connectElementStream} for end-to-end element-stream
|
|
333
|
+
* → grid wiring.
|
|
334
|
+
*
|
|
335
|
+
* @public
|
|
336
|
+
*/
|
|
301
337
|
async function* parseElementStream(stream) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
throw new Error(state.error.message);
|
|
329
|
-
}
|
|
330
|
-
if (state.rootId !== null) {
|
|
331
|
-
const root = state.nodes[state.rootId];
|
|
332
|
-
if (jsonStream.isArrayNode(root)) {
|
|
333
|
-
while (yieldedCount < root.children.length) {
|
|
334
|
-
const childNode = state.nodes[root.children[yieldedCount]];
|
|
335
|
-
if (jsonStream.isComplete(childNode) && childNode.value !== void 0) {
|
|
336
|
-
yield childNode.value;
|
|
337
|
-
}
|
|
338
|
-
yieldedCount++;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
338
|
+
let state = (0, _cacheplane_json_stream.create)();
|
|
339
|
+
let yieldedCount = 0;
|
|
340
|
+
for await (const chunk of stream) {
|
|
341
|
+
state = (0, _cacheplane_json_stream.push)(state, chunk);
|
|
342
|
+
if (state.error) throw new Error(state.error.message);
|
|
343
|
+
if (state.rootId !== null) {
|
|
344
|
+
const root = state.nodes[state.rootId];
|
|
345
|
+
if (!(0, _cacheplane_json_stream.isArrayNode)(root)) throw new Error(`parseElementStream expects root to be an array, got "${root.kind}"`);
|
|
346
|
+
while (yieldedCount < root.children.length) {
|
|
347
|
+
const childNode = state.nodes[root.children[yieldedCount]];
|
|
348
|
+
if (!(0, _cacheplane_json_stream.isComplete)(childNode)) break;
|
|
349
|
+
if (childNode.value !== void 0) yield childNode.value;
|
|
350
|
+
yieldedCount++;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
state = (0, _cacheplane_json_stream.finish)(state);
|
|
355
|
+
if (state.error) throw new Error(state.error.message);
|
|
356
|
+
if (state.rootId !== null) {
|
|
357
|
+
const root = state.nodes[state.rootId];
|
|
358
|
+
if ((0, _cacheplane_json_stream.isArrayNode)(root)) while (yieldedCount < root.children.length) {
|
|
359
|
+
const childNode = state.nodes[root.children[yieldedCount]];
|
|
360
|
+
if ((0, _cacheplane_json_stream.isComplete)(childNode) && childNode.value !== void 0) yield childNode.value;
|
|
361
|
+
yieldedCount++;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
342
364
|
}
|
|
365
|
+
|
|
366
|
+
//#endregion
|
|
367
|
+
//#region src/parse-partial-stream.ts
|
|
368
|
+
/**
|
|
369
|
+
* Parse a UTF-8 string stream into an `AsyncIterable<Partial<TRow>>`.
|
|
370
|
+
*
|
|
371
|
+
* The root must be a single JSON **object**, not an array — a non-object root
|
|
372
|
+
* throws. Each yielded value is the cumulative snapshot of that object as more
|
|
373
|
+
* keys resolve, not a delta, so the last value yielded is the complete row.
|
|
374
|
+
* Useful when an LLM is streaming partial JSON for one row and you want
|
|
375
|
+
* field-by-field updates instead of waiting for the object to close.
|
|
376
|
+
*
|
|
377
|
+
* For a stream of many complete rows, use {@link parseElementStream}, which
|
|
378
|
+
* does take a top-level array.
|
|
379
|
+
*
|
|
380
|
+
* Pair with {@link connectPartialStream} for end-to-end partial-stream
|
|
381
|
+
* → grid wiring.
|
|
382
|
+
*
|
|
383
|
+
* @public
|
|
384
|
+
*/
|
|
343
385
|
async function* parsePartialStream(stream) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
state = jsonStream.finish(state);
|
|
365
|
-
if (state.error) {
|
|
366
|
-
throw new Error(state.error.message);
|
|
367
|
-
}
|
|
368
|
-
if (state.rootId !== null) {
|
|
369
|
-
const root = state.nodes[state.rootId];
|
|
370
|
-
if (jsonStream.isObjectNode(root) && root.value !== void 0 && root.value !== lastValue && Object.keys(root.value).length > 0) {
|
|
371
|
-
yield root.value;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
386
|
+
let state = (0, _cacheplane_json_stream.create)();
|
|
387
|
+
let lastValue;
|
|
388
|
+
for await (const chunk of stream) {
|
|
389
|
+
state = (0, _cacheplane_json_stream.push)(state, chunk);
|
|
390
|
+
if (state.error) throw new Error(state.error.message);
|
|
391
|
+
if (state.rootId !== null) {
|
|
392
|
+
const root = state.nodes[state.rootId];
|
|
393
|
+
if (!(0, _cacheplane_json_stream.isObjectNode)(root)) throw new Error(`parsePartialStream expects root to be an object, got "${root.kind}"`);
|
|
394
|
+
if (root.value !== void 0 && root.value !== lastValue && Object.keys(root.value).length > 0) {
|
|
395
|
+
lastValue = root.value;
|
|
396
|
+
yield root.value;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
state = (0, _cacheplane_json_stream.finish)(state);
|
|
401
|
+
if (state.error) throw new Error(state.error.message);
|
|
402
|
+
if (state.rootId !== null) {
|
|
403
|
+
const root = state.nodes[state.rootId];
|
|
404
|
+
if ((0, _cacheplane_json_stream.isObjectNode)(root) && root.value !== void 0 && root.value !== lastValue && Object.keys(root.value).length > 0) yield root.value;
|
|
405
|
+
}
|
|
374
406
|
}
|
|
375
407
|
|
|
408
|
+
//#endregion
|
|
376
409
|
exports.connectElementStream = connectElementStream;
|
|
377
410
|
exports.connectPartialStream = connectPartialStream;
|
|
378
411
|
exports.createBatcher = createBatcher;
|
|
379
412
|
exports.parseElementStream = parseElementStream;
|
|
380
413
|
exports.parsePartialStream = parsePartialStream;
|
|
414
|
+
//# sourceMappingURL=index.cjs.map
|