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