@selvajs/compute 4.3.0-beta.1 → 5.0.0-beta.10

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.
@@ -1,1787 +0,0 @@
1
- import { A as RetryPolicy, N as ComputeError, O as ComputeAuth, _ as isDefinitionRef, a as extractFilesFromComputeResponse, c as ProcessedFile, g as SolveDefinition, h as DefinitionRef, k as ComputeConfig, o as FileBaseInfo, r as downloadFileData, s as FileData } from "./index-BR_XZvjj.cjs";
2
- //#region src/grasshopper/server/compute-server-stats.d.ts
3
- /**
4
- * ComputeServerStats provides methods to query Rhino Compute server statistics.
5
- *
6
- * @public Use this for server health monitoring and statistics.
7
- *
8
- * @example
9
- * ```typescript
10
- * const stats = new ComputeServerStats('http://localhost:6500', 'your-api-key');
11
- *
12
- * try {
13
- * const isOnline = await stats.isServerOnline();
14
- * const children = await stats.getActiveChildren();
15
- * const version = await stats.getVersion();
16
- *
17
- * // Or get everything at once
18
- * const allStats = await stats.getServerStats();
19
- * } finally {
20
- * await stats.dispose(); // Clean up resources
21
- * }
22
- * ```
23
- */
24
- declare class ComputeServerStats {
25
- private readonly serverUrl;
26
- private readonly headers;
27
- private disposed;
28
- private activeMonitors;
29
- private activeTimeouts;
30
- /** Timeout (ms) for the fast read/monitoring endpoints. */
31
- private static readonly DEFAULT_TIMEOUT_MS;
32
- /** Timeout (ms) for child-lifecycle POSTs — a cold Windows child can take ~30s to spawn. */
33
- private static readonly LIFECYCLE_TIMEOUT_MS;
34
- /** Floor for `monitor()`'s `intervalMs` — anything lower hot-loops the server. */
35
- private static readonly MIN_MONITOR_INTERVAL_MS;
36
- /**
37
- * @param serverUrl - Base URL of the Rhino Compute server with http:// or https:// scheme (e.g., 'http://localhost:6500')
38
- * @param auth - An API key, or the same auth fields a solve's `ComputeConfig` carries
39
- * (`apiKey`, `apiKeyHeader`, `authToken`, `headers`).
40
- */
41
- constructor(serverUrl: string, auth?: string | ComputeAuth);
42
- /**
43
- * `fetch` wrapper that aborts after `timeoutMs` so a hung connection can't stall
44
- * a probe (or the `monitor()` loop) forever. Pass `0` to disable the timeout.
45
- */
46
- private fetchWithTimeout;
47
- /**
48
- * Check if the server is online.
49
- *
50
- * This is a single-sample probe: it returns `true` only on a 2xx or a redirect
51
- * from the proxy liveness root `/`, and `false` for every other outcome (4xx/5xx,
52
- * network error, or timeout). A cold or briefly-busy-but-up server can therefore
53
- * read as offline — callers that gate on this (e.g. client construction)
54
- * should retry rather than treat a single `false` as authoritative.
55
- *
56
- * @param timeoutMs - Abort the probe after this many ms (default: 5000).
57
- * Pass `0` to disable the timeout. Prevents a hung connection from
58
- * stalling the caller indefinitely.
59
- */
60
- isServerOnline(timeoutMs?: number): Promise<boolean>;
61
- /**
62
- * Detailed liveness probe backing {@link isServerOnline}.
63
- *
64
- * Reports what the probe actually saw so callers can distinguish "connection
65
- * failed" (`error` set) from "server answered non-2xx" (`status` set) — e.g.
66
- * a 401 from a proxy that requires an API key is a misconfiguration, not an
67
- * offline server. Same single-sample caveat as {@link isServerOnline}.
68
- *
69
- * @param timeoutMs - Abort the probe after this many ms (default: 5000).
70
- * Pass `0` to disable the timeout.
71
- * @returns `online` plus either the HTTP `status` the server answered with,
72
- * or the `error` the connection attempt failed with.
73
- */
74
- probeServer(timeoutMs?: number): Promise<{
75
- online: boolean;
76
- status?: number;
77
- error?: string;
78
- }>;
79
- /**
80
- * Get the number of active child processes on the server.
81
- *
82
- * By default the proxy's `/activechildren` endpoint will *spawn* children up
83
- * to the configured count if none are running, then report the count — which
84
- * wakes (and bills) an idle server. Pass `{ initialize: false }` for a passive
85
- * read that reports the current count without spawning; use this for
86
- * monitoring or before a purge/probe where you must not wake the server.
87
- *
88
- * @param options.initialize - When `false`, append `?initialize=false` so the
89
- * server reports without spawning. Defaults to `true` (the server's default).
90
- * @returns Number of active children, or null if unavailable
91
- */
92
- getActiveChildren(options?: {
93
- initialize?: boolean;
94
- }): Promise<number | null>;
95
- /**
96
- * Get the server version information.
97
- *
98
- * @returns Version object with rhino, compute, and git_sha, or null if unavailable
99
- */
100
- getVersion(): Promise<{
101
- rhino: string;
102
- compute: string;
103
- git_sha: string | null;
104
- } | null>;
105
- /**
106
- * Get the plugins installed on the server.
107
- *
108
- * Returns a `name → version` map of non-core plugins the server has loaded,
109
- * or `null` if the request failed. Pass `kind` to choose which inventory:
110
- * `'gh'` (default) lists Grasshopper add-on assemblies via
111
- * `/plugins/gh/installed`; `'rhino'` lists Rhino plugins via
112
- * `/plugins/rhino/installed`. Plugins that ship with Rhino / are core
113
- * libraries are excluded by the server.
114
- *
115
- * @param kind - `'gh'` for Grasshopper add-ons (default) or `'rhino'` for Rhino plugins.
116
- * @returns Map of plugin name to version, or `null` on failure.
117
- *
118
- * @example
119
- * ```ts
120
- * const gh = await stats.getInstalledPlugins(); // Grasshopper add-ons
121
- * const selvaVersion = gh?.['Selva'] ?? null;
122
- * ```
123
- */
124
- getInstalledPlugins(kind?: 'gh' | 'rhino'): Promise<Record<string, string> | null>;
125
- /**
126
- * Get comprehensive server statistics.
127
- * Fetches all available server information in parallel.
128
- *
129
- * @returns Object containing server status and available stats
130
- */
131
- getServerStats(): Promise<{
132
- isOnline: boolean;
133
- version?: {
134
- rhino: string;
135
- compute: string;
136
- git_sha: string | null;
137
- };
138
- activeChildren?: number;
139
- }>;
140
- /**
141
- * Purge the server's solve-results / URL-data cache.
142
- *
143
- * POSTs to `cache/purge` and returns the number of entries removed, or `null`
144
- * if the request failed. This clears cached solve responses and fetched
145
- * definition-URL data; it does NOT evict the definition cache (active
146
- * `pointer` references stay valid).
147
- *
148
- * **Caveat:** `cache/purge` is forwarded by the rhino.compute proxy to a
149
- * single round-robin-selected child, so in a multi-child deployment one call
150
- * purges one child's cache. Call repeatedly (or size the pool to 1) if you
151
- * need a fleet-wide purge.
152
- *
153
- * @returns Number of entries removed, or `null` on failure.
154
- *
155
- * @example
156
- * ```ts
157
- * const removed = await stats.purgeCache();
158
- * if (removed !== null) console.log(`Purged ${removed} cached solves`);
159
- * ```
160
- */
161
- purgeCache(): Promise<number | null>;
162
- /**
163
- * Best-effort fleet-wide cache purge across a multi-child deployment.
164
- *
165
- * A single {@link purgeCache} POST is forwarded by the rhino.compute proxy to
166
- * just ONE round-robin-selected child, so the other children keep serving
167
- * stale cached solves. There is no proxy endpoint that addresses children
168
- * individually, so this method reads the active child count (passively, never
169
- * spawning) and fires `2 × count` sequential purges, relying on the proxy's
170
- * round-robin to spread the hits across the pool.
171
- *
172
- * **This is best-effort, not a guarantee.** Round-robin can revisit one child
173
- * and skip another; under concurrent traffic the rotation drifts. The result's
174
- * `confident` flag is `true` only when the server reports a single child (where
175
- * one purge is exact) — surface it so callers don't over-promise. For a hard
176
- * fleet-wide guarantee, run the deployment at `--childcount 1` or add a
177
- * server-side fan-out endpoint.
178
- *
179
- * @returns `{ totalPurged, calls, children, confident }`, or `null` if the
180
- * child count couldn't be read (server unreachable). `totalPurged` sums the
181
- * per-call counts; `calls` is how many purges were issued; `children` is the
182
- * reported pool size; `confident` is `true` only at a single-child pool.
183
- *
184
- * @example
185
- * ```ts
186
- * const r = await stats.purgeAllChildren();
187
- * if (r && !r.confident) {
188
- * console.warn(`Purged ~${r.totalPurged} across ${r.children} children (best-effort)`);
189
- * }
190
- * ```
191
- */
192
- purgeAllChildren(): Promise<{
193
- totalPurged: number;
194
- calls: number;
195
- children: number;
196
- confident: boolean;
197
- } | null>;
198
- /**
199
- * Get the server's current UTC clock.
200
- *
201
- * GETs `/servertime`, which the server emits as a JSON-encoded ISO-8601
202
- * timestamp (e.g. `"2026-06-18T08:30:00Z"`). Useful for detecting clock skew
203
- * between caller and server. Returns `null` if the request failed or the body
204
- * isn't a parseable date.
205
- *
206
- * @returns A `Date` for the server's UTC time, or `null` on failure.
207
- */
208
- getServerTime(): Promise<Date | null>;
209
- /**
210
- * Get how long the rhino.compute proxy has been idle.
211
- *
212
- * GETs `/idlespan` on the proxy, which returns the seconds elapsed since the
213
- * last request was forwarded to a compute child. This is a proxy-level metric
214
- * (not proxied to a child) used by autoscalers to decide when a node can be
215
- * drained. Returns `null` if unavailable.
216
- *
217
- * @returns Idle time in seconds, or `null` on failure.
218
- */
219
- getIdleSpan(): Promise<number | null>;
220
- /**
221
- * Fill the compute child pool up to the server's configured baseline.
222
- *
223
- * POSTs `/launch-children`. No-op when the pool is already at or above the
224
- * configured `--childcount`. Returns `{ spawned, active }` — how many children
225
- * were started and the resulting child count — or `null` on failure.
226
- *
227
- * To raise capacity above the baseline use {@link launchChild}; the baseline
228
- * itself can only be changed by restarting rhino.compute.
229
- *
230
- * @returns `{ spawned, active }`, or `null` on failure.
231
- */
232
- launchChildren(): Promise<{
233
- spawned: number[];
234
- active: number;
235
- } | null>;
236
- /**
237
- * Add a single compute child to the pool, optionally on a specific port.
238
- *
239
- * POSTs `/launch-child` (with `?port=N` when `port` is given). Unlike
240
- * {@link launchChildren}, this can push the pool above the baseline, up to the
241
- * server's `MaxChildren` cap. Returns `{ spawned: [port] }` on success, or
242
- * `null` on failure (server replies 400 for a bad port, 409 if the port is in
243
- * use, 503 at the max-children cap).
244
- *
245
- * @param port - Optional specific port to launch on; otherwise the next free one.
246
- * @returns `{ spawned }` listing the launched port, or `null` on failure.
247
- */
248
- launchChild(port?: number): Promise<{
249
- spawned: number[];
250
- } | null>;
251
- /**
252
- * Gracefully shut down compute children without respawning them.
253
- *
254
- * POSTs `/shutdown-children`. With no `port` it shuts down every child; with
255
- * `port` it targets just that one. Children do not respawn, but the next
256
- * `/grasshopper` request auto-spawns the pool back to the baseline. Returns
257
- * `{ shutdown, active }` — how many were stopped and the remaining count — or
258
- * `null` on failure.
259
- *
260
- * @param port - Optional port to target; omit to shut down all children.
261
- * @returns `{ shutdown, active }`, or `null` on failure.
262
- */
263
- shutdownChildren(port?: number): Promise<{
264
- shutdown: number;
265
- active: number;
266
- } | null>;
267
- /**
268
- * Shut down compute children and respawn replacements (rolling restart).
269
- *
270
- * POSTs `/recycle-children`. With no `port` it recycles every child; with
271
- * `port` it recycles just that one. The server recycles sequentially (each
272
- * replacement is serving before the next child is stopped) so the pool never
273
- * drops to zero mid-recycle. Returns `{ shutdown, spawned, active }`, or
274
- * `null` on failure.
275
- *
276
- * @param port - Optional port to target; omit to recycle all children.
277
- * @returns `{ shutdown, spawned, active }`, or `null` on failure.
278
- */
279
- recycleChildren(port?: number): Promise<{
280
- shutdown: number;
281
- spawned: number[];
282
- active: number;
283
- } | null>;
284
- /**
285
- * POST a control endpoint that replies with a JSON object and return it,
286
- * degrading to `null` on any non-2xx, non-JSON, or network failure. Shared by
287
- * the child-lifecycle methods so their failure semantics stay identical. Uses
288
- * the longer lifecycle timeout since a spawn/recycle can take ~30s.
289
- */
290
- private postJson;
291
- /**
292
- * Continuously monitor server stats at specified interval.
293
- *
294
- * @param callback - Function called with stats on each interval
295
- * @param intervalMs - Milliseconds between checks (default: 5000). Must be a
296
- * finite number of at least 100 ms — lower values would hot-loop the server.
297
- * @returns Function to stop monitoring
298
- * @throws {ComputeError} `INVALID_CONFIG` if `intervalMs` is not a finite number >= 100.
299
- *
300
- * @example
301
- * ```typescript
302
- * const stopMonitoring = stats.monitor((data) => {
303
- * console.log('Server stats:', data);
304
- * }, 3000);
305
- *
306
- * // Later...
307
- * stopMonitoring();
308
- * ```
309
- */
310
- monitor(callback: (stats: Awaited<ReturnType<typeof this.getServerStats>>) => void, intervalMs?: number): () => void;
311
- /**
312
- * Disposes of all resources and stops all active monitors.
313
- * Call this when you're done using the stats instance.
314
- */
315
- dispose(): Promise<void>;
316
- /**
317
- * Ensures the instance hasn't been disposed.
318
- */
319
- private ensureNotDisposed;
320
- }
321
- //#endregion
322
- //#region src/grasshopper/types/inputs.d.ts
323
- type DataTreePath = `{${string}}`;
324
- interface DataItem {
325
- type: string;
326
- data: string;
327
- id: string;
328
- }
329
- type DataTreeDefault<T = any> = { [K in DataTreePath]?: T[]; };
330
- type InnerTreeData = { [path in DataTreePath]: DataItem[]; };
331
- /**
332
- * Tree with parameter metadata (used in compute requests and responses).
333
- *
334
- * Field casing varies by server branch: stock mcneel compute (8.x/9.x)
335
- * serializes `Resthopper.IO.DataTree` in PascalCase (`ParamName`/`InnerTree`
336
- * — the C# class carries no `[JsonProperty]` attributes), while
337
- * camelCase-serializing forks return `paramName`/`innerTree` instead. This
338
- * client always *sends* PascalCase (see `DataTree.toCompute()` in
339
- * `data-tree.ts`), so the PascalCase fields remain the canonical/required
340
- * shape; the optional camelCase fields exist so responses from camelCase
341
- * forks are representable without casts. Code that must read trees across
342
- * both server families should use `readField`/`hasField`
343
- * (`@/core/utils/read-field`, case-insensitive) rather than direct property
344
- * access — `warnOnEmptyInnerTrees` in `solve.ts` is the reference example.
345
- */
346
- interface DataTree {
347
- /** PascalCase — stock mcneel servers, and the request shape this client sends. */
348
- InnerTree: InnerTreeData;
349
- /** PascalCase — stock mcneel servers, and the request shape this client sends. */
350
- ParamName: string;
351
- /** camelCase — sent instead of `InnerTree` by camelCase server forks. */
352
- innerTree?: InnerTreeData;
353
- /** camelCase — sent instead of `ParamName` by camelCase server forks. */
354
- paramName?: string;
355
- }
356
- type OutputType = 'System.String' | 'System.Double' | 'System.Int32' | 'System.Boolean' | 'Rhino.Geometry.Point3d' | 'Rhino.Geometry.Line' | 'Rhino.Geometry.Circle' | 'Rhino.Geometry.Arc' | 'Rhino.Geometry.NurbsCurve' | 'Rhino.Geometry.Brep' | 'Rhino.Geometry.Mesh' | 'Rhino.Geometry.Vector3d' | 'Rhino.Geometry.Plane' | 'Rhino.Geometry.Box' | (string & {});
357
- /**
358
- * Union type for all possible default value types
359
- */
360
- type DefaultValue<T> = T | T[] | DataTreeDefault<T> | undefined | null;
361
- /**
362
- * Base properties common to all processed input types.
363
- * Note: `groupName` and `id` require the custom Rhino Compute branch.
364
- */
365
- interface BaseInputType {
366
- description: string;
367
- name: string;
368
- nickname: string | null;
369
- treeAccess: boolean;
370
- /**
371
- * Name of the group this parameter belongs to.
372
- * @requires Custom branch of compute.rhino3d
373
- */
374
- groupName?: string;
375
- /**
376
- * Unique identifier for the parameter.
377
- * @requires Custom branch of compute.rhino3d
378
- */
379
- id?: string;
380
- }
381
- /**
382
- * Numeric input type (Number or Integer)
383
- */
384
- interface NumericInputType extends BaseInputType {
385
- paramType: 'Number' | 'Integer';
386
- minimum?: number | null;
387
- maximum?: number | null;
388
- atLeast?: number | null;
389
- atMost?: number | null;
390
- stepSize?: number | null;
391
- default: DefaultValue<number>;
392
- }
393
- /**
394
- * Text input type
395
- */
396
- interface TextInputType extends BaseInputType {
397
- paramType: 'Text';
398
- default: DefaultValue<string>;
399
- }
400
- /**
401
- * Boolean input type
402
- */
403
- interface BooleanInputType extends BaseInputType {
404
- paramType: 'Boolean';
405
- default: DefaultValue<boolean>;
406
- }
407
- /**
408
- * Geometry input type (generic geometry)
409
- */
410
- interface GeometryInputType extends BaseInputType {
411
- paramType: 'Geometry';
412
- default: DefaultValue<object | string>;
413
- }
414
- /**
415
- * ValueList input type (dropdown/select)
416
- */
417
- interface ValueListInputType extends BaseInputType {
418
- paramType: 'ValueList';
419
- values: Record<string, string>;
420
- default?: string;
421
- }
422
- /**
423
- * File input type
424
- */
425
- interface FileInputType extends BaseInputType {
426
- paramType: 'File';
427
- acceptedFormats?: string[];
428
- default: DefaultValue<object | string>;
429
- }
430
- /**
431
- * Color input type (stored as hex string)
432
- */
433
- interface ColorInputType extends BaseInputType {
434
- paramType: 'Color';
435
- default: DefaultValue<string>;
436
- }
437
- /**
438
- * Discriminated union of all input parameter types
439
- */
440
- type InputParam = NumericInputType | BooleanInputType | TextInputType | ValueListInputType | GeometryInputType | FileInputType | ColorInputType;
441
- //#endregion
442
- //#region src/grasshopper/types/schema.d.ts
443
- type RhinoModelUnit = 'None' | 'Microns' | 'Millimeters' | 'Centimeters' | 'Decimeters' | 'Meters' | 'Kilometers' | 'Mils' | 'Inches' | 'Feet' | 'Yards' | 'Miles' | 'CustomUnits' | 'Unset';
444
- /**
445
- * Base Grasshopper schema properties shared by config, args, and response
446
- */
447
- interface GrasshopperBaseSchema {
448
- /** Absolute tolerance used in computation */
449
- absolutetolerance?: number | null;
450
- /** Angular tolerance used in computation */
451
- angletolerance?: number | null;
452
- /** Model units used */
453
- modelunits?: RhinoModelUnit | null;
454
- /** Data version (7 or 8) */
455
- dataversion?: 7 | 8 | null;
456
- /** Whether to use cached solution */
457
- cachesolve?: boolean | null;
458
- /**
459
- * Opt-in: cache a solve even when the definition reported GH errors. Default
460
- * (false/unset) means errored solves are never cached server-side. Some
461
- * definitions throw GH errors by design (a guarded Python component, a
462
- * filtered branch) while still producing correct geometry — set this so those
463
- * still benefit from the server's solve cache. Only meaningful with
464
- * `cachesolve`. Requires a server that honors it (VektorNode fork).
465
- */
466
- cacheerroredsolves?: boolean | null;
467
- }
468
- /**
469
- * Where a Selva-family plugin running inside the solve may POST live events, and
470
- * the bearer it presents. The VektorNode fork hands these to the document as
471
- * constants; a stock server ignores the block. Never echoed in the response.
472
- */
473
- interface SelvaEventTarget {
474
- url: string;
475
- solveId: string;
476
- token: string;
477
- }
478
- /**
479
- * Definition source (used in args and response)
480
- */
481
- interface GrasshopperDefinitionSource {
482
- /** Base64 encoded algorithm (if embedded) */
483
- algo?: string | null;
484
- /** URL pointer to definition file */
485
- pointer?: string | null;
486
- /** Filename of the definition */
487
- filename?: string | null;
488
- }
489
- /**
490
- * Configuration for Grasshopper compute operations
491
- * Combines server config with optional Grasshopper-specific computation settings
492
- *
493
- * Note: The definition source (pointer/algo) is NOT part of config.
494
- * Instead, pass the definition directly to methods like solve(), getIO(), etc.
495
- */
496
- interface GrasshopperComputeConfig extends ComputeConfig {
497
- /** Absolute tolerance used in computation */
498
- absolutetolerance?: number | null;
499
- /** Angular tolerance used in computation */
500
- angletolerance?: number | null;
501
- /** Model units used */
502
- modelunits?: RhinoModelUnit | null;
503
- /** Data version (7 or 8) */
504
- dataversion?: 7 | 8 | null;
505
- /** Whether to use cached solution */
506
- cachesolve?: boolean | null;
507
- /**
508
- * Opt-in: cache a solve even when the definition reported GH errors. See
509
- * {@link GrasshopperBaseSchema.cacheerroredsolves}. Only meaningful with
510
- * `cachesolve`.
511
- */
512
- cacheerroredsolves?: boolean | null;
513
- /** Per-solve live-event callback; see {@link SelvaEventTarget}. */
514
- selvaevents?: SelvaEventTarget | null;
515
- }
516
- /**
517
- * Arguments sent to Grasshopper compute endpoint
518
- * Includes config options + definition source + input values
519
- */
520
- interface GrasshopperRequestSchema extends GrasshopperBaseSchema, GrasshopperDefinitionSource {
521
- /** Input values organized by parameter */
522
- values?: DataTree[];
523
- /** Per-solve live-event callback; see {@link SelvaEventTarget}. */
524
- selvaevents?: SelvaEventTarget | null;
525
- }
526
- /**
527
- * Response from Grasshopper compute server
528
- * Includes all schema fields + computed results
529
- *
530
- * `pointer` is deliberately excluded (`Omit`): the solve layer (`runSolve` in
531
- * `solve.ts`) splits the server's echoed `pointer` off as the solve's
532
- * `cacheKey` and strips it from the returned response, so client-returned
533
- * responses never carry it.
534
- *
535
- * The schema-echo fields (`cachesolve`/`modelunits`/`dataversion`) stay
536
- * optional as inherited from {@link GrasshopperBaseSchema}: the server echoes
537
- * them back when set, but nothing client-side enforces their presence — don't
538
- * rely on them without a fallback.
539
- */
540
- interface GrasshopperComputeResponse extends GrasshopperBaseSchema, Omit<GrasshopperDefinitionSource, 'pointer'> {
541
- /**
542
- * Model units the definition was solved in. Every conforming server response
543
- * carries this (it drives downstream scaling, e.g. the webdisplay parser),
544
- * but note it is not validated client-side — a non-conforming server or
545
- * hand-built mock may omit it at runtime.
546
- */
547
- modelunits: RhinoModelUnit;
548
- /**
549
- * The server echoes the request's full base64 definition back as `algo`, but the client strips
550
- * it before returning — retaining it would pin a multi-MB copy of the definition per response,
551
- * multiplied by every cache that holds responses. Always `undefined` on client-returned
552
- * responses (inherited optional field from {@link GrasshopperDefinitionSource}).
553
- */
554
- algo?: string | null;
555
- /** Filename of the definition (always present in response) */
556
- filename: string | null;
557
- /** Recursion level used */
558
- recursionlevel?: number;
559
- /** Output values organized by parameter */
560
- values: DataTree[];
561
- /** Computation errors */
562
- errors?: string[];
563
- /** Computation warnings */
564
- warnings?: string[];
565
- /** Set by the VektorNode fork when a Selva plugin judged the solve; see {@link SelvaResponseBlock}. */
566
- selva?: SelvaResponseBlock | null;
567
- }
568
- /**
569
- * The Selva plugin's verdict on a solve, which the VektorNode fork copies verbatim into the
570
- * response. `outcome` is `SolveOutcome` from `@selvajs/schemas`, typed loosely here because
571
- * this package does not depend on it. A blocked or aborted outcome comes with empty `values`.
572
- * Absent from a stock server, an older plugin, or a definition without a Selva component.
573
- */
574
- interface SelvaResponseBlock {
575
- outcome?: unknown;
576
- }
577
- /**
578
- * Output parameter
579
- */
580
- interface OutputParamSchema {
581
- name: string;
582
- nickname: string | null;
583
- paramType: string;
584
- /**
585
- * Grasshopper parameter instance GUID
586
- */
587
- id: string;
588
- }
589
- /**
590
- * Input parameter
591
- */
592
- interface InputParamSchema {
593
- /**
594
- * Grasshopper parameter instance GUID
595
- */
596
- id: string;
597
- name: string;
598
- nickname: string | null;
599
- description: string;
600
- paramType: string;
601
- treeAccess: boolean;
602
- minimum: number | null;
603
- maximum: number | null;
604
- atLeast: number;
605
- atMost: number;
606
- stepSize?: number;
607
- default: any;
608
- /**
609
- * Key-value pairs for dropdown options
610
- */
611
- values?: Record<string, string>;
612
- /**
613
- * Accepted file formats for File input
614
- */
615
- acceptedFormats?: string[];
616
- groupName?: string | null;
617
- }
618
- //#endregion
619
- //#region src/grasshopper/types/outputs.d.ts
620
- /**
621
- * Parsed input/output structure with raw schemas.
622
- *
623
- * `loadWarnings` / `loadErrors` carry the server's definition-load diagnostics
624
- * (missing plugin, broken component, etc.) from the `/io` response. They are
625
- * distinct from per-input parse failures (`InputParseError`): these come from
626
- * the server loading the definition, those from the client typing an input.
627
- */
628
- interface GrasshopperParsedIORaw {
629
- inputs: InputParamSchema[];
630
- outputs: OutputParamSchema[];
631
- /** Server-side definition-load warnings, if any. */
632
- loadWarnings?: string[];
633
- /** Server-side definition-load errors, if any (e.g. missing plugin). */
634
- loadErrors?: string[];
635
- }
636
- /**
637
- * Per-input parse failure. The corresponding entry in `inputs` was filled
638
- * with a safe default so the rest of the pipeline can keep going — but the
639
- * caller should surface this so the user knows their definition has a
640
- * misconfigured parameter.
641
- */
642
- interface InputParseError {
643
- /** The input's `name` (or `'unknown'` if the schema didn't have one). */
644
- inputName: string;
645
- /** The declared paramType from the raw schema. */
646
- paramType: string;
647
- /** Human-readable reason from the underlying ComputeError. */
648
- message: string;
649
- /** Error code from the underlying ComputeError, if available. */
650
- code?: string;
651
- }
652
- /**
653
- * Parsed input/output structure with processed types.
654
- *
655
- * `parseErrors` is populated when one or more inputs failed validation and
656
- * fell back to a safe default. The result is still usable, but the UI should
657
- * surface these so the user can fix their definition.
658
- */
659
- interface GrasshopperParsedIO {
660
- inputs: InputParam[];
661
- outputs: OutputParamSchema[];
662
- parseErrors?: InputParseError[];
663
- /**
664
- * Server-side definition-load warnings from the `/io` response (e.g. an
665
- * obsolete component). Surface these so the user understands a degraded IO
666
- * list. Distinct from `parseErrors` (client-side input typing failures).
667
- */
668
- loadWarnings?: string[];
669
- /**
670
- * Server-side definition-load errors from the `/io` response (e.g. a missing
671
- * plugin that left inputs unresolved). When present, the inputs/outputs may
672
- * be incomplete — the user needs to fix their server/definition.
673
- */
674
- loadErrors?: string[];
675
- }
676
- //#endregion
677
- //#region src/grasshopper/scheduler/types.d.ts
678
- /**
679
- * Scheduling mode — controls how concurrent `solve()` calls interact.
680
- *
681
- * - `latest-wins`: One in flight at a time. New calls supersede any pending
682
- * call (in-flight one is aborted). Optimal for slider scrubs / live UIs.
683
- * - `queue`: FIFO queue. Each solve runs to completion. Concurrency capped
684
- * by `maxConcurrent`. Use for "submit job" flows where every request matters.
685
- * - `parallel`: No scheduling — calls run concurrently up to `maxConcurrent`.
686
- * Closest to plain `client.solve()` but with shared cancel/state.
687
- */
688
- type SchedulerMode = 'latest-wins' | 'queue' | 'parallel';
689
- interface CacheOptions {
690
- /**
691
- * Total byte budget for retained responses, evicted LRU. The only size bound
692
- * there is: responses range KB→100s of MB, so memory is the constraint that
693
- * matters and an entry count would only obscure it.
694
- *
695
- * Sizing uses the response's wire size (JSON text length, recorded at the
696
- * fetch boundary — no re-serialization); a response without that hint
697
- * (custom executor) is sized by a one-off `JSON.stringify`. A single
698
- * response larger than the whole budget is served but never retained.
699
- *
700
- * Required and must be > 0 — to disable caching, pass `cache: false`.
701
- */
702
- maxBytes: number;
703
- /**
704
- * Time-to-live in ms. Set to `0` for no expiry (default, and the right
705
- * choice for a solve keyed by immutable definition+inputs — expiry there
706
- * only buys a paid re-solve of an identical answer). Meaningful only when a
707
- * definition reaches outside its inputs (external data source, clock), where
708
- * a stale result is genuinely wrong rather than merely old.
709
- *
710
- * Expiry is evaluated lazily on read: an expired entry keeps its bytes
711
- * counted against `maxBytes` until that exact key is next consulted.
712
- */
713
- ttlMs?: number;
714
- /**
715
- * Cache responses that carry Grasshopper `errors`. Default `true`: an
716
- * errored solve is a valid, deterministic result — definitions raise GH
717
- * errors by design (guarded components, validation branches), so replaying
718
- * one from cache is correct. Set `false` for parity with Rhino's opt-in
719
- * `cacheerroredsolves` server flag, e.g. when a definition's errors are
720
- * transient (external data sources) rather than functions of the inputs.
721
- */
722
- cacheErroredSolves?: boolean;
723
- }
724
- interface SolveSchedulerOptions {
725
- mode?: SchedulerMode;
726
- maxConcurrent?: number;
727
- /**
728
- * Backpressure — cap on how many calls may wait in the FIFO queue (i.e.
729
- * excluding the ones already in flight). When the queue is full, a new
730
- * `solve()` is rejected immediately with `code: QUEUE_FULL` (retryable, meant to
731
- * map to HTTP 503 + Retry-After) instead of piling up unbounded. Bounds the
732
- * miss path under load. Only applies to `queue` / `parallel` modes —
733
- * `latest-wins` has an intrinsic depth of 1. Default: unbounded.
734
- */
735
- maxQueueDepth?: number;
736
- /**
737
- * Backpressure — max time (ms) a call may sit queued before it starts
738
- * executing. If it's still waiting after this long it's rejected with
739
- * `code: QUEUE_TIMEOUT` rather than burning compute on a stale request.
740
- * Bounds tail latency. Only applies to `queue` / `parallel` modes. Default:
741
- * no deadline.
742
- */
743
- queueWaitMs?: number;
744
- timeoutMs?: number;
745
- retry?: RetryPolicy;
746
- /**
747
- * Response caching keyed by hash of (definition, dataTree). Omit or pass
748
- * `false` to disable; otherwise a byte budget is required, so an unbounded
749
- * cache can't be enabled by accident.
750
- */
751
- cache?: false | CacheOptions;
752
- /**
753
- * Reuse the server's definition cache key so a large (base64/binary)
754
- * definition is uploaded once and subsequent solves reference it by
755
- * `pointer` instead of re-sending the full payload. Hugely cheaper for
756
- * multi-MB definitions on a live UI (slider scrubs, etc.).
757
- *
758
- * Requires a `cacheKeyExecutor` to be supplied (the client wires one). Has no
759
- * effect for URL-pointer definitions (already a reference). On a server-side
760
- * cache miss the executor transparently falls back to a full upload, so this
761
- * is safe to leave on. Default: `true` when a `cacheKeyExecutor` is present.
762
- */
763
- reuseServerDefinitionCache?: boolean;
764
- /** Lifecycle hooks — fired in order. Errors thrown by hooks are logged, not rethrown. */
765
- onStart?: (ctx: SolveContext) => void;
766
- onSettle?: (ctx: SolveContext, result: SolveResult) => void;
767
- onSuperseded?: (ctx: SolveContext) => void;
768
- }
769
- interface SolveContext {
770
- /** Stable hash of (definition, dataTree). */
771
- key: string;
772
- /** Timestamp when scheduler.solve() was called. */
773
- enqueuedAt: number;
774
- /** Timestamp when execution actually started (after queueing). */
775
- startedAt: number | null;
776
- }
777
- type SolveResult = {
778
- status: 'success';
779
- response: GrasshopperComputeResponse;
780
- durationMs: number;
781
- fromCache: boolean;
782
- /**
783
- * Definition-cache telemetry for a real compute call (not a Selva-cache
784
- * `fromCache` hit). `false` → the server reused its cached definition via
785
- * the pointer (no upload); `true` → the pointer was cold/stale so the full
786
- * definition was re-uploaded. `undefined` when the server-definition-cache
787
- * fast path didn't run (reuse disabled, or a non-reusable definition such
788
- * as a remote URL).
789
- */
790
- definitionReuploaded?: boolean;
791
- } | {
792
- status: 'error';
793
- error: ComputeError;
794
- durationMs: number;
795
- } | {
796
- status: 'superseded';
797
- };
798
- type SolveExecutor = (definition: SolveDefinition, dataTree: DataTree[], config: GrasshopperComputeConfig) => Promise<GrasshopperComputeResponse>;
799
- /**
800
- * Cache-key-aware executor. When `cacheKey` is provided, the executor solves by
801
- * reference (`pointer: cacheKey`) and falls back to a full upload on a server
802
- * cache miss. Always reports the (possibly refreshed) `cacheKey` so the
803
- * scheduler can update its definition→key map, plus whether the fast path
804
- * `missed` (for telemetry). When `cacheKey` is null it's a first solve — upload
805
- * fully and capture the key the server assigns.
806
- *
807
- * Supplied by the client (which owns the solve primitives); the scheduler stays
808
- * decoupled from the transport.
809
- */
810
- type CacheKeyExecutor = (definition: SolveDefinition, dataTree: DataTree[], cacheKey: string | null, config: GrasshopperComputeConfig) => Promise<{
811
- response: GrasshopperComputeResponse;
812
- cacheKey: string | null;
813
- missed: boolean;
814
- }>;
815
- //#endregion
816
- //#region src/grasshopper/scheduler/solve-scheduler.d.ts
817
- /**
818
- * Robust scheduler for Grasshopper solves.
819
- *
820
- * Sits between your application code and the underlying compute call,
821
- * adding:
822
- * - Configurable scheduling (latest-wins for sliders, queue for jobs)
823
- * - Backpressure (bounded queue depth + queue-wait deadline) for the miss path
824
- * - In-flight cancellation (per-call signal + cancelAll)
825
- * - Optional response caching for repeated inputs
826
- * - Lifecycle hooks for UI indicators (start / settle / superseded)
827
- * - State observability via subscribe()
828
- *
829
- * Multiple schedulers can share a single GrasshopperClient — typically one
830
- * per UI surface (e.g. one for slider scrubs, one for long-running submits).
831
- *
832
- * @example
833
- * ```ts
834
- * const scheduler = client.createScheduler({ mode: 'latest-wins', timeoutMs: 30_000 });
835
- *
836
- * // From a slider handler:
837
- * scheduler.solve(definition, tree).then((result) => {
838
- * updateMeshes(result);
839
- * }).catch((err) => {
840
- * if (err.code !== 'SUPERSEDED') showError(err);
841
- * });
842
- *
843
- * // From a UI binding:
844
- * scheduler.subscribe(() => {
845
- * showSpinner = scheduler.isSolving;
846
- * });
847
- * ```
848
- */
849
- export declare class SolveScheduler {
850
- private readonly executor;
851
- private readonly baseConfig;
852
- private readonly mode;
853
- /**
854
- * Mutable via {@link setMaxConcurrent}: the compute server's worker pool can grow
855
- * or shrink while this scheduler is alive, and the dispatch loops re-read this on
856
- * every pass rather than capturing it.
857
- */
858
- private maxConcurrent;
859
- private readonly maxQueueDepth;
860
- private readonly queueWaitMs;
861
- private readonly timeoutMs;
862
- private readonly retry;
863
- private readonly cacheEnabled;
864
- private readonly cacheMaxBytes;
865
- private readonly cacheTtl;
866
- private readonly cacheErroredSolves;
867
- private readonly cache;
868
- /** Sum of `sizeBytes` across retained cache entries. */
869
- private cacheBytes;
870
- /**
871
- * Cumulative hit/miss/eviction counters for {@link cacheStats}. Deliberately
872
- * NOT reset by `clearCache()` — they measure this scheduler's whole lifetime,
873
- * so a hit rate stays comparable across a session rather than restarting at
874
- * every clear.
875
- */
876
- private cacheHits;
877
- private cacheMisses;
878
- private cacheEvictions;
879
- /** Optional cache-key-aware executor and whether server-def-cache reuse is on. */
880
- private readonly cacheKeyExecutor?;
881
- private readonly reuseServerDefinitionCache;
882
- /** definition identity → server cache key (`pointer`) learned from past solves. */
883
- private readonly serverCacheKeys;
884
- private readonly onStart?;
885
- private readonly onSettle?;
886
- private readonly onSuperseded?;
887
- private readonly subscribers;
888
- private readonly inFlight;
889
- private pendingForLatestWins;
890
- private readonly fifoQueue;
891
- private _lastResult;
892
- private _lastError;
893
- private _lastDurationMs;
894
- /** Ordinal handed to each solve() call. */
895
- private solveSeq;
896
- /** seq of the solve that last wrote _lastResult/_lastError — see writeLastState. */
897
- private lastStateSeq;
898
- private disposed;
899
- constructor(executor: SolveExecutor, baseConfig: GrasshopperComputeConfig, options?: SolveSchedulerOptions, cacheKeyExecutor?: CacheKeyExecutor);
900
- get isSolving(): boolean;
901
- get hasPending(): boolean;
902
- get inFlightCount(): number;
903
- get queueDepth(): number;
904
- get lastResult(): GrasshopperComputeResponse | null;
905
- get lastError(): ComputeError | null;
906
- get lastDurationMs(): number | null;
907
- /**
908
- * Adjust how many solves may run at once, for when the compute server's worker
909
- * pool changes size after this scheduler was built.
910
- *
911
- * Raising it drains queued work immediately. Lowering it never interrupts work
912
- * already in flight — those finish above the new limit, and the cap applies from
913
- * the next dispatch. Values below 1 are clamped, since 0 would wedge the queue.
914
- */
915
- setMaxConcurrent(value: number): void;
916
- /** Current concurrency cap — reflects any {@link setMaxConcurrent} adjustment. */
917
- getMaxConcurrent(): number;
918
- /** Subscribe to state changes. */
919
- subscribe(listener: () => void): () => void;
920
- private notify;
921
- /**
922
- * Schedule a solve. Returns a promise that:
923
- * - Resolves with the compute response on success.
924
- * - Rejects with `ComputeError` on failure.
925
- * - Rejects with `code: ErrorCodes.SUPERSEDED` when the call was canceled because
926
- * newer values arrived (latest-wins mode).
927
- * - Rejects with `code: ErrorCodes.ABORTED` when the call was canceled via
928
- * caller-supplied signal or `cancelAll()`.
929
- * - Rejects with `code: ErrorCodes.QUEUE_FULL` when `maxQueueDepth` is set and
930
- * the queue was already full (backpressure; `statusCode: 503`).
931
- * - Rejects with `code: ErrorCodes.QUEUE_TIMEOUT` when `queueWaitMs` is set and
932
- * the call sat queued longer than that before starting (`statusCode: 503`).
933
- *
934
- * Caller-supplied `signal` cancels just this call (rejects with `ABORTED`) —
935
- * including while the call is still queued, before execution starts.
936
- *
937
- * A {@link DefinitionRef} definition is keyed by its `key` (result cache and
938
- * server-pointer map alike) without materializing bytes — `load()` runs only
939
- * when an upload is unavoidable. Its immutability contract is trusted here:
940
- * a reused key serves the other content's cached solve.
941
- *
942
- * Responses served from the cache (and via `lastResult`) are shared objects,
943
- * not copies — treat them as immutable. Mutating one poisons every later
944
- * cache hit for that key.
945
- *
946
- * Partial-success contract: unlike `GrasshopperClient.solve()`, which throws
947
- * `COMPUTATION_ERROR` when the response carries solver errors, this RESOLVES
948
- * with the response as-is — check `response.errors` yourself if a partial
949
- * success must not be treated as a result (see `cacheErroredSolves` for the
950
- * caching side of the same distinction).
951
- */
952
- solve(definition: SolveDefinition, dataTree: DataTree[], options?: {
953
- signal?: AbortSignal;
954
- selvaevents?: SelvaEventTarget;
955
- }): Promise<GrasshopperComputeResponse>;
956
- /**
957
- * Record last-result state, but only if no newer solve has written since —
958
- * a slow solve settling late must not overwrite the state a newer solve
959
- * (or cache hit) already published.
960
- */
961
- private writeLastState;
962
- /** latest-wins: supersede the pending item and abort everything in flight. */
963
- private supersedeCurrent;
964
- /** Settle a still-queued item as ABORTED and remove it from its queue. */
965
- private abortQueuedItem;
966
- /**
967
- * Backpressure: settle an incoming item as QUEUE_FULL without ever enqueuing
968
- * it. The structured context lets an HTTP layer map it to 503 + Retry-After.
969
- */
970
- private shedAsQueueFull;
971
- /**
972
- * Arm the queue-wait deadline for an item about to be queued. If the item is
973
- * still waiting when it fires, it's rejected as QUEUE_TIMEOUT and removed from
974
- * the queue. Cleared on execute/settle via {@link clearQueueWaitTimer}.
975
- */
976
- private armQueueWaitTimer;
977
- /** Clear a queued item's wait-deadline timer, if one is pending. */
978
- private clearQueueWaitTimer;
979
- private enqueue;
980
- private execute;
981
- /**
982
- * Run the solve, using the server-definition-cache fast path when it's
983
- * enabled and the definition is reusable. Learns/updates the definition's
984
- * server cache key from the result so later solves can reference it.
985
- *
986
- * `definitionHash` is the {@link hashDefinition} result already computed at
987
- * `solve()` entry — threaded through rather than recomputed, so each solve
988
- * pays exactly one linear pass over the definition (issue 57).
989
- */
990
- private runExecutor;
991
- private drainNext;
992
- private supersede;
993
- private makeAbortError;
994
- /**
995
- * Settle a pending/in-flight item exactly once with an error.
996
- *
997
- * A solve promise can be settled from four concurrent sources — the executor
998
- * resolving, the executor rejecting, `supersede`, and `cancelAll` — and a JS
999
- * promise silently ignores a second settle. This guard is the single place the
1000
- * settle-once invariant lives: it makes the *first* settle win and reports
1001
- * whether this call was that winner, so callers fire their own hook only when
1002
- * they actually settled. Any new settle path must go through here (or
1003
- * {@link settleSuccess}) so the guard can't be forgotten.
1004
- *
1005
- * @returns `true` if this call settled the item; `false` if it was already settled.
1006
- */
1007
- private settleError;
1008
- /**
1009
- * Settle a pending/in-flight item exactly once with a successful response.
1010
- * The success counterpart to {@link settleError}; see it for the invariant.
1011
- *
1012
- * @returns `true` if this call settled the item; `false` if it was already settled.
1013
- */
1014
- private settleSuccess;
1015
- /** Detach the queued-phase abort listener, if one is still attached. */
1016
- private removeQueuedAbortHandler;
1017
- private isAbortLikeError;
1018
- private normalizeExecutionError;
1019
- /** Cancel everything — in-flight and pending. */
1020
- cancelAll(): void;
1021
- private rejectAsAborted;
1022
- private readCache;
1023
- private writeCache;
1024
- /** Remove one cache entry and release its bytes from the running total. */
1025
- private dropCacheEntry;
1026
- clearCache(): void;
1027
- /**
1028
- * Observability snapshot of the solve cache: current size plus lifetime
1029
- * hit/miss/eviction counters.
1030
- *
1031
- * `hits`/`misses` count cache CONSULTATIONS, so `hits / (hits + misses)` is the
1032
- * hit rate. A TTL-expired entry counts as a miss (the solve runs either way).
1033
- * `evictions` counts only entries dropped under size/byte pressure — not
1034
- * replace-in-place writes or TTL expiry, which are not capacity signals.
1035
- * Counters are cumulative and survive `clearCache()`.
1036
- */
1037
- cacheStats(): {
1038
- entries: number;
1039
- bytes: number;
1040
- hits: number;
1041
- misses: number;
1042
- evictions: number;
1043
- };
1044
- dispose(): void;
1045
- private runHook;
1046
- }
1047
- //#endregion
1048
- //#region src/grasshopper/client/grasshopper-client.d.ts
1049
- /**
1050
- * Per-call options that override the client's default ComputeConfig values.
1051
- *
1052
- * Use these for per-request control without mutating the client config:
1053
- * - `signal` — cancel a specific solve (e.g. when a slider value is superseded)
1054
- * - `timeoutMs` — extend timeout for a long-running solve, or pass `0` to disable
1055
- * - `retry` — override retry policy for this call only
1056
- */
1057
- interface SolveOptions {
1058
- signal?: AbortSignal;
1059
- timeoutMs?: number;
1060
- retry?: RetryPolicy;
1061
- /** Per-solve live-event callback, forwarded onto the request body. */
1062
- selvaevents?: SelvaEventTarget;
1063
- }
1064
- /**
1065
- * GrasshopperClient provides a simple API for interacting with a Rhino Compute server and grasshopper.
1066
- *
1067
- * @public This is the recommended high-level API for Rhino Compute operations.
1068
- *
1069
- * **Security Warning:**
1070
- * Using this client in a browser environment exposes your server URL and API key to users.
1071
- * For production, use this library server-side or proxy requests through your own backend.
1072
- *
1073
- * @example
1074
- * ```typescript
1075
- * const client = await GrasshopperClient.create({
1076
- * serverUrl: 'http://localhost:6500',
1077
- * apiKey: 'your-api-key'
1078
- * });
1079
- *
1080
- * try {
1081
- * const result = await client.solve(definitionUrl, { x: 1, y: 2 });
1082
- * } finally {
1083
- * await client.dispose(); // Clean up resources
1084
- * }
1085
- * ```
1086
- */
1087
- declare class GrasshopperClient {
1088
- private readonly config;
1089
- readonly serverStats: ComputeServerStats;
1090
- private disposed;
1091
- /**
1092
- * Per-probe timeout for the `create()` liveness gate. A healthy `GET /` on the
1093
- * proxy answers in milliseconds; this bound only ever applies to a server that
1094
- * is not answering, where every extra second is multiplied by the retry count
1095
- * and paid by whoever is waiting on the solve.
1096
- */
1097
- private static readonly CREATE_PROBE_TIMEOUT_MS;
1098
- private constructor();
1099
- /**
1100
- * Creates and initializes a GrasshopperClient with server validation.
1101
- *
1102
- * The pre-flight liveness probe (a GET on the proxy root `/`) is a
1103
- * single-sample boolean gate that reads a cold or briefly-busy-but-up server
1104
- * as offline. To avoid failing construction on that transient class, the probe
1105
- * is retried with a short exponential backoff before giving up.
1106
- *
1107
- * Retries stop early when {@link classifyProbeFailure} says waiting cannot
1108
- * change the answer — connection refused, or a 401/403. This runs in front of
1109
- * a user who clicked Solve, so the retry ladder must not spend its whole
1110
- * budget confirming that a machine is switched off.
1111
- *
1112
- * Each probe is bounded by {@link CREATE_PROBE_TIMEOUT_MS} rather than the
1113
- * stats default: a healthy `GET /` answers in milliseconds, so a longer
1114
- * per-probe timeout only multiplies the wait when the server is unreachable.
1115
- *
1116
- * @throws {ComputeError} with code NETWORK_ERROR if the server stays
1117
- * unreachable across all attempts. `context.probeVerdict` carries the
1118
- * {@link ProbeVerdict} so callers can render a specific cause.
1119
- * @throws {ComputeError} with code INVALID_CONFIG if configuration is invalid
1120
- */
1121
- static create(config: GrasshopperComputeConfig): Promise<GrasshopperClient>;
1122
- /**
1123
- * Gets the client's configuration.
1124
- * Useful for passing to lower-level functions.
1125
- */
1126
- getConfig(): GrasshopperComputeConfig;
1127
- /**
1128
- * Get input/output parameters of a Grasshopper definition.
1129
- */
1130
- getIO(definition: string | Uint8Array): Promise<GrasshopperParsedIO>;
1131
- getRawIO(definition: string | Uint8Array): Promise<GrasshopperParsedIORaw>;
1132
- /**
1133
- * Run a compute job with a Grasshopper definition.
1134
- *
1135
- * @throws {ComputeError} with code INVALID_INPUT if definition is empty
1136
- * @throws {ComputeError} with code NETWORK_ERROR if server is offline
1137
- * @throws {ComputeError} with code COMPUTATION_ERROR if computation fails.
1138
- * On a partial-success response (some outputs computed, some errored) the
1139
- * error's `context.values` carries the outputs that did compute — pass
1140
- * `{ values } as GrasshopperComputeResponse` to the response processors to
1141
- * render them. `context.inputSummary` describes the inputs (param names,
1142
- * item counts, byte sizes) without pinning the full data tree.
1143
- */
1144
- solve(definition: SolveDefinition, dataTree: DataTree[], options?: SolveOptions): Promise<GrasshopperComputeResponse>;
1145
- /**
1146
- * Create a scheduler bound to this client. Use a scheduler for any UI surface
1147
- * that fires solves frequently (sliders, live editors) or that needs cancel
1148
- * semantics, response caching, or state observability.
1149
- *
1150
- * Multiple schedulers can be created from a single client — typically one per
1151
- * UI surface so their queues stay independent.
1152
- *
1153
- * @example
1154
- * ```ts
1155
- * const sliderScheduler = client.createScheduler({ mode: 'latest-wins' });
1156
- * const submitScheduler = client.createScheduler({ mode: 'queue', timeoutMs: 0, retry: { attempts: 1 } });
1157
- * ```
1158
- */
1159
- createScheduler(options?: SolveSchedulerOptions): SolveScheduler;
1160
- /**
1161
- * Disposes of client resources.
1162
- * Call this when you're done using the client.
1163
- */
1164
- dispose(): Promise<void>;
1165
- /**
1166
- * Ensures the client hasn't been disposed.
1167
- */
1168
- private ensureNotDisposed;
1169
- /**
1170
- * Validates and normalizes a compute configuration.
1171
- *
1172
- * @throws {ComputeError} with code INVALID_CONFIG if configuration is invalid
1173
- */
1174
- private normalizeComputeConfig;
1175
- }
1176
- //#endregion
1177
- //#region src/grasshopper/io/output/response-processors.d.ts
1178
- interface ParsedContext {
1179
- [key: string]: any;
1180
- }
1181
- interface GetValuesOptions {
1182
- parseValues?: boolean;
1183
- rhino?: any;
1184
- /**
1185
- * If true, only include values of type System.String in the result.
1186
- * Non-string types are filtered out.
1187
- */
1188
- stringOnly?: boolean;
1189
- }
1190
- interface GetValuesResult<T = ParsedContext> {
1191
- values: T;
1192
- /**
1193
- * Free every rhino3dm WASM object decoded into `values`. When a `rhino`
1194
- * instance was passed, decoded geometry lives on the WASM heap and is never
1195
- * garbage-collected — call this once the values are consumed, or the heap
1196
- * grows monotonically across solves. Idempotent; a no-op when nothing was
1197
- * decoded. `values` must not be used after disposal.
1198
- */
1199
- dispose: () => void;
1200
- }
1201
- //#endregion
1202
- //#region src/grasshopper/client/grasshopper-response-processor.d.ts
1203
- /**
1204
- * High-level wrapper for interacting with Grasshopper Compute responses.
1205
- *
1206
- * This class exposes a clean, consistent API for accessing parsed values,
1207
- * geometry, and produced files. It is designed to be the primary interface
1208
- * when working with Grasshopper results in client applications.
1209
- */
1210
- declare class GrasshopperResponseProcessor {
1211
- /**
1212
- * The raw compute response. Public so callers can hand it to a renderer-side parser — e.g.
1213
- * `getThreeMeshesFromComputeResponse` in `@selvajs/visualization/parse`, which replaced this
1214
- * class's former `extractMeshesFromResponse()`.
1215
- */
1216
- readonly response: GrasshopperComputeResponse;
1217
- /**
1218
- * Retained for call-signature compatibility. Its only consumer was the removed
1219
- * `extractMeshesFromResponse()`, which merged it into the parse options; pass `debug`
1220
- * directly to the parser in `@selvajs/visualization/parse` instead.
1221
- */
1222
- readonly debug: boolean;
1223
- constructor(
1224
- /**
1225
- * The raw compute response. Public so callers can hand it to a renderer-side parser — e.g.
1226
- * `getThreeMeshesFromComputeResponse` in `@selvajs/visualization/parse`, which replaced this
1227
- * class's former `extractMeshesFromResponse()`.
1228
- */
1229
- response: GrasshopperComputeResponse,
1230
- /**
1231
- * Retained for call-signature compatibility. Its only consumer was the removed
1232
- * `extractMeshesFromResponse()`, which merged it into the parse options; pass `debug`
1233
- * directly to the parser in `@selvajs/visualization/parse` instead.
1234
- */
1235
- debug?: boolean);
1236
- /**
1237
- * Extract all values in the response.
1238
- *
1239
- * @typeParam T - Expected structure of the return value. Defaults to a simple key/value map. (later cast as needed)
1240
- * @param byId - Key by parameter ID instead of name. Requires the VektorNode rhino.compute branch.
1241
- * @param options - Controls parsing behavior such as Rhino geometry decoding.
1242
- * @returns Parsed Grasshopper output values.
1243
- *
1244
- * @example
1245
- * ```ts
1246
- * const processor = new GrasshopperResponseProcessor(response);
1247
- * const { values } = processor.getValues();
1248
- * ```
1249
- *
1250
- */
1251
- getValues<T = ParsedContext>(byId?: boolean, options?: GetValuesOptions): GetValuesResult<T>;
1252
- /**
1253
- * Retrieve a specific value by parameter name or ID.
1254
- *
1255
- * @param selector - `{ byName }` for the human-readable name, `{ byId }` for the parameter GUID.
1256
- * @param options - Parsing configuration (e.g. disable parsing or enable Rhino).
1257
- * @returns Single parsed value, array of values, or undefined if the parameter is absent.
1258
- *
1259
- * `byId` requires the VektorNode rhino.compute branch.
1260
- *
1261
- * @example
1262
- * ```ts
1263
- * const schema = processor.getValue({ byName: 'Schema' });
1264
- * const output = processor.getValue({ byId: 'a4be1c1e-23f9-4c27-b942-7f3bb2c45c6f' });
1265
- * ```
1266
- */
1267
- getValue(selector: {
1268
- byName: string;
1269
- } | {
1270
- byId: string;
1271
- }, options?: GetValuesOptions): any;
1272
- /**
1273
- * REMOVED: `extractMeshesFromResponse()`. Mesh decoding lives in `@selvajs/visualization` now, so
1274
- * this package stays pure solve/data and carries no `three` dependency. Call the parser directly
1275
- * with the raw response:
1276
- *
1277
- * ```ts
1278
- * import { getThreeMeshesFromComputeResponse } from '@selvajs/visualization/parse';
1279
- *
1280
- * const meshes = await getThreeMeshesFromComputeResponse(processor.response, { rhino });
1281
- * scene.add(...meshes);
1282
- * ```
1283
- */
1284
- private getFileData;
1285
- /**
1286
- * Download all files generated by Grasshopper, optionally including
1287
- * additional user-provided files.
1288
- *
1289
- * Files are grouped under the specified folder name when downloaded.
1290
- *
1291
- * @param folderName - Name for the download directory.
1292
- * @param additionalFiles - Extra files to package (single file, array, or null).
1293
- *
1294
- * @example
1295
- * ```ts
1296
- * await processor.getAndDownloadFiles('gh-output');
1297
- * ```
1298
- *
1299
- * @example
1300
- * ```ts
1301
- * const extra = { name: 'notes.txt', data: 'Example' };
1302
- * await processor.getAndDownloadFiles('project', extra);
1303
- * ```
1304
- */
1305
- getAndDownloadFiles(folderName: string, additionalFiles?: FileBaseInfo[] | FileBaseInfo | null): Promise<void>;
1306
- }
1307
- //#endregion
1308
- //#region src/grasshopper/scheduler/stable-hash.d.ts
1309
- /**
1310
- * Deterministic stringify with sorted keys. {a:1,b:2} and {b:2,a:1} produce
1311
- * the same string. Safely handles circular references and non-finite numbers.
1312
- *
1313
- * The output is a cache key, so the invariant that matters is: two payloads
1314
- * that serialize differently on the wire must stringify differently here
1315
- * (false misses are harmless; false hits serve the wrong cached solve).
1316
- */
1317
- export declare function stableStringify(value: unknown): string;
1318
- /**
1319
- * Hash definition and data tree into a stable cache key.
1320
- *
1321
- * The definition is the *identity* of what we solve, so a binary definition is
1322
- * hashed over its full content (`fnv1aBytes`) — a length-only or sampled key
1323
- * would let two different `.gh` files collide and serve one's cached solve for
1324
- * the other. `.gh` files are small enough that a single linear pass is
1325
- * negligible. A {@link DefinitionRef} is keyed by its `key` alone — the
1326
- * caller-declared identity of immutable bytes — so no bytes are materialized
1327
- * or hashed at all.
1328
- *
1329
- * The key keeps the definition and tree hashes as separate parts rather than
1330
- * collapsing them into one 32-bit hash: a single FNV pass over the pair would
1331
- * birthday-collide quadratically in cache size, while requiring both 32-bit
1332
- * parts (plus lengths) to collide at once makes that negligible.
1333
- */
1334
- export declare function hashSolveInput(definition: SolveDefinition, dataTree: unknown): string;
1335
- /**
1336
- * Stable identity of a definition alone (no inputs) — used to key the
1337
- * server-cache-key map so the same definition reuses its `pointer` across solves
1338
- * with different inputs. Same full-content hashing as {@link hashSolveInput}: a
1339
- * binary definition is hashed over all its bytes so two distinct `.gh` files of
1340
- * equal length can't share a cache key. A {@link DefinitionRef} is keyed by its
1341
- * `key` verbatim (refs are short identities like UUIDs, safe as Map keys) —
1342
- * its immutability contract makes the key equivalent to a content hash.
1343
- */
1344
- export declare function hashDefinition(definition: SolveDefinition): string;
1345
- //#endregion
1346
- //#region src/grasshopper/solve.d.ts
1347
- /**
1348
- * Runs a Rhino Compute job using the provided tree prototypes and Grasshopper definition.
1349
- *
1350
- * @public Use this for direct compute control. For high-level API, use `GrasshopperClient.solve()`.
1351
- *
1352
- * @param dataTree - An array of `DataTree` objects representing the input data for the compute job.
1353
- * @param definition - The Grasshopper definition, which can be:
1354
- * - A URL string (e.g., 'https://example.com/definition.gh')
1355
- * - A base64-encoded string of the .gh file
1356
- * - A plain string (will be base64-encoded)
1357
- * - A Uint8Array of the .gh file (will be base64-encoded)
1358
- * - A `DefinitionRef` (bytes are loaded via `ref.load()` for the upload)
1359
- * @param config - Compute configuration (server URL, API key, etc. along with optional timeout, units, etc.)
1360
- * @returns An object containing the compute result and extracted file data.
1361
- *
1362
- * @example
1363
- * // Using a URL
1364
- * await solveGrasshopperDefinition(trees, 'https://example.com/definition.gh', config);
1365
- *
1366
- * // Using a base64 string
1367
- * await solveGrasshopperDefinition(trees, 'UEsDBBQAAAAIAL...', config);
1368
- *
1369
- * // Using binary data
1370
- * const fileData = new Uint8Array([...]);
1371
- * await solveGrasshopperDefinition(trees, fileData, config);
1372
- */
1373
- export declare function solveGrasshopperDefinition(dataTree: DataTree[], definition: SolveDefinition, config: GrasshopperComputeConfig): Promise<GrasshopperComputeResponse>;
1374
- //#endregion
1375
- //#region src/grasshopper/io/definition-io.d.ts
1376
- /**
1377
- * Fetches raw input/output schemas from a Grasshopper definition.
1378
- *
1379
- * "Raw" means no per-type parsing (no default coercion, no discriminated-union
1380
- * typing) — but NOT byte-for-byte wire data. The response IS normalized:
1381
- * per-param field KEYS are canonicalized to camelCase across server branches
1382
- * ({@link normalizeInputSchema} / {@link normalizeOutputSchema}, with honest
1383
- * fallbacks for missing required fields), missing/non-array `inputs`/`outputs`
1384
- * coerce to `[]`, and server load diagnostics surface as
1385
- * `loadWarnings`/`loadErrors` (coerced to strings). Field VALUES — notably
1386
- * `default` and the `values` dropdown-label map — pass through verbatim.
1387
- *
1388
- * @param definition - The Grasshopper definition (URL, base64 string, or Uint8Array)
1389
- * @param config - Compute configuration (server URL, API key, etc.)
1390
- * @returns Key-normalized inputs and outputs with no per-type processing
1391
- * @throws {ComputeError} If fetch fails or response is invalid
1392
- *
1393
- * @public Use `fetchParsedDefinitionIO()` for processed, type-safe inputs
1394
- */
1395
- export declare function fetchDefinitionIO(definition: string | Uint8Array, config: ComputeConfig): Promise<GrasshopperParsedIORaw>;
1396
- /**
1397
- * Fetches and processes input/output schemas from a Grasshopper definition.
1398
- * Returns strongly-typed, validated input parameters ready for use.
1399
- *
1400
- * @public This is the recommended way to fetch definition I/O schemas.
1401
- *
1402
- * @param definition - The Grasshopper definition (URL, base64 string, or Uint8Array)
1403
- * @param config - Compute configuration (server URL, API key, etc.)
1404
- * @returns Processed inputs with discriminated union types and outputs
1405
- * @throws {ComputeError} If fetch fails or response is invalid
1406
- *
1407
- * @example
1408
- * ```typescript
1409
- * const { inputs, outputs } = await fetchParsedDefinitionIO(
1410
- * 'https://example.com/definition.gh',
1411
- * { serverUrl: 'https://compute.rhino3d.com', apiKey: 'YOUR_KEY' }
1412
- * );
1413
- *
1414
- * // Inputs are now strongly typed
1415
- * inputs.forEach(input => {
1416
- * if (input.paramType === 'Number') {
1417
- * console.log(input.minimum, input.maximum); // TypeScript knows these exist
1418
- * }
1419
- * });
1420
- * ```
1421
- */
1422
- export declare function fetchParsedDefinitionIO(definition: string | Uint8Array, config: ComputeConfig): Promise<GrasshopperParsedIO>;
1423
- //#endregion
1424
- //#region src/grasshopper/io/schema-endpoint.d.ts
1425
- /** One entry of the schema endpoint's response, after wrapper-key normalization. */
1426
- interface SchemaEndpointResult<TSchema = unknown> {
1427
- /** Schemas embedded in that file. Absent when the file yielded none. */
1428
- schemas?: TSchema[];
1429
- /** Per-file diagnosis. Compute reports this and still answers 200. */
1430
- error?: string;
1431
- }
1432
- /**
1433
- * Read compute's `/grasshopper/schema` body: `[{ FileName, Schemas }]` per
1434
- * uploaded file, or a bare object for a single file.
1435
- *
1436
- * Use this rather than unwrapping the body by hand. The wrapper's casing varies
1437
- * by server branch — mcneel serializes `FileName`/`Schemas`, the VektorNode fork
1438
- * `fileName`/`schemas` — so a fixed-key read silently yields `undefined` against
1439
- * half the servers, and the endpoint answers 200 either way. The failure looks
1440
- * like "this definition has no schemas", which sends you debugging the wrong
1441
- * thing entirely.
1442
- *
1443
- * A blanket key-rewrite (the old `camelcaseKeys` approach) is NOT the fix: it
1444
- * reaches inside the schemas and mangles user-authored names — `"Display3d"` →
1445
- * `"display3d"`, value-list labels like `"Option A"` → `"optionA"`. Only the two
1446
- * wrapper keys are read here; schema CONTENTS pass through untouched, which is
1447
- * why `TSchema` is a pass-through type parameter this module never inspects.
1448
- *
1449
- * @typeParam TSchema - Your schema type (e.g. `UISchema`). Not inspected.
1450
- * @param raw - The parsed JSON body.
1451
- */
1452
- export declare function readSchemaResults<TSchema = unknown>(raw: unknown): SchemaEndpointResult<TSchema>[];
1453
- //#endregion
1454
- //#region src/grasshopper/io/normalize-ui-schema.d.ts
1455
- /**
1456
- * Canonicalize a `/grasshopper/schema` body's key CASING.
1457
- *
1458
- * ## Why this exists
1459
- *
1460
- * Compute serializes the plugin's `UISchema` POCO, whose camelCase wire names
1461
- * live in Newtonsoft `[JsonProperty]` attributes. `Selva.gha` ILRepack-merges
1462
- * Newtonsoft into itself, so those attributes have type
1463
- * `Selva!Newtonsoft.Json.JsonPropertyAttribute`. When the serializer that runs is
1464
- * compute's OWN Newtonsoft assembly, it does not recognize that type as its own
1465
- * attribute, reads no attributes at all, and falls back to raw CLR member names —
1466
- * emitting `Inputs`/`Layout`/`SchemaVersion`.
1467
- *
1468
- * Nothing throws on the wire. Every consumer reads `schema.inputs` as
1469
- * `undefined`, so the definition renders with no inputs, and `schemaVersion`
1470
- * reads `undefined` — which also silently disables the newer-plugin version gate.
1471
- *
1472
- * This is the schema-body counterpart to {@link normalizeInputSchema}, which
1473
- * solves the same split for the `/io` endpoint's param records.
1474
- *
1475
- * ## Why a casing rule, and not a key allowlist
1476
- *
1477
- * The wire names are the CLR names run through Newtonsoft's camelCase strategy,
1478
- * so reproducing that strategy covers every key. An allowlist would have to
1479
- * enumerate every structural key in `UISchema` and drift out of date each time
1480
- * the schema gains a field, failing silently and in exactly this way again.
1481
- *
1482
- * ## What it does NOT touch
1483
- *
1484
- * `options`, `defaultOptions` and `values` hold USER-AUTHORED keys — dropdown
1485
- * labels like `"Standart Beschichtung"`, `"Use 10 Elements instead"`, `"True"`.
1486
- * Those maps are copied verbatim; only the key naming them is canonicalized.
1487
- * Rewriting their contents is the exact regression that motivated deleting the
1488
- * old global `camelcaseKeys` pass (see `read-field.ts`), which mangled
1489
- * `"Option A"` into `"optionA"` and silently changed what a definition solved
1490
- * with.
1491
- *
1492
- * Values are never inspected — only object keys are rewritten.
1493
- */
1494
- /**
1495
- * Returns a schema whose structural keys are camelCase, regardless of which
1496
- * Newtonsoft serialized it. A body that is already camelCase passes through
1497
- * unchanged in shape (it is still rebuilt, so the result is always a fresh
1498
- * object the caller may mutate).
1499
- *
1500
- * Safe to call on any parsed JSON value; non-objects are returned as-is.
1501
- */
1502
- export declare function normalizeUISchemaCasing<T>(raw: T): T;
1503
- //#endregion
1504
- //#region src/grasshopper/io/input/input-processors.d.ts
1505
- /**
1506
- * Parse one raw Grasshopper input schema into a typed {@link InputParam}.
1507
- * Validation failures are swallowed and replaced with a safe default; use
1508
- * {@link processInputWithError} to receive them.
1509
- */
1510
- export declare function processInput(rawInput: InputParamSchema): InputParam;
1511
- //#endregion
1512
- //#region src/grasshopper/data-tree/data-tree.d.ts
1513
- /**
1514
- * Value types that can be stored in a DataTree
1515
- */
1516
- type DataTreeValue = string | number | boolean | object | null;
1517
- /**
1518
- * Simple data item for compute requests (not to be confused with DataItem interface for responses).
1519
- * Note: While TypeScript defines this as string, Rhino Compute accepts boolean/number primitives in JSON.
1520
- */
1521
- interface ComputeDataItem {
1522
- data: string | boolean | number;
1523
- }
1524
- /**
1525
- * InnerTree data structure for compute requests.
1526
- */
1527
- type ComputeInnerTreeData = { [path in DataTreePath]: ComputeDataItem[]; };
1528
- /**
1529
- * Standalone TreeBuilder class for constructing Grasshopper TreeBuilder structures.
1530
- * Does not depend on RhinoCompute library.
1531
- *
1532
- * @example
1533
- * ```ts
1534
- * const tree = new TreeBuilder('MyParam')
1535
- * .append([0], [1, 2, 3])
1536
- * .append([1], [4, 5])
1537
- * .toComputeFormat();
1538
- * ```
1539
- */
1540
- export declare class TreeBuilder {
1541
- private innerTree;
1542
- private paramName;
1543
- constructor(paramName: string);
1544
- /**
1545
- * Append values to a specific path in the tree.
1546
- *
1547
- * @param path - Array of integers representing the branch path (e.g., [0], [0, 1])
1548
- * @param items - Values to append at this path
1549
- * @returns this for method chaining
1550
- */
1551
- append(path: number[], items: DataTreeValue[]): this;
1552
- /**
1553
- * Append a single value to a path.
1554
- *
1555
- * @param path - Branch path
1556
- * @param item - Single value to append
1557
- * @returns this for method chaining
1558
- */
1559
- appendSingle(path: number[], item: DataTreeValue): this;
1560
- /**
1561
- * Set values from a DataTreeDefault structure.
1562
- * Replaces any existing tree data.
1563
- *
1564
- * @param treeData - TreeBuilder structure with path keys like "{0;1}"
1565
- * @returns this for method chaining
1566
- */
1567
- fromDataTreeDefault(treeData: DataTreeDefault): this;
1568
- /**
1569
- * Append flattened values to path [0].
1570
- * Useful for simple flat inputs.
1571
- *
1572
- * @param values - Single value or array of values
1573
- * @returns this for method chaining
1574
- */
1575
- appendFlat(values: DataTreeValue | DataTreeValue[]): this;
1576
- /**
1577
- * Get the flattened list of all values in the tree.
1578
- *
1579
- * @returns Array of all values across all branches
1580
- */
1581
- flatten(): DataTreeValue[];
1582
- /**
1583
- * Get all paths in the tree.
1584
- *
1585
- * @returns Array of path strings
1586
- */
1587
- getPaths(): DataTreePath[];
1588
- /**
1589
- * Get values at a specific path.
1590
- *
1591
- * @param path - Path to retrieve values from
1592
- * @returns Array of values or undefined if path doesn't exist
1593
- */
1594
- getPath(path: number[]): DataTreeValue[] | undefined;
1595
- /**
1596
- * Convert to format compatible with Grasshopper Compute API.
1597
- *
1598
- * @returns InnerTree object ready for compute
1599
- */
1600
- toComputeFormat(): DataTree;
1601
- /**
1602
- * Get the raw InnerTree data structure.
1603
- *
1604
- * @returns InnerTree data
1605
- */
1606
- getInnerTree(): ComputeInnerTreeData;
1607
- /**
1608
- * Get the parameter name.
1609
- *
1610
- * @returns Parameter name
1611
- */
1612
- getParamName(): string;
1613
- /**
1614
- * Create DataTrees from an array of InputParam definitions.
1615
- * Handles tree access, numeric constraints, and value parsing.
1616
- *
1617
- * @param inputs - Array of input parameter definitions
1618
- * @returns Array of InnerTree instances ready for compute
1619
- *
1620
- * @example
1621
- * ```ts
1622
- * const trees = TreeBuilder.fromInputParams(inputs);
1623
- * ```
1624
- */
1625
- static fromInputParams(inputs: InputParam[]): DataTree[];
1626
- /**
1627
- * Create a TreeBuilder from a single InputParam.
1628
- *
1629
- * @param input - Input parameter definition
1630
- * @returns InnerTree ready for compute or undefined if value is invalid
1631
- */
1632
- static fromInputParam(input: InputParam): DataTree | undefined;
1633
- /**
1634
- * Set or replace a parameter value within a TreeBuilder or InnerTree array.
1635
- *
1636
- * Supports both high-level `DataTree[]` instances and low-level `InnerTree[]` format.
1637
- *
1638
- * **Architecture Note:**
1639
- * - Use with `DataTree[]` when building/modifying before computation
1640
- * - Use with `InnerTree[]` when modifying compute API results
1641
- * - `DataTree` is the high-level builder; `InnerTree` is the Rhino Compute format
1642
- *
1643
- * Copy-on-write: returns a new array; the caller's array is never mutated.
1644
- *
1645
- * @overload For TreeBuilder instances (high-level builder)
1646
- * @param trees - Array of TreeBuilder instances to read from (not mutated)
1647
- * @param paramName - The parameter name to set or replace
1648
- * @param newValue - The new value (scalar, array, or TreeBuilder structure)
1649
- * @returns A new TreeBuilder array with the updated parameter
1650
- *
1651
- * @overload For compiled InnerTree (low-level API format)
1652
- * @param trees - The compiled InnerTree array (typically from `client.solve()`; not mutated)
1653
- * @param paramName - The parameter name to set or replace
1654
- * @param newValue - The new value (scalar, array, or TreeBuilder structure)
1655
- * @returns A new InnerTree array with the updated parameter
1656
- *
1657
- * @example
1658
- * ```ts
1659
- * // With TreeBuilder instances (high-level)
1660
- * let trees = [new TreeBuilder('X'), new TreeBuilder('Y')];
1661
- * trees = TreeBuilder.replaceTreeValue(trees, 'X', 42);
1662
- * const result = await client.solve(definitionUrl,
1663
- * trees.map(t => t.toComputeFormat())
1664
- * );
1665
- * ```
1666
- *
1667
- * @example
1668
- * ```ts
1669
- * // With InnerTree format (low-level, from API)
1670
- * let trees = await client.solve(definitionUrl, initialInputs);
1671
- * trees = TreeBuilder.replaceTreeValue(trees, 'X', 42);
1672
- * trees = TreeBuilder.replaceTreeValue(trees, 'Y', [1, 2, 3]);
1673
- * ```
1674
- */
1675
- static replaceTreeValue(trees: TreeBuilder[], paramName: string, newValue: DataTreeValue): TreeBuilder[];
1676
- static replaceTreeValue(trees: DataTree[], paramName: string, newValue: DataTreeValue): DataTree[];
1677
- /**
1678
- * Build a TreeBuilder from a single value, dispatching on shape:
1679
- * DataTreeDefault structure, array, or scalar.
1680
- */
1681
- private static buildFromValue;
1682
- /**
1683
- * Extract a value from a TreeBuilder or InnerTree array by parameter name.
1684
- *
1685
- * Automatically unwraps single values for convenience.
1686
- * Works with both high-level `DataTree[]` instances and low-level `InnerTree[]` format.
1687
- *
1688
- * **Architecture Note:**
1689
- * - Use with `DataTree[]` to read builder instances
1690
- * - Use with `InnerTree[]` to read compute API responses
1691
- * - Return behavior is consistent across both formats
1692
- *
1693
- * **Return Value Behavior:**
1694
- * - Single value → unwrapped (returns `5` not `[5]`)
1695
- * - Multiple values → array of values
1696
- * - Not found → `null`
1697
- *
1698
- * @overload For TreeBuilder instances
1699
- * @param trees - Array of TreeBuilder instances to read from
1700
- * @param paramName - The parameter name to retrieve
1701
- * @returns The unwrapped value, array of values, or null if parameter not found
1702
- *
1703
- * @overload For compiled InnerTree
1704
- * @param trees - The compiled InnerTree array (typically from `client.solve()`)
1705
- * @param paramName - The parameter name to retrieve
1706
- * @returns The unwrapped value, array of values, or null if parameter not found
1707
- *
1708
- * @example
1709
- * ```ts
1710
- * // With TreeBuilder instances
1711
- * const trees = [new TreeBuilder('X'), new TreeBuilder('Y')];
1712
- * trees[0].appendFlat(42);
1713
- * const x = TreeBuilder.getTreeValue(trees, 'X'); // Returns 42
1714
- * ```
1715
- *
1716
- * @example
1717
- * ```ts
1718
- * // With InnerTree from compute results
1719
- * const result = await client.solve(definitionUrl, inputs);
1720
- * const x = TreeBuilder.getTreeValue(result, 'X'); // Returns 42 (not [42])
1721
- * const points = TreeBuilder.getTreeValue(result, 'Points'); // Returns [point1, point2, ...]
1722
- * ```
1723
- */
1724
- static getTreeValue(trees: TreeBuilder[], paramName: string): DataTreeValue | null;
1725
- static getTreeValue(trees: DataTree[], paramName: string): DataTreeValue | null;
1726
- /**
1727
- * Read all values for `paramName` across every branch of the matching builder.
1728
- * Returns null when the builder isn't found.
1729
- */
1730
- private static readFromBuilders;
1731
- /**
1732
- * Read values from the first branch of the matching compiled InnerTree
1733
- * (multi-branch responses are not flattened — current semantics, pinned by
1734
- * the "reads from the first branch path only" test).
1735
- */
1736
- private static readFromDataTrees;
1737
- /**
1738
- * Parse a TreeBuilder path string like "{0;1;2}" into [0, 1, 2].
1739
- * Negative indices ("{-1;2}") and the root path "{}" are valid.
1740
- *
1741
- * @param pathStr - Path string
1742
- * @returns Array of path indices
1743
- * @throws {ComputeError} `INVALID_INPUT` when the path string is not a valid
1744
- * Grasshopper branch path. Malformed keys must never silently collapse to a
1745
- * default branch — two distinct unparseable keys would merge their items
1746
- * into one branch.
1747
- */
1748
- static parsePathString(pathStr: string): number[];
1749
- /**
1750
- * Format a path array into TreeBuilder path string format.
1751
- *
1752
- * @param path - Path as number array
1753
- * @returns Formatted path string like "{0;1;2}"
1754
- */
1755
- static formatPathString(path: number[]): DataTreePath;
1756
- /** Apply numeric constraints to all tree values. */
1757
- private applyNumericConstraints;
1758
- /**
1759
- * Serialize a value for compute requests.
1760
- * Preserves booleans and numbers as primitives for proper Grasshopper parameter handling.
1761
- */
1762
- private static serializeValue;
1763
- /**
1764
- * Deserialize a value back to its original type.
1765
- * Handles both string-encoded values and primitive values.
1766
- */
1767
- private static deserializeValue;
1768
- /**
1769
- * Check if a value is valid for inclusion in a DataTree.
1770
- */
1771
- private static hasValidValue;
1772
- /**
1773
- * Check if input is numeric type.
1774
- */
1775
- private static isNumericInput;
1776
- /**
1777
- * Process array of values based on input type.
1778
- */
1779
- private static processValues;
1780
- /**
1781
- * Clamp numeric value to constraints.
1782
- */
1783
- private static clampValue;
1784
- }
1785
- //#endregion
1786
- export { type BooleanInputType, type CacheOptions, ComputeServerStats, type DataItem, type DataTree, type DataTreeDefault, type DataTreePath, type DataTreeValue, type DefaultValue, type DefinitionRef, type FileBaseInfo, type FileData, type FileInputType, type GeometryInputType, type GetValuesOptions, type GetValuesResult, GrasshopperClient, type GrasshopperComputeConfig, type GrasshopperComputeResponse, type GrasshopperParsedIO, type GrasshopperParsedIORaw, type GrasshopperRequestSchema, GrasshopperResponseProcessor, type InnerTreeData, type InputParam, type InputParamSchema, type NumericInputType, type OutputParamSchema, type OutputType, type ParsedContext, type ProcessedFile, type RhinoModelUnit, type SchedulerMode, type SchemaEndpointResult, type SelvaEventTarget, type SelvaResponseBlock, type SolveContext, type SolveDefinition, type SolveOptions, type SolveResult, type SolveSchedulerOptions, type TextInputType, type ValueListInputType, downloadFileData, extractFilesFromComputeResponse, isDefinitionRef };
1787
- //# sourceMappingURL=grasshopper.d.cts.map