streamfold 0.1.7 → 0.1.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "streamfold",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Protocol-neutral incremental state for structured AI streams",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.d.ts CHANGED
@@ -240,6 +240,9 @@ export function createStructuredStreamPool<Id = string>(
240
240
  options?: StructuredStreamPoolOptions,
241
241
  ): StructuredStreamPool<Id>;
242
242
 
243
+ /** Compile and cache the embedded WebAssembly module before creating scanners. */
244
+ export function prepareStreamfold(): Promise<void>;
245
+
243
246
  export const STREAMFOLD_ENGINE: "rust-wasm";
244
247
  export const DEFAULT_STREAM_LIMITS: Readonly<
245
248
  Required<
package/src/index.js CHANGED
@@ -9,6 +9,7 @@ import { applyImmutableChanges, freezeJson } from "./internal/snapshots.js";
9
9
  import { annotateError, streamError } from "./internal/errors.js";
10
10
 
11
11
  export { isStructuredStreamError } from "./internal/errors.js";
12
+ export { prepareWasm as prepareStreamfold } from "./internal/wasm-runtime.js";
12
13
  export { defineAdapter } from "./adapter.js";
13
14
  export { readStructured } from "./read-structured.js";
14
15
 
@@ -17,9 +17,11 @@ const PATCH_COMPLETE = 8;
17
17
 
18
18
  const encoder = new TextEncoder();
19
19
  let exports;
20
+ let compiledModule;
21
+ let compiling;
20
22
 
21
- const decodeBase64 = (base64) => {
22
- const binary = globalThis.atob(base64);
23
+ const decodeWasmBytes = () => {
24
+ const binary = globalThis.atob(wasmBinaryBase64);
23
25
  const bytes = new Uint8Array(binary.length);
24
26
  for (let index = 0; index < binary.length; index++) {
25
27
  bytes[index] = binary.charCodeAt(index);
@@ -32,11 +34,39 @@ const getExports = () => {
32
34
  if (typeof WebAssembly !== "object") {
33
35
  throw new Error("Streamfold requires WebAssembly support");
34
36
  }
35
- const module = new WebAssembly.Module(decodeBase64(wasmBinaryBase64));
37
+ const module =
38
+ compiledModule ?? new WebAssembly.Module(decodeWasmBytes());
36
39
  exports = new WebAssembly.Instance(module, {}).exports;
37
40
  return exports;
38
41
  };
39
42
 
43
+ export const prepareWasm = () => {
44
+ if (exports !== undefined || compiledModule !== undefined)
45
+ return Promise.resolve();
46
+ if (compiling !== undefined) return compiling;
47
+ if (
48
+ typeof WebAssembly !== "object" ||
49
+ typeof WebAssembly.compile !== "function"
50
+ ) {
51
+ return Promise.reject(new Error("Streamfold requires WebAssembly support"));
52
+ }
53
+ try {
54
+ compiling = WebAssembly.compile(decodeWasmBytes()).then(
55
+ (module) => {
56
+ compiledModule = module;
57
+ compiling = undefined;
58
+ },
59
+ (error) => {
60
+ compiling = undefined;
61
+ throw error;
62
+ },
63
+ );
64
+ } catch (error) {
65
+ return Promise.reject(error);
66
+ }
67
+ return compiling;
68
+ };
69
+
40
70
  const describeParserError = ({ wasm, handle, maxBytes, maxDepth }, code) => {
41
71
  const offset = wasm.streamfold_parser_error_offset(handle) >>> 0;
42
72
  const byte = wasm.streamfold_parser_error_byte(handle);
@@ -207,14 +237,16 @@ const pushChunk = (parser, chunk) => {
207
237
  );
208
238
  }
209
239
  const { wasm, handle } = parser;
210
- const capacity = chunk.length * 3;
240
+ const remaining = parser.maxBytes - (wasm.streamfold_parser_bytes_seen(handle) >>> 0);
241
+ if (chunk.length > remaining) throw parserError(parser, 7);
242
+ const capacity = Math.min(chunk.length * 3, remaining);
211
243
  const pointer = wasm.streamfold_parser_input(handle, capacity);
212
244
  let length = 0;
213
245
  if (capacity > 0) {
214
246
  const input = new Uint8Array(wasm.memory.buffer, pointer, capacity);
215
247
  const result = encoder.encodeInto(chunk, input);
216
248
  if (result.read !== chunk.length) {
217
- throw new Error("Unable to encode the complete stream fragment");
249
+ throw parserError(parser, 7);
218
250
  }
219
251
  length = result.written;
220
252
  }