@selvajs/compute 3.1.0-beta.1 → 3.1.0-beta.11

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-7XMD5YXP.cjs +62 -0
  3. package/dist/chunk-7XMD5YXP.cjs.map +1 -0
  4. package/dist/chunk-C7P43VZF.js +2 -0
  5. package/dist/chunk-C7P43VZF.js.map +1 -0
  6. package/dist/chunk-CUQQ3ZBV.cjs +4 -0
  7. package/dist/chunk-CUQQ3ZBV.cjs.map +1 -0
  8. package/dist/chunk-PX2YTSHJ.js +62 -0
  9. package/dist/chunk-PX2YTSHJ.js.map +1 -0
  10. package/dist/chunk-QZECCPT3.cjs +2 -0
  11. package/dist/chunk-QZECCPT3.cjs.map +1 -0
  12. package/dist/chunk-WPB2LKCD.js +4 -0
  13. package/dist/chunk-WPB2LKCD.js.map +1 -0
  14. package/dist/core.cjs +1 -1
  15. package/dist/core.cjs.map +1 -1
  16. package/dist/core.d.cts +40 -3
  17. package/dist/core.d.ts +40 -3
  18. package/dist/core.js +1 -1
  19. package/dist/grasshopper.cjs +1 -1
  20. package/dist/grasshopper.cjs.map +1 -1
  21. package/dist/grasshopper.d.cts +222 -32
  22. package/dist/grasshopper.d.ts +222 -32
  23. package/dist/grasshopper.js +1 -1
  24. package/dist/{handle-files-9pkEgDIp.d.ts → handle-files-BISo_wob.d.cts} +51 -67
  25. package/dist/{handle-files-9pkEgDIp.d.cts → handle-files-BISo_wob.d.ts} +51 -67
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +4 -4
  29. package/dist/index.d.ts +4 -4
  30. package/dist/index.js +1 -1
  31. package/dist/types-BGhtYxZ-.d.cts +45 -0
  32. package/dist/types-BGhtYxZ-.d.ts +45 -0
  33. package/dist/{types-DK2-skCK.d.cts → types-C8XWc4Ab.d.cts} +92 -67
  34. package/dist/{types-jb_K_a0s.d.ts → types-Dtok-mVq.d.ts} +92 -67
  35. package/dist/visualization-4RSUYQG2.cjs +2 -0
  36. package/dist/visualization-4RSUYQG2.cjs.map +1 -0
  37. package/dist/visualization-MOYO6MDN.js +2 -0
  38. package/dist/visualization.cjs +1 -1
  39. package/dist/visualization.cjs.map +1 -1
  40. package/dist/visualization.d.cts +200 -37
  41. package/dist/visualization.d.ts +200 -37
  42. package/dist/visualization.js +1 -1
  43. package/package.json +3 -3
  44. package/dist/chunk-C2HJB4MH.js +0 -55
  45. package/dist/chunk-C2HJB4MH.js.map +0 -1
  46. package/dist/chunk-DRG5SLIP.cjs +0 -4
  47. package/dist/chunk-DRG5SLIP.cjs.map +0 -1
  48. package/dist/chunk-ESPPM542.js +0 -2
  49. package/dist/chunk-ESPPM542.js.map +0 -1
  50. package/dist/chunk-J3MFKB33.js +0 -4
  51. package/dist/chunk-J3MFKB33.js.map +0 -1
  52. package/dist/chunk-LP7LO5PR.cjs +0 -2
  53. package/dist/chunk-LP7LO5PR.cjs.map +0 -1
  54. package/dist/chunk-QZ573TYU.cjs +0 -55
  55. package/dist/chunk-QZ573TYU.cjs.map +0 -1
  56. package/dist/types-ChF690kY.d.cts +0 -88
  57. package/dist/types-ChF690kY.d.ts +0 -88
  58. package/dist/visualization-3E3Q76VG.cjs +0 -2
  59. package/dist/visualization-3E3Q76VG.cjs.map +0 -1
  60. package/dist/visualization-XBMHHG6L.js +0 -2
  61. /package/dist/{visualization-XBMHHG6L.js.map → visualization-MOYO6MDN.js.map} +0 -0
@@ -1,12 +1,56 @@
1
- import { R as RhinoComputeError, C as ComputeServerStats, F as FileBaseInfo } from './handle-files-9pkEgDIp.js';
2
- export { b as FileData, P as ProcessedFile, d as downloadFileData, e as extractFilesFromComputeResponse } from './handle-files-9pkEgDIp.js';
3
- import { R as RetryPolicy, C as ComputeConfig } from './types-ChF690kY.js';
4
- export { a as RhinoModelUnit } from './types-ChF690kY.js';
5
- import { f as GrasshopperComputeResponse, a as DataTree, e as GrasshopperComputeConfig, g as GrasshopperParsedIO, h as GrasshopperParsedIORaw, M as MeshExtractionOptions, k as InputParamSchema, j as InputParam, b as DataTreeDefault, c as DataTreePath } from './types-jb_K_a0s.js';
6
- export { B as BooleanInputType, D as DataItem, d as DefaultValue, F as FileInputType, G as GeometryInputType, i as GrasshopperRequestSchema, I as InnerTreeData, N as NumericInputType, O as OutputParamSchema, l as OutputType, T as TextInputType, V as ValueListInputType } from './types-jb_K_a0s.js';
1
+ import { R as RhinoComputeError, C as ComputeServerStats, F as FileBaseInfo } from './handle-files-BISo_wob.js';
2
+ export { b as FileData, P as ProcessedFile, d as downloadFileData, e as extractFilesFromComputeResponse } from './handle-files-BISo_wob.js';
3
+ import { R as RetryPolicy, C as ComputeConfig } from './types-BGhtYxZ-.js';
4
+ export { a as RhinoModelUnit } from './types-BGhtYxZ-.js';
5
+ import { f as GrasshopperComputeResponse, a as DataTree, e as GrasshopperComputeConfig, g as GrasshopperParsedIO, h as GrasshopperParsedIORaw, m as MeshExtractionOptions, k as InputParamSchema, j as InputParam, b as DataTreeDefault, c as DataTreePath } from './types-Dtok-mVq.js';
6
+ export { B as BooleanInputType, D as DataItem, d as DefaultValue, F as FileInputType, G as GeometryInputType, i as GrasshopperRequestSchema, I as InnerTreeData, N as NumericInputType, O as OutputParamSchema, l as OutputType, T as TextInputType, V as ValueListInputType } from './types-Dtok-mVq.js';
7
7
  import * as THREE from 'three';
8
8
  import 'rhino3dm';
9
9
 
10
+ /**
11
+ * By-reference definition form for solves.
12
+ *
13
+ * Lets a caller that already knows a definition's identity (e.g. a stored
14
+ * version's UUID) schedule solves without materializing the multi-MB bytes:
15
+ * cache keys and the server-pointer map are derived from `key` alone, and
16
+ * `load()` is only called when an upload is genuinely unavoidable (first solve
17
+ * of a definition, or a server-side pointer miss).
18
+ */
19
+ /**
20
+ * A definition identified by a stable key, with bytes materialized on demand.
21
+ *
22
+ * **Immutability contract — read this before constructing one.** `key` must
23
+ * identify IMMUTABLE bytes: every `load()` for a given `key` must return the
24
+ * same content, forever. All caching (the scheduler's result cache, the
25
+ * server-pointer map, and any durable cache built on these keys) trusts the
26
+ * key as the definition's identity WITHOUT looking at the bytes. If two
27
+ * different byte contents ever share a key, cached solves from one are served
28
+ * for the other — silent cache poisoning with no diagnostic. Use an identity
29
+ * that can never be reused for different content (e.g. a version UUID), never
30
+ * a mutable name or path.
31
+ */
32
+ interface DefinitionRef {
33
+ /**
34
+ * Identity of immutable bytes (e.g. a version UUID). Two different byte
35
+ * contents must never share a key — cache poisoning otherwise.
36
+ */
37
+ key: string;
38
+ /**
39
+ * Materialize the bytes. Called ONLY when an upload is unavoidable — inside
40
+ * the solve execution, so it counts toward the solve's abort semantics.
41
+ */
42
+ load: () => Promise<Uint8Array>;
43
+ }
44
+ /**
45
+ * Every definition form accepted by the solve entry points:
46
+ * - a URL, base64 string, or plain string (content-hashed for caching)
47
+ * - raw `.gh` bytes (content-hashed)
48
+ * - a {@link DefinitionRef} (identity-keyed; bytes loaded lazily)
49
+ */
50
+ type SolveDefinition = string | Uint8Array | DefinitionRef;
51
+ /** Narrow a {@link SolveDefinition} to the by-reference form. */
52
+ declare function isDefinitionRef(definition: SolveDefinition): definition is DefinitionRef;
53
+
10
54
  /**
11
55
  * Scheduling mode — controls how concurrent `solve()` calls interact.
12
56
  *
@@ -23,10 +67,36 @@ interface CacheOptions {
23
67
  maxEntries?: number;
24
68
  /** Time-to-live in ms. Set to `0` for no expiry (default). */
25
69
  ttlMs?: number;
70
+ /**
71
+ * Cache responses that carry Grasshopper `errors`. Default `true`: an
72
+ * errored solve is a valid, deterministic result — definitions raise GH
73
+ * errors by design (guarded components, validation branches), so replaying
74
+ * one from cache is correct. Set `false` for parity with Rhino's opt-in
75
+ * `cacheerroredsolves` server flag, e.g. when a definition's errors are
76
+ * transient (external data sources) rather than functions of the inputs.
77
+ */
78
+ cacheErroredSolves?: boolean;
26
79
  }
27
80
  interface SolveSchedulerOptions {
28
81
  mode?: SchedulerMode;
29
82
  maxConcurrent?: number;
83
+ /**
84
+ * Backpressure — cap on how many calls may wait in the FIFO queue (i.e.
85
+ * excluding the ones already in flight). When the queue is full, a new
86
+ * `solve()` is shed immediately with `code: QUEUE_FULL` (retryable, meant to
87
+ * map to HTTP 503 + Retry-After) instead of piling up unbounded. Bounds the
88
+ * miss path under load. Only applies to `queue` / `parallel` modes —
89
+ * `latest-wins` has an intrinsic depth of 1. Default: unbounded.
90
+ */
91
+ maxQueueDepth?: number;
92
+ /**
93
+ * Backpressure — max time (ms) a call may sit queued before it starts
94
+ * executing. If it's still waiting after this long it's shed with
95
+ * `code: QUEUE_TIMEOUT` rather than burning compute on a stale request.
96
+ * Bounds tail latency. Only applies to `queue` / `parallel` modes. Default:
97
+ * no deadline.
98
+ */
99
+ queueWaitMs?: number;
30
100
  timeoutMs?: number;
31
101
  retry?: RetryPolicy;
32
102
  /** Enable response caching keyed by hash of (definition, dataTree). */
@@ -81,7 +151,7 @@ type SolveResult = {
81
151
  * Adapter for the underlying solve function. Lets the scheduler be tested
82
152
  * without a real Compute server, and decouples it from the client class.
83
153
  */
84
- type SolveExecutor = (definition: string | Uint8Array, dataTree: DataTree[], config: GrasshopperComputeConfig) => Promise<GrasshopperComputeResponse>;
154
+ type SolveExecutor = (definition: SolveDefinition, dataTree: DataTree[], config: GrasshopperComputeConfig) => Promise<GrasshopperComputeResponse>;
85
155
  /**
86
156
  * Cache-key-aware executor. When `cacheKey` is provided, the executor solves by
87
157
  * reference (`pointer: cacheKey`) and falls back to a full upload on a server
@@ -93,7 +163,7 @@ type SolveExecutor = (definition: string | Uint8Array, dataTree: DataTree[], con
93
163
  * Supplied by the client (which owns the solve primitives); the scheduler stays
94
164
  * decoupled from the transport.
95
165
  */
96
- type CacheKeyExecutor = (definition: string | Uint8Array, dataTree: DataTree[], cacheKey: string | null, config: GrasshopperComputeConfig) => Promise<{
166
+ type CacheKeyExecutor = (definition: SolveDefinition, dataTree: DataTree[], cacheKey: string | null, config: GrasshopperComputeConfig) => Promise<{
97
167
  response: GrasshopperComputeResponse;
98
168
  cacheKey: string | null;
99
169
  missed: boolean;
@@ -104,6 +174,7 @@ type CacheKeyExecutor = (definition: string | Uint8Array, dataTree: DataTree[],
104
174
  * Sits between your application code and the underlying compute call,
105
175
  * adding:
106
176
  * - Configurable scheduling (latest-wins for sliders, queue for jobs)
177
+ * - Backpressure (bounded queue depth + queue-wait deadline) for the miss path
107
178
  * - In-flight cancellation (per-call signal + cancelAll)
108
179
  * - Optional response caching for repeated inputs
109
180
  * - Lifecycle hooks for UI indicators (start / settle / superseded)
@@ -134,11 +205,14 @@ declare class SolveScheduler {
134
205
  private readonly baseConfig;
135
206
  private readonly mode;
136
207
  private readonly maxConcurrent;
208
+ private readonly maxQueueDepth;
209
+ private readonly queueWaitMs;
137
210
  private readonly timeoutMs;
138
211
  private readonly retry;
139
212
  private readonly cacheEnabled;
140
213
  private readonly cacheMax;
141
214
  private readonly cacheTtl;
215
+ private readonly cacheErroredSolves;
142
216
  private readonly cache;
143
217
  /** Optional cache-key-aware executor and whether server-def-cache reuse is on. */
144
218
  private readonly cacheKeyExecutor?;
@@ -155,6 +229,10 @@ declare class SolveScheduler {
155
229
  private _lastResult;
156
230
  private _lastError;
157
231
  private _lastDurationMs;
232
+ /** Ordinal handed to each solve() call. */
233
+ private solveSeq;
234
+ /** seq of the solve that last wrote _lastResult/_lastError — see writeLastState. */
235
+ private lastStateSeq;
158
236
  private disposed;
159
237
  constructor(executor: SolveExecutor, baseConfig: GrasshopperComputeConfig, options?: SolveSchedulerOptions, cacheKeyExecutor?: CacheKeyExecutor);
160
238
  get isSolving(): boolean;
@@ -164,6 +242,7 @@ declare class SolveScheduler {
164
242
  get lastResult(): GrasshopperComputeResponse | null;
165
243
  get lastError(): RhinoComputeError | null;
166
244
  get lastDurationMs(): number | null;
245
+ /** Subscribe to state changes. */
167
246
  subscribe(listener: () => void): () => void;
168
247
  private notify;
169
248
  /**
@@ -174,18 +253,59 @@ declare class SolveScheduler {
174
253
  * newer values arrived (latest-wins mode).
175
254
  * - Rejects with `code: ErrorCodes.ABORTED` when the call was canceled via
176
255
  * caller-supplied signal or `cancelAll()`.
256
+ * - Rejects with `code: ErrorCodes.QUEUE_FULL` when `maxQueueDepth` is set and
257
+ * the queue was already full (backpressure; `statusCode: 503`).
258
+ * - Rejects with `code: ErrorCodes.QUEUE_TIMEOUT` when `queueWaitMs` is set and
259
+ * the call sat queued longer than that before starting (`statusCode: 503`).
177
260
  *
178
- * Caller-supplied `signal` cancels just this call (rejects with `ABORTED`).
261
+ * Caller-supplied `signal` cancels just this call (rejects with `ABORTED`) —
262
+ * including while the call is still queued, before execution starts.
263
+ *
264
+ * A {@link DefinitionRef} definition is keyed by its `key` (result cache and
265
+ * server-pointer map alike) without materializing bytes — `load()` runs only
266
+ * when an upload is unavoidable. Its immutability contract is trusted here:
267
+ * a reused key serves the other content's cached solve.
268
+ *
269
+ * Responses served from the cache (and via `lastResult`) are shared objects,
270
+ * not copies — treat them as immutable. Mutating one poisons every later
271
+ * cache hit for that key.
179
272
  */
180
- solve(definition: string | Uint8Array, dataTree: DataTree[], options?: {
273
+ solve(definition: SolveDefinition, dataTree: DataTree[], options?: {
181
274
  signal?: AbortSignal;
182
275
  }): Promise<GrasshopperComputeResponse>;
276
+ /**
277
+ * Record last-result state, but only if no newer solve has written since —
278
+ * a slow solve settling late must not overwrite the state a newer solve
279
+ * (or cache hit) already published.
280
+ */
281
+ private writeLastState;
282
+ /** latest-wins: supersede the pending item and abort everything in flight. */
283
+ private supersedeCurrent;
284
+ /** Settle a still-queued item as ABORTED and remove it from its queue. */
285
+ private abortQueuedItem;
286
+ /**
287
+ * Backpressure: settle an incoming item as QUEUE_FULL without ever enqueuing
288
+ * it. The structured context lets an HTTP layer map it to 503 + Retry-After.
289
+ */
290
+ private shedAsQueueFull;
291
+ /**
292
+ * Arm the queue-wait deadline for an item about to be queued. If the item is
293
+ * still waiting when it fires, it's shed as QUEUE_TIMEOUT and removed from the
294
+ * queue. Cleared on execute/settle via {@link clearQueueWaitTimer}.
295
+ */
296
+ private armQueueWaitTimer;
297
+ /** Clear a queued item's wait-deadline timer, if one is pending. */
298
+ private clearQueueWaitTimer;
183
299
  private enqueue;
184
300
  private execute;
185
301
  /**
186
302
  * Run the solve, using the server-definition-cache fast path when it's
187
303
  * enabled and the definition is reusable. Learns/updates the definition's
188
304
  * server cache key from the result so later solves can reference it.
305
+ *
306
+ * `definitionHash` is the {@link hashDefinition} result already computed at
307
+ * `solve()` entry — threaded through rather than recomputed, so each solve
308
+ * pays exactly one linear pass over the definition (issue 57).
189
309
  */
190
310
  private runExecutor;
191
311
  private drainNext;
@@ -212,6 +332,8 @@ declare class SolveScheduler {
212
332
  * @returns `true` if this call settled the item; `false` if it was already settled.
213
333
  */
214
334
  private settleSuccess;
335
+ /** Detach the queued-phase abort listener, if one is still attached. */
336
+ private removeQueuedAbortHandler;
215
337
  private isAbortLikeError;
216
338
  private normalizeExecutionError;
217
339
  /** Cancel everything — in-flight and pending. */
@@ -295,9 +417,14 @@ declare class GrasshopperClient {
295
417
  *
296
418
  * @throws {RhinoComputeError} with code INVALID_INPUT if definition is empty
297
419
  * @throws {RhinoComputeError} with code NETWORK_ERROR if server is offline
298
- * @throws {RhinoComputeError} with code COMPUTATION_ERROR if computation fails
420
+ * @throws {RhinoComputeError} with code COMPUTATION_ERROR if computation fails.
421
+ * On a partial-success response (some outputs computed, some errored) the
422
+ * error's `context.values` carries the outputs that did compute — pass
423
+ * `{ values } as GrasshopperComputeResponse` to the response processors to
424
+ * render them. `context.inputSummary` describes the inputs (param names,
425
+ * item counts, byte sizes) without pinning the full data tree.
299
426
  */
300
- solve(definition: string | Uint8Array, dataTree: DataTree[], options?: SolveOptions): Promise<GrasshopperComputeResponse>;
427
+ solve(definition: SolveDefinition, dataTree: DataTree[], options?: SolveOptions): Promise<GrasshopperComputeResponse>;
301
428
  /**
302
429
  * Create a scheduler bound to this client. Use a scheduler for any UI surface
303
430
  * that fires solves frequently (sliders, live editors) or that needs cancel
@@ -344,6 +471,14 @@ interface GetValuesOptions {
344
471
  }
345
472
  interface GetValuesResult<T = ParsedContext> {
346
473
  values: T;
474
+ /**
475
+ * Free every rhino3dm WASM object decoded into `values`. When a `rhino`
476
+ * instance was passed, decoded geometry lives on the WASM heap and is never
477
+ * garbage-collected — call this once the values are consumed, or the heap
478
+ * grows monotonically across solves. Idempotent; a no-op when nothing was
479
+ * decoded. `values` must not be used after disposal.
480
+ */
481
+ dispose: () => void;
347
482
  }
348
483
 
349
484
  /**
@@ -371,10 +506,6 @@ declare class GrasshopperResponseProcessor {
371
506
  * const { values } = processor.getValues();
372
507
  * ```
373
508
  *
374
- * @example
375
- * ```ts
376
- * const { values } = processor.getValues(true); // keyed by param ID
377
- * ```
378
509
  */
379
510
  getValues<T = ParsedContext>(byId?: boolean, options?: GetValuesOptions): GetValuesResult<T>;
380
511
  /**
@@ -414,11 +545,6 @@ declare class GrasshopperResponseProcessor {
414
545
  * ```
415
546
  */
416
547
  extractMeshesFromResponse(options?: MeshExtractionOptions): Promise<THREE.Object3D<THREE.Object3DEventMap>[]>;
417
- /**
418
- * Raw file entries packaged in the response (textures, JSON, CAD exports, …).
419
- * Produced by the Selva **Block to File** / **Geometry To File** components on
420
- * the VektorNode rhino.compute branch.
421
- */
422
548
  private getFileData;
423
549
  /**
424
550
  * Download all files generated by Grasshopper, optionally including
@@ -443,6 +569,57 @@ declare class GrasshopperResponseProcessor {
443
569
  getAndDownloadFiles(folderName: string, additionalFiles?: FileBaseInfo[] | FileBaseInfo | null): Promise<void>;
444
570
  }
445
571
 
572
+ /**
573
+ * Stable hashing for solve deduplication and caching.
574
+ *
575
+ * The public keying surface here — {@link stableStringify}, {@link hashDefinition},
576
+ * {@link hashSolveInput} — is exported from the package barrel so a durable
577
+ * (app-layer) cache or a pre-solved bundle viewer can reproduce the *exact*
578
+ * canonicalize-and-hash path the scheduler's in-process cache uses. Key parity
579
+ * across the two layers is a correctness requirement: a durable-cache key that
580
+ * canonicalizes even slightly differently would miss every entry the scheduler
581
+ * wrote (harmless) or, worse, collide differently (not). The FNV plumbing
582
+ * (`fnv1a`/`fnv1aBytes`) and the pre-hashed-definition fast path
583
+ * (`hashSolveInputForDefinition`) stay internal.
584
+ */
585
+
586
+ /**
587
+ * Deterministic stringify with sorted keys. {a:1,b:2} and {b:2,a:1} produce
588
+ * the same string. Safely handles circular references and non-finite numbers.
589
+ *
590
+ * The output is a cache key, so the invariant that matters is: two payloads
591
+ * that serialize differently on the wire must stringify differently here
592
+ * (false misses are harmless; false hits serve the wrong cached solve).
593
+ */
594
+ declare function stableStringify(value: unknown): string;
595
+ /**
596
+ * Hash definition and data tree into a stable cache key.
597
+ *
598
+ * The definition is the *identity* of what we solve, so a binary definition is
599
+ * hashed over its full content (`fnv1aBytes`) — a length-only or sampled key
600
+ * would let two different `.gh` files collide and serve one's cached solve for
601
+ * the other. `.gh` files are small enough that a single linear pass is
602
+ * negligible. A {@link DefinitionRef} is keyed by its `key` alone — the
603
+ * caller-declared identity of immutable bytes — so no bytes are materialized
604
+ * or hashed at all.
605
+ *
606
+ * The key keeps the definition and tree hashes as separate parts rather than
607
+ * collapsing them into one 32-bit hash: a single FNV pass over the pair would
608
+ * birthday-collide quadratically in cache size, while requiring both 32-bit
609
+ * parts (plus lengths) to collide at once makes that negligible.
610
+ */
611
+ declare function hashSolveInput(definition: SolveDefinition, dataTree: unknown): string;
612
+ /**
613
+ * Stable identity of a definition alone (no inputs) — used to key the
614
+ * server-cache-key map so the same definition reuses its `pointer` across solves
615
+ * with different inputs. Same full-content hashing as {@link hashSolveInput}: a
616
+ * binary definition is hashed over all its bytes so two distinct `.gh` files of
617
+ * equal length can't share a cache key. A {@link DefinitionRef} is keyed by its
618
+ * `key` verbatim (refs are short identities like UUIDs, safe as Map keys) —
619
+ * its immutability contract makes the key equivalent to a content hash.
620
+ */
621
+ declare function hashDefinition(definition: SolveDefinition): string;
622
+
446
623
  /**
447
624
  * Runs a Rhino Compute job using the provided tree prototypes and Grasshopper definition.
448
625
  *
@@ -454,6 +631,7 @@ declare class GrasshopperResponseProcessor {
454
631
  * - A base64-encoded string of the .gh file
455
632
  * - A plain string (will be base64-encoded)
456
633
  * - A Uint8Array of the .gh file (will be base64-encoded)
634
+ * - A `DefinitionRef` (bytes are loaded via `ref.load()` for the upload)
457
635
  * @param config - Compute configuration (server URL, API key, etc. along with optional timeout, units, etc.)
458
636
  * @returns An object containing the compute result and extracted file data.
459
637
  *
@@ -468,15 +646,23 @@ declare class GrasshopperResponseProcessor {
468
646
  * const fileData = new Uint8Array([...]);
469
647
  * await solveGrasshopperDefinition(trees, fileData, config);
470
648
  */
471
- declare function solveGrasshopperDefinition(dataTree: DataTree[], definition: string | Uint8Array, config: GrasshopperComputeConfig): Promise<GrasshopperComputeResponse>;
649
+ declare function solveGrasshopperDefinition(dataTree: DataTree[], definition: SolveDefinition, config: GrasshopperComputeConfig): Promise<GrasshopperComputeResponse>;
472
650
 
473
651
  /**
474
652
  * Fetches raw input/output schemas from a Grasshopper definition.
475
- * Returns unprocessed data exactly as received from the Rhino Compute API (camelCased).
653
+ *
654
+ * "Raw" means no per-type parsing (no default coercion, no discriminated-union
655
+ * typing) — but NOT byte-for-byte wire data. The response IS normalized:
656
+ * per-param field KEYS are canonicalized to camelCase across server branches
657
+ * ({@link normalizeInputSchema} / {@link normalizeOutputSchema}, with honest
658
+ * fallbacks for missing required fields), missing/non-array `inputs`/`outputs`
659
+ * coerce to `[]`, and server load diagnostics surface as
660
+ * `loadWarnings`/`loadErrors` (coerced to strings). Field VALUES — notably
661
+ * `default` and the `values` dropdown-label map — pass through verbatim.
476
662
  *
477
663
  * @param definition - The Grasshopper definition (URL, base64 string, or Uint8Array)
478
664
  * @param config - Compute configuration (server URL, API key, etc.)
479
- * @returns Raw inputs and outputs with no type processing
665
+ * @returns Key-normalized inputs and outputs with no per-type processing
480
666
  * @throws {RhinoComputeError} If fetch fails or response is invalid
481
667
  *
482
668
  * @public Use `fetchParsedDefinitionIO()` for processed, type-safe inputs
@@ -655,17 +841,19 @@ declare class TreeBuilder {
655
841
  * - Use with `InnerTree[]` when modifying compute API results
656
842
  * - `DataTree` is the high-level builder; `InnerTree` is the Rhino Compute format
657
843
  *
844
+ * Copy-on-write: returns a new array; the caller's array is never mutated.
845
+ *
658
846
  * @overload For TreeBuilder instances (high-level builder)
659
- * @param trees - Array of TreeBuilder instances to modify
847
+ * @param trees - Array of TreeBuilder instances to read from (not mutated)
660
848
  * @param paramName - The parameter name to set or replace
661
849
  * @param newValue - The new value (scalar, array, or TreeBuilder structure)
662
- * @returns A new/modified TreeBuilder array with the updated parameter
850
+ * @returns A new TreeBuilder array with the updated parameter
663
851
  *
664
852
  * @overload For compiled InnerTree (low-level API format)
665
- * @param trees - The compiled InnerTree array (typically from `client.solve()`)
853
+ * @param trees - The compiled InnerTree array (typically from `client.solve()`; not mutated)
666
854
  * @param paramName - The parameter name to set or replace
667
855
  * @param newValue - The new value (scalar, array, or TreeBuilder structure)
668
- * @returns A new/modified InnerTree array with the updated parameter
856
+ * @returns A new InnerTree array with the updated parameter
669
857
  *
670
858
  * @example
671
859
  * ```ts
@@ -749,9 +937,13 @@ declare class TreeBuilder {
749
937
  private static readFromDataTrees;
750
938
  /**
751
939
  * Parse a TreeBuilder path string like "{0;1;2}" into [0, 1, 2].
940
+ * Negative indices ("{-1;2}") and the root path "{}" are valid.
752
941
  *
753
942
  * @param pathStr - Path string
754
943
  * @returns Array of path indices
944
+ * @throws Error when the path string is not a valid Grasshopper branch path.
945
+ * Malformed keys must never silently collapse to a default branch —
946
+ * two distinct unparseable keys would merge their items into one branch.
755
947
  */
756
948
  static parsePathString(pathStr: string): number[];
757
949
  /**
@@ -761,9 +953,7 @@ declare class TreeBuilder {
761
953
  * @returns Formatted path string like "{0;1;2}"
762
954
  */
763
955
  static formatPathString(path: number[]): DataTreePath;
764
- /**
765
- * Apply numeric constraints to all tree values.
766
- */
956
+ /** Apply numeric constraints to all tree values. */
767
957
  private applyNumericConstraints;
768
958
  /**
769
959
  * Serialize a value for compute requests.
@@ -793,4 +983,4 @@ declare class TreeBuilder {
793
983
  private static clampValue;
794
984
  }
795
985
 
796
- export { type CacheOptions, ComputeConfig, DataTree, DataTreeDefault, DataTreePath, type DataTreeValue, FileBaseInfo, type GetValuesOptions, type GetValuesResult, GrasshopperClient, GrasshopperComputeConfig, GrasshopperComputeResponse, GrasshopperParsedIO, GrasshopperParsedIORaw, GrasshopperResponseProcessor, InputParam, InputParamSchema, type ParsedContext, RetryPolicy, RhinoComputeError, type SchedulerMode, type SolveContext, type SolveOptions, type SolveResult, SolveScheduler, type SolveSchedulerOptions, TreeBuilder, fetchDefinitionIO, fetchParsedDefinitionIO, processInput, processInputs, solveGrasshopperDefinition };
986
+ export { type CacheOptions, ComputeConfig, DataTree, DataTreeDefault, DataTreePath, type DataTreeValue, type DefinitionRef, FileBaseInfo, type GetValuesOptions, type GetValuesResult, GrasshopperClient, GrasshopperComputeConfig, GrasshopperComputeResponse, GrasshopperParsedIO, GrasshopperParsedIORaw, GrasshopperResponseProcessor, InputParam, InputParamSchema, type ParsedContext, RetryPolicy, RhinoComputeError, type SchedulerMode, type SolveContext, type SolveDefinition, type SolveOptions, type SolveResult, SolveScheduler, type SolveSchedulerOptions, TreeBuilder, fetchDefinitionIO, fetchParsedDefinitionIO, hashDefinition, hashSolveInput, isDefinitionRef, processInput, processInputs, solveGrasshopperDefinition, stableStringify };
@@ -1,2 +1,2 @@
1
- import{a as d,b as e,c as f,d as g,e as h,f as i,g as j,h as k,i as l}from"./chunk-ESPPM542.js";import{d as a,q as b,r as c}from"./chunk-J3MFKB33.js";export{f as GrasshopperClient,g as GrasshopperResponseProcessor,a as RhinoComputeError,e as SolveScheduler,l as TreeBuilder,c as downloadFileData,b as extractFilesFromComputeResponse,j as fetchDefinitionIO,k as fetchParsedDefinitionIO,h as processInput,i as processInputs,d as solveGrasshopperDefinition};
1
+ import{a as d,b as e,c as f,d as g,e as h,f as i,g as j,h as k,i as l,j as m,k as n,l as o,m as p}from"./chunk-C7P43VZF.js";import{d as a,s as b,t as c}from"./chunk-WPB2LKCD.js";export{j as GrasshopperClient,k as GrasshopperResponseProcessor,a as RhinoComputeError,i as SolveScheduler,p as TreeBuilder,c as downloadFileData,b as extractFilesFromComputeResponse,n as fetchDefinitionIO,o as fetchParsedDefinitionIO,h as hashDefinition,g as hashSolveInput,d as isDefinitionRef,l as processInput,m as processInputs,e as solveGrasshopperDefinition,f as stableStringify};
2
2
  //# sourceMappingURL=grasshopper.js.map
@@ -25,14 +25,16 @@ declare class ComputeServerStats {
25
25
  private disposed;
26
26
  private activeMonitors;
27
27
  private activeTimeouts;
28
- /**
29
- * @param serverUrl - Base URL of the Rhino Compute server with http:// or https:// scheme (e.g., 'http://localhost:6500')
30
- * @param apiKey - Optional API key for authentication
31
- */
32
28
  /** Timeout (ms) for the fast read/monitoring endpoints. */
33
29
  private static readonly DEFAULT_TIMEOUT_MS;
34
30
  /** Timeout (ms) for child-lifecycle POSTs — a cold Windows child can take ~30s to spawn. */
35
31
  private static readonly LIFECYCLE_TIMEOUT_MS;
32
+ /** Floor for `monitor()`'s `intervalMs` — anything lower hot-loops the server. */
33
+ private static readonly MIN_MONITOR_INTERVAL_MS;
34
+ /**
35
+ * @param serverUrl - Base URL of the Rhino Compute server with http:// or https:// scheme (e.g., 'http://localhost:6500')
36
+ * @param apiKey - Optional API key for authentication
37
+ */
36
38
  constructor(serverUrl: string, apiKey?: string);
37
39
  /**
38
40
  * Build request headers with optional API key.
@@ -273,8 +275,10 @@ declare class ComputeServerStats {
273
275
  * Continuously monitor server stats at specified interval.
274
276
  *
275
277
  * @param callback - Function called with stats on each interval
276
- * @param intervalMs - Milliseconds between checks (default: 5000)
278
+ * @param intervalMs - Milliseconds between checks (default: 5000). Must be a
279
+ * finite number of at least 100 ms — lower values would hot-loop the server.
277
280
  * @returns Function to stop monitoring
281
+ * @throws {RangeError} If `intervalMs` is not a finite number >= 100.
278
282
  *
279
283
  * @example
280
284
  * ```typescript
@@ -298,9 +302,6 @@ declare class ComputeServerStats {
298
302
  private ensureNotDisposed;
299
303
  }
300
304
 
301
- /**
302
- * Error types and codes for `@selvajs/compute`.
303
- */
304
305
  declare const ErrorCodes: {
305
306
  readonly NETWORK_ERROR: "NETWORK_ERROR";
306
307
  readonly AUTH_ERROR: "AUTH_ERROR";
@@ -308,6 +309,17 @@ declare const ErrorCodes: {
308
309
  readonly COMPUTATION_ERROR: "COMPUTATION_ERROR";
309
310
  readonly TIMEOUT_ERROR: "TIMEOUT_ERROR";
310
311
  readonly CORS_ERROR: "CORS_ERROR";
312
+ /** HTTP 404 — the endpoint path does not exist on the server (usually a typo'd route or wrong server). Never retried. */
313
+ readonly NOT_FOUND: "NOT_FOUND";
314
+ /** HTTP 429 — the server is rate-limiting requests. Retried by default (honors `Retry-After`); see `RetryPolicy.retryOn429`. */
315
+ readonly RATE_LIMIT: "RATE_LIMIT";
316
+ /**
317
+ * The server answered 2xx but the body is deterministically not JSON (the
318
+ * response declared a non-JSON `Content-Type`, e.g. an HTML captive-portal or
319
+ * proxy login page, or a misconfigured endpoint). Never retried — refetching
320
+ * returns the same page.
321
+ */
322
+ readonly INVALID_RESPONSE: "INVALID_RESPONSE";
311
323
  readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
312
324
  readonly INVALID_STATE: "INVALID_STATE";
313
325
  readonly INVALID_INPUT: "INVALID_INPUT";
@@ -321,6 +333,19 @@ declare const ErrorCodes: {
321
333
  readonly SUPERSEDED: "SUPERSEDED";
322
334
  /** Scheduler / caller-supplied AbortSignal: this call was aborted. */
323
335
  readonly ABORTED: "ABORTED";
336
+ /**
337
+ * Scheduler backpressure: the queue was already at `maxQueueDepth` when this
338
+ * call arrived, so it was shed immediately rather than queued. Retryable — the
339
+ * caller (or an HTTP layer, as 503 + Retry-After) should back off and retry.
340
+ * The error `context` carries `{ queueDepth, maxQueueDepth }`.
341
+ */
342
+ readonly QUEUE_FULL: "QUEUE_FULL";
343
+ /**
344
+ * Scheduler backpressure: this call sat queued longer than `queueWaitMs`
345
+ * without starting, so it was shed before wasting compute on a stale request.
346
+ * Retryable. The error `context` carries `{ waitedMs, queueWaitMs }`.
347
+ */
348
+ readonly QUEUE_TIMEOUT: "QUEUE_TIMEOUT";
324
349
  /**
325
350
  * A solve referenced a definition by `pointer` (server-side cache key), but the
326
351
  * server no longer holds that definition (evicted / GC'd / a different child in
@@ -357,94 +382,53 @@ declare class RhinoComputeError extends Error {
357
382
  }
358
383
 
359
384
  /**
360
- * Represents raw file data from Grasshopper/Rhino Compute response.
361
- *
362
- * This type encapsulates file output from compute operations, with metadata
363
- * for processing (decoding, naming, organization). Files are typically combined
364
- * with additional files and packaged into a ZIP archive for download.
365
- *
366
- * @see {@link ProcessedFile} for the normalized format after processing
385
+ * Raw file data from Grasshopper/Rhino Compute response, with metadata for processing.
386
+ * Files are typically combined with additional files and packaged into a ZIP archive.
367
387
  * @see {@link extractFilesFromComputeResponse} for extraction from compute responses
368
388
  */
369
389
  type FileData = {
370
390
  /** Base filename without extension (e.g., "model") */
371
391
  fileName: string;
372
- /** File content as a base64-encoded or plain string, depending on {@link IsBase64Encoded} */
392
+ /** File content, base64-encoded or plain string depending on isBase64Encoded flag */
373
393
  data: string;
374
- /** File extension including the dot (e.g., ".3dm", ".json"). Appended to {@link FileName} to create the full filename */
394
+ /** File extension including the dot (e.g., ".3dm", ".json"). Appended to fileName to create the full filename */
375
395
  fileType: string;
376
- /** Whether {@link Data} is base64-encoded. If true, must be decoded to binary before use. If false, can be used as a plain text string */
396
+ /** Whether data is base64-encoded. If true, must be decoded to binary before use */
377
397
  isBase64Encoded: boolean;
378
- /** Directory path for organizing the file in archive structures (e.g., ZIP). Typically empty string for root-level files, or a path like "subfolder/nested" */
398
+ /** Directory path for archive organization (e.g., "subfolder/nested"). Empty string for root-level files */
379
399
  subFolder: string;
380
- /** Arbitrary user-supplied metadata (e.g. tags, indexing keys) attached in Grasshopper. Not interpreted by compute; passed through for downstream consumers. May be absent on older payloads. */
400
+ /** Arbitrary metadata attached in Grasshopper. Not interpreted by compute; passed through for downstream consumers. May be absent on older payloads */
381
401
  metadata?: Record<string, string>;
382
402
  };
383
403
  /**
384
- * Represents a normalized, processed file ready for consumption or archival.
385
- *
386
- * This is the unified intermediate format produced by processing both {@link FileData}
387
- * and {@link FileBaseInfo}. Files in this format are ready to be packaged into archives
388
- * (e.g., ZIP files) or returned to callers for programmatic use.
389
- *
390
- * @see {@link FileData} for raw compute response files
391
- * @see {@link FileBaseInfo} for external file references
404
+ * Normalized file ready for consumption or archival.
405
+ * Unified intermediate format from FileData or FileBaseInfo, ready to be packaged into archives or returned to callers.
392
406
  */
393
407
  type ProcessedFile = {
394
408
  /** Full filename including extension (e.g., "model.3dm") */
395
409
  fileName: string;
396
- /** File content as either binary data or text. Binary format (Uint8Array) is used for decoded base64 or fetched binary files; text format is used for plain text content */
410
+ /** File content as binary data (Uint8Array for decoded base64 or fetched binary) or text */
397
411
  content: Uint8Array | string;
398
- /** File path for archive organization (e.g., "subfolder/model.3dm"). Used when creating ZIP archives or other hierarchical structures */
412
+ /** File path for archive organization (e.g., "subfolder/model.3dm") */
399
413
  path: string;
400
414
  };
401
415
  /**
402
- * Represents a reference to an external file to be included in file operations.
403
- *
404
- * This type is used to specify additional files (beyond compute response files)
405
- * that should be fetched and included when processing files. The file is fetched
406
- * from the provided URL and processed as a {@link ProcessedFile}.
407
- *
408
- *
409
- * @see {@link FileData} for files from compute responses
410
- * @see {@link fetchRemoteFiles} for how FileBaseInfo is processed (fetched and converted)
416
+ * Reference to an external file to be fetched and included in file operations.
417
+ * Specifies additional files (beyond compute response files) to fetch and process as ProcessedFile.
418
+ * @see {@link fetchRemoteFiles} for how FileBaseInfo is fetched and converted
411
419
  */
412
420
  type FileBaseInfo = {
413
421
  /** Destination filename for the file in the archive or result set (e.g., "additional-data.json") */
414
422
  fileName: string;
415
423
  /** URL to fetch the file from. Must be accessible from the runtime environment */
416
424
  filePath: string;
425
+ /** Optional directory path for archive organization (e.g., "extras/docs"). When omitted, file lands at archive root */
426
+ subFolder?: string;
417
427
  };
418
428
 
419
- /**
420
- * Extracts and processes files from compute response data without downloading them.
421
- * Returns an array of ProcessedFile objects that can be used programmatically.
422
- *
423
- * @param downloadableFiles - An array of FileData items from the compute response.
424
- * @param additionalFiles - Optional additional files to include (fetched from URLs).
425
- * @returns A Promise resolving to an array of ProcessedFile objects.
426
- * @throws Will throw an error if file processing fails.
427
- *
428
- * @example
429
- * const files = await extractFilesFromComputeResponse(fileData);
430
- * files.forEach(file => {
431
- * console.log(`File: ${file.fileName}, Size: ${file.content.length}`);
432
- * });
433
- */
429
+ /** Extracts and processes files from compute response data without downloading them. */
434
430
  declare const extractFilesFromComputeResponse: (downloadableFiles: FileData[], additionalFiles?: FileBaseInfo[] | FileBaseInfo | null) => Promise<ProcessedFile[]>;
435
- /**
436
- * Downloads files from a compute response as a ZIP archive.
437
- * Packages multiple files into a single ZIP file and triggers a browser download.
438
- *
439
- * @param downloadableFiles - An array of FileData items from the compute response.
440
- * @param additionalFiles - Optional additional files to include in the ZIP (fetched from URLs).
441
- * @param fileFoldername - The name of the ZIP file (without extension).
442
- * @throws Will throw an error if the file handling or download fails.
443
- *
444
- * @example
445
- * await downloadDataFromComputeResponse(fileData, null, 'my-export');
446
- * // Downloads 'my-export.zip'
447
- */
431
+ /** Downloads files from a compute response as a ZIP archive. */
448
432
  declare const downloadFileData: (downloadableFiles: FileData[], fileFoldername: string, additionalFiles?: FileBaseInfo[] | FileBaseInfo | null) => Promise<void>;
449
433
 
450
434
  export { ComputeServerStats as C, type ErrorCode as E, type FileBaseInfo as F, type ProcessedFile as P, RhinoComputeError as R, ErrorCodes as a, type FileData as b, downloadFileData as d, extractFilesFromComputeResponse as e };