@selvajs/compute 1.5.1 → 1.5.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _chunkIJZNCO5Xcjs = require('./chunk-IJZNCO5X.cjs');function v(r){return Buffer.from(r,"utf-8").toString("base64")}function T(r){return!r||r.length<2||r.length%4!==0?!1:/^[A-Za-z0-9+/]+={0,2}$/.test(r)}function S(r){if(typeof globalThis.Buffer=="function"){let e=globalThis.Buffer.from(r,"base64");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}if(typeof globalThis.atob=="function"){let e=globalThis.atob(r),n=new Uint8Array(e.length);for(let a=0;a<e.length;a++)n[a]=e.charCodeAt(a)&255;return n}throw new (0, _chunkIJZNCO5Xcjs.d)("Base64 decoding not supported in this environment.",_chunkIJZNCO5Xcjs.c.INVALID_STATE,{context:{environmentInfo:"atob or Buffer not available"}})}function C(r){if(r==null)throw new (0, _chunkIJZNCO5Xcjs.d)("Input bytes must not be null or undefined",_chunkIJZNCO5Xcjs.c.INVALID_INPUT,{context:{receivedValue:r}});let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=r;n.length>=3&&n[0]===239&&n[1]===187&&n[2]===191&&(n=n.slice(3));let a=n.byteLength,y=a%3,u=a-y,b="",o,i,c,l,d;for(let t=0;t<u;t+=3){let f=n[t]!==void 0?n[t]:0,h=n[t+1]!==void 0?n[t+1]:0,g=n[t+2]!==void 0?n[t+2]:0,s=f<<16|h<<8|g;if(o=(s&16515072)>>18,i=(s&258048)>>12,c=(s&4032)>>6,l=s&63,typeof e!="string")throw new Error("encodings must be a string");if(typeof o!="number"||o<0||o>=e.length)throw new Error("Invalid index a");if(typeof i!="number"||i<0||i>=e.length)throw new Error("Invalid index b");if(typeof c!="number"||c<0||c>=e.length)throw new Error("Invalid index c");if(typeof l!="number"||l<0||l>=e.length)throw new Error("Invalid index d");let w=e[o],B=e[i],x=e[c],I=e[l];if(w===void 0||B===void 0||x===void 0||I===void 0)throw new Error("Invalid encoding index");b+=w+B+x+I}if(y===1){if(d=n[u],d===void 0)throw new Error("'chunk' must not be undefined");o=(d&252)>>2,i=(d&3)<<4;let t=e[o],f=e[i];if(t===void 0||f===void 0)throw new Error("Invalid encoding index");b+=`${t+f}==`}else if(y===2){let t=_nullishCoalesce(n[u], () => (0)),f=n[u+1]!==void 0?n[u+1]:0;if(typeof t!="number"||t<0||t>255||typeof f!="number"||f<0||f>255)throw new Error("Invalid byte1");d=t<<8|f,o=(d&64512)>>10,i=(d&1008)>>4,c=(d&15)<<2;let h=e[o],g=e[i],s=e[c];if(h===void 0||g===void 0||s===void 0)throw new Error("Invalid encoding index");b+=`${h+g+s}=`}return b}exports.a = v; exports.b = T; exports.c = S; exports.d = C;
2
- //# sourceMappingURL=chunk-LNIUUPA5.cjs.map
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _chunkXULONXVPcjs = require('./chunk-XULONXVP.cjs');function v(r){return Buffer.from(r,"utf-8").toString("base64")}function T(r){return!r||r.length<2||r.length%4!==0?!1:/^[A-Za-z0-9+/]+={0,2}$/.test(r)}function S(r){if(typeof globalThis.Buffer=="function"){let e=globalThis.Buffer.from(r,"base64");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}if(typeof globalThis.atob=="function"){let e=globalThis.atob(r),n=new Uint8Array(e.length);for(let a=0;a<e.length;a++)n[a]=e.charCodeAt(a)&255;return n}throw new (0, _chunkXULONXVPcjs.d)("Base64 decoding not supported in this environment.",_chunkXULONXVPcjs.c.INVALID_STATE,{context:{environmentInfo:"atob or Buffer not available"}})}function C(r){if(r==null)throw new (0, _chunkXULONXVPcjs.d)("Input bytes must not be null or undefined",_chunkXULONXVPcjs.c.INVALID_INPUT,{context:{receivedValue:r}});let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=r;n.length>=3&&n[0]===239&&n[1]===187&&n[2]===191&&(n=n.slice(3));let a=n.byteLength,y=a%3,u=a-y,b="",o,i,c,l,d;for(let t=0;t<u;t+=3){let f=n[t]!==void 0?n[t]:0,h=n[t+1]!==void 0?n[t+1]:0,g=n[t+2]!==void 0?n[t+2]:0,s=f<<16|h<<8|g;if(o=(s&16515072)>>18,i=(s&258048)>>12,c=(s&4032)>>6,l=s&63,typeof e!="string")throw new Error("encodings must be a string");if(typeof o!="number"||o<0||o>=e.length)throw new Error("Invalid index a");if(typeof i!="number"||i<0||i>=e.length)throw new Error("Invalid index b");if(typeof c!="number"||c<0||c>=e.length)throw new Error("Invalid index c");if(typeof l!="number"||l<0||l>=e.length)throw new Error("Invalid index d");let w=e[o],B=e[i],x=e[c],I=e[l];if(w===void 0||B===void 0||x===void 0||I===void 0)throw new Error("Invalid encoding index");b+=w+B+x+I}if(y===1){if(d=n[u],d===void 0)throw new Error("'chunk' must not be undefined");o=(d&252)>>2,i=(d&3)<<4;let t=e[o],f=e[i];if(t===void 0||f===void 0)throw new Error("Invalid encoding index");b+=`${t+f}==`}else if(y===2){let t=_nullishCoalesce(n[u], () => (0)),f=n[u+1]!==void 0?n[u+1]:0;if(typeof t!="number"||t<0||t>255||typeof f!="number"||f<0||f>255)throw new Error("Invalid byte1");d=t<<8|f,o=(d&64512)>>10,i=(d&1008)>>4,c=(d&15)<<2;let h=e[o],g=e[i],s=e[c];if(h===void 0||g===void 0||s===void 0)throw new Error("Invalid encoding index");b+=`${h+g+s}=`}return b}exports.a = v; exports.b = T; exports.c = S; exports.d = C;
2
+ //# sourceMappingURL=chunk-2NFN5ERT.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/selva-compute/selva-compute/dist/chunk-LNIUUPA5.cjs","../src/core/utils/encoding.ts"],"names":["encodeStringToBase64","str","isBase64","decodeBase64ToBinary","base64File","buf","binary","bytes","i","RhinoComputeError","ErrorCodes","base64ByteArray","encodings","inputBytes","byteLength","byteRemainder","mainLength","base64","a","b","d","chunk","byte1","byte2","byte3","innerChunk","charA","charB","charC","charD"],"mappings":"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","file":"/home/runner/work/selva-compute/selva-compute/dist/chunk-LNIUUPA5.cjs","sourcesContent":[null,"import { RhinoComputeError } from '../errors/base';\nimport { ErrorCodes } from '../errors/error-codes';\nimport { getLogger } from './logger';\n\n/**\n * Encodes a string to base64 (Node 20+ safe)\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param str - String to encode\n * @returns Base64 encoded string\n */\nexport function encodeStringToBase64(str: string): string {\n\treturn Buffer.from(str, 'utf-8').toString('base64');\n}\n\n/**\n * Decodes a base64 string to a UTF-8 string (Node 20+ safe)\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param base64Str - Base64 encoded string\n * @returns Decoded UTF-8 string\n */\nexport function decodeBase64ToString(base64Str: string): string {\n\treturn Buffer.from(base64Str, 'base64').toString('utf-8');\n}\n\n/**\n * Checks if a string is valid base64\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param str - String to check\n * @returns True if the string is valid base64\n */\nexport function isBase64(str: string): boolean {\n\tif (!str || str.length < 2) return false;\n\t// Length must be a multiple of 4, only alphabet chars + at most 2 trailing '='\n\tif (str.length % 4 !== 0) return false;\n\treturn /^[A-Za-z0-9+/]+={0,2}$/.test(str);\n}\n\n/**\n * Decodes a base64 string to binary data (Uint8Array)\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param base64File - Base64 encoded string\n * @returns Decoded binary data as Uint8Array\n * @throws {RhinoComputeError} If base64 decoding is not supported in this environment.\n */\nexport function decodeBase64ToBinary(base64File: string): Uint8Array {\n\t// Prefer Buffer in Node — it's faster and avoids the latin-1 string detour\n\t// that atob + charCodeAt requires.\n\tif (typeof (globalThis as any).Buffer === 'function') {\n\t\tconst buf = (globalThis as any).Buffer.from(base64File, 'base64');\n\t\treturn new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n\t}\n\tif (typeof globalThis.atob === 'function') {\n\t\tconst binary = globalThis.atob(base64File);\n\t\tconst bytes = new Uint8Array(binary.length);\n\t\tfor (let i = 0; i < binary.length; i++) {\n\t\t\tbytes[i] = binary.charCodeAt(i) & 0xff;\n\t\t}\n\t\treturn bytes;\n\t}\n\n\tthrow new RhinoComputeError(\n\t\t'Base64 decoding not supported in this environment.',\n\t\tErrorCodes.INVALID_STATE,\n\t\t{ context: { environmentInfo: 'atob or Buffer not available' } }\n\t);\n}\n\n/**\n * Encodes binary data (Uint8Array) to base64 string\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * Source: https://github.com/mcneel/compute.rhino3d.appserver/blob/92c95a3b1d076a4d4a5360214ffd27c46425ff03/src/examples/convert/scriptjs\n * https://gist.github.com/jonleighton/958841\n *\n * MIT LICENSE\n * Copyright 2011 Jon Leighton\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\nexport function base64ByteArray(bytes: Uint8Array | null | undefined): string {\n\tif (bytes === null || bytes === undefined) {\n\t\tthrow new RhinoComputeError(\n\t\t\t'Input bytes must not be null or undefined',\n\t\t\tErrorCodes.INVALID_INPUT,\n\t\t\t{ context: { receivedValue: bytes } }\n\t\t);\n\t}\n\n\tconst encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n\tlet inputBytes = bytes;\n\n\t// strip bom (Byte Order Mark)\n\tif (\n\t\tinputBytes.length >= 3 &&\n\t\tinputBytes[0] === 239 &&\n\t\tinputBytes[1] === 187 &&\n\t\tinputBytes[2] === 191\n\t) {\n\t\tinputBytes = inputBytes.slice(3);\n\t}\n\n\tconst byteLength = inputBytes.byteLength;\n\tconst byteRemainder = byteLength % 3;\n\tconst mainLength = byteLength - byteRemainder;\n\n\tlet base64 = '';\n\tlet a, b, c, d;\n\tlet chunk;\n\n\t// Main loop deals with bytes in chunks of 3\n\tfor (let i = 0; i < mainLength; i += 3) {\n\t\t// Combine the three bytes into a single integer\n\n\t\tconst byte1 = inputBytes[i] !== undefined ? inputBytes[i] : 0;\n\t\tconst byte2 = inputBytes[i + 1] !== undefined ? inputBytes[i + 1] : 0;\n\t\tconst byte3 = inputBytes[i + 2] !== undefined ? inputBytes[i + 2] : 0;\n\n\t\tconst innerChunk = (byte1 << 16) | (byte2 << 8) | byte3;\n\n\t\t// Use bitmasks to extract 6-bit segments from the triplet\n\t\ta = (innerChunk & 16515072) >> 18;\n\t\tb = (innerChunk & 258048) >> 12;\n\t\tc = (innerChunk & 4032) >> 6;\n\t\td = innerChunk & 63;\n\n\t\t// Convert the raw binary segments to the appropriate ASCII encoding\n\t\tif (typeof encodings !== 'string') {\n\t\t\tthrow new Error('encodings must be a string');\n\t\t}\n\n\t\tif (typeof a !== 'number' || a < 0 || a >= encodings.length) {\n\t\t\tthrow new Error('Invalid index a');\n\t\t}\n\n\t\tif (typeof b !== 'number' || b < 0 || b >= encodings.length) {\n\t\t\tthrow new Error('Invalid index b');\n\t\t}\n\n\t\tif (typeof c !== 'number' || c < 0 || c >= encodings.length) {\n\t\t\tthrow new Error('Invalid index c');\n\t\t}\n\n\t\tif (typeof d !== 'number' || d < 0 || d >= encodings.length) {\n\t\t\tthrow new Error('Invalid index d');\n\t\t}\n\n\t\tconst charA = encodings[a];\n\t\tconst charB = encodings[b];\n\t\tconst charC = encodings[c];\n\t\tconst charD = encodings[d];\n\n\t\tif (charA === undefined || charB === undefined || charC === undefined || charD === undefined) {\n\t\t\tthrow new Error('Invalid encoding index');\n\t\t}\n\n\t\tbase64 += charA + charB + charC + charD;\n\t}\n\n\t// Deal with the remaining bytes and padding\n\tif (byteRemainder === 1) {\n\t\tchunk = inputBytes[mainLength];\n\n\t\tif (chunk === undefined) {\n\t\t\tthrow new Error(\"'chunk' must not be undefined\");\n\t\t}\n\n\t\ta = (chunk & 252) >> 2;\n\t\tb = (chunk & 3) << 4;\n\n\t\tconst charA = encodings[a];\n\t\tconst charB = encodings[b];\n\n\t\tif (charA === undefined || charB === undefined) {\n\t\t\tthrow new Error('Invalid encoding index');\n\t\t}\n\n\t\tbase64 += `${charA + charB}==`;\n\t} else if (byteRemainder === 2) {\n\t\tconst byte1 = inputBytes[mainLength] ?? 0;\n\t\tconst byte2 = inputBytes[mainLength + 1] !== undefined ? inputBytes[mainLength + 1] : 0;\n\n\t\tif (\n\t\t\ttypeof byte1 !== 'number' ||\n\t\t\tbyte1 < 0 ||\n\t\t\tbyte1 > 255 ||\n\t\t\ttypeof byte2 !== 'number' ||\n\t\t\tbyte2 < 0 ||\n\t\t\tbyte2 > 255\n\t\t) {\n\t\t\tthrow new Error('Invalid byte1');\n\t\t}\n\n\t\tchunk = (byte1 << 8) | byte2;\n\n\t\ta = (chunk & 64512) >> 10;\n\t\tb = (chunk & 1008) >> 4;\n\t\tc = (chunk & 15) << 2;\n\n\t\tconst charA = encodings[a];\n\t\tconst charB = encodings[b];\n\t\tconst charC = encodings[c];\n\n\t\tif (charA === undefined || charB === undefined || charC === undefined) {\n\t\t\tthrow new Error('Invalid encoding index');\n\t\t}\n\n\t\tbase64 += `${charA + charB + charC}=`;\n\t}\n\n\treturn base64;\n}\n\n/**\n * Convert base64 string to rhino object\n *\n * @internal Internal helper for decoding Rhino objects — not public API.\n *\n * Source: https://github.com/mcneel/compute.rhino3d.appserver/blob/92c95a3b1d076a4d4a5360214ffd27c46425ff03/src/examples/convert/scriptjs\n * @param rhino is the rhino module form rhino3dm. Since not properly typed its not used here.\n * @param item\n * @returns\n */\nexport function base64ToRhinoObject(\n\trhino: any,\n\titem: {\n\t\ttype: string;\n\t\tdata: string;\n\t}\n) {\n\t//Make a type definition for this?\n\tlet decodata: null | object = null;\n\ttry {\n\t\tdecodata = JSON.parse(item.data);\n\t} catch (error) {\n\t\tdecodata = item;\n\t\tgetLogger().warn('Failed to parse JSON, returning original data:', error, item);\n\t}\n\tif (item.type === 'System.String') {\n\t\ttry {\n\t\t\treturn rhino.DracoCompression.decompressBase64String(decodata);\n\t\t} catch (error) {\n\t\t\tgetLogger().error('Failed to decompress Draco base64 string:', error);\n\t\t}\n\t} else if (\n\t\ttypeof decodata === 'object' &&\n\t\tObject.prototype.hasOwnProperty.call(decodata, 'opennurbs')\n\t) {\n\t\treturn rhino.CommonObject.decode(decodata);\n\t} else if (typeof decodata === 'object') {\n\t\ttry {\n\t\t\treturn rhino.CommonObject.decode(decodata);\n\t\t} catch (error) {\n\t\t\tgetLogger().error('Failed to decode Rhino object:', error);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/selva-compute/selva-compute/dist/chunk-2NFN5ERT.cjs","../src/core/utils/encoding.ts"],"names":["encodeStringToBase64","str","isBase64","decodeBase64ToBinary","base64File","buf","binary","bytes","i","RhinoComputeError","ErrorCodes","base64ByteArray","encodings","inputBytes","byteLength","byteRemainder","mainLength","base64","a","b","d","chunk","byte1","byte2","byte3","innerChunk","charA","charB","charC","charD"],"mappings":"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","file":"/home/runner/work/selva-compute/selva-compute/dist/chunk-2NFN5ERT.cjs","sourcesContent":[null,"import { RhinoComputeError } from '../errors/base';\nimport { ErrorCodes } from '../errors/error-codes';\nimport { getLogger } from './logger';\n\n/**\n * Encodes a string to base64 (Node 20+ safe)\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param str - String to encode\n * @returns Base64 encoded string\n */\nexport function encodeStringToBase64(str: string): string {\n\treturn Buffer.from(str, 'utf-8').toString('base64');\n}\n\n/**\n * Decodes a base64 string to a UTF-8 string (Node 20+ safe)\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param base64Str - Base64 encoded string\n * @returns Decoded UTF-8 string\n */\nexport function decodeBase64ToString(base64Str: string): string {\n\treturn Buffer.from(base64Str, 'base64').toString('utf-8');\n}\n\n/**\n * Checks if a string is valid base64\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param str - String to check\n * @returns True if the string is valid base64\n */\nexport function isBase64(str: string): boolean {\n\tif (!str || str.length < 2) return false;\n\t// Length must be a multiple of 4, only alphabet chars + at most 2 trailing '='\n\tif (str.length % 4 !== 0) return false;\n\treturn /^[A-Za-z0-9+/]+={0,2}$/.test(str);\n}\n\n/**\n * Decodes a base64 string to binary data (Uint8Array)\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * @param base64File - Base64 encoded string\n * @returns Decoded binary data as Uint8Array\n * @throws {RhinoComputeError} If base64 decoding is not supported in this environment.\n */\nexport function decodeBase64ToBinary(base64File: string): Uint8Array {\n\t// Prefer Buffer in Node — it's faster and avoids the latin-1 string detour\n\t// that atob + charCodeAt requires.\n\tif (typeof (globalThis as any).Buffer === 'function') {\n\t\tconst buf = (globalThis as any).Buffer.from(base64File, 'base64');\n\t\treturn new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n\t}\n\tif (typeof globalThis.atob === 'function') {\n\t\tconst binary = globalThis.atob(base64File);\n\t\tconst bytes = new Uint8Array(binary.length);\n\t\tfor (let i = 0; i < binary.length; i++) {\n\t\t\tbytes[i] = binary.charCodeAt(i) & 0xff;\n\t\t}\n\t\treturn bytes;\n\t}\n\n\tthrow new RhinoComputeError(\n\t\t'Base64 decoding not supported in this environment.',\n\t\tErrorCodes.INVALID_STATE,\n\t\t{ context: { environmentInfo: 'atob or Buffer not available' } }\n\t);\n}\n\n/**\n * Encodes binary data (Uint8Array) to base64 string\n *\n * @internal Internal encoding helper — kept internal to `@selvajs/compute`.\n *\n * Source: https://github.com/mcneel/compute.rhino3d.appserver/blob/92c95a3b1d076a4d4a5360214ffd27c46425ff03/src/examples/convert/scriptjs\n * https://gist.github.com/jonleighton/958841\n *\n * MIT LICENSE\n * Copyright 2011 Jon Leighton\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\nexport function base64ByteArray(bytes: Uint8Array | null | undefined): string {\n\tif (bytes === null || bytes === undefined) {\n\t\tthrow new RhinoComputeError(\n\t\t\t'Input bytes must not be null or undefined',\n\t\t\tErrorCodes.INVALID_INPUT,\n\t\t\t{ context: { receivedValue: bytes } }\n\t\t);\n\t}\n\n\tconst encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n\tlet inputBytes = bytes;\n\n\t// strip bom (Byte Order Mark)\n\tif (\n\t\tinputBytes.length >= 3 &&\n\t\tinputBytes[0] === 239 &&\n\t\tinputBytes[1] === 187 &&\n\t\tinputBytes[2] === 191\n\t) {\n\t\tinputBytes = inputBytes.slice(3);\n\t}\n\n\tconst byteLength = inputBytes.byteLength;\n\tconst byteRemainder = byteLength % 3;\n\tconst mainLength = byteLength - byteRemainder;\n\n\tlet base64 = '';\n\tlet a, b, c, d;\n\tlet chunk;\n\n\t// Main loop deals with bytes in chunks of 3\n\tfor (let i = 0; i < mainLength; i += 3) {\n\t\t// Combine the three bytes into a single integer\n\n\t\tconst byte1 = inputBytes[i] !== undefined ? inputBytes[i] : 0;\n\t\tconst byte2 = inputBytes[i + 1] !== undefined ? inputBytes[i + 1] : 0;\n\t\tconst byte3 = inputBytes[i + 2] !== undefined ? inputBytes[i + 2] : 0;\n\n\t\tconst innerChunk = (byte1 << 16) | (byte2 << 8) | byte3;\n\n\t\t// Use bitmasks to extract 6-bit segments from the triplet\n\t\ta = (innerChunk & 16515072) >> 18;\n\t\tb = (innerChunk & 258048) >> 12;\n\t\tc = (innerChunk & 4032) >> 6;\n\t\td = innerChunk & 63;\n\n\t\t// Convert the raw binary segments to the appropriate ASCII encoding\n\t\tif (typeof encodings !== 'string') {\n\t\t\tthrow new Error('encodings must be a string');\n\t\t}\n\n\t\tif (typeof a !== 'number' || a < 0 || a >= encodings.length) {\n\t\t\tthrow new Error('Invalid index a');\n\t\t}\n\n\t\tif (typeof b !== 'number' || b < 0 || b >= encodings.length) {\n\t\t\tthrow new Error('Invalid index b');\n\t\t}\n\n\t\tif (typeof c !== 'number' || c < 0 || c >= encodings.length) {\n\t\t\tthrow new Error('Invalid index c');\n\t\t}\n\n\t\tif (typeof d !== 'number' || d < 0 || d >= encodings.length) {\n\t\t\tthrow new Error('Invalid index d');\n\t\t}\n\n\t\tconst charA = encodings[a];\n\t\tconst charB = encodings[b];\n\t\tconst charC = encodings[c];\n\t\tconst charD = encodings[d];\n\n\t\tif (charA === undefined || charB === undefined || charC === undefined || charD === undefined) {\n\t\t\tthrow new Error('Invalid encoding index');\n\t\t}\n\n\t\tbase64 += charA + charB + charC + charD;\n\t}\n\n\t// Deal with the remaining bytes and padding\n\tif (byteRemainder === 1) {\n\t\tchunk = inputBytes[mainLength];\n\n\t\tif (chunk === undefined) {\n\t\t\tthrow new Error(\"'chunk' must not be undefined\");\n\t\t}\n\n\t\ta = (chunk & 252) >> 2;\n\t\tb = (chunk & 3) << 4;\n\n\t\tconst charA = encodings[a];\n\t\tconst charB = encodings[b];\n\n\t\tif (charA === undefined || charB === undefined) {\n\t\t\tthrow new Error('Invalid encoding index');\n\t\t}\n\n\t\tbase64 += `${charA + charB}==`;\n\t} else if (byteRemainder === 2) {\n\t\tconst byte1 = inputBytes[mainLength] ?? 0;\n\t\tconst byte2 = inputBytes[mainLength + 1] !== undefined ? inputBytes[mainLength + 1] : 0;\n\n\t\tif (\n\t\t\ttypeof byte1 !== 'number' ||\n\t\t\tbyte1 < 0 ||\n\t\t\tbyte1 > 255 ||\n\t\t\ttypeof byte2 !== 'number' ||\n\t\t\tbyte2 < 0 ||\n\t\t\tbyte2 > 255\n\t\t) {\n\t\t\tthrow new Error('Invalid byte1');\n\t\t}\n\n\t\tchunk = (byte1 << 8) | byte2;\n\n\t\ta = (chunk & 64512) >> 10;\n\t\tb = (chunk & 1008) >> 4;\n\t\tc = (chunk & 15) << 2;\n\n\t\tconst charA = encodings[a];\n\t\tconst charB = encodings[b];\n\t\tconst charC = encodings[c];\n\n\t\tif (charA === undefined || charB === undefined || charC === undefined) {\n\t\t\tthrow new Error('Invalid encoding index');\n\t\t}\n\n\t\tbase64 += `${charA + charB + charC}=`;\n\t}\n\n\treturn base64;\n}\n\n/**\n * Convert base64 string to rhino object\n *\n * @internal Internal helper for decoding Rhino objects — not public API.\n *\n * Source: https://github.com/mcneel/compute.rhino3d.appserver/blob/92c95a3b1d076a4d4a5360214ffd27c46425ff03/src/examples/convert/scriptjs\n * @param rhino is the rhino module form rhino3dm. Since not properly typed its not used here.\n * @param item\n * @returns\n */\nexport function base64ToRhinoObject(\n\trhino: any,\n\titem: {\n\t\ttype: string;\n\t\tdata: string;\n\t}\n) {\n\t//Make a type definition for this?\n\tlet decodata: null | object = null;\n\ttry {\n\t\tdecodata = JSON.parse(item.data);\n\t} catch (error) {\n\t\tdecodata = item;\n\t\tgetLogger().warn('Failed to parse JSON, returning original data:', error, item);\n\t}\n\tif (item.type === 'System.String') {\n\t\ttry {\n\t\t\treturn rhino.DracoCompression.decompressBase64String(decodata);\n\t\t} catch (error) {\n\t\t\tgetLogger().error('Failed to decompress Draco base64 string:', error);\n\t\t}\n\t} else if (\n\t\ttypeof decodata === 'object' &&\n\t\tObject.prototype.hasOwnProperty.call(decodata, 'opennurbs')\n\t) {\n\t\treturn rhino.CommonObject.decode(decodata);\n\t} else if (typeof decodata === 'object') {\n\t\ttry {\n\t\t\treturn rhino.CommonObject.decode(decodata);\n\t\t} catch (error) {\n\t\t\tgetLogger().error('Failed to decode Rhino object:', error);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import{a as z,b as W,c as q,d as _}from"./chunk-XZUTU46G.js";import{b as p,c as f,d as l,e as m,h as N,i as j,k as $}from"./chunk-CZCPL35F.js";function L(t){let e=new WeakSet,r=n=>{if(n==null)return JSON.stringify(n);if(typeof n=="number")return Number.isFinite(n)?String(n):JSON.stringify(null);if(typeof n=="string"||typeof n=="boolean")return JSON.stringify(n);if(typeof n=="bigint")return JSON.stringify(n.toString());if(n instanceof Uint8Array){let o=n.length>64?Array.from(n.slice(0,32)).concat(Array.from(n.slice(-32))):Array.from(n);return JSON.stringify({__u8:!0,len:n.length,sample:o})}return Array.isArray(n)?`[${n.map(r).join(",")}]`:typeof n=="object"?e.has(n)?JSON.stringify("[Circular]"):(e.add(n),`{${Object.keys(n).sort().map(a=>`${JSON.stringify(a)}:${r(n[a])}`).join(",")}}`):JSON.stringify(null)};return r(t)}function J(t){let e=2166136261;for(let r=0;r<t.length;r++)e^=t.charCodeAt(r),e=e+((e<<1)+(e<<4)+(e<<7)+(e<<8)+(e<<24))>>>0;return e.toString(16).padStart(8,"0")}function v(t,e){let r=typeof t=="string"?t:L({__u8:!0,len:t.length});return J(`${r}|${L(e)}`)}var h=class{constructor(e,r,n={}){p(this,"executor");p(this,"baseConfig");p(this,"mode");p(this,"maxConcurrent");p(this,"timeoutMs");p(this,"retry");p(this,"cacheEnabled");p(this,"cacheMax");p(this,"cacheTtl");p(this,"cache",new Map);p(this,"onStart");p(this,"onSettle");p(this,"onSuperseded");p(this,"subscribers",new Set);p(this,"inFlight",new Set);p(this,"pendingForLatestWins",null);p(this,"fifoQueue",[]);p(this,"_lastResult",null);p(this,"_lastError",null);p(this,"_lastDurationMs",null);p(this,"disposed",!1);this.executor=e,this.baseConfig=r,this.mode=n.mode??"latest-wins",this.maxConcurrent=Math.max(1,n.maxConcurrent??(this.mode==="parallel"?4:1)),this.timeoutMs=n.timeoutMs,this.retry=n.retry;let o=n.cache;this.cacheEnabled=o!==void 0&&o!==!1;let s=typeof o=="object"?o:{};this.cacheMax=s.maxEntries??50,this.cacheTtl=s.ttlMs??0,this.onStart=n.onStart,this.onSettle=n.onSettle,this.onSuperseded=n.onSuperseded}get isSolving(){return this.inFlight.size>0}get hasPending(){return this.pendingForLatestWins!==null||this.fifoQueue.length>0}get inFlightCount(){return this.inFlight.size}get queueDepth(){return this.fifoQueue.length+(this.pendingForLatestWins?1:0)}get lastResult(){return this._lastResult}get lastError(){return this._lastError}get lastDurationMs(){return this._lastDurationMs}subscribe(e){return this.subscribers.add(e),()=>this.subscribers.delete(e)}notify(){for(let e of this.subscribers)try{e()}catch(r){m().error("[SolveScheduler] subscriber threw:",r)}}solve(e,r,n){if(this.disposed)return Promise.reject(new l("SolveScheduler has been disposed and cannot be used",f.INVALID_STATE));let o=v(e,r),s={key:o,enqueuedAt:Date.now(),startedAt:null};if(this.cacheEnabled){let a=this.readCache(o);if(a){let i={status:"success",response:a,durationMs:0,fromCache:!0};return this._lastResult=a,this._lastError=null,this._lastDurationMs=0,this.runHook(this.onStart,s),this.runHook(this.onSettle,s,i),this.notify(),Promise.resolve(a)}}return new Promise((a,i)=>{let u={definition:e,dataTree:r,ctx:s,resolve:a,reject:i,externalSignal:n?.signal};if(u.externalSignal?.aborted){i(this.makeAbortError(s));return}this.enqueue(u)})}enqueue(e){switch(this.mode){case"latest-wins":{this.pendingForLatestWins&&(this.supersede(this.pendingForLatestWins),this.pendingForLatestWins=null);for(let r of this.inFlight)this.supersede(r),r.controller.abort();this.inFlight.size===0?this.execute(e):this.pendingForLatestWins=e;break}case"queue":{this.inFlight.size<this.maxConcurrent?this.execute(e):this.fifoQueue.push(e);break}case"parallel":{this.inFlight.size<this.maxConcurrent?this.execute(e):this.fifoQueue.push(e);break}}this.notify()}async execute(e){let r=new AbortController,n={...e,controller:r};this.inFlight.add(n),e.ctx.startedAt=Date.now();let o=()=>r.abort();e.externalSignal?.addEventListener("abort",o,{once:!0}),this.runHook(this.onStart,e.ctx),this.notify();let s=performance.now();try{let a={...this.baseConfig,signal:r.signal,...this.timeoutMs!==void 0&&{timeoutMs:this.timeoutMs},...this.retry!==void 0&&{retry:this.retry}},i=await this.executor(e.definition,e.dataTree,a),u=performance.now()-s;this.cacheEnabled&&this.writeCache(e.ctx.key,i),this._lastResult=i,this._lastError=null,this._lastDurationMs=u,e.resolve(i),this.runHook(this.onSettle,e.ctx,{status:"success",response:i,durationMs:u,fromCache:!1})}catch(a){let i=performance.now()-s,u=a instanceof l?a:new l(a instanceof Error?a.message:String(a),f.UNKNOWN_ERROR,{originalError:a instanceof Error?a:new Error(String(a))});this._lastError=u,this._lastDurationMs=i,e.reject(u),this.runHook(this.onSettle,e.ctx,{status:"error",error:u,durationMs:i})}finally{e.externalSignal?.removeEventListener("abort",o),this.inFlight.delete(n),this.drainNext(),this.notify()}}drainNext(){if(!this.disposed){if(this.mode==="latest-wins"){if(this.pendingForLatestWins&&this.inFlight.size===0){let e=this.pendingForLatestWins;this.pendingForLatestWins=null,this.execute(e)}return}for(;this.fifoQueue.length>0&&this.inFlight.size<this.maxConcurrent;){let e=this.fifoQueue.shift();this.execute(e)}}}supersede(e){let r=new l("Superseded by newer solve",f.UNKNOWN_ERROR,{context:{key:e.ctx.key,enqueuedAt:e.ctx.enqueuedAt}});e.reject(r),this.runHook(this.onSuperseded,e.ctx)}makeAbortError(e){return new l("Request aborted by caller",f.UNKNOWN_ERROR,{context:{key:e.key,enqueuedAt:e.enqueuedAt}})}cancelAll(){for(this.pendingForLatestWins&&(this.pendingForLatestWins.reject(this.makeAbortError(this.pendingForLatestWins.ctx)),this.pendingForLatestWins=null);this.fifoQueue.length>0;){let e=this.fifoQueue.shift();e.reject(this.makeAbortError(e.ctx))}for(let e of this.inFlight)e.controller.abort();this.notify()}readCache(e){if(!this.cacheEnabled)return null;let r=this.cache.get(e);return r?this.cacheTtl>0&&Date.now()-r.insertedAt>this.cacheTtl?(this.cache.delete(e),null):(this.cache.delete(e),this.cache.set(e,r),r.response):null}writeCache(e,r){if(this.cacheEnabled)for(this.cache.set(e,{response:r,insertedAt:Date.now()});this.cache.size>this.cacheMax;){let n=this.cache.keys().next().value;if(n===void 0)break;this.cache.delete(n)}}clearCache(){this.cache.clear()}dispose(){this.disposed||(this.disposed=!0,this.cancelAll(),this.subscribers.clear(),this.cache.clear())}runHook(e,...r){if(e)try{e(...r)}catch(n){m().error("[SolveScheduler] hook threw:",n)}}};var T=class t{constructor(e){p(this,"config");p(this,"serverStats");p(this,"disposed",!1);this.config=this.normalizeComputeConfig(e),this.serverStats=new j(this.config.serverUrl,this.config.apiKey)}static async create(e){let r=new t(e);if(!await r.serverStats.isServerOnline())throw new l("Rhino Compute server is not online",f.NETWORK_ERROR,{context:{serverUrl:r.config.serverUrl}});return r}getConfig(){return this.ensureNotDisposed(),{...this.config}}async getIO(e){return this.ensureNotDisposed(),R(e,this.config)}async getRawIO(e){return this.ensureNotDisposed(),S(e,this.config)}async solve(e,r,n){this.ensureNotDisposed();try{if(typeof e=="string"&&!e?.trim())throw new l("Definition URL/content is required",f.INVALID_INPUT,{context:{receivedUrl:e}});if(e instanceof Uint8Array&&e.length===0)throw new l("Definition content is empty",f.INVALID_INPUT);let o={...this.config,...n?.signal!==void 0&&{signal:n.signal},...n?.timeoutMs!==void 0&&{timeoutMs:n.timeoutMs},...n?.retry!==void 0&&{retry:n.retry}},s=await x(r,e,o);if(s&&typeof s=="object"&&"message"in s&&!("fileData"in s))throw new l(s.message||"Computation failed",f.COMPUTATION_ERROR,{context:{definition:typeof e=="string"&&e.length<200?e:"...content...",inputs:r}});return s}catch(o){throw this.config.debug&&m().error("Compute failed:",o),o instanceof l?o:new l(o instanceof Error?o.message:String(o),f.COMPUTATION_ERROR,{context:{definition:typeof e=="string"&&e.length<200?e:"...content...",inputs:r},originalError:o instanceof Error?o:new Error(String(o))})}}createScheduler(e){this.ensureNotDisposed();let r=(n,o,s)=>x(o,n,s);return new h(r,this.config,e)}async dispose(){this.disposed||(this.disposed=!0,"dispose"in this.serverStats&&typeof this.serverStats.dispose=="function"&&await this.serverStats.dispose())}ensureNotDisposed(){if(this.disposed)throw new l("GrasshopperClient has been disposed and cannot be used",f.INVALID_STATE)}normalizeComputeConfig(e){if(!e.serverUrl?.trim())throw new l("serverUrl is required",f.INVALID_CONFIG,{context:{receivedServerUrl:e.serverUrl}});try{new URL(e.serverUrl)}catch{throw new l("serverUrl must be a valid URL",f.INVALID_CONFIG,{context:{receivedServerUrl:e.serverUrl}})}if(e.serverUrl===""||e.serverUrl==="https://compute.rhino3d.com/")throw new l("serverUrl must be set to your Compute server URL. The default public endpoint is not allowed.",f.INVALID_CONFIG,{context:{receivedServerUrl:e.serverUrl}});return{...e,serverUrl:e.serverUrl.replace(/\/+$/,""),apiKey:e.apiKey,authToken:e.authToken,debug:e.debug??!1,suppressClientSideWarning:e.suppressClientSideWarning}}};var M=async(t,e=null)=>{try{return await K(t,e)}catch(r){throw new l("Failed to extract files from compute response",f.INVALID_STATE,{context:{originalError:r instanceof Error?r.message:String(r)},originalError:r instanceof Error?r:void 0})}},P=async(t,e,r=null)=>{if(typeof document>"u"||typeof Blob>"u")throw new l("File download functionality is only available in browser environments. This function requires the DOM API (document, Blob).",f.BROWSER_ONLY,{context:{environment:typeof window<"u"?"browser (SSR)":"Node.js",documentAvailable:typeof document<"u",blobAvailable:typeof Blob<"u"}});try{let n=await K(t,r);await ie(n,e)}catch(n){throw n instanceof l?n:new l("Failed to download files from compute response",f.INVALID_STATE,{context:{originalError:n instanceof Error?n.message:String(n)},originalError:n instanceof Error?n:void 0})}},K=async(t,e)=>{let r=[];if(t.forEach(n=>{let o=`${n.fileName}${n.fileType}`;if(n.subFolder&&n.subFolder.trim()!==""&&(o=`${n.subFolder}/${o}`),n.isBase64Encoded===!0&&n.data){let s=q(n.data);r.push({fileName:`${n.fileName}${n.fileType}`,content:new Uint8Array(s.buffer),path:o})}else n.isBase64Encoded===!1&&n.data&&r.push({fileName:`${n.fileName}${n.fileType}`,content:n.data,path:o})}),e){let n=Array.isArray(e)?e:[e],o=await Promise.all(n.map(async s=>{try{let a=await fetch(s.filePath);if(!a.ok)return m().warn(`Failed to fetch additional file from URL: ${s.filePath}`),null;let u=await(await a.blob()).arrayBuffer();return{fileName:s.fileName,content:new Uint8Array(u),path:s.fileName}}catch(a){return m().error(`Error fetching additional file from URL: ${s.filePath}`,a),null}}));r.push(...o.filter(s=>s!==null))}return r};async function ie(t,e){let{zipSync:r,strToU8:n}=await import("fflate"),o={};t.forEach(i=>{o[i.path]=typeof i.content=="string"?n(i.content):i.content});let s=r(o,{level:6}),a=new Blob([s],{type:"application/zip"});ue(a,`${e}.zip`)}function ue(t,e){if(typeof document>"u")throw new l("saveFile requires a browser environment with DOM API access.",f.BROWSER_ONLY,{context:{function:"saveFile",requiredAPI:"document"}});let r=document.createElement("a");r.href=URL.createObjectURL(t),r.download=e,r.click(),URL.revokeObjectURL(r.href)}var A=new Map;function H(t,e){A.set(t,e)}H("Rhino.Geometry.Point3d",(t,e)=>{let r=e;return!r||typeof r.X!="number"?null:new t.Point([r.X,r.Y,r.Z])});H("Rhino.Geometry.Line",(t,e)=>{let r=e;return!r||!r.From||!r.To?null:new t.Line([r.From.X,r.From.Y,r.From.Z],[r.To.X,r.To.Y,r.To.Z])});function le(t){if(A.has(t))return A.get(t);for(let[e,r]of A)if(t.startsWith(e))return r}function pe(t){return!t||typeof t!="object"?null:t.data??t.value??null}function Y(t,e,r){let n=le(e);if(n)try{return n(r,t)}catch(o){m().warn(`Failed to decode Rhino type ${e}:`,o)}try{let o=pe(t);if(o)return r.CommonObject.decode(o)}catch(o){return m().warn(`Failed to decode ${e} with CommonObject:`,o),{__decodeError:!0,type:e,raw:t}}return t}var C={STRING:"System.String",INT:"System.Int32",DOUBLE:"System.Double",BOOL:"System.Boolean"},ce="Rhino.Geometry.",fe=["WebDisplay"],me="FileData";function Q(t){return fe.some(e=>t.includes(e))}function X(t){if(typeof t!="string")return t;let e=t.trim();if(!(e.startsWith("{")||e.startsWith("[")||e.startsWith('"')))return t;try{let n=JSON.parse(e);if(typeof n=="string")try{return JSON.parse(n)}catch{return n}return n}catch{return t}}function de(t,e,r){switch(e){case C.STRING:return typeof t!="string"?t:t.replace(/^"(.*)"$/,"$1");case C.INT:return Number.parseInt(t,10);case C.DOUBLE:return Number.parseFloat(t);case C.BOOL:return String(t).toLowerCase()==="true";default:return r&&e.startsWith(ce)?Y(t,e,r):t}}function Z(t,e,r,n){if(typeof t!="string")return t;let o=r?X(t):t;return de(o,e,n)}function E(t,e){for(let r of Object.values(t))if(Array.isArray(r))for(let n of r)e(n)}function ee(t,e=!1,r={}){let{parseValues:n=!0,rhino:o,stringOnly:s=!1}=r,a={};for(let i of t.values)E(i.InnerTree,u=>{if(Q(u.type)||s&&u.type!==C.STRING)return;let c=e?u.id:i.ParamName;if(!c)return;let d=Z(u.data,u.type,n,o);a[c]===void 0?a[c]=d:Array.isArray(a[c])?a[c].push(d):a[c]=[a[c],d]});return{values:a}}function te(t){let e=[];for(let r of t.values)E(r.InnerTree,n=>{if(!n.type.includes(me))return;let o=X(n.data);o&&o.fileName&&o.fileType&&"data"in o&&typeof o.isBase64Encoded=="boolean"&&typeof o.subFolder=="string"&&e.push(o)});return e}function k(t,e,r={}){let{parseValues:n=!0,rhino:o,stringOnly:s=!1}=r,a;if("byName"in e?a=t.values.find(u=>u.ParamName===e.byName):a=t.values.find(u=>{let c=!1;return E(u.InnerTree,d=>{d.id===e.byId&&(c=!0)}),c}),!a)return;let i=[];if(E(a.InnerTree,u=>{if("byId"in e&&u.id!==e.byId||Q(u.type)||s&&u.type!==C.STRING)return;let c=Z(u.data,u.type,n,o);i.push(c)}),i.length!==0)return i.length===1?i[0]:i}var I=class{constructor(e,r=!1){this.response=e;this.debug=r}getValues(e=!1,r={}){return ee(this.response,e,r)}getValueByParamName(e,r){return k(this.response,{byName:e},r)}getValueByParamId(e,r){return k(this.response,{byId:e},r)}async extractMeshesFromResponse(e){let r={debug:this.debug,...e},n;try{({getThreeMeshesFromComputeResponse:n}=await import("./visualization.js"))}catch(o){throw new l("Failed to load three.js visualization module. Ensure three.js is installed as a peer dependency.",f.INVALID_STATE,{context:{originalError:o instanceof Error?o.message:String(o)}})}return n(this.response,r)}getFileData(){return te(this.response)}getAndDownloadFiles(e,r){let n=this.getFileData();P(n,e,r)}};function V(t,e){e||typeof window<"u"&&m().warn(`Warning: ${t} is running on the client side. For better performance and security, consider running this on the server side.`)}async function x(t,e,r){r.debug&&V("solveGrasshopperDefinition",r.suppressClientSideWarning);let n=B(e,t);he(n,r);let o=await N("grasshopper",n,r);if("pointer"in o){let{pointer:s,...a}=o;return a}return o}function B(t,e){let r={algo:null,pointer:null,values:e};return t instanceof Uint8Array?r.algo=_(t):/^https?:\/\//i.test(t)?r.pointer=t:W(t)?r.algo=t:r.algo=z(t),r}function he(t,e){e.cachesolve!=null&&(t.cachesolve=e.cachesolve),e.modelunits!=null&&(t.modelunits=e.modelunits),e.angletolerance!=null&&(t.angletolerance=e.angletolerance),e.absolutetolerance!=null&&(t.absolutetolerance=e.absolutetolerance),e.dataversion!=null&&(t.dataversion=e.dataversion)}function re(t){if(typeof t.default!="object"||t.default===null)return;if(!("innerTree"in t.default)){m().warn("Unexpected structure in input.default:",t.default),t.default=null;return}let e=t.default.innerTree;if(Object.keys(e).length===0){t.default=void 0;return}if(t.treeAccess||t.atMost&&t.atMost>1){let n={};for(let[o,s]of Object.entries(e))n[o]=s.map(a=>{if(typeof a.data=="string"){if(a.type==="System.Double"||a.type==="System.Int32"){let i=Number(a.data);return Number.isNaN(i)?a.data:i}if(a.type==="System.Boolean")return a.data.toLowerCase()==="true";if(a.type.startsWith("Rhino.Geometry")||a.type==="System.String")try{return JSON.parse(a.data)}catch{return a.data}}return a.data});t.default=n;return}let r=[];for(let n of Object.values(e))Array.isArray(n)&&n.forEach(o=>{o&&typeof o=="object"&&"data"in o&&r.push(o.data)});r.length===0?t.default=void 0:r.length===1?t.default=r[0]:t.default=r}function O(t,e){let{transform:r,setUndefinedOnEmpty:n=!0}=e;if(!(t.default===void 0||t.default===null))if(Array.isArray(t.default)){let o=t.default.map(r).filter(s=>s!==null);t.default=o.length>0?o:void 0}else{let o=r(t.default);o!==null?t.default=o:n&&(t.default=void 0)}}function ye(){return t=>{if(typeof t=="number")return t;if(typeof t=="string"){let e=Number(t.trim());return Number.isNaN(e)?null:e}return null}}function ge(){return t=>{if(typeof t=="boolean")return t;if(typeof t=="string"){let e=t.toLowerCase();if(e==="true")return!0;if(e==="false")return!1;throw new Error(`Invalid boolean string: "${t}"`)}return null}}function be(){return t=>typeof t=="string"?t.startsWith('"')&&t.endsWith('"')||t.startsWith('"')?t.slice(1,-1):t:null}function Te(){return t=>{if(typeof t=="string"){let e=t.trim();return e.startsWith('"')&&e.endsWith('"')&&(e=e.slice(1,-1).trim()),e}return null}}function xe(t){O(t,{transform:Te(),setUndefinedOnEmpty:!1})}function Se(t="unknown"){return e=>{if(typeof e=="object"&&e!==null)return e;if(typeof e=="string"&&e.trim()!=="")try{let r=JSON.parse(e);return typeof r=="object"&&r!==null?r:(m().warn(`Parsed value for input ${t} is not an object`),null)}catch(r){return m().warn(`Failed to parse object value "${e}" for input ${t}`,r),null}return null}}function ne(t,e,r){let n=Number(t.toFixed(e));return Math.abs(t-n)<r?n:t}function Ce(t,e=1e-8){if(!Number.isFinite(t)||t===0)return .1;let r=Math.abs(t);if(r>=1){let y=String(t).split(".")[1];if(y&&y.length>0){let g=Math.min(y.length,12),b=Math.pow(10,-g),U=Number(b.toFixed(g));return Math.abs(U-b)<e?U:b}return 1}let n=String(t),o=n.toLowerCase().match(/e(-?\d+)/);if(o){let G=Number(o[1]);if(G<0||n.toLowerCase().includes("e-")){let y=Math.abs(G),g=Math.pow(10,-y),b=Number(g.toFixed(y));return Math.abs(b-g)<e?b:g}return .1}let s=12,i=r.toFixed(s).replace(/0+$/,""),u=Math.min((i.split(".")[1]||"").length,s);if(u===0)return .1;let c=Math.pow(10,-u),d=Number(c.toFixed(u));return Math.abs(d-c)<e?d:c}function oe(t,e=1e-8){let r=t.paramType==="Integer";if(O(t,{transform:ye()}),r){Array.isArray(t.default)?t.default=t.default.map(s=>typeof s=="number"?Math.round(s):s):typeof t.default=="number"&&(t.default=Math.round(t.default)),t.stepSize=1;return}let n=Array.isArray(t.default)?t.default[0]:t.default,o;if(typeof n=="number"&&Number.isFinite(n)&&n!==0?o=n:typeof t.minimum=="number"&&Number.isFinite(t.minimum)&&t.minimum!==0?o=t.minimum:typeof t.maximum=="number"&&Number.isFinite(t.maximum)&&t.maximum!==0&&(o=t.maximum),o!==void 0?t.stepSize=Ce(o,e):t.stepSize=.1,typeof t.stepSize=="number"){let s=0,a=String(t.stepSize),i=a.toLowerCase().match(/e(-?\d+)/);if(i?s=Math.abs(Number(i[1])):s=a.split(".")[1]?.length??0,s===0&&typeof n=="number"&&n!==0&&Math.abs(n)<1){let u=Math.ceil(-Math.log10(Math.abs(n)));Number.isFinite(u)&&u>0&&(s=u)}s=Math.min(Math.max(s,0),12),Array.isArray(t.default)?t.default=t.default.map(u=>typeof u=="number"?ne(u,s,e):u):typeof t.default=="number"&&(t.default=ne(t.default,s,e))}}function Ie(t){try{O(t,{transform:ge(),setUndefinedOnEmpty:!1})}catch(e){throw e instanceof Error?new l(e.message):e}}function De(t){O(t,{transform:be(),setUndefinedOnEmpty:!1})}function se(t){O(t,{transform:Se(t.nickname||"unnamed"),setUndefinedOnEmpty:!0})}function ve(t){if(!t.values||typeof t.values!="object"||Object.keys(t.values).length===0)throw l.missingValues(t.nickname||"unnamed","ValueList");if(t.default!==void 0&&t.default!==null){let e=String(t.default).toLowerCase();Object.keys(t.values).some(n=>n.toLowerCase()===e)||m().warn(`ValueList input "${t.nickname||"unnamed"}" default value "${t.default}" is not in available values`)}}var ae={Number:oe,Integer:oe,Boolean:Ie,Text:De,ValueList:ve,Geometry:se,File:se,Color:xe};function Re(t,e){let r=(t.atMost??1)>1;switch(t.paramType){case"Number":case"Integer":return{...e,paramType:t.paramType,minimum:t.minimum,maximum:t.maximum,atLeast:t.atLeast,atMost:t.atMost,default:r?[0]:0};case"Boolean":return{...e,paramType:"Boolean",default:r?[!1]:!1};case"Text":return{...e,paramType:"Text",default:r?[""]:""};case"ValueList":return{...e,paramType:"ValueList",values:t.values??{},default:r?[t.default]:t.default};case"File":return{...e,paramType:"File",default:r?[null]:null};case"Color":return{...e,paramType:"Color",default:r?["0, 0, 0"]:"0, 0, 0"};default:return{...e,paramType:"Geometry",default:r?[null]:null}}}function F(t){let e={description:t.description,name:t.name,nickname:t.nickname,treeAccess:t.treeAccess,groupName:t.groupName??"",id:t.id};try{re(t);let r=ae[t.paramType];if(!r)throw l.unknownParamType(t.paramType,t.name);switch(r(t),t.paramType){case"Number":case"Integer":return{...e,paramType:t.paramType,minimum:t.minimum,maximum:t.maximum,atLeast:t.atLeast,atMost:t.atMost,stepSize:t.stepSize,default:t.default};case"Boolean":return{...e,paramType:"Boolean",default:t.default};case"Text":return{...e,paramType:"Text",default:t.default};case"ValueList":return{...e,paramType:"ValueList",values:t.values,default:t.default};case"Geometry":return{...e,paramType:t.paramType,default:t.default};case"File":return{...e,paramType:t.paramType,acceptedFormats:t.acceptedFormats,default:t.default};case"Color":return{...e,paramType:"Color",default:t.default};default:throw l.unknownParamType(t.paramType,t.name)}}catch(r){if(r instanceof l)return m().error(`Validation error for input ${t.name||"unknown"}:`,r.message),Re(t,e);throw new l(r instanceof Error?r.message:String(r),"VALIDATION_ERROR",{context:{paramName:t.name,paramType:t.paramType},originalError:r instanceof Error?r:new Error(String(r))})}}function D(t){return t.map(e=>F(e))}async function S(t,e){let r=B(t,[]),n={};if(r.algo&&(n.algo=r.algo),r.pointer&&(n.pointer=r.pointer),!n.algo&&!n.pointer)throw new l("Definition must resolve to either a URL pointer or base64 algo",f.INVALID_INPUT,{context:{definition:t}});let o=await N("io",n,e);if(!o||typeof o!="object")throw new l("Invalid IO response structure",f.INVALID_INPUT,{context:{response:o,definition:t}});let s=$(o,{deep:!0});return{inputs:s.inputs,outputs:s.outputs}}async function R(t,e){V("fetchParsedDefinitionIO",e.suppressClientSideWarning);let{inputs:r,outputs:n}=await S(t,e);return{inputs:D(r),outputs:n}}var w=class t{constructor(e){p(this,"innerTree");p(this,"paramName");this.paramName=e,this.innerTree={}}append(e,r){let n=t.formatPathString(e);this.innerTree[n]||(this.innerTree[n]=[]);let o=r.map(s=>({data:t.serializeValue(s)}));return this.innerTree[n].push(...o),this}appendSingle(e,r){return this.append(e,[r])}fromDataTreeDefault(e){this.innerTree={};for(let[r,n]of Object.entries(e)){if(!Array.isArray(n))continue;let o=t.parsePathString(r);this.append(o,n)}return this}appendFlat(e){let r=Array.isArray(e)?e:[e];return this.append([0],r)}flatten(){let e=[];for(let r of Object.values(this.innerTree))if(Array.isArray(r))for(let n of r)e.push(t.deserializeValue(n.data));return e}getPaths(){return Object.keys(this.innerTree)}getPath(e){let r=t.formatPathString(e),n=this.innerTree[r];if(n)return n.map(o=>t.deserializeValue(o.data))}toComputeFormat(){return{ParamName:this.paramName,InnerTree:this.innerTree}}getInnerTree(){return this.innerTree}getParamName(){return this.paramName}static fromInputParams(e){return e.filter(r=>t.hasValidValue(r.default)).map(r=>{let n=new t(r.nickname||"unnamed"),o=r.default;if(r.treeAccess&&t.isDataTreeStructure(o))n.fromDataTreeDefault(o),t.isNumericInput(r)&&n.applyNumericConstraints(r.minimum,r.maximum,r.nickname||"unnamed");else{let s=Array.isArray(o)?o:[o],a=t.processValues(s,r);n.appendFlat(a)}return n.toComputeFormat()})}static fromInputParam(e){return t.hasValidValue(e.default)?t.fromInputParams([e])[0]:void 0}static replaceTreeValue(e,r,n){if(e.length>0&&e[0]instanceof t){let s=e,a=s.findIndex(u=>u.getParamName()===r),i=new t(r);return typeof n=="object"&&n!==null&&!Array.isArray(n)&&t.isDataTreeStructure(n)?i.fromDataTreeDefault(n):(Array.isArray(n),i.appendFlat(n)),a!==-1?s[a]=i:s.push(i),s}else{let s=e,a=s.findIndex(c=>c.ParamName===r),i=new t(r);typeof n=="object"&&n!==null&&!Array.isArray(n)&&t.isDataTreeStructure(n)?i.fromDataTreeDefault(n):(Array.isArray(n),i.appendFlat(n));let u=i.toComputeFormat();return a!==-1?s[a]=u:s.push(u),s}}static getTreeValue(e,r){if(e.length>0&&e[0]instanceof t){let s=e.find(i=>i.getParamName()===r);if(!s)return null;let a=s.flatten();return a.length===0?null:a.length===1?a[0]:a}else{let s=e.find(c=>c.ParamName===r);if(!s)return null;let a=s.InnerTree;if(!a)return null;let i=Object.keys(a)[0];if(!i)return null;let u=a[i];if(Array.isArray(u)){if(u.length===1){let c=u[0]?.data;return c!==void 0?t.deserializeValue(c):null}return u.map(c=>c?.data!==void 0?t.deserializeValue(c.data):null).filter(c=>c!==null)}return u?.data!==void 0?t.deserializeValue(u.data):u}}static parsePathString(e){let r=e.match(/^\{([\d;]*)\}$/);return r?r[1]===""?[]:r[1].split(";").map(Number):(m().warn(`Invalid TreeBuilder path format: ${e}, using [0]`),[0])}static formatPathString(e){return`{${e.join(";")}}`}applyNumericConstraints(e,r,n){for(let o of Object.values(this.innerTree))if(Array.isArray(o))for(let s of o){let a=t.deserializeValue(s.data);if(typeof a=="number"){let i=t.clampValue(a,e,r,n);s.data=t.serializeValue(i)}}}static serializeValue(e){return typeof e=="boolean"||typeof e=="number"||typeof e=="string"?e:typeof e=="object"&&e!==null?JSON.stringify(e):String(e)}static deserializeValue(e){if(typeof e=="boolean"||typeof e=="number"||typeof e!="string")return e;if(e.startsWith("{")||e.startsWith("["))try{return JSON.parse(e)}catch{return e}return isNaN(Number(e))?e==="true"?!0:e==="false"?!1:e:Number(e)}static hasValidValue(e){return e==null?!1:typeof e=="string"?!0:!(Array.isArray(e)&&e.length===0||typeof e=="object"&&!Array.isArray(e)&&Object.keys(e).length===0)}static isDataTreeStructure(e){return typeof e!="object"||e===null||Array.isArray(e)?!1:Object.entries(e).every(([r,n])=>typeof r=="string"&&/^\{[\d;]+\}$/.test(r)&&Array.isArray(n))}static isNumericInput(e){return e.paramType==="Number"||e.paramType==="Integer"}static processValues(e,r){return e.map(n=>t.isNumericInput(r)&&typeof n=="number"?t.clampValue(n,r.minimum,r.maximum,r.nickname||"unnamed"):n).filter(n=>n!=null)}static clampValue(e,r,n,o){let s=e;return r!=null&&s<r&&(m().warn(`${o}: ${e} below min ${r}, clamping`),s=r),n!=null&&s>n&&(m().warn(`${o}: ${e} above max ${n}, clamping`),s=n),s}};export{v as a,h as b,T as c,M as d,P as e,I as f,x as g,F as h,D as i,S as j,R as k,w as l};
2
+ //# sourceMappingURL=chunk-BKGFHI2J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/features/grasshopper/scheduler/stable-hash.ts","../src/features/grasshopper/scheduler/solve-scheduler.ts","../src/features/grasshopper/client/grasshopper-client.ts","../src/features/grasshopper/file-handling/handle-files.ts","../src/features/grasshopper/io/output/rhino-decoder.ts","../src/features/grasshopper/io/output/response-processors.ts","../src/features/grasshopper/client/grasshopper-response-processor.ts","../src/core/utils/warnings.ts","../src/features/grasshopper/compute/solve.ts","../src/features/grasshopper/io/input/input-validators.ts","../src/features/grasshopper/io/input/input-parsers.ts","../src/features/grasshopper/io/input/input-processors.ts","../src/features/grasshopper/io/definition-io.ts","../src/features/grasshopper/data-tree/data-tree.ts"],"sourcesContent":["/**\n * Stable hashing helpers for solve dedupe / cache keys.\n *\n * @internal\n */\n\n/**\n * Deterministic JSON stringify — keys are sorted at every object level so\n * `{a:1,b:2}` and `{b:2,a:1}` produce the same string. Handles circular\n * references safely (replaces with a sentinel) and non-finite numbers.\n */\nexport function stableStringify(value: unknown): string {\n\tconst seen = new WeakSet<object>();\n\n\tconst stringify = (v: unknown): string => {\n\t\tif (v === null || v === undefined) return JSON.stringify(v);\n\t\tif (typeof v === 'number') {\n\t\t\treturn Number.isFinite(v) ? String(v) : JSON.stringify(null);\n\t\t}\n\t\tif (typeof v === 'string' || typeof v === 'boolean') return JSON.stringify(v);\n\t\tif (typeof v === 'bigint') return JSON.stringify(v.toString());\n\t\tif (v instanceof Uint8Array) {\n\t\t\t// Hash bytes by length + a sample to avoid stringifying multi-MB buffers fully\n\t\t\tconst sample = v.length > 64 ? Array.from(v.slice(0, 32)).concat(Array.from(v.slice(-32))) : Array.from(v);\n\t\t\treturn JSON.stringify({ __u8: true, len: v.length, sample });\n\t\t}\n\t\tif (Array.isArray(v)) {\n\t\t\treturn `[${v.map(stringify).join(',')}]`;\n\t\t}\n\t\tif (typeof v === 'object') {\n\t\t\tif (seen.has(v as object)) return JSON.stringify('[Circular]');\n\t\t\tseen.add(v as object);\n\t\t\tconst keys = Object.keys(v as object).sort();\n\t\t\tconst parts = keys.map((k) => `${JSON.stringify(k)}:${stringify((v as any)[k])}`);\n\t\t\treturn `{${parts.join(',')}}`;\n\t\t}\n\t\t// Fallback for functions, symbols, etc.\n\t\treturn JSON.stringify(null);\n\t};\n\n\treturn stringify(value);\n}\n\n/**\n * 32-bit FNV-1a hash. Fast, no deps, good enough for dedupe/cache keys.\n * Returns an unsigned hex string.\n */\nexport function fnv1a(input: string): string {\n\tlet hash = 0x811c9dc5;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = (hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24))) >>> 0;\n\t}\n\treturn hash.toString(16).padStart(8, '0');\n}\n\n/**\n * Hash a (definition, dataTree) pair into a short stable key.\n * For Uint8Array definitions we use length + endpoint bytes rather than the\n * full content to keep hashing cheap.\n */\nexport function hashSolveInput(definition: string | Uint8Array, dataTree: unknown): string {\n\tconst defKey =\n\t\ttypeof definition === 'string'\n\t\t\t? definition\n\t\t\t: stableStringify({ __u8: true, len: definition.length });\n\treturn fnv1a(`${defKey}|${stableStringify(dataTree)}`);\n}\n","import { RhinoComputeError, ErrorCodes } from '@/core/errors';\nimport type { RetryPolicy } from '@/core/types';\nimport { getLogger } from '@/core/utils/logger';\n\nimport type {\n\tDataTree,\n\tGrasshopperComputeResponse,\n\tGrasshopperComputeConfig\n} from '../types';\nimport { hashSolveInput } from './stable-hash';\n\n/**\n * Scheduling mode — controls how concurrent `solve()` calls interact.\n *\n * - `latest-wins`: One in flight at a time. New calls supersede any pending\n * call (in-flight one is aborted). Optimal for slider scrubs / live UIs.\n * - `queue`: FIFO queue. Each solve runs to completion. Concurrency capped\n * by `maxConcurrent`. Use for \"submit job\" flows where every request matters.\n * - `parallel`: No scheduling — calls run concurrently up to `maxConcurrent`.\n * Closest to plain `client.solve()` but with shared cancel/state.\n */\nexport type SchedulerMode = 'latest-wins' | 'queue' | 'parallel';\n\nexport interface CacheOptions {\n\t/** Maximum entries kept in the LRU. Default: 50. */\n\tmaxEntries?: number;\n\t/** Time-to-live in ms. Set to `0` for no expiry (default). */\n\tttlMs?: number;\n}\n\nexport interface SolveSchedulerOptions {\n\tmode?: SchedulerMode;\n\tmaxConcurrent?: number;\n\ttimeoutMs?: number;\n\tretry?: RetryPolicy;\n\t/** Enable response caching keyed by hash of (definition, dataTree). */\n\tcache?: boolean | CacheOptions;\n\t/** Lifecycle hooks — fired in order. Errors thrown by hooks are logged, not rethrown. */\n\tonStart?: (ctx: SolveContext) => void;\n\tonSettle?: (ctx: SolveContext, result: SolveResult) => void;\n\tonSuperseded?: (ctx: SolveContext) => void;\n}\n\nexport interface SolveContext {\n\t/** Stable hash of (definition, dataTree). */\n\tkey: string;\n\t/** Wall-clock timestamp when scheduler.solve() was called. */\n\tenqueuedAt: number;\n\t/** Wall-clock timestamp when execution actually started (after queueing). */\n\tstartedAt: number | null;\n}\n\nexport type SolveResult =\n\t| { status: 'success'; response: GrasshopperComputeResponse; durationMs: number; fromCache: boolean }\n\t| { status: 'error'; error: RhinoComputeError; durationMs: number }\n\t| { status: 'superseded' };\n\ninterface CacheEntry {\n\tresponse: GrasshopperComputeResponse;\n\tinsertedAt: number;\n}\n\ninterface PendingItem {\n\tdefinition: string | Uint8Array;\n\tdataTree: DataTree[];\n\tctx: SolveContext;\n\tresolve: (response: GrasshopperComputeResponse) => void;\n\treject: (error: RhinoComputeError) => void;\n\texternalSignal?: AbortSignal;\n}\n\ninterface InFlightItem extends PendingItem {\n\tcontroller: AbortController;\n}\n\n/**\n * Adapter for the underlying solve function. Lets the scheduler be tested\n * without a real Compute server, and decouples it from the client class.\n */\nexport type SolveExecutor = (\n\tdefinition: string | Uint8Array,\n\tdataTree: DataTree[],\n\tconfig: GrasshopperComputeConfig\n) => Promise<GrasshopperComputeResponse>;\n\n/**\n * Robust scheduler for Grasshopper solves.\n *\n * Sits between your application code and the underlying compute call,\n * adding:\n * - Configurable scheduling (latest-wins for sliders, queue for jobs)\n * - In-flight cancellation (per-call signal + cancelAll)\n * - Optional response caching for repeated inputs\n * - Lifecycle hooks for UI indicators (start / settle / superseded)\n * - State observability via subscribe()\n *\n * Multiple schedulers can share a single GrasshopperClient — typically one\n * per UI surface (e.g. one for slider scrubs, one for long-running submits).\n *\n * @example\n * ```ts\n * const scheduler = client.createScheduler({ mode: 'latest-wins', timeoutMs: 30_000 });\n *\n * // From a slider handler:\n * scheduler.solve(definition, tree).then((result) => {\n * updateMeshes(result);\n * }).catch((err) => {\n * if (err.code !== 'SUPERSEDED') showError(err);\n * });\n *\n * // From a UI binding:\n * scheduler.subscribe(() => {\n * showSpinner = scheduler.isSolving;\n * });\n * ```\n */\nexport class SolveScheduler {\n\tprivate readonly executor: SolveExecutor;\n\tprivate readonly baseConfig: GrasshopperComputeConfig;\n\n\tprivate readonly mode: SchedulerMode;\n\tprivate readonly maxConcurrent: number;\n\tprivate readonly timeoutMs: number | undefined;\n\tprivate readonly retry: RetryPolicy | undefined;\n\n\tprivate readonly cacheEnabled: boolean;\n\tprivate readonly cacheMax: number;\n\tprivate readonly cacheTtl: number;\n\tprivate readonly cache = new Map<string, CacheEntry>();\n\n\tprivate readonly onStart?: SolveSchedulerOptions['onStart'];\n\tprivate readonly onSettle?: SolveSchedulerOptions['onSettle'];\n\tprivate readonly onSuperseded?: SolveSchedulerOptions['onSuperseded'];\n\n\tprivate readonly subscribers = new Set<() => void>();\n\n\tprivate readonly inFlight = new Set<InFlightItem>();\n\tprivate pendingForLatestWins: PendingItem | null = null;\n\tprivate readonly fifoQueue: PendingItem[] = [];\n\n\tprivate _lastResult: GrasshopperComputeResponse | null = null;\n\tprivate _lastError: RhinoComputeError | null = null;\n\tprivate _lastDurationMs: number | null = null;\n\n\tprivate disposed = false;\n\n\tconstructor(\n\t\texecutor: SolveExecutor,\n\t\tbaseConfig: GrasshopperComputeConfig,\n\t\toptions: SolveSchedulerOptions = {}\n\t) {\n\t\tthis.executor = executor;\n\t\tthis.baseConfig = baseConfig;\n\t\tthis.mode = options.mode ?? 'latest-wins';\n\t\tthis.maxConcurrent = Math.max(1, options.maxConcurrent ?? (this.mode === 'parallel' ? 4 : 1));\n\t\tthis.timeoutMs = options.timeoutMs;\n\t\tthis.retry = options.retry;\n\n\t\tconst cacheOpt = options.cache;\n\t\tthis.cacheEnabled = cacheOpt !== undefined && cacheOpt !== false;\n\t\tconst cacheConfig = typeof cacheOpt === 'object' ? cacheOpt : {};\n\t\tthis.cacheMax = cacheConfig.maxEntries ?? 50;\n\t\tthis.cacheTtl = cacheConfig.ttlMs ?? 0;\n\n\t\tthis.onStart = options.onStart;\n\t\tthis.onSettle = options.onSettle;\n\t\tthis.onSuperseded = options.onSuperseded;\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Public state\n\t// --------------------------------------------------------------------------\n\n\tget isSolving(): boolean {\n\t\treturn this.inFlight.size > 0;\n\t}\n\n\tget hasPending(): boolean {\n\t\treturn this.pendingForLatestWins !== null || this.fifoQueue.length > 0;\n\t}\n\n\tget inFlightCount(): number {\n\t\treturn this.inFlight.size;\n\t}\n\n\tget queueDepth(): number {\n\t\treturn this.fifoQueue.length + (this.pendingForLatestWins ? 1 : 0);\n\t}\n\n\tget lastResult(): GrasshopperComputeResponse | null {\n\t\treturn this._lastResult;\n\t}\n\n\tget lastError(): RhinoComputeError | null {\n\t\treturn this._lastError;\n\t}\n\n\tget lastDurationMs(): number | null {\n\t\treturn this._lastDurationMs;\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Subscribe — minimal observable. Called whenever observable state changes.\n\t// --------------------------------------------------------------------------\n\n\tsubscribe(listener: () => void): () => void {\n\t\tthis.subscribers.add(listener);\n\t\treturn () => this.subscribers.delete(listener);\n\t}\n\n\tprivate notify(): void {\n\t\tfor (const listener of this.subscribers) {\n\t\t\ttry {\n\t\t\t\tlistener();\n\t\t\t} catch (err) {\n\t\t\t\tgetLogger().error('[SolveScheduler] subscriber threw:', err);\n\t\t\t}\n\t\t}\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// solve()\n\t// --------------------------------------------------------------------------\n\n\t/**\n\t * Schedule a solve. Returns a promise that:\n\t * - Resolves with the compute response on success.\n\t * - Rejects with `RhinoComputeError` on failure.\n\t * - Rejects with `code: ErrorCodes.UNKNOWN_ERROR` and `message: 'Superseded'`\n\t * when the call was canceled because newer values arrived (latest-wins mode).\n\t *\n\t * Caller-supplied `signal` cancels just this call (rejects with abort error).\n\t */\n\tsolve(\n\t\tdefinition: string | Uint8Array,\n\t\tdataTree: DataTree[],\n\t\toptions?: { signal?: AbortSignal }\n\t): Promise<GrasshopperComputeResponse> {\n\t\tif (this.disposed) {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew RhinoComputeError(\n\t\t\t\t\t'SolveScheduler has been disposed and cannot be used',\n\t\t\t\t\tErrorCodes.INVALID_STATE\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tconst key = hashSolveInput(definition, dataTree);\n\t\tconst ctx: SolveContext = {\n\t\t\tkey,\n\t\t\tenqueuedAt: Date.now(),\n\t\t\tstartedAt: null\n\t\t};\n\n\t\t// Cache hit — return synchronously-resolved promise\n\t\tif (this.cacheEnabled) {\n\t\t\tconst cached = this.readCache(key);\n\t\t\tif (cached) {\n\t\t\t\tconst result: SolveResult = {\n\t\t\t\t\tstatus: 'success',\n\t\t\t\t\tresponse: cached,\n\t\t\t\t\tdurationMs: 0,\n\t\t\t\t\tfromCache: true\n\t\t\t\t};\n\t\t\t\tthis._lastResult = cached;\n\t\t\t\tthis._lastError = null;\n\t\t\t\tthis._lastDurationMs = 0;\n\t\t\t\tthis.runHook(this.onStart, ctx);\n\t\t\t\tthis.runHook(this.onSettle, ctx, result);\n\t\t\t\tthis.notify();\n\t\t\t\treturn Promise.resolve(cached);\n\t\t\t}\n\t\t}\n\n\t\treturn new Promise<GrasshopperComputeResponse>((resolve, reject) => {\n\t\t\tconst item: PendingItem = {\n\t\t\t\tdefinition,\n\t\t\t\tdataTree,\n\t\t\t\tctx,\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t\texternalSignal: options?.signal\n\t\t\t};\n\n\t\t\t// External signal cancellation — reject immediately if already aborted\n\t\t\tif (item.externalSignal?.aborted) {\n\t\t\t\treject(this.makeAbortError(ctx));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.enqueue(item);\n\t\t});\n\t}\n\n\tprivate enqueue(item: PendingItem): void {\n\t\tswitch (this.mode) {\n\t\t\tcase 'latest-wins': {\n\t\t\t\t// Reject any pending one as superseded\n\t\t\t\tif (this.pendingForLatestWins) {\n\t\t\t\t\tthis.supersede(this.pendingForLatestWins);\n\t\t\t\t\tthis.pendingForLatestWins = null;\n\t\t\t\t}\n\t\t\t\t// Abort any in-flight one as superseded\n\t\t\t\tfor (const inflight of this.inFlight) {\n\t\t\t\t\tthis.supersede(inflight);\n\t\t\t\t\tinflight.controller.abort();\n\t\t\t\t}\n\t\t\t\t// Run immediately if no slot is taken\n\t\t\t\tif (this.inFlight.size === 0) {\n\t\t\t\t\tthis.execute(item);\n\t\t\t\t} else {\n\t\t\t\t\tthis.pendingForLatestWins = item;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase 'queue': {\n\t\t\t\tif (this.inFlight.size < this.maxConcurrent) {\n\t\t\t\t\tthis.execute(item);\n\t\t\t\t} else {\n\t\t\t\t\tthis.fifoQueue.push(item);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase 'parallel': {\n\t\t\t\tif (this.inFlight.size < this.maxConcurrent) {\n\t\t\t\t\tthis.execute(item);\n\t\t\t\t} else {\n\t\t\t\t\tthis.fifoQueue.push(item);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tthis.notify();\n\t}\n\n\tprivate async execute(item: PendingItem): Promise<void> {\n\t\tconst controller = new AbortController();\n\t\tconst inflight: InFlightItem = { ...item, controller };\n\t\tthis.inFlight.add(inflight);\n\t\titem.ctx.startedAt = Date.now();\n\n\t\tconst externalAbortHandler = () => controller.abort();\n\t\titem.externalSignal?.addEventListener('abort', externalAbortHandler, { once: true });\n\n\t\tthis.runHook(this.onStart, item.ctx);\n\t\tthis.notify();\n\n\t\tconst startTime = performance.now();\n\t\ttry {\n\t\t\tconst config: GrasshopperComputeConfig = {\n\t\t\t\t...this.baseConfig,\n\t\t\t\tsignal: controller.signal,\n\t\t\t\t...(this.timeoutMs !== undefined && { timeoutMs: this.timeoutMs }),\n\t\t\t\t...(this.retry !== undefined && { retry: this.retry })\n\t\t\t};\n\n\t\t\tconst response = await this.executor(item.definition, item.dataTree, config);\n\t\t\tconst durationMs = performance.now() - startTime;\n\n\t\t\tif (this.cacheEnabled) this.writeCache(item.ctx.key, response);\n\n\t\t\tthis._lastResult = response;\n\t\t\tthis._lastError = null;\n\t\t\tthis._lastDurationMs = durationMs;\n\n\t\t\titem.resolve(response);\n\t\t\tthis.runHook(this.onSettle, item.ctx, {\n\t\t\t\tstatus: 'success',\n\t\t\t\tresponse,\n\t\t\t\tdurationMs,\n\t\t\t\tfromCache: false\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconst durationMs = performance.now() - startTime;\n\t\t\tconst err =\n\t\t\t\terror instanceof RhinoComputeError\n\t\t\t\t\t? error\n\t\t\t\t\t: new RhinoComputeError(\n\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t\tErrorCodes.UNKNOWN_ERROR,\n\t\t\t\t\t\t\t{ originalError: error instanceof Error ? error : new Error(String(error)) }\n\t\t\t\t\t\t);\n\n\t\t\tthis._lastError = err;\n\t\t\tthis._lastDurationMs = durationMs;\n\n\t\t\titem.reject(err);\n\t\t\tthis.runHook(this.onSettle, item.ctx, { status: 'error', error: err, durationMs });\n\t\t} finally {\n\t\t\titem.externalSignal?.removeEventListener('abort', externalAbortHandler);\n\t\t\tthis.inFlight.delete(inflight);\n\t\t\tthis.drainNext();\n\t\t\tthis.notify();\n\t\t}\n\t}\n\n\tprivate drainNext(): void {\n\t\tif (this.disposed) return;\n\n\t\t// latest-wins: promote pending if no in-flight\n\t\tif (this.mode === 'latest-wins') {\n\t\t\tif (this.pendingForLatestWins && this.inFlight.size === 0) {\n\t\t\t\tconst next = this.pendingForLatestWins;\n\t\t\t\tthis.pendingForLatestWins = null;\n\t\t\t\tthis.execute(next);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// queue / parallel: pull from FIFO until at capacity\n\t\twhile (this.fifoQueue.length > 0 && this.inFlight.size < this.maxConcurrent) {\n\t\t\tconst next = this.fifoQueue.shift()!;\n\t\t\tthis.execute(next);\n\t\t}\n\t}\n\n\tprivate supersede(item: PendingItem): void {\n\t\tconst err = new RhinoComputeError('Superseded by newer solve', ErrorCodes.UNKNOWN_ERROR, {\n\t\t\tcontext: { key: item.ctx.key, enqueuedAt: item.ctx.enqueuedAt }\n\t\t});\n\t\titem.reject(err);\n\t\tthis.runHook(this.onSuperseded, item.ctx);\n\t}\n\n\tprivate makeAbortError(ctx: SolveContext): RhinoComputeError {\n\t\treturn new RhinoComputeError('Request aborted by caller', ErrorCodes.UNKNOWN_ERROR, {\n\t\t\tcontext: { key: ctx.key, enqueuedAt: ctx.enqueuedAt }\n\t\t});\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Cancellation\n\t// --------------------------------------------------------------------------\n\n\t/** Cancel everything — in-flight and pending. */\n\tcancelAll(): void {\n\t\t// Reject pending\n\t\tif (this.pendingForLatestWins) {\n\t\t\tthis.pendingForLatestWins.reject(this.makeAbortError(this.pendingForLatestWins.ctx));\n\t\t\tthis.pendingForLatestWins = null;\n\t\t}\n\t\twhile (this.fifoQueue.length > 0) {\n\t\t\tconst item = this.fifoQueue.shift()!;\n\t\t\titem.reject(this.makeAbortError(item.ctx));\n\t\t}\n\t\t// Abort in-flight — their finally blocks will reject their promises\n\t\tfor (const inflight of this.inFlight) {\n\t\t\tinflight.controller.abort();\n\t\t}\n\t\tthis.notify();\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Cache\n\t// --------------------------------------------------------------------------\n\n\tprivate readCache(key: string): GrasshopperComputeResponse | null {\n\t\tif (!this.cacheEnabled) return null;\n\t\tconst entry = this.cache.get(key);\n\t\tif (!entry) return null;\n\t\tif (this.cacheTtl > 0 && Date.now() - entry.insertedAt > this.cacheTtl) {\n\t\t\tthis.cache.delete(key);\n\t\t\treturn null;\n\t\t}\n\t\t// LRU touch\n\t\tthis.cache.delete(key);\n\t\tthis.cache.set(key, entry);\n\t\treturn entry.response;\n\t}\n\n\tprivate writeCache(key: string, response: GrasshopperComputeResponse): void {\n\t\tif (!this.cacheEnabled) return;\n\t\tthis.cache.set(key, { response, insertedAt: Date.now() });\n\t\twhile (this.cache.size > this.cacheMax) {\n\t\t\tconst oldest = this.cache.keys().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis.cache.delete(oldest);\n\t\t}\n\t}\n\n\tclearCache(): void {\n\t\tthis.cache.clear();\n\t}\n\n\t// --------------------------------------------------------------------------\n\t// Lifecycle\n\t// --------------------------------------------------------------------------\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.cancelAll();\n\t\tthis.subscribers.clear();\n\t\tthis.cache.clear();\n\t}\n\n\tprivate runHook<H extends (...args: any[]) => void>(\n\t\thook: H | undefined,\n\t\t...args: Parameters<H>\n\t): void {\n\t\tif (!hook) return;\n\t\ttry {\n\t\t\thook(...args);\n\t\t} catch (err) {\n\t\t\tgetLogger().error('[SolveScheduler] hook threw:', err);\n\t\t}\n\t}\n}\n","import { ErrorCodes } from '@/core/errors';\nimport { RhinoComputeError } from '@/core/errors/base';\nimport { getLogger } from '@/core/utils/logger';\nimport ComputeServerStats from '@/core/server/compute-server-stats';\nimport { ComputeConfig, RetryPolicy } from '@/core/types';\n\nimport { fetchDefinitionIO, fetchParsedDefinitionIO, solveGrasshopperDefinition } from '..';\nimport { GrasshopperComputeConfig, GrasshopperComputeResponse, DataTree } from '../types';\nimport { SolveScheduler, SolveSchedulerOptions } from '../scheduler';\n\n/**\n * Per-call options that override the client's default ComputeConfig values.\n *\n * Use these for per-request control without mutating the client config:\n * - `signal` — cancel a specific solve (e.g. when a slider value is superseded)\n * - `timeoutMs` — extend timeout for a long-running solve, or pass `0` to disable\n * - `retry` — override retry policy for this call only\n */\nexport interface SolveOptions {\n\tsignal?: AbortSignal;\n\ttimeoutMs?: number;\n\tretry?: RetryPolicy;\n}\n\n/**\n * GrasshopperClient provides a simple API for interacting with a Rhino Compute server and grasshopper.\n *\n * @public This is the recommended high-level API for Rhino Compute operations.\n *\n * **Security Warning:**\n * Using this client in a browser environment exposes your server URL and API key to users.\n * For production, use this library server-side or proxy requests through your own backend.\n *\n * @example\n * ```typescript\n * const client = await GrasshopperClient.create({\n * serverUrl: 'http://localhost:6500',\n * apiKey: 'your-api-key'\n * });\n *\n * try {\n * const result = await client.solve(definitionUrl, { x: 1, y: 2 });\n * } finally {\n * await client.dispose(); // Clean up resources\n * }\n * ```\n */\nexport default class GrasshopperClient {\n\tprivate readonly config: GrasshopperComputeConfig;\n\tpublic readonly serverStats: ComputeServerStats;\n\tprivate disposed = false;\n\n\tprivate constructor(config: GrasshopperComputeConfig) {\n\t\tthis.config = this.normalizeComputeConfig(config);\n\t\tthis.serverStats = new ComputeServerStats(this.config.serverUrl, this.config.apiKey);\n\t}\n\n\t/**\n\t * Creates and initializes a GrasshopperClient with server validation.\n\t *\n\t * @throws {RhinoComputeError} with code NETWORK_ERROR if server is offline\n\t * @throws {RhinoComputeError} with code INVALID_CONFIG if configuration is invalid\n\t */\n\tstatic async create(config: GrasshopperComputeConfig): Promise<GrasshopperClient> {\n\t\tconst client = new GrasshopperClient(config);\n\n\t\t// Check server is online before returning\n\t\tif (!(await client.serverStats.isServerOnline())) {\n\t\t\tthrow new RhinoComputeError('Rhino Compute server is not online', ErrorCodes.NETWORK_ERROR, {\n\t\t\t\tcontext: { serverUrl: client.config.serverUrl }\n\t\t\t});\n\t\t}\n\n\t\treturn client;\n\t}\n\n\t/**\n\t * Gets the client's configuration.\n\t * Useful for passing to lower-level functions.\n\t */\n\tpublic getConfig(): GrasshopperComputeConfig {\n\t\tthis.ensureNotDisposed();\n\t\treturn { ...this.config };\n\t}\n\n\t/**\n\t * Get input/output parameters of a Grasshopper definition.\n\t */\n\tpublic async getIO(definition: string | Uint8Array) {\n\t\tthis.ensureNotDisposed();\n\t\treturn fetchParsedDefinitionIO(definition, this.config);\n\t}\n\n\tpublic async getRawIO(definition: string | Uint8Array) {\n\t\tthis.ensureNotDisposed();\n\t\treturn fetchDefinitionIO(definition, this.config);\n\t}\n\n\t/**\n\t * Run a compute job with a Grasshopper definition.\n\t *\n\t * @throws {RhinoComputeError} with code INVALID_INPUT if definition is empty\n\t * @throws {RhinoComputeError} with code NETWORK_ERROR if server is offline\n\t * @throws {RhinoComputeError} with code COMPUTATION_ERROR if computation fails\n\t */\n\tpublic async solve(\n\t\tdefinition: string | Uint8Array,\n\t\tdataTree: DataTree[],\n\t\toptions?: SolveOptions\n\t): Promise<GrasshopperComputeResponse> {\n\t\tthis.ensureNotDisposed();\n\n\t\ttry {\n\t\t\t// Validate inputs\n\t\t\tif (typeof definition === 'string' && !definition?.trim()) {\n\t\t\t\tthrow new RhinoComputeError(\n\t\t\t\t\t'Definition URL/content is required',\n\t\t\t\t\tErrorCodes.INVALID_INPUT,\n\t\t\t\t\t{\n\t\t\t\t\t\tcontext: { receivedUrl: definition }\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} else if (definition instanceof Uint8Array && definition.length === 0) {\n\t\t\t\tthrow new RhinoComputeError('Definition content is empty', ErrorCodes.INVALID_INPUT);\n\t\t\t}\n\n\t\t\t// Per-call options override the client's stored config for this request only\n\t\t\tconst effectiveConfig: GrasshopperComputeConfig = {\n\t\t\t\t...this.config,\n\t\t\t\t...(options?.signal !== undefined && { signal: options.signal }),\n\t\t\t\t...(options?.timeoutMs !== undefined && { timeoutMs: options.timeoutMs }),\n\t\t\t\t...(options?.retry !== undefined && { retry: options.retry })\n\t\t\t};\n\n\t\t\t// Skip the redundant pre-flight healthcheck — fetchRhinoCompute already surfaces\n\t\t\t// network failures with a NETWORK_ERROR code, so adding a roundtrip here only\n\t\t\t// doubles latency on every solve.\n\t\t\tconst result = await solveGrasshopperDefinition(dataTree, definition, effectiveConfig);\n\n\t\t\t// Check for errors\n\t\t\tif (result && typeof result === 'object' && 'message' in result && !('fileData' in result)) {\n\t\t\t\tthrow new RhinoComputeError(\n\t\t\t\t\t(result as { message: string }).message || 'Computation failed',\n\t\t\t\t\tErrorCodes.COMPUTATION_ERROR,\n\t\t\t\t\t{\n\t\t\t\t\t\tcontext: {\n\t\t\t\t\t\t\tdefinition:\n\t\t\t\t\t\t\t\ttypeof definition === 'string' && definition.length < 200\n\t\t\t\t\t\t\t\t\t? definition\n\t\t\t\t\t\t\t\t\t: '...content...',\n\t\t\t\t\t\t\tinputs: dataTree\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tif (this.config.debug) {\n\t\t\t\tgetLogger().error('Compute failed:', error);\n\t\t\t}\n\n\t\t\tif (error instanceof RhinoComputeError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tthrow new RhinoComputeError(\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\tErrorCodes.COMPUTATION_ERROR,\n\t\t\t\t{\n\t\t\t\t\tcontext: {\n\t\t\t\t\t\tdefinition:\n\t\t\t\t\t\t\ttypeof definition === 'string' && definition.length < 200\n\t\t\t\t\t\t\t\t? definition\n\t\t\t\t\t\t\t\t: '...content...',\n\t\t\t\t\t\tinputs: dataTree\n\t\t\t\t\t},\n\t\t\t\t\toriginalError: error instanceof Error ? error : new Error(String(error))\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Create a scheduler bound to this client. Use a scheduler for any UI surface\n\t * that fires solves frequently (sliders, live editors) or that needs cancel\n\t * semantics, response caching, or state observability.\n\t *\n\t * Multiple schedulers can be created from a single client — typically one per\n\t * UI surface so their queues stay independent.\n\t *\n\t * @example\n\t * ```ts\n\t * const sliderScheduler = client.createScheduler({ mode: 'latest-wins' });\n\t * const submitScheduler = client.createScheduler({ mode: 'queue', timeoutMs: 0, retry: { attempts: 1 } });\n\t * ```\n\t */\n\tpublic createScheduler(options?: SolveSchedulerOptions): SolveScheduler {\n\t\tthis.ensureNotDisposed();\n\t\tconst executor = (\n\t\t\tdefinition: string | Uint8Array,\n\t\t\tdataTree: DataTree[],\n\t\t\tconfig: GrasshopperComputeConfig\n\t\t) => solveGrasshopperDefinition(dataTree, definition, config);\n\t\treturn new SolveScheduler(executor, this.config, options);\n\t}\n\n\t/**\n\t * Disposes of client resources.\n\t * Call this when you're done using the client.\n\t */\n\tpublic async dispose(): Promise<void> {\n\t\tif (this.disposed) return;\n\n\t\tthis.disposed = true;\n\n\t\t// If serverStats has a dispose method, call it\n\t\tif ('dispose' in this.serverStats && typeof this.serverStats.dispose === 'function') {\n\t\t\tawait this.serverStats.dispose();\n\t\t}\n\n\t\t// Clear any cached data or connections if needed\n\t}\n\n\t/**\n\t * Ensures the client hasn't been disposed.\n\t */\n\tprivate ensureNotDisposed(): void {\n\t\tif (this.disposed) {\n\t\t\tthrow new RhinoComputeError(\n\t\t\t\t'GrasshopperClient has been disposed and cannot be used',\n\t\t\t\tErrorCodes.INVALID_STATE\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Validates and normalizes a compute configuration.\n\t *\n\t * @throws {RhinoComputeError} with code INVALID_CONFIG if configuration is invalid\n\t */\n\tprivate normalizeComputeConfig<T extends ComputeConfig | GrasshopperComputeConfig>(config: T): T {\n\t\tif (!config.serverUrl?.trim()) {\n\t\t\tthrow new RhinoComputeError('serverUrl is required', ErrorCodes.INVALID_CONFIG, {\n\t\t\t\tcontext: { receivedServerUrl: config.serverUrl }\n\t\t\t});\n\t\t}\n\n\t\t// Validate URL format\n\t\ttry {\n\t\t\tnew URL(config.serverUrl);\n\t\t} catch {\n\t\t\tthrow new RhinoComputeError('serverUrl must be a valid URL', ErrorCodes.INVALID_CONFIG, {\n\t\t\t\tcontext: { receivedServerUrl: config.serverUrl }\n\t\t\t});\n\t\t}\n\n\t\t// Validate that it's not the default public endpoint\n\t\tif (config.serverUrl === '' || config.serverUrl === 'https://compute.rhino3d.com/') {\n\t\t\tthrow new RhinoComputeError(\n\t\t\t\t'serverUrl must be set to your Compute server URL. The default public endpoint is not allowed.',\n\t\t\t\tErrorCodes.INVALID_CONFIG,\n\t\t\t\t{ context: { receivedServerUrl: config.serverUrl } }\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\t...config,\n\t\t\tserverUrl: config.serverUrl.replace(/\\/+$/, ''), // Remove trailing slashes\n\t\t\tapiKey: config.apiKey,\n\t\t\tauthToken: config.authToken,\n\t\t\tdebug: config.debug ?? false,\n\t\t\tsuppressClientSideWarning: config.suppressClientSideWarning\n\t\t} as T;\n\t}\n}\n","import { RhinoComputeError, ErrorCodes, getLogger } from '@/core';\nimport { decodeBase64ToBinary } from '@/core/utils/encoding';\n\nimport { FileBaseInfo, FileData, ProcessedFile } from './types';\n\n/**\n * Extracts and processes files from compute response data without downloading them.\n * Returns an array of ProcessedFile objects that can be used programmatically.\n *\n * @param downloadableFiles - An array of FileData items from the compute response.\n * @param additionalFiles - Optional additional files to include (fetched from URLs).\n * @returns A Promise resolving to an array of ProcessedFile objects.\n * @throws Will throw an error if file processing fails.\n *\n * @example\n * const files = await extractFilesFromComputeResponse(fileData);\n * files.forEach(file => {\n * console.log(`File: ${file.fileName}, Size: ${file.content.length}`);\n * });\n */\nexport const extractFilesFromComputeResponse = async (\n\tdownloadableFiles: FileData[],\n\tadditionalFiles: FileBaseInfo[] | FileBaseInfo | null = null\n): Promise<ProcessedFile[]> => {\n\ttry {\n\t\treturn await processFiles(downloadableFiles, additionalFiles);\n\t} catch (err) {\n\t\tthrow new RhinoComputeError(\n\t\t\t'Failed to extract files from compute response',\n\t\t\tErrorCodes.INVALID_STATE,\n\t\t\t{\n\t\t\t\tcontext: { originalError: err instanceof Error ? err.message : String(err) },\n\t\t\t\toriginalError: err instanceof Error ? err : undefined\n\t\t\t}\n\t\t);\n\t}\n};\n\n/**\n * Downloads files from a compute response as a ZIP archive.\n * Packages multiple files into a single ZIP file and triggers a browser download.\n *\n * @param downloadableFiles - An array of FileData items from the compute response.\n * @param additionalFiles - Optional additional files to include in the ZIP (fetched from URLs).\n * @param fileFoldername - The name of the ZIP file (without extension).\n * @throws Will throw an error if the file handling or download fails.\n *\n * @example\n * await downloadDataFromComputeResponse(fileData, null, 'my-export');\n * // Downloads 'my-export.zip'\n */\nexport const downloadFileData = async (\n\tdownloadableFiles: FileData[],\n\tfileFoldername: string,\n\tadditionalFiles: FileBaseInfo[] | FileBaseInfo | null = null\n): Promise<void> => {\n\t// Check if we're in a browser environment\n\tif (typeof document === 'undefined' || typeof Blob === 'undefined') {\n\t\tthrow new RhinoComputeError(\n\t\t\t'File download functionality is only available in browser environments. This function requires the DOM API (document, Blob).',\n\t\t\tErrorCodes.BROWSER_ONLY,\n\t\t\t{\n\t\t\t\tcontext: {\n\t\t\t\t\tenvironment: typeof window !== 'undefined' ? 'browser (SSR)' : 'Node.js',\n\t\t\t\t\tdocumentAvailable: typeof document !== 'undefined',\n\t\t\t\t\tblobAvailable: typeof Blob !== 'undefined'\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\ttry {\n\t\tconst processedFiles = await processFiles(downloadableFiles, additionalFiles);\n\t\tawait createAndDownloadZip(processedFiles, fileFoldername);\n\t} catch (err) {\n\t\t// Re-throw if it's already a RhinoComputeError\n\t\tif (err instanceof RhinoComputeError) {\n\t\t\tthrow err;\n\t\t}\n\t\tthrow new RhinoComputeError(\n\t\t\t'Failed to download files from compute response',\n\t\t\tErrorCodes.INVALID_STATE,\n\t\t\t{\n\t\t\t\tcontext: { originalError: err instanceof Error ? err.message : String(err) },\n\t\t\t\toriginalError: err instanceof Error ? err : undefined\n\t\t\t}\n\t\t);\n\t}\n};\n\n/**\n * Processes files from compute response data and additional files.\n * Converts base64-encoded data to binary and fetches additional files from URLs.\n *\n * @param dataItems - An array of FileData items to process.\n * @param additionalFiles - Optional additional files to fetch and include.\n * @returns A Promise resolving to an array of ProcessedFile objects.\n */\nconst processFiles = async (\n\tdataItems: FileData[],\n\tadditionalFiles: FileBaseInfo[] | FileBaseInfo | null\n): Promise<ProcessedFile[]> => {\n\tconst processedFiles: ProcessedFile[] = [];\n\n\t// Process compute response files\n\tdataItems.forEach((item) => {\n\t\tlet filePath = `${item.fileName}${item.fileType}`;\n\n\t\tif (item.subFolder && item.subFolder.trim() !== '') {\n\t\t\tfilePath = `${item.subFolder}/${filePath}`;\n\t\t}\n\n\t\tif (item.isBase64Encoded === true && item.data) {\n\t\t\tconst bites = decodeBase64ToBinary(item.data);\n\t\t\tprocessedFiles.push({\n\t\t\t\tfileName: `${item.fileName}${item.fileType}`,\n\t\t\t\tcontent: new Uint8Array(bites.buffer),\n\t\t\t\tpath: filePath\n\t\t\t});\n\t\t} else if (item.isBase64Encoded === false && item.data) {\n\t\t\tprocessedFiles.push({\n\t\t\t\tfileName: `${item.fileName}${item.fileType}`,\n\t\t\t\tcontent: item.data,\n\t\t\t\tpath: filePath\n\t\t\t});\n\t\t}\n\t});\n\n\tif (additionalFiles) {\n\t\tconst filesArray = Array.isArray(additionalFiles) ? additionalFiles : [additionalFiles];\n\t\tconst additionalProcessed = await Promise.all(\n\t\t\tfilesArray.map(async (file) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst response = await fetch(file.filePath);\n\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\tgetLogger().warn(`Failed to fetch additional file from URL: ${file.filePath}`);\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tconst fileBlob = await response.blob();\n\t\t\t\t\tconst arrayBuffer = await fileBlob.arrayBuffer();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tfileName: file.fileName,\n\t\t\t\t\t\tcontent: new Uint8Array(arrayBuffer),\n\t\t\t\t\t\tpath: file.fileName\n\t\t\t\t\t} as ProcessedFile;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tgetLogger().error(`Error fetching additional file from URL: ${file.filePath}`, error);\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\n\t\tprocessedFiles.push(...additionalProcessed.filter((f): f is ProcessedFile => f !== null));\n\t}\n\n\treturn processedFiles;\n};\n\n/**\n * Creates a ZIP archive from processed files and triggers a browser download.\n *\n * @param files - An array of ProcessedFile objects to include in the ZIP.\n * @param zipName - The name of the ZIP file (without extension).\n * @returns A Promise that resolves when the ZIP is generated and download is triggered.\n */\nasync function createAndDownloadZip(files: ProcessedFile[], zipName: string): Promise<void> {\n\tconst { zipSync, strToU8 } = await import('fflate');\n\n\t// Convert files to fflate format\n\tconst zipData: Record<string, Uint8Array> = {};\n\tfiles.forEach((file) => {\n\t\tzipData[file.path] = typeof file.content === 'string' ? strToU8(file.content) : file.content;\n\t});\n\n\tconst zipped = zipSync(zipData, { level: 6 });\n\n\tconst blob = new Blob([zipped as BlobPart], { type: 'application/zip' });\n\tsaveFile(blob, `${zipName}.zip`);\n}\n\n/**\n * Saves a Blob object as a file in the user's browser.\n *\n * @param blob - The Blob object representing the file content.\n * @param filename - The name to give the downloaded file (including extension).\n * @throws {RhinoComputeError} If not running in a browser environment.\n */\nfunction saveFile(blob: Blob, filename: string) {\n\tif (typeof document === 'undefined') {\n\t\tthrow new RhinoComputeError(\n\t\t\t'saveFile requires a browser environment with DOM API access.',\n\t\t\tErrorCodes.BROWSER_ONLY,\n\t\t\t{\n\t\t\t\tcontext: { function: 'saveFile', requiredAPI: 'document' }\n\t\t\t}\n\t\t);\n\t}\n\n\tconst a = document.createElement('a');\n\ta.href = URL.createObjectURL(blob);\n\ta.download = filename;\n\ta.click();\n\tURL.revokeObjectURL(a.href);\n}\n","import type { RhinoModule } from 'rhino3dm';\nimport { getLogger } from '@/core';\n\n// -----------------------------------------------------------------------------\n// Decoder Types\n// -----------------------------------------------------------------------------\n\ntype RhinoDecoder = (rhino: RhinoModule, data: unknown) => unknown;\n\nconst decoderRegistry = new Map<string, RhinoDecoder>();\n\n// -----------------------------------------------------------------------------\n// Registration\n// -----------------------------------------------------------------------------\n\nexport function registerDecoder(typeName: string, decoder: RhinoDecoder): void {\n\tdecoderRegistry.set(typeName, decoder);\n}\n\nregisterDecoder('Rhino.Geometry.Point3d', (rhino, data) => {\n\tconst d = data as any;\n\tif (!d || typeof d.X !== 'number') return null;\n\treturn new rhino.Point([d.X, d.Y, d.Z]);\n});\n\nregisterDecoder('Rhino.Geometry.Line', (rhino, data) => {\n\tconst d = data as any;\n\tif (!d || !d.From || !d.To) return null;\n\treturn new rhino.Line([d.From.X, d.From.Y, d.From.Z], [d.To.X, d.To.Y, d.To.Z]);\n});\n\n// -----------------------------------------------------------------------------\n// Utility Functions\n// -----------------------------------------------------------------------------\n\nfunction findDecoder(rhinoType: string): RhinoDecoder | undefined {\n\tif (decoderRegistry.has(rhinoType)) return decoderRegistry.get(rhinoType);\n\tfor (const [key, dec] of decoderRegistry) {\n\t\tif (rhinoType.startsWith(key)) return dec;\n\t}\n\treturn undefined;\n}\n\nfunction extractPayload(parsedData: any): any {\n\tif (!parsedData || typeof parsedData !== 'object') return null;\n\treturn (parsedData as any).data ?? (parsedData as any).value ?? null;\n}\n\n// -----------------------------------------------------------------------------\n// Geometry Decoding\n// -----------------------------------------------------------------------------\n\nexport function decodeRhinoGeometry(\n\tparsedData: unknown,\n\trhinoType: string,\n\trhino: RhinoModule\n): unknown {\n\tconst decoder = findDecoder(rhinoType);\n\tif (decoder) {\n\t\ttry {\n\t\t\treturn decoder(rhino, parsedData);\n\t\t} catch (error) {\n\t\t\tgetLogger().warn(`Failed to decode Rhino type ${rhinoType}:`, error);\n\t\t}\n\t}\n\n\t// Fallback using CommonObject.decode\n\ttry {\n\t\tconst payload = extractPayload(parsedData);\n\t\tif (payload) return rhino.CommonObject.decode(payload);\n\t} catch (error) {\n\t\tgetLogger().warn(`Failed to decode ${rhinoType} with CommonObject:`, error);\n\t\treturn { __decodeError: true, type: rhinoType, raw: parsedData };\n\t}\n\n\treturn parsedData;\n}\n\n// -----------------------------------------------------------------------------\n// Object Decoder\n// -----------------------------------------------------------------------------\n\nexport interface DecodeRhinoOptions {\n\tkeys?: string[];\n\tskipKeys?: string[];\n\tdeep?: boolean;\n}\n\nexport function decodeRhinoObject<T extends Record<string, unknown>>(\n\tobj: T,\n\trhino: RhinoModule,\n\toptions: DecodeRhinoOptions = {}\n): T {\n\tconst { keys, skipKeys, deep } = options;\n\tconst out: Record<string, unknown> = { ...obj };\n\n\tconst shouldProcessKey = (k: string) => {\n\t\tif (skipKeys?.includes(k)) return false;\n\t\tif (keys && !keys.includes(k)) return false;\n\t\treturn true;\n\t};\n\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (!shouldProcessKey(key)) continue;\n\t\tif (!value || typeof value !== 'object') continue;\n\n\t\tconst v: any = value;\n\t\tconst maybeType = typeof v.type === 'string' ? v.type : undefined;\n\n\t\tif (maybeType) {\n\t\t\tout[key] = decodeRhinoGeometry(v, maybeType, rhino);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (deep && typeof v === 'object') {\n\t\t\tout[key] = decodeRhinoObject(v as any, rhino, options);\n\t\t}\n\t}\n\n\treturn out as T;\n}\n","import { FileData } from '../../file-handling/types';\nimport { GrasshopperComputeResponse, DataItem } from '../../types';\nimport { decodeRhinoGeometry } from './rhino-decoder';\n\nexport interface ParsedContext {\n\t[key: string]: any;\n}\n\nexport interface GetValuesOptions {\n\tparseValues?: boolean;\n\trhino?: any;\n\t/**\n\t * If true, only include values of type System.String in the result.\n\t * Non-string types are filtered out.\n\t */\n\tstringOnly?: boolean;\n}\n\nexport interface GetValuesResult<T = ParsedContext> {\n\tvalues: T;\n}\n\n// -----------------------------------------------------------------------------\n// Constants\n// -----------------------------------------------------------------------------\n\nconst SYSTEM_TYPES = {\n\tSTRING: 'System.String',\n\tINT: 'System.Int32',\n\tDOUBLE: 'System.Double',\n\tBOOL: 'System.Boolean'\n};\n\nconst RHINO_GEOMETRY_PREFIX = 'Rhino.Geometry.';\n\n// Only relevant is Selva plugin is used\nconst EXCLUDED_TYPES = ['WebDisplay'];\nconst FILE_DATA_TYPE = 'FileData';\n\n// -----------------------------------------------------------------------------\n// Utilities\n// -----------------------------------------------------------------------------\n\n/**\n * Checks if a given type string should be excluded by verifying if it contains\n * any of the substrings defined in the `EXCLUDED_TYPES` list.\n *\n * @param type - The string representation of the type to check.\n * @returns `true` if the type matches any excluded pattern; otherwise, `false`.\n */\nfunction isExcludedType(type: string): boolean {\n\treturn EXCLUDED_TYPES.some((t) => type.includes(t));\n}\n\nfunction tryDecodeJSON(value: string): any {\n\tif (typeof value !== 'string') return value;\n\n\tconst trimmed = value.trim();\n\tconst looksJson = trimmed.startsWith('{') || trimmed.startsWith('[') || trimmed.startsWith('\"');\n\tif (!looksJson) return value;\n\n\ttry {\n\t\tconst first = JSON.parse(trimmed);\n\t\tif (typeof first === 'string') {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(first);\n\t\t\t} catch {\n\t\t\t\treturn first;\n\t\t\t}\n\t\t}\n\t\treturn first;\n\t} catch {\n\t\treturn value;\n\t}\n}\n\nfunction decodeBySystemType(raw: any, type: string, rhino?: any): any {\n\tswitch (type) {\n\t\tcase SYSTEM_TYPES.STRING:\n\t\t\tif (typeof raw !== 'string') return raw;\n\t\t\treturn raw.replace(/^\"(.*)\"$/, '$1');\n\n\t\tcase SYSTEM_TYPES.INT:\n\t\t\treturn Number.parseInt(raw, 10);\n\n\t\tcase SYSTEM_TYPES.DOUBLE:\n\t\t\treturn Number.parseFloat(raw);\n\n\t\tcase SYSTEM_TYPES.BOOL: {\n\t\t\tconst str = String(raw).toLowerCase();\n\t\t\treturn str === 'true';\n\t\t}\n\n\t\tdefault:\n\t\t\tif (rhino && type.startsWith(RHINO_GEOMETRY_PREFIX)) {\n\t\t\t\treturn decodeRhinoGeometry(raw, type, rhino);\n\t\t\t}\n\t\t\treturn raw;\n\t}\n}\n\n// Main extractor — assumes type has already been filtered through isExcludedType\n// at the call site. Returning a sentinel from here would pollute the aggregated\n// arrays in getValues / getValue when multiple branches are mixed.\nfunction extractItemValue(data: any, type: string, parseValues: boolean, rhino?: any): any {\n\tif (typeof data !== 'string') return data;\n\n\tconst raw = parseValues ? tryDecodeJSON(data) : data;\n\treturn decodeBySystemType(raw, type, rhino);\n}\n\n// Traversal helper\n/**\n * Iterates over every data item within a Grasshopper tree structure.\n *\n * @param tree - The Grasshopper tree structure containing branches of items.\n * @param handler - A callback function invoked for each {@link DataItem} found within the tree branches.\n */\nfunction forEachTreeItem(\n\ttree: GrasshopperComputeResponse['values'][0]['InnerTree'],\n\thandler: (item: DataItem) => void\n) {\n\tfor (const list of Object.values(tree)) {\n\t\tif (Array.isArray(list)) {\n\t\t\tfor (const item of list) handler(item);\n\t\t}\n\t}\n}\n\n// -----------------------------------------------------------------------------\n// Public API\n// -----------------------------------------------------------------------------\n\n/**\n * Extracts and processes values from a Grasshopper Compute response object.\n *\n * This function iterates through the internal tree structure of the response parameters,\n * extracts individual data items, and aggregates them into a structured result object.\n * Values can be mapped by their parameter names or unique identifiers.\n *\n * @template T - The type of the resulting parsed context values.\n * @param response - The raw response object received from the Grasshopper Compute service.\n * @param byId - Whether to use the parameter's unique ID as the key (true) or its name (false).\n * @param options - Configuration options for value extraction.\n * @param options.parseValues - Whether to attempt parsing complex data types into JavaScript objects.\n * @param options.rhino - An optional Rhino3dm instance used for geometry decoding.\n * @param options.stringOnly - If true, only items identified as strings will be included in the output.\n * @returns A result object containing the mapped values, where duplicate keys are aggregated into arrays.\n */\nexport function getValues<T = ParsedContext>(\n\tresponse: GrasshopperComputeResponse,\n\tbyId: boolean = false,\n\toptions: GetValuesOptions = {}\n): GetValuesResult<T> {\n\tconst { parseValues = true, rhino, stringOnly = false } = options;\n\tconst result: ParsedContext = {};\n\n\tfor (const param of response.values) {\n\t\tforEachTreeItem(param.InnerTree, (item) => {\n\t\t\t// Skip excluded types (e.g. WebDisplay) entirely — leaving them in\n\t\t\t// would write null into the aggregated result.\n\t\t\tif (isExcludedType(item.type)) return;\n\t\t\t// Skip non-string types if stringOnly is enabled\n\t\t\tif (stringOnly && item.type !== SYSTEM_TYPES.STRING) return;\n\n\t\t\tconst key = byId ? item.id : param.ParamName;\n\t\t\tif (!key) return;\n\n\t\t\tconst value = extractItemValue(item.data, item.type, parseValues, rhino);\n\n\t\t\tif (result[key] === undefined) {\n\t\t\t\tresult[key] = value;\n\t\t\t} else if (Array.isArray(result[key])) {\n\t\t\t\tresult[key].push(value);\n\t\t\t} else {\n\t\t\t\tresult[key] = [result[key], value];\n\t\t\t}\n\t\t});\n\t}\n\n\treturn { values: result as T };\n}\n\n/**\n * Extracts and decodes file data from a Grasshopper Compute response.\n *\n * This function iterates through all parameter values in the compute response,\n * identifies items that match the file data type, and attempts to decode their\n * JSON content into {@link FileData} objects.\n *\n * @param response - The response object received from a Grasshopper Compute request.\n * @returns An array of valid {@link FileData} objects extracted from the response trees.\n */\nexport function extractFileData(response: GrasshopperComputeResponse): FileData[] {\n\tconst output: FileData[] = [];\n\n\tfor (const param of response.values) {\n\t\tforEachTreeItem(param.InnerTree, (item) => {\n\t\t\tif (!item.type.includes(FILE_DATA_TYPE)) return;\n\n\t\t\tconst parsed = tryDecodeJSON(item.data);\n\t\t\tif (\n\t\t\t\tparsed &&\n\t\t\t\tparsed.fileName &&\n\t\t\t\tparsed.fileType &&\n\t\t\t\t'data' in parsed &&\n\t\t\t\ttypeof parsed.isBase64Encoded === 'boolean' &&\n\t\t\t\ttypeof parsed.subFolder === 'string'\n\t\t\t) {\n\t\t\t\toutput.push(parsed as FileData);\n\t\t\t}\n\t\t});\n\t}\n\n\treturn output;\n}\n\n/**\n * Extracts a value or collection of values from a Grasshopper Compute response based on the provided criteria.\n *\n * This function searches through the `InnerTree` structures of the response values. If searching `byName`,\n * it returns all values (or a single value) within that parameter's tree. If searching `byId`, it specifically\n * targets items matching that unique identifier.\n *\n * @param response - The compute response object containing the results of a Grasshopper definition execution.\n * @param options - Search criteria, either a `{ byName: string }` to match a `ParamName`, or `{ byId: string }` to match a specific item ID.\n * @param parseOptions - Optional configuration for how values are extracted and filtered.\n * @param parseOptions.parseValues - Whether to process raw data into formatted values (defaults to `true`).\n * @param parseOptions.rhino - Optional Rhino/OpenNURBS instance used for geometry decoding.\n * @param parseOptions.stringOnly - If `true`, non-string types will be filtered out (defaults to `false`).\n *\n * @returns\n * - `undefined` if no matching parameter or items are found.\n * - A single extracted value if only one matching item exists.\n * - An array of extracted values if multiple matching items are found.\n */\nexport function getValue(\n\tresponse: GrasshopperComputeResponse,\n\toptions: { byName: string } | { byId: string },\n\tparseOptions: GetValuesOptions = {}\n): any {\n\tconst { parseValues = true, rhino, stringOnly = false } = parseOptions;\n\n\tlet targetParam: GrasshopperComputeResponse['values'][0] | undefined;\n\n\tif ('byName' in options) {\n\t\ttargetParam = response.values.find((p) => p.ParamName === options.byName);\n\t} else {\n\t\ttargetParam = response.values.find((p) => {\n\t\t\tlet found = false;\n\t\t\tforEachTreeItem(p.InnerTree, (item) => {\n\t\t\t\tif (item.id === options.byId) found = true;\n\t\t\t});\n\t\t\treturn found;\n\t\t});\n\t}\n\n\tif (!targetParam) return undefined;\n\n\tconst collected: any[] = [];\n\n\tforEachTreeItem(targetParam.InnerTree, (item) => {\n\t\tif ('byId' in options && item.id !== options.byId) return;\n\t\t// Skip excluded types (e.g. WebDisplay) entirely.\n\t\tif (isExcludedType(item.type)) return;\n\t\t// Skip non-string types if stringOnly is enabled\n\t\tif (stringOnly && item.type !== SYSTEM_TYPES.STRING) return;\n\t\tconst v = extractItemValue(item.data, item.type, parseValues, rhino);\n\t\tcollected.push(v);\n\t});\n\n\tif (collected.length === 0) return undefined;\n\tif (collected.length === 1) return collected[0];\n\treturn collected;\n}\n","import { downloadFileData } from '@/features/grasshopper/file-handling';\nimport { FileBaseInfo, FileData } from '@/features/grasshopper/file-handling/types';\nimport type { MeshExtractionOptions } from '@/features/visualization/webdisplay/types';\nimport { RhinoComputeError, ErrorCodes } from '@/core/errors';\n\nimport { GrasshopperComputeResponse } from '../types';\n\nimport {\n\textractFileData,\n\tgetValue,\n\tgetValues,\n\tGetValuesOptions,\n\tGetValuesResult,\n\tParsedContext\n} from '../io/output/response-processors';\n\n/**\n * High-level wrapper for interacting with Grasshopper Compute responses.\n *\n * This class exposes a clean, consistent API for accessing parsed values,\n * geometry, and produced files. It is designed to be the primary interface\n * when working with Grasshopper results in client applications.\n */\nexport default class GrasshopperResponseProcessor {\n\t/**\n\t * Store the compute response for reuse.\n\t */\n\tconstructor(\n\t\tprivate readonly response: GrasshopperComputeResponse,\n\t\tprivate readonly debug: boolean = false\n\t) {}\n\n\t/**\n\t * Extract all values in the response.\n\t *\n\t * @typeParam T - Expected structure of the return value. Defaults to a simple key/value map. (later cast as needed)\n\t * @param byId - If true, keys are parameter IDs; if false, keys are parameter names.\n\t * @param options - Controls parsing behavior such as Rhino geometry decoding.\n\t * @returns Parsed Grasshopper output values.\n\t *\n\t * **Note:** Using `byId` only works with the custom VektorNode rhino.compute branch.\n\t *\n\t * @example\n\t * ```ts\n\t * const processor = new GrasshopperResponseProcessor(response);\n\t * const { values } = processor.getValues();\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * const { values } = processor.getValues(true); // keyed by param ID\n\t * ```\n\t */\n\tpublic getValues<T = ParsedContext>(\n\t\tbyId: boolean = false,\n\t\toptions: GetValuesOptions = {}\n\t): GetValuesResult<T> {\n\t\treturn getValues<T>(this.response, byId, options);\n\t}\n\n\t/**\n\t * Retrieve a specific value using the parameter name.\n\t *\n\t * @param paramName - Human-readable parameter name from the Grasshopper definition.\n\t * @param options - Parsing configuration (e.g. disable parsing or enable Rhino).\n\t * @returns Single parsed value, array of values, or undefined if the parameter is absent.\n\t *\n\t * @example\n\t * ```ts\n\t * const schema = processor.getValueByParamName('Schema');\n\t * ```\n\t */\n\tpublic getValueByParamName(paramName: string, options?: GetValuesOptions): any {\n\t\treturn getValue(this.response, { byName: paramName }, options);\n\t}\n\n\t/**\n\t * Retrieve a specific value using the parameter ID.\n\t *\n\t * @param paramId - Parameter GUID from the Grasshopper definition.\n\t * @param options - Parsing configuration (e.g. disable parsing or enable Rhino).\n\t * @returns Parsed value, array of values, or undefined if not present.\n\t *\n\t * @example\n\t * ```ts\n\t * const output = processor.getValueByParamId('a4be1c1e-23f9-4c27-b942-7f3bb2c45c6f');\n\t * ```\n\t */\n\tpublic getValueByParamId(paramId: string, options?: GetValuesOptions): any {\n\t\treturn getValue(this.response, { byId: paramId }, options);\n\t}\n\n\t/**\n\t * Convert all geometry results into Three.js mesh objects.\n\t *\n\t * This uses internal helpers to decode Rhino geometry into Three.js\n\t * primitives such as meshes and lines, making them ready for rendering.\n\t *\n\t * All processing options (scaling, positioning, compression, etc.) can be customized.\n\t * The processor's debug flag is merged with options - explicit options take precedence.\n\t *\n\t * **Note:** This only works when using the **Selva Display** component in Grasshopper, and requires the custom branch of rhino.compute from VektorNode. This method dynamically imports three.js visualization modules. Ensure three.js is installed as a peer dependency if you use this feature.\n\t *\n\t * @param options - Configuration for mesh extraction and parsing. Overrides processor's debug flag if provided.\n\t * @returns Promise resolving to an array of Three.js mesh objects.\n\t * @throws {RhinoComputeError} If three.js visualization module cannot be loaded.\n\t *\n\t * @example\n\t * ```ts\n\t * const meshes = await processor.extractMeshesFromResponse();\n\t * scene.add(...meshes);\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * const meshes = await processor.extractMeshesFromResponse({\n\t * debug: true,\n\t * allowScaling: true,\n\t * allowAutoPosition: false,\n\t * parsing: {\n\t * mergeByMaterial: false,\n\t * applyTransforms: true,\n\t * debug: true,\n\t * },\n\t * });\n\t * ```\n\t */\n\tpublic async extractMeshesFromResponse(options?: MeshExtractionOptions) {\n\t\tconst mergedOptions: MeshExtractionOptions = {\n\t\t\tdebug: this.debug,\n\t\t\t...options\n\t\t};\n\n\t\t// Dynamically import visualization module to avoid coupling three.js at module load time.\n\t\t// Narrow the try/catch to the import only — errors from mesh extraction itself should\n\t\t// propagate so callers can debug them, not get re-wrapped as \"failed to load\".\n\t\tlet getThreeMeshesFromComputeResponse: typeof import('@/features/visualization').getThreeMeshesFromComputeResponse;\n\t\ttry {\n\t\t\t({ getThreeMeshesFromComputeResponse } = await import('@/features/visualization'));\n\t\t} catch (error) {\n\t\t\tthrow new RhinoComputeError(\n\t\t\t\t'Failed to load three.js visualization module. Ensure three.js is installed as a peer dependency.',\n\t\t\t\tErrorCodes.INVALID_STATE,\n\t\t\t\t{\n\t\t\t\t\tcontext: { originalError: error instanceof Error ? error.message : String(error) }\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn getThreeMeshesFromComputeResponse(this.response, mergedOptions);\n\t}\n\n\t/**\n\t * Extract internal file data structures from the response.\n\t * This includes Grasshopper-generated textures, JSON exports,\n\t * CAD formats, or any file structure packaged in the response.\n\t *\n\t * **Note:** This only works when using the **Block to File** and **Geometry To File** components from the Selva plugin in Grasshopper, and requires the custom branch of rhino.compute from VektorNode.\n\t *\n\t * @returns Raw file data entries.\n\t */\n\tprivate getFileData(): FileData[] {\n\t\treturn extractFileData(this.response);\n\t}\n\n\t/**\n\t * Download all files generated by Grasshopper, optionally including\n\t * additional user-provided files.\n\t *\n\t * Files are grouped under the specified folder name when downloaded.\n\t *\n\t * @param folderName - Name for the download directory.\n\t * @param additionalFiles - Extra files to package (single file, array, or null).\n\t *\n\t * @example\n\t * ```ts\n\t * processor.getAndDownloadFiles('gh-output');\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * const extra = { name: 'notes.txt', data: 'Example' };\n\t * processor.getAndDownloadFiles('project', extra);\n\t * ```\n\t */\n\tpublic getAndDownloadFiles(\n\t\tfolderName: string,\n\t\tadditionalFiles?: FileBaseInfo[] | FileBaseInfo | null\n\t) {\n\t\tconst files = this.getFileData();\n\t\tdownloadFileData(files, folderName, additionalFiles);\n\t}\n}\n","import { getLogger } from './logger';\n\nexport function warnIfClientSide(functionName: string, suppress?: boolean): void {\n\tif (suppress) {\n\t\treturn;\n\t}\n\n\tif (typeof window !== 'undefined') {\n\t\tgetLogger().warn(\n\t\t\t`Warning: ${functionName} is running on the client side. For better performance and security, consider running this on the server side.`\n\t\t);\n\t}\n}\n","import { fetchRhinoCompute } from '@/core';\nimport { base64ByteArray, encodeStringToBase64, isBase64 } from '@/core/utils/encoding';\nimport { warnIfClientSide } from '@/core/utils/warnings';\n\nimport {\n\tGrasshopperRequestSchema,\n\tGrasshopperComputeConfig,\n\tGrasshopperComputeResponse,\n\tDataTree\n} from '../types';\n\n/**\n * Runs a Rhino Compute job using the provided tree prototypes and Grasshopper definition.\n *\n * @public Use this for direct compute control. For high-level API, use `GrasshopperClient.solve()`.\n *\n * @param dataTree - An array of `DataTree` objects representing the input data for the compute job.\n * @param definition - The Grasshopper definition, which can be:\n * - A URL string (e.g., 'https://example.com/definition.gh')\n * - A base64-encoded string of the .gh file\n * - A plain string (will be base64-encoded)\n * - A Uint8Array of the .gh file (will be base64-encoded)\n * @param config - Compute configuration (server URL, API key, etc. along with optional timeout, units, etc.)\n * @returns An object containing the compute result and extracted file data.\n *\n * @example\n * // Using a URL\n * await solveGrasshopperDefinition(trees, 'https://example.com/definition.gh', config);\n *\n * // Using a base64 string\n * await solveGrasshopperDefinition(trees, 'UEsDBBQAAAAIAL...', config);\n *\n * // Using binary data\n * const fileData = new Uint8Array([...]);\n * await solveGrasshopperDefinition(trees, fileData, config);\n */\nexport async function solveGrasshopperDefinition(\n\tdataTree: DataTree[],\n\tdefinition: string | Uint8Array,\n\tconfig: GrasshopperComputeConfig\n): Promise<GrasshopperComputeResponse> {\n\tif (config.debug) {\n\t\twarnIfClientSide('solveGrasshopperDefinition', config.suppressClientSideWarning);\n\t}\n\n\tconst args = prepareGrasshopperArgs(definition, dataTree);\n\tapplyOptionalComputeSettings(args, config);\n\n\tconst result = await fetchRhinoCompute('grasshopper', args, config);\n\n\tif ('pointer' in result) {\n\t\t// Strip via shallow copy rather than `delete result.pointer` so we don't\n\t\t// mutate an object the scheduler (or any caller holding a reference) may\n\t\t// have already observed.\n\t\tconst { pointer: _pointer, ...rest } = result as GrasshopperComputeResponse & {\n\t\t\tpointer?: unknown;\n\t\t};\n\t\treturn rest as GrasshopperComputeResponse;\n\t}\n\n\treturn result;\n}\n\n// ============================================================================\n// Grasshopper Arguments\n// ============================================================================\n\n/**\n * Prepares Grasshopper arguments from a definition and data tree.\n * Automatically detects the definition format and converts it appropriately.\n *\n * @param definition - Can be a URL, base64 string, plain string, or Uint8Array\n * @param dataTree - Array of DataTree objects for compute inputs\n * @internal\n */\nexport function prepareGrasshopperArgs(\n\tdefinition: string | Uint8Array,\n\tdataTree: DataTree[]\n): GrasshopperRequestSchema {\n\tconst args: GrasshopperRequestSchema = {\n\t\talgo: null,\n\t\tpointer: null,\n\t\tvalues: dataTree\n\t};\n\n\tif (definition instanceof Uint8Array) {\n\t\t// Binary data → convert to base64\n\t\targs.algo = base64ByteArray(definition);\n\t} else if (/^https?:\\/\\//i.test(definition)) {\n\t\t// URL → use as pointer reference\n\t\targs.pointer = definition;\n\t} else if (isBase64(definition)) {\n\t\t// Already base64 → use as-is\n\t\targs.algo = definition;\n\t} else {\n\t\t// Plain string → encode to base64\n\t\targs.algo = encodeStringToBase64(definition);\n\t}\n\n\treturn args;\n}\n\n/**\n * @internal\n */\nexport function applyOptionalComputeSettings(\n\targlist: GrasshopperRequestSchema,\n\toptions: GrasshopperComputeConfig\n): void {\n\tif (options.cachesolve != null) arglist.cachesolve = options.cachesolve;\n\tif (options.modelunits != null) arglist.modelunits = options.modelunits;\n\tif (options.angletolerance != null) arglist.angletolerance = options.angletolerance;\n\tif (options.absolutetolerance != null) arglist.absolutetolerance = options.absolutetolerance;\n\tif (options.dataversion != null) arglist.dataversion = options.dataversion;\n}\n","import { RhinoComputeError } from '@/core/errors';\nimport { getLogger } from '@/core';\nimport type { InputParamSchema } from '../../types';\n\n/**\n * Validation utilities for input parameters\n * Consolidates scattered validation logic from input parsers and processors\n *\n * @internal This is an internal validation utilities module.\n */\n\n/**\n * Context for validation operations\n */\nexport interface ValidationContext {\n\tinputName: string;\n\tparamType?: string;\n\texpectedType?: string;\n}\n\n/**\n * Validates that a ValueList input has defined values\n *\n * @param input - The input parameter to validate\n * @throws {RhinoComputeError} If values object is missing or empty\n */\nexport function validateValueListValues(input: InputParamSchema): void {\n\tif (!input.values || typeof input.values !== 'object' || Object.keys(input.values).length === 0) {\n\t\tthrow RhinoComputeError.missingValues(input.nickname || 'unnamed', 'ValueList');\n\t}\n}\n\n/**\n * Validates that a default value exists in a ValueList's available values\n *\n * @param input - The input parameter to validate\n * @param warnOnly - If true, logs warning instead of throwing (default: true)\n */\nexport function validateValueListDefault(input: InputParamSchema, warnOnly: boolean = true): void {\n\tif (!input.values || input.default === undefined || input.default === null) {\n\t\treturn;\n\t}\n\n\t// Case-insensitive check\n\tconst defaultLower = String(input.default).toLowerCase();\n\tconst valueExists = Object.keys(input.values).some((key) => key.toLowerCase() === defaultLower);\n\n\tif (!valueExists) {\n\t\tconst message = `ValueList input \"${input.nickname || 'unnamed'}\" default value \"${input.default}\" is not in available values`;\n\t\tif (warnOnly) {\n\t\t\tgetLogger().warn(message);\n\t\t} else {\n\t\t\tthrow RhinoComputeError.invalidDefault(\n\t\t\t\tinput.nickname || 'unnamed',\n\t\t\t\tinput.default,\n\t\t\t\tObject.values(input.values)\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Validates that an input parameter has a valid paramType\n *\n * @param paramType - The parameter type to validate\n * @param validTypes - Array of valid parameter types\n * @param inputName - Name of the input (for error reporting)\n * @throws {RhinoComputeError} If paramType is not in the valid types list\n */\nexport function validateParameterType(\n\tparamType: string,\n\tvalidTypes: string[],\n\tinputName?: string\n): void {\n\tif (!validTypes.includes(paramType)) {\n\t\tthrow RhinoComputeError.unknownParamType(paramType, inputName);\n\t}\n}\n\n/**\n * Normalizes a group name for consistent key generation\n *\n * @param groupName - The raw group name to normalize\n * @param options - Normalization options\n * @returns Normalized group name\n *\n * @remarks\n * - Removes whitespace\n * - Converts to lowercase\n * - Special handling for \"hidden\" / \"hide\" → \"__hidden__\"\n * - Optionally capitalizes for display\n */\nexport function normalizeGroupName(\n\tgroupName: string,\n\toptions?: {\n\t\tcapitalize?: boolean;\n\t\thandleHidden?: boolean;\n\t}\n): string {\n\tlet normalized = groupName.trim().replace(/\\s+/g, '').toLowerCase();\n\n\tif (options?.handleHidden && (normalized === 'hidden' || normalized === 'hide')) {\n\t\treturn '__hidden__';\n\t}\n\n\tif (options?.capitalize) {\n\t\tnormalized = normalized.replace(/\\b\\w/g, (char) => char.toUpperCase());\n\t}\n\n\treturn normalized;\n}\n\n/**\n * Validates that numeric input has valid min/max constraints\n *\n * @param input - The input parameter to validate\n * @throws {RhinoComputeError} If constraints are invalid\n */\nexport function validateNumericConstraints(input: InputParamSchema): void {\n\tif (\n\t\tinput.minimum !== undefined &&\n\t\tinput.minimum !== null &&\n\t\tinput.maximum !== undefined &&\n\t\tinput.maximum !== null\n\t) {\n\t\tif (input.minimum > input.maximum) {\n\t\t\tthrow RhinoComputeError.validation(\n\t\t\t\tinput.nickname || 'unnamed',\n\t\t\t\t`minimum (${input.minimum}) cannot be greater than maximum (${input.maximum})`\n\t\t\t);\n\t\t}\n\t}\n\n\tif (input.atLeast !== undefined && input.atMost !== undefined) {\n\t\tif (input.atLeast > input.atMost) {\n\t\t\tthrow RhinoComputeError.validation(\n\t\t\t\tinput.nickname || 'unnamed',\n\t\t\t\t`atLeast (${input.atLeast}) cannot be greater than atMost (${input.atMost})`\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Extracts numeric precision from a value\n *\n * @param value - The numeric value to analyze\n * @returns Number of decimal places\n */\nexport function extractNumericPrecision(value: number): number {\n\tif (!Number.isFinite(value) || value === 0) {\n\t\treturn 0;\n\t}\n\n\tconst str = String(value);\n\n\t// Handle exponential notation\n\tconst expMatch = str.toLowerCase().match(/e(-?\\d+)/);\n\tif (expMatch) {\n\t\treturn Math.abs(Number(expMatch[1]));\n\t}\n\n\t// Handle standard decimal notation\n\tconst decimalPart = str.split('.')[1];\n\tif (!decimalPart) {\n\t\treturn 0;\n\t}\n\n\treturn Math.min(decimalPart.length, 12);\n}\n\n/**\n * Validates input structure for expected types\n *\n * @param input - The input to validate\n * @param expectedStructure - Description of expected structure\n * @throws {RhinoComputeError} If structure doesn't match expectations\n */\nexport function validateInputStructure(\n\tinput: unknown,\n\texpectedStructure: string,\n\tinputName?: string\n): void {\n\tif (!input || typeof input !== 'object') {\n\t\tthrow RhinoComputeError.invalidStructure(inputName || 'unknown', expectedStructure);\n\t}\n}\n\n/**\n * Validates that required properties exist in an object\n *\n * @param obj - The object to validate\n * @param requiredProps - Array of required property names\n * @param context - Validation context for error reporting\n * @throws {RhinoComputeError} If any required property is missing\n */\nexport function validateRequiredProperties(\n\tobj: Record<string, unknown>,\n\trequiredProps: string[],\n\tcontext: ValidationContext\n): void {\n\tconst missing = requiredProps.filter((prop) => !(prop in obj));\n\n\tif (missing.length > 0) {\n\t\tthrow RhinoComputeError.validation(\n\t\t\tcontext.inputName,\n\t\t\t`missing required properties: ${missing.join(', ')}`\n\t\t);\n\t}\n}\n\n/**\n * Pre-processes raw input to normalize default values\n * Handles data tree structures, flattening, and type parsing\n *\n * @param input - The input parameter to pre-process\n *\n * @remarks\n * This consolidates preprocessing logic from input-processors.ts\n * Handles:\n * - Empty data trees → undefined\n * - Tree structure preservation for tree access parameters\n * - Flattening of multiple values\n * - Type-aware parsing (numbers, booleans, JSON)\n */\nexport function preProcessInputDefault(input: InputParamSchema): void {\n\tif (typeof input.default !== 'object' || input.default === null) {\n\t\treturn;\n\t}\n\n\tif (!('innerTree' in input.default)) {\n\t\tgetLogger().warn('Unexpected structure in input.default:', input.default);\n\t\tinput.default = null;\n\t\treturn;\n\t}\n\n\tconst innerTree = (input.default as any).innerTree;\n\n\t// If innerTree is empty, set default to undefined\n\tif (Object.keys(innerTree).length === 0) {\n\t\tinput.default = undefined;\n\t\treturn;\n\t}\n\n\t// If treeAccess is true or atMost > 1, preserve the tree structure\n\tif (input.treeAccess || (input.atMost && input.atMost > 1)) {\n\t\t// Convert each branch to an array of parsed data\n\t\tconst tree: Record<string, any[]> = {};\n\t\tfor (const [branch, items] of Object.entries(innerTree)) {\n\t\t\ttree[branch] = (items as any[]).map((item) => {\n\t\t\t\t// Try to parse numbers, booleans, or JSON if possible\n\t\t\t\tif (typeof item.data === 'string') {\n\t\t\t\t\tif (item.type === 'System.Double' || item.type === 'System.Int32') {\n\t\t\t\t\t\tconst num = Number(item.data);\n\t\t\t\t\t\treturn Number.isNaN(num) ? item.data : num;\n\t\t\t\t\t}\n\t\t\t\t\tif (item.type === 'System.Boolean') {\n\t\t\t\t\t\treturn item.data.toLowerCase() === 'true';\n\t\t\t\t\t}\n\t\t\t\t\tif (item.type.startsWith('Rhino.Geometry') || item.type === 'System.String') {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn JSON.parse(item.data);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn item.data;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn item.data;\n\t\t\t});\n\t\t}\n\t\tinput.default = tree;\n\t\treturn;\n\t}\n\n\t// Otherwise, flatten all values as before\n\tconst allValues: any[] = [];\n\tfor (const items of Object.values(innerTree)) {\n\t\tif (Array.isArray(items)) {\n\t\t\titems.forEach((item) => {\n\t\t\t\tif (item && typeof item === 'object' && 'data' in item) {\n\t\t\t\t\tallValues.push(item.data);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\tif (allValues.length === 0) {\n\t\tinput.default = undefined;\n\t} else if (allValues.length === 1) {\n\t\tinput.default = allValues[0];\n\t} else {\n\t\tinput.default = allValues;\n\t}\n}\n","import { RhinoComputeError } from '@/core/errors';\nimport { getLogger } from '@/core';\nimport type { InputParamSchema } from '../../types';\n\n/**\n * Type for a single value transformer function\n */\nexport type ValueTransformer<T> = (value: unknown) => T | null;\n\n/**\n * Options for processing input values\n */\nexport interface ProcessValueOptions<T> {\n\t/**\n\t * Function to transform a single value\n\t */\n\ttransform: ValueTransformer<T>;\n\t/**\n\t * Whether to set default to undefined if all values fail transformation\n\t * @default true\n\t */\n\tsetUndefinedOnEmpty?: boolean;\n}\n\n/**\n * Generic utility to process input default values (arrays or single values)\n *\n * @internal\n */\nfunction processInputValue<T>(input: InputParamSchema, options: ProcessValueOptions<T>): void {\n\tconst { transform, setUndefinedOnEmpty = true } = options;\n\n\t// Don't process undefined or null - preserve them as is\n\tif (input.default === undefined || input.default === null) {\n\t\treturn;\n\t}\n\n\tif (Array.isArray(input.default)) {\n\t\tconst processedArray = input.default.map(transform).filter((v): v is T => v !== null);\n\n\t\t// For arrays, always set to undefined if empty (regardless of setUndefinedOnEmpty)\n\t\tinput.default = processedArray.length > 0 ? processedArray : undefined;\n\t} else {\n\t\tconst transformed = transform(input.default);\n\t\tif (transformed !== null) {\n\t\t\t// Transformation succeeded\n\t\t\tinput.default = transformed;\n\t\t} else {\n\t\t\t// Transformation failed - set to undefined only if setUndefinedOnEmpty is true\n\t\t\tif (setUndefinedOnEmpty) {\n\t\t\t\tinput.default = undefined;\n\t\t\t}\n\t\t\t// Otherwise preserve original value\n\t\t}\n\t}\n}\n\n/**\n * Creates a numeric value transformer (for Number and Integer types)\n */\nfunction createNumericTransformer(): ValueTransformer<number> {\n\treturn (value: unknown): number | null => {\n\t\tif (typeof value === 'number') {\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value === 'string') {\n\t\t\tconst parsed = Number(value.trim());\n\t\t\treturn Number.isNaN(parsed) ? null : parsed;\n\t\t}\n\t\treturn null;\n\t};\n}\n\n/**\n * Creates a boolean value transformer\n */\nfunction createBooleanTransformer(): ValueTransformer<boolean> {\n\treturn (value: unknown): boolean | null => {\n\t\tif (typeof value === 'boolean') {\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value === 'string') {\n\t\t\tconst lowerValue = value.toLowerCase();\n\t\t\tif (lowerValue === 'true') return true;\n\t\t\tif (lowerValue === 'false') return false;\n\t\t\tthrow new Error(`Invalid boolean string: \"${value}\"`);\n\t\t}\n\t\treturn null;\n\t};\n}\n\n/**\n * Creates a text value transformer that removes surrounding quotes\n */\nfunction createTextTransformer(): ValueTransformer<string> {\n\treturn (value: unknown): string | null => {\n\t\tif (typeof value === 'string') {\n\t\t\t// Handle strings with both start and end quotes\n\t\t\tif (value.startsWith('\"') && value.endsWith('\"')) {\n\t\t\t\treturn value.slice(1, -1);\n\t\t\t}\n\t\t\t// Handle strings that start with quote but don't end with one (legacy behavior)\n\t\t\tif (value.startsWith('\"')) {\n\t\t\t\treturn value.slice(1, -1);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\treturn null;\n\t};\n}\n\n/**\n * Creates a color value transformer that normalizes RGB strings\n */\nfunction createColorTransformer(): ValueTransformer<string> {\n\treturn (value: unknown): string | null => {\n\t\tif (typeof value === 'string') {\n\t\t\t// Remove surrounding quotes if present\n\t\t\tlet cleaned = value.trim();\n\t\t\tif (cleaned.startsWith('\"') && cleaned.endsWith('\"')) {\n\t\t\t\tcleaned = cleaned.slice(1, -1).trim();\n\t\t\t}\n\t\t\t// Return as-is if it's a valid RGB string\n\t\t\treturn cleaned;\n\t\t}\n\t\treturn null;\n\t};\n}\n\n/**\n * Processes color input parameters\n */\nfunction processColorInput(input: InputParamSchema): void {\n\tprocessInputValue(input, {\n\t\ttransform: createColorTransformer(),\n\t\tsetUndefinedOnEmpty: false\n\t});\n}\n\n/**\n * Creates an object value transformer that parses JSON strings\n */\nfunction createObjectTransformer(inputName: string = 'unknown'): ValueTransformer<object> {\n\treturn (value: unknown): object | null => {\n\t\tif (typeof value === 'object' && value !== null) {\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value === 'string' && value.trim() !== '') {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(value);\n\t\t\t\tif (typeof parsed === 'object' && parsed !== null) {\n\t\t\t\t\treturn parsed;\n\t\t\t\t}\n\t\t\t\tgetLogger().warn(`Parsed value for input ${inputName} is not an object`);\n\t\t\t\treturn null;\n\t\t\t} catch (err) {\n\t\t\t\tgetLogger().warn(`Failed to parse object value \"${value}\" for input ${inputName}`, err);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n}\n\n/**\n * Applies rounding with tolerance to avoid floating-point artifacts\n */\nfunction applyRounding(value: number, decimalPlaces: number, tolerance: number): number {\n\tconst rounded = Number(value.toFixed(decimalPlaces));\n\n\t// If the difference is within tolerance, use the rounded value\n\tif (Math.abs(value - rounded) < tolerance) {\n\t\treturn rounded;\n\t}\n\n\treturn value;\n}\n\n/**\n * Calculates the step size for a given numeric input value based on its decimal precision.\n */\nfunction getInputStepSize(value: number, roundingTolerance: number = 1e-8): number {\n\tif (!Number.isFinite(value)) return 0.1;\n\tif (value === 0) return 0.1;\n\n\tconst abs = Math.abs(value);\n\n\tif (abs >= 1) {\n\t\tconst str = String(value);\n\t\tconst decimalPart = str.split('.')[1];\n\t\tif (decimalPart && decimalPart.length > 0) {\n\t\t\tconst decimals = Math.min(decimalPart.length, 12);\n\t\t\tconst step = Math.pow(10, -decimals);\n\t\t\tconst rounded = Number(step.toFixed(decimals));\n\t\t\treturn Math.abs(rounded - step) < roundingTolerance ? rounded : step;\n\t\t}\n\t\treturn 1;\n\t}\n\n\t// Handle exponential notation\n\tconst s = String(value);\n\tconst expMatch = s.toLowerCase().match(/e(-?\\d+)/);\n\tif (expMatch) {\n\t\tconst exp = Number(expMatch[1]);\n\t\tif (exp < 0 || s.toLowerCase().includes('e-')) {\n\t\t\tconst absExp = Math.abs(exp);\n\t\t\tconst step = Math.pow(10, -absExp);\n\t\t\tconst rounded = Number(step.toFixed(absExp));\n\t\t\treturn Math.abs(rounded - step) < roundingTolerance ? rounded : step;\n\t\t}\n\t\treturn 0.1;\n\t}\n\n\t// Handle standard decimal notation\n\tconst MAX_DECIMALS = 12;\n\tconst fixed = abs.toFixed(MAX_DECIMALS);\n\tconst trimmed = fixed.replace(/0+$/, '');\n\tconst decimals = Math.min((trimmed.split('.')[1] || '').length, MAX_DECIMALS);\n\n\tif (decimals === 0) return 0.1;\n\n\tconst step = Math.pow(10, -decimals);\n\tconst rounded = Number(step.toFixed(decimals));\n\treturn Math.abs(rounded - step) < roundingTolerance ? rounded : step;\n}\n\n/**\n * Processes numeric input parameters including step size and decimal places\n */\nfunction processNumericInput(input: InputParamSchema, roundingTolerance: number = 1e-8): void {\n\tconst isIntegerType = input.paramType === 'Integer';\n\n\t// Convert string values to numbers\n\tprocessInputValue(input, {\n\t\ttransform: createNumericTransformer()\n\t});\n\n\t// Round to integer if it's an integer type\n\tif (isIntegerType) {\n\t\tif (Array.isArray(input.default)) {\n\t\t\tinput.default = input.default.map((val) => (typeof val === 'number' ? Math.round(val) : val));\n\t\t} else if (typeof input.default === 'number') {\n\t\t\tinput.default = Math.round(input.default);\n\t\t}\n\n\t\t// Integer inputs always have step size of 1\n\t\tinput.stepSize = 1;\n\t\treturn;\n\t}\n\n\t// Calculate step size from the first numeric value\n\tconst firstValue = Array.isArray(input.default) ? input.default[0] : input.default;\n\n\tlet stepSource: number | undefined;\n\n\tif (typeof firstValue === 'number' && Number.isFinite(firstValue) && firstValue !== 0) {\n\t\tstepSource = firstValue;\n\t} else if (\n\t\ttypeof input.minimum === 'number' &&\n\t\tNumber.isFinite(input.minimum) &&\n\t\tinput.minimum !== 0\n\t) {\n\t\tstepSource = input.minimum;\n\t} else if (\n\t\ttypeof input.maximum === 'number' &&\n\t\tNumber.isFinite(input.maximum) &&\n\t\tinput.maximum !== 0\n\t) {\n\t\tstepSource = input.maximum;\n\t}\n\n\tif (stepSource !== undefined) {\n\t\tinput.stepSize = getInputStepSize(stepSource, roundingTolerance);\n\t} else {\n\t\tinput.stepSize = 0.1;\n\t}\n\n\t// Apply precision to all numeric values\n\tif (typeof input.stepSize === 'number') {\n\t\tlet decimalPlaces = 0;\n\t\tconst stepStr = String(input.stepSize);\n\n\t\tconst expMatch = stepStr.toLowerCase().match(/e(-?\\d+)/);\n\t\tif (expMatch) {\n\t\t\tdecimalPlaces = Math.abs(Number(expMatch[1]));\n\t\t} else {\n\t\t\tdecimalPlaces = stepStr.split('.')[1]?.length ?? 0;\n\t\t}\n\n\t\t// Infer decimal places from small values when step size doesn't provide enough precision\n\t\tif (\n\t\t\tdecimalPlaces === 0 &&\n\t\t\ttypeof firstValue === 'number' &&\n\t\t\tfirstValue !== 0 &&\n\t\t\tMath.abs(firstValue) < 1\n\t\t) {\n\t\t\tconst inferred = Math.ceil(-Math.log10(Math.abs(firstValue)));\n\t\t\tif (Number.isFinite(inferred) && inferred > 0) {\n\t\t\t\tdecimalPlaces = inferred;\n\t\t\t}\n\t\t}\n\n\t\tdecimalPlaces = Math.min(Math.max(decimalPlaces, 0), 12);\n\n\t\t// Apply precision to all values\n\t\tif (Array.isArray(input.default)) {\n\t\t\tinput.default = input.default.map((val) =>\n\t\t\t\ttypeof val === 'number' ? applyRounding(val, decimalPlaces, roundingTolerance) : val\n\t\t\t);\n\t\t} else if (typeof input.default === 'number') {\n\t\t\tinput.default = applyRounding(input.default, decimalPlaces, roundingTolerance);\n\t\t}\n\t}\n}\n\n/**\n * Processes boolean input parameters\n */\nfunction processBooleanInput(input: InputParamSchema): void {\n\ttry {\n\t\tprocessInputValue(input, {\n\t\t\ttransform: createBooleanTransformer(),\n\t\t\tsetUndefinedOnEmpty: false\n\t\t});\n\t} catch (error) {\n\t\t// Re-throw as RhinoComputeError for consistency\n\t\tif (error instanceof Error) {\n\t\t\tthrow new RhinoComputeError(error.message);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Processes text input parameters\n */\nfunction processTextInput(input: InputParamSchema): void {\n\tprocessInputValue(input, {\n\t\ttransform: createTextTransformer(),\n\t\tsetUndefinedOnEmpty: false\n\t});\n}\n\n/**\n * Processes object input parameters by parsing JSON strings\n */\nfunction parseToObject(input: InputParamSchema): void {\n\tprocessInputValue(input, {\n\t\ttransform: createObjectTransformer(input.nickname || 'unnamed'),\n\t\tsetUndefinedOnEmpty: true\n\t});\n}\n\n/**\n * Processes a ValueList input parameter.\n * Validates that the values object exists and contains at least one entry.\n */\nfunction processValueListInput(input: InputParamSchema): void {\n\tif (!input.values || typeof input.values !== 'object' || Object.keys(input.values).length === 0) {\n\t\tthrow RhinoComputeError.missingValues(input.nickname || 'unnamed', 'ValueList');\n\t}\n\n\t// Validate that default is one of the available values (if default exists)\n\tif (input.default !== undefined && input.default !== null) {\n\t\t// Case-insensitive check\n\t\tconst defaultLower = String(input.default).toLowerCase();\n\t\tconst valueExists = Object.keys(input.values).some((key) => key.toLowerCase() === defaultLower);\n\n\t\tif (!valueExists) {\n\t\t\tgetLogger().warn(\n\t\t\t\t`ValueList input \"${input.nickname || 'unnamed'}\" default value \"${input.default}\" is not in available values`\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Maps parameter types to their parsing functions\n */\nexport const PARSERS: Record<string, (input: InputParamSchema) => void> = {\n\tNumber: processNumericInput,\n\tInteger: processNumericInput,\n\tBoolean: processBooleanInput,\n\tText: processTextInput,\n\tValueList: processValueListInput,\n\tGeometry: parseToObject,\n\tFile: parseToObject,\n\tColor: processColorInput\n};\n\n// Export parser functions for direct use\nexport {\n\tprocessNumericInput,\n\tprocessBooleanInput,\n\tprocessTextInput,\n\tparseToObject,\n\tprocessValueListInput,\n\tprocessColorInput\n};\n","import { RhinoComputeError } from '@/core/errors';\n\nimport { preProcessInputDefault } from './input-validators';\nimport { PARSERS } from './input-parsers';\nimport { getLogger } from '@/core/utils/logger';\n\nimport type {\n\tBaseInputType,\n\tBooleanInputType,\n\tGeometryInputType,\n\tInputParam,\n\tNumericInputType,\n\tInputParamSchema,\n\tTextInputType,\n\tValueListInputType,\n\tFileInputType,\n\tColorInputType\n} from '../../types';\n\n/**\n * Creates a safe default InputType when processing fails\n */\nfunction createSafeDefault(rawInput: InputParamSchema, baseInput: BaseInputType): InputParam {\n\tconst isList = (rawInput.atMost ?? 1) > 1;\n\tswitch (rawInput.paramType) {\n\t\tcase 'Number':\n\t\tcase 'Integer':\n\t\t\treturn {\n\t\t\t\t...baseInput,\n\t\t\t\tparamType: rawInput.paramType,\n\t\t\t\tminimum: rawInput.minimum,\n\t\t\t\tmaximum: rawInput.maximum,\n\t\t\t\tatLeast: rawInput.atLeast,\n\t\t\t\tatMost: rawInput.atMost,\n\t\t\t\tdefault: isList ? [0] : 0\n\t\t\t} as NumericInputType;\n\t\tcase 'Boolean':\n\t\t\treturn {\n\t\t\t\t...baseInput,\n\t\t\t\tparamType: 'Boolean',\n\t\t\t\tdefault: isList ? [false] : false\n\t\t\t} as BooleanInputType;\n\t\tcase 'Text':\n\t\t\treturn {\n\t\t\t\t...baseInput,\n\t\t\t\tparamType: 'Text',\n\t\t\t\tdefault: isList ? [''] : ''\n\t\t\t} as TextInputType;\n\t\tcase 'ValueList':\n\t\t\treturn {\n\t\t\t\t...baseInput,\n\t\t\t\tparamType: 'ValueList',\n\t\t\t\tvalues: rawInput.values ?? {},\n\t\t\t\tdefault: isList ? [rawInput.default] : rawInput.default\n\t\t\t} as ValueListInputType;\n\t\tcase 'File':\n\t\t\treturn {\n\t\t\t\t...baseInput,\n\t\t\t\tparamType: 'File',\n\t\t\t\tdefault: isList ? [null] : null\n\t\t\t} as FileInputType;\n\t\tcase 'Color':\n\t\t\treturn {\n\t\t\t\t...baseInput,\n\t\t\t\tparamType: 'Color',\n\t\t\t\tdefault: isList ? ['0, 0, 0'] : '0, 0, 0'\n\t\t\t} as ColorInputType;\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\t...baseInput,\n\t\t\t\tparamType: 'Geometry',\n\t\t\t\tdefault: isList ? [null] : null\n\t\t\t} as GeometryInputType;\n\t}\n}\n\n/**\n * Processes a raw input parameter schema and converts it into a typed InputParam object.\n *\n * @internal This is an internal processor. Use `fetchParsedDefinitionIO()` to get processed inputs instead.\n *\n * This function handles the transformation of raw input parameter data from Grasshopper into\n * a structured, type-safe format. It performs validation, type-specific processing, and error\n * handling for various parameter types including numeric, boolean, text, geometry, point, and line inputs.\n *\n * @param rawInput - The raw input parameter schema to process\n * @returns A fully processed and typed InputParam object with appropriate type-specific properties\n *\n * @throws {RhinoComputeError} When an unknown paramType is encountered\n * @throws {Error} Re-throws any non-RhinoComputeError exceptions\n *\n * @remarks\n * The function performs the following operations:\n * - Extracts base properties common to all input types\n * - Preprocesses the raw input data\n * - Applies type-specific validation and transformation\n * - Handles errors gracefully by creating safe default values for validation errors\n *\n * Supported parameter types:\n * - `Number` and `Integer`: Numeric inputs with optional min/max constraints\n * - `Boolean`: Boolean flag inputs\n * - `Text`: String inputs\n * - `Geometry`: Generic geometry objects\n * - `Point`: 3D point objects\n * - `Line`: Line objects\n *\n * @example\n * ```typescript\n * const rawInput = {\n * name: 'Length',\n * paramType: 'Number',\n * minimum: 0,\n * maximum: 100,\n * default: 50\n * };\n * const processedInput = processInput(rawInput);\n * ```\n */\nexport function processInput(rawInput: InputParamSchema): InputParam {\n\t// Create base properties outside try-catch so it's accessible in catch block\n\tconst baseInput: BaseInputType = {\n\t\tdescription: rawInput.description,\n\t\tname: rawInput.name,\n\t\tnickname: rawInput.nickname,\n\t\ttreeAccess: rawInput.treeAccess,\n\t\tgroupName: rawInput.groupName ?? '',\n\t\tid: rawInput.id\n\t};\n\n\ttry {\n\t\t// Handle default object processing\n\t\tpreProcessInputDefault(rawInput);\n\n\t\t// Get parser for this type\n\t\tconst parser = PARSERS[rawInput.paramType];\n\t\tif (!parser) {\n\t\t\tthrow RhinoComputeError.unknownParamType(rawInput.paramType, rawInput.name);\n\t\t}\n\n\t\t// Apply type-specific parsing\n\t\tparser(rawInput);\n\n\t\t// Return typed result based on paramType\n\t\tswitch (rawInput.paramType) {\n\t\t\tcase 'Number':\n\t\t\tcase 'Integer':\n\t\t\t\treturn {\n\t\t\t\t\t...baseInput,\n\t\t\t\t\tparamType: rawInput.paramType,\n\t\t\t\t\tminimum: rawInput.minimum,\n\t\t\t\t\tmaximum: rawInput.maximum,\n\t\t\t\t\tatLeast: rawInput.atLeast,\n\t\t\t\t\tatMost: rawInput.atMost,\n\t\t\t\t\tstepSize: rawInput.stepSize,\n\t\t\t\t\tdefault: rawInput.default as number | undefined\n\t\t\t\t} as NumericInputType;\n\t\t\tcase 'Boolean':\n\t\t\t\treturn {\n\t\t\t\t\t...baseInput,\n\t\t\t\t\tparamType: 'Boolean',\n\t\t\t\t\tdefault: rawInput.default as boolean | undefined\n\t\t\t\t} as BooleanInputType;\n\t\t\tcase 'Text':\n\t\t\t\treturn {\n\t\t\t\t\t...baseInput,\n\t\t\t\t\tparamType: 'Text',\n\t\t\t\t\tdefault: rawInput.default as string | undefined\n\t\t\t\t} as TextInputType;\n\t\t\tcase 'ValueList':\n\t\t\t\treturn {\n\t\t\t\t\t...baseInput,\n\t\t\t\t\tparamType: 'ValueList',\n\t\t\t\t\tvalues: rawInput.values as Record<string, string>,\n\t\t\t\t\tdefault: rawInput.default as string | undefined\n\t\t\t\t} as ValueListInputType;\n\t\t\tcase 'Geometry':\n\t\t\t\treturn {\n\t\t\t\t\t...baseInput,\n\t\t\t\t\tparamType: rawInput.paramType as 'Geometry',\n\t\t\t\t\tdefault: rawInput.default as object | string | undefined\n\t\t\t\t} as GeometryInputType;\n\t\t\tcase 'File':\n\t\t\t\treturn {\n\t\t\t\t\t...baseInput,\n\t\t\t\t\tparamType: rawInput.paramType as 'File',\n\t\t\t\t\tacceptedFormats: rawInput.acceptedFormats,\n\t\t\t\t\tdefault: rawInput.default as object | string | undefined\n\t\t\t\t} as FileInputType;\n\t\t\tcase 'Color':\n\t\t\t\treturn {\n\t\t\t\t\t...baseInput,\n\t\t\t\t\tparamType: 'Color',\n\t\t\t\t\tdefault: rawInput.default as string | undefined\n\t\t\t\t} as ColorInputType;\n\t\t\tdefault:\n\t\t\t\t// This should be unreachable due to parser registry check above\n\t\t\t\tthrow RhinoComputeError.unknownParamType(rawInput.paramType, rawInput.name);\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof RhinoComputeError) {\n\t\t\tgetLogger().error(`Validation error for input ${rawInput.name || 'unknown'}:`, error.message);\n\t\t\t// Return a safe default based on paramType\n\t\t\treturn createSafeDefault(rawInput, baseInput);\n\t\t} else {\n\t\t\t// Transform unexpected errors\n\t\t\tthrow new RhinoComputeError(\n\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t'VALIDATION_ERROR',\n\t\t\t\t{\n\t\t\t\t\tcontext: { paramName: rawInput.name, paramType: rawInput.paramType },\n\t\t\t\t\toriginalError: error instanceof Error ? error : new Error(String(error))\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Processes raw Grasshopper input schemas into strongly-typed TypeScript interfaces.\n *\n * @internal This is an internal batch processor. Use `fetchParsedDefinitionIO()` to get processed inputs instead.\n *\n * Transforms each raw input parameter by:\n * - Normalizing default values (flattening data trees, parsing primitives)\n * - Applying type-specific parsing (Number, Text, Boolean, Geometry, etc.)\n * - Validating constraints (min/max, required fields)\n * - Converting to discriminated union types for type safety\n *\n * @param rawInputs - Array of raw input schemas from Rhino Compute API\n * @returns Array of processed, strongly-typed input parameters\n *\n * @remarks\n * - Empty data trees are converted to `undefined`\n * - Single values are extracted from arrays when appropriate\n * - Tree structures are preserved for list/tree access parameters\n * - Invalid inputs fall back to safe defaults with console warnings\n *\n * @example\n * ```typescript\n * const rawInputs = [\n * { paramType: 'Number', name: 'radius', minimum: 0, default: 10 },\n * { paramType: 'Text', name: 'label', default: 'Hello' }\n * ];\n *\n * const processed = processInputs(rawInputs);\n * // Result: [\n * // { paramType: 'Number', name: 'radius', minimum: 0, default: 10, ... },\n * // { paramType: 'Text', name: 'label', default: 'Hello', ... }\n * // ]\n *\n * // Now type-safe:\n * if (processed[0].paramType === 'Number') {\n * console.log(processed[0].minimum); // TypeScript knows this exists\n * }\n * ```\n *\n * @see {@link processInput} for individual input processing logic\n */\nexport function processInputs(rawInputs: InputParamSchema[]): InputParam[] {\n\treturn rawInputs.map((rawInput) => processInput(rawInput));\n}\n","import { ComputeConfig, RhinoComputeError, ErrorCodes } from '@/core';\nimport { fetchRhinoCompute } from '@/core/compute-fetch/compute-fetch';\nimport { camelcaseKeys } from '@/core/utils/camel-case';\nimport { warnIfClientSide } from '@/core/utils/warnings';\nimport { prepareGrasshopperArgs } from '../compute/solve';\n\nimport {\n\tInputParam,\n\tGrasshopperParsedIO,\n\tGrasshopperParsedIORaw,\n\tIoResponseSchema\n} from '../types';\n\nimport { processInputs } from './input/input-processors';\n\n/**\n * Fetches raw input/output schemas from a Grasshopper definition.\n * Returns unprocessed data exactly as received from the Rhino Compute API (camelCased).\n *\n * @param definition - The Grasshopper definition (URL, base64 string, or Uint8Array)\n * @param config - Compute configuration (server URL, API key, etc.)\n * @returns Raw inputs and outputs with no type processing\n * @throws {RhinoComputeError} If fetch fails or response is invalid\n *\n * @public Use `fetchParsedDefinitionIO()` for processed, type-safe inputs\n */\nexport async function fetchDefinitionIO(\n\tdefinition: string | Uint8Array,\n\tconfig: ComputeConfig\n): Promise<GrasshopperParsedIORaw> {\n\tconst args = prepareGrasshopperArgs(definition, []);\n\tconst payload: { algo?: string | null; pointer?: string | null } = {};\n\tif (args.algo) payload.algo = args.algo;\n\tif (args.pointer) payload.pointer = args.pointer;\n\n\tif (!payload.algo && !payload.pointer) {\n\t\tthrow new RhinoComputeError(\n\t\t\t'Definition must resolve to either a URL pointer or base64 algo',\n\t\t\tErrorCodes.INVALID_INPUT,\n\t\t\t{ context: { definition } }\n\t\t);\n\t}\n\n\tconst response = await fetchRhinoCompute<'io'>('io', payload, config);\n\n\tif (!response || typeof response !== 'object') {\n\t\tthrow new RhinoComputeError('Invalid IO response structure', ErrorCodes.INVALID_INPUT, {\n\t\t\tcontext: { response, definition }\n\t\t});\n\t}\n\n\t// Convert PascalCase to camelCase\n\tconst camelCased = camelcaseKeys(response, { deep: true }) as IoResponseSchema;\n\n\treturn {\n\t\tinputs: camelCased.inputs,\n\t\toutputs: camelCased.outputs\n\t};\n}\n\n/**\n * Fetches and processes input/output schemas from a Grasshopper definition.\n * Returns strongly-typed, validated input parameters ready for use.\n *\n * @public This is the recommended way to fetch definition I/O schemas.\n *\n * @param definition - The Grasshopper definition (URL, base64 string, or Uint8Array)\n * @param config - Compute configuration (server URL, API key, etc.)\n * @returns Processed inputs with discriminated union types and outputs\n * @throws {RhinoComputeError} If fetch fails or response is invalid\n *\n * @example\n * ```typescript\n * const { inputs, outputs } = await fetchParsedDefinitionIO(\n * 'https://example.com/definition.gh',\n * { serverUrl: 'https://compute.rhino3d.com', apiKey: 'YOUR_KEY' }\n * );\n *\n * // Inputs are now strongly typed\n * inputs.forEach(input => {\n * if (input.paramType === 'Number') {\n * console.log(input.minimum, input.maximum); // TypeScript knows these exist\n * }\n * });\n * ```\n */\nexport async function fetchParsedDefinitionIO(\n\tdefinition: string | Uint8Array,\n\tconfig: ComputeConfig\n): Promise<GrasshopperParsedIO> {\n\twarnIfClientSide('fetchParsedDefinitionIO', config.suppressClientSideWarning);\n\n\tconst { inputs: rawInputs, outputs } = await fetchDefinitionIO(definition, config);\n\tconst inputs: InputParam[] = processInputs(rawInputs);\n\n\treturn { inputs, outputs };\n}\n","import { DataTreeDefault, DataTreePath, InputParam, DataTree } from '../types';\nimport { getLogger } from '@/core';\n\n/**\n * Value types that can be stored in a DataTree\n */\nexport type DataTreeValue = string | number | boolean | object | null;\n\n/**\n * Simple data item for compute requests (not to be confused with DataItem interface for responses).\n * Note: While TypeScript defines this as string, Rhino Compute accepts boolean/number primitives in JSON.\n */\ninterface ComputeDataItem {\n\tdata: string | boolean | number;\n}\n\n/**\n * InnerTree data structure for compute requests.\n */\ntype ComputeInnerTreeData = {\n\t[path in DataTreePath]: ComputeDataItem[];\n};\n\n/**\n * Standalone TreeBuilder class for constructing Grasshopper TreeBuilder structures.\n * Does not depend on RhinoCompute library.\n *\n * @example\n * ```ts\n * const tree = new TreeBuilder('MyParam')\n * .append([0], [1, 2, 3])\n * .append([1], [4, 5])\n * .toComputeFormat();\n * ```\n */\nexport class TreeBuilder {\n\tprivate innerTree: ComputeInnerTreeData;\n\tprivate paramName: string;\n\n\tconstructor(paramName: string) {\n\t\tthis.paramName = paramName;\n\t\tthis.innerTree = {} as ComputeInnerTreeData;\n\t}\n\n\t/**\n\t * Append values to a specific path in the tree.\n\t *\n\t * @param path - Array of integers representing the branch path (e.g., [0], [0, 1])\n\t * @param items - Values to append at this path\n\t * @returns this for method chaining\n\t */\n\tpublic append(path: number[], items: DataTreeValue[]): this {\n\t\tconst pathKey = TreeBuilder.formatPathString(path);\n\n\t\tif (!this.innerTree[pathKey]) {\n\t\t\tthis.innerTree[pathKey] = [];\n\t\t}\n\n\t\tconst dataItems: ComputeDataItem[] = items.map((item) => ({\n\t\t\tdata: TreeBuilder.serializeValue(item)\n\t\t}));\n\n\t\tthis.innerTree[pathKey].push(...dataItems);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Append a single value to a path.\n\t *\n\t * @param path - Branch path\n\t * @param item - Single value to append\n\t * @returns this for method chaining\n\t */\n\tpublic appendSingle(path: number[], item: DataTreeValue): this {\n\t\treturn this.append(path, [item]);\n\t}\n\n\t/**\n\t * Set values from a DataTreeDefault structure.\n\t * Replaces any existing tree data.\n\t *\n\t * @param treeData - TreeBuilder structure with path keys like \"{0;1}\"\n\t * @returns this for method chaining\n\t */\n\tpublic fromDataTreeDefault(treeData: DataTreeDefault): this {\n\t\tthis.innerTree = {} as ComputeInnerTreeData;\n\n\t\tfor (const [pathStr, items] of Object.entries(treeData)) {\n\t\t\tif (!Array.isArray(items)) continue;\n\t\t\tconst path = TreeBuilder.parsePathString(pathStr);\n\t\t\tthis.append(path, items);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Append flattened values to path [0].\n\t * Useful for simple flat inputs.\n\t *\n\t * @param values - Single value or array of values\n\t * @returns this for method chaining\n\t */\n\tpublic appendFlat(values: DataTreeValue | DataTreeValue[]): this {\n\t\tconst items = Array.isArray(values) ? values : [values];\n\t\treturn this.append([0], items);\n\t}\n\n\t/**\n\t * Get the flattened list of all values in the tree.\n\t *\n\t * @returns Array of all values across all branches\n\t */\n\tpublic flatten(): DataTreeValue[] {\n\t\tconst result: DataTreeValue[] = [];\n\n\t\tfor (const items of Object.values(this.innerTree)) {\n\t\t\tif (Array.isArray(items)) {\n\t\t\t\tfor (const item of items) {\n\t\t\t\t\tresult.push(TreeBuilder.deserializeValue(item.data));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get all paths in the tree.\n\t *\n\t * @returns Array of path strings\n\t */\n\tpublic getPaths(): DataTreePath[] {\n\t\treturn Object.keys(this.innerTree) as DataTreePath[];\n\t}\n\n\t/**\n\t * Get values at a specific path.\n\t *\n\t * @param path - Path to retrieve values from\n\t * @returns Array of values or undefined if path doesn't exist\n\t */\n\tpublic getPath(path: number[]): DataTreeValue[] | undefined {\n\t\tconst pathKey = TreeBuilder.formatPathString(path);\n\t\tconst items = this.innerTree[pathKey];\n\t\tif (!items) return undefined;\n\t\treturn items.map((item: ComputeDataItem) => TreeBuilder.deserializeValue(item.data));\n\t}\n\n\t/**\n\t * Convert to format compatible with Grasshopper Compute API.\n\t *\n\t * @returns InnerTree object ready for compute\n\t */\n\tpublic toComputeFormat(): DataTree {\n\t\treturn {\n\t\t\tParamName: this.paramName,\n\t\t\tInnerTree: this.innerTree as any // Cast to any because request format differs from response type\n\t\t};\n\t}\n\n\t/**\n\t * Get the raw InnerTree data structure.\n\t *\n\t * @returns InnerTree data\n\t */\n\tpublic getInnerTree(): ComputeInnerTreeData {\n\t\treturn this.innerTree;\n\t}\n\n\t/**\n\t * Get the parameter name.\n\t *\n\t * @returns Parameter name\n\t */\n\tpublic getParamName(): string {\n\t\treturn this.paramName;\n\t}\n\n\t// ============================================================================\n\t// Static Factory Methods\n\t// ============================================================================\n\n\t/**\n\t * Create DataTrees from an array of InputParam definitions.\n\t * Handles tree access, numeric constraints, and value parsing.\n\t *\n\t * @param inputs - Array of input parameter definitions\n\t * @returns Array of InnerTree instances ready for compute\n\t *\n\t * @example\n\t * ```ts\n\t * const trees = TreeBuilder.fromInputParams(inputs);\n\t * ```\n\t */\n\tpublic static fromInputParams(inputs: InputParam[]): DataTree[] {\n\t\treturn inputs\n\t\t\t.filter((input) => TreeBuilder.hasValidValue(input.default))\n\t\t\t.map((input) => {\n\t\t\t\tconst tree = new TreeBuilder(input.nickname || 'unnamed');\n\t\t\t\tconst value = input.default;\n\n\t\t\t\t// Handle tree access (complex TreeBuilder structure)\n\t\t\t\tif (input.treeAccess && TreeBuilder.isDataTreeStructure(value)) {\n\t\t\t\t\ttree.fromDataTreeDefault(value as DataTreeDefault);\n\n\t\t\t\t\t// Apply numeric constraints to tree items\n\t\t\t\t\tif (TreeBuilder.isNumericInput(input)) {\n\t\t\t\t\t\ttree.applyNumericConstraints(input.minimum, input.maximum, input.nickname || 'unnamed');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Handle flat inputs\n\t\t\t\telse {\n\t\t\t\t\tconst values = Array.isArray(value) ? value : [value];\n\t\t\t\t\tconst processed = TreeBuilder.processValues(values, input);\n\t\t\t\t\ttree.appendFlat(processed);\n\t\t\t\t}\n\n\t\t\t\treturn tree.toComputeFormat();\n\t\t\t});\n\t}\n\n\t/**\n\t * Create a TreeBuilder from a single InputParam.\n\t *\n\t * @param input - Input parameter definition\n\t * @returns InnerTree ready for compute or undefined if value is invalid\n\t */\n\tpublic static fromInputParam(input: InputParam): DataTree | undefined {\n\t\tif (!TreeBuilder.hasValidValue(input.default)) return undefined;\n\n\t\tconst trees = TreeBuilder.fromInputParams([input]);\n\t\treturn trees[0];\n\t}\n\n\t/**\n\t * Set or replace a parameter value within a TreeBuilder or InnerTree array.\n\t *\n\t * Supports both high-level `DataTree[]` instances and low-level `InnerTree[]` format.\n\t *\n\t * **Architecture Note:**\n\t * - Use with `DataTree[]` when building/modifying before computation\n\t * - Use with `InnerTree[]` when modifying compute API results\n\t * - `DataTree` is the high-level builder; `InnerTree` is the Rhino Compute format\n\t *\n\t * @overload For TreeBuilder instances (high-level builder)\n\t * @param trees - Array of TreeBuilder instances to modify\n\t * @param paramName - The parameter name to set or replace\n\t * @param newValue - The new value (scalar, array, or TreeBuilder structure)\n\t * @returns A new/modified TreeBuilder array with the updated parameter\n\t *\n\t * @overload For compiled InnerTree (low-level API format)\n\t * @param trees - The compiled InnerTree array (typically from `client.solve()`)\n\t * @param paramName - The parameter name to set or replace\n\t * @param newValue - The new value (scalar, array, or TreeBuilder structure)\n\t * @returns A new/modified InnerTree array with the updated parameter\n\t *\n\t * @example\n\t * ```ts\n\t * // With TreeBuilder instances (high-level)\n\t * let trees = [new TreeBuilder('X'), new TreeBuilder('Y')];\n\t * trees = TreeBuilder.replaceTreeValue(trees, 'X', 42);\n\t * const result = await client.solve(definitionUrl,\n\t * trees.map(t => t.toComputeFormat())\n\t * );\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * // With InnerTree format (low-level, from API)\n\t * let trees = await client.solve(definitionUrl, initialInputs);\n\t * trees = TreeBuilder.replaceTreeValue(trees, 'X', 42);\n\t * trees = TreeBuilder.replaceTreeValue(trees, 'Y', [1, 2, 3]);\n\t * ```\n\t */\n\tpublic static replaceTreeValue(\n\t\ttrees: TreeBuilder[],\n\t\tparamName: string,\n\t\tnewValue: DataTreeValue\n\t): TreeBuilder[];\n\tpublic static replaceTreeValue(\n\t\ttrees: DataTree[],\n\t\tparamName: string,\n\t\tnewValue: DataTreeValue\n\t): DataTree[];\n\tpublic static replaceTreeValue(\n\t\ttrees: TreeBuilder[] | DataTree[],\n\t\tparamName: string,\n\t\tnewValue: DataTreeValue\n\t): TreeBuilder[] | DataTree[] {\n\t\t// Check if we're working with TreeBuilder instances or InnerTree objects\n\t\tconst isDataTreeArray = trees.length > 0 && trees[0] instanceof TreeBuilder;\n\n\t\tif (isDataTreeArray) {\n\t\t\t// Handle DataTree[] instances\n\t\t\tconst dataTrees = trees as TreeBuilder[];\n\t\t\tconst existingIndex = dataTrees.findIndex((t) => t.getParamName() === paramName);\n\t\t\tconst tree = new TreeBuilder(paramName);\n\n\t\t\t// Handle different input formats\n\t\t\tif (\n\t\t\t\ttypeof newValue === 'object' &&\n\t\t\t\tnewValue !== null &&\n\t\t\t\t!Array.isArray(newValue) &&\n\t\t\t\tTreeBuilder.isDataTreeStructure(newValue)\n\t\t\t) {\n\t\t\t\ttree.fromDataTreeDefault(newValue as DataTreeDefault);\n\t\t\t} else if (Array.isArray(newValue)) {\n\t\t\t\ttree.appendFlat(newValue);\n\t\t\t} else {\n\t\t\t\ttree.appendFlat(newValue);\n\t\t\t}\n\n\t\t\tif (existingIndex !== -1) {\n\t\t\t\tdataTrees[existingIndex] = tree;\n\t\t\t} else {\n\t\t\t\tdataTrees.push(tree);\n\t\t\t}\n\n\t\t\treturn dataTrees;\n\t\t} else {\n\t\t\t// Handle InnerTree[] (compiled format)\n\t\t\tconst innerTrees = trees as DataTree[];\n\t\t\tconst existingIndex = innerTrees.findIndex((t) => t.ParamName === paramName);\n\t\t\tconst tree = new TreeBuilder(paramName);\n\n\t\t\t// Handle different input formats\n\t\t\tif (\n\t\t\t\ttypeof newValue === 'object' &&\n\t\t\t\tnewValue !== null &&\n\t\t\t\t!Array.isArray(newValue) &&\n\t\t\t\tTreeBuilder.isDataTreeStructure(newValue)\n\t\t\t) {\n\t\t\t\ttree.fromDataTreeDefault(newValue as DataTreeDefault);\n\t\t\t} else if (Array.isArray(newValue)) {\n\t\t\t\ttree.appendFlat(newValue);\n\t\t\t} else {\n\t\t\t\ttree.appendFlat(newValue);\n\t\t\t}\n\n\t\t\tconst newTree = tree.toComputeFormat();\n\n\t\t\tif (existingIndex !== -1) {\n\t\t\t\tinnerTrees[existingIndex] = newTree;\n\t\t\t} else {\n\t\t\t\tinnerTrees.push(newTree);\n\t\t\t}\n\n\t\t\treturn innerTrees;\n\t\t}\n\t}\n\n\t/**\n\t * Extract a value from a TreeBuilder or InnerTree array by parameter name.\n\t *\n\t * Automatically unwraps single values for convenience.\n\t * Works with both high-level `DataTree[]` instances and low-level `InnerTree[]` format.\n\t *\n\t * **Architecture Note:**\n\t * - Use with `DataTree[]` to read builder instances\n\t * - Use with `InnerTree[]` to read compute API responses\n\t * - Return behavior is consistent across both formats\n\t *\n\t * **Return Value Behavior:**\n\t * - Single value → unwrapped (returns `5` not `[5]`)\n\t * - Multiple values → array of values\n\t * - Not found → `null`\n\t *\n\t * @overload For TreeBuilder instances\n\t * @param trees - Array of TreeBuilder instances to read from\n\t * @param paramName - The parameter name to retrieve\n\t * @returns The unwrapped value, array of values, or null if parameter not found\n\t *\n\t * @overload For compiled InnerTree\n\t * @param trees - The compiled InnerTree array (typically from `client.solve()`)\n\t * @param paramName - The parameter name to retrieve\n\t * @returns The unwrapped value, array of values, or null if parameter not found\n\t *\n\t * @example\n\t * ```ts\n\t * // With TreeBuilder instances\n\t * const trees = [new TreeBuilder('X'), new TreeBuilder('Y')];\n\t * trees[0].appendFlat(42);\n\t * const x = TreeBuilder.getTreeValue(trees, 'X'); // Returns 42\n\t * ```\n\t *\n\t * @example\n\t * ```ts\n\t * // With InnerTree from compute results\n\t * const result = await client.solve(definitionUrl, inputs);\n\t * const x = TreeBuilder.getTreeValue(result, 'X'); // Returns 42 (not [42])\n\t * const points = TreeBuilder.getTreeValue(result, 'Points'); // Returns [point1, point2, ...]\n\t * ```\n\t */\n\tpublic static getTreeValue(trees: TreeBuilder[], paramName: string): DataTreeValue | null;\n\tpublic static getTreeValue(trees: DataTree[], paramName: string): DataTreeValue | null;\n\tpublic static getTreeValue(\n\t\ttrees: TreeBuilder[] | DataTree[],\n\t\tparamName: string\n\t): DataTreeValue | null {\n\t\t// Check if we're working with TreeBuilder instances or InnerTree objects\n\t\tconst isDataTreeArray = trees.length > 0 && trees[0] instanceof TreeBuilder;\n\n\t\tif (isDataTreeArray) {\n\t\t\t// Handle DataTree[] instances\n\t\t\tconst dataTrees = trees as TreeBuilder[];\n\t\t\tconst tree = dataTrees.find((t) => t.getParamName() === paramName);\n\n\t\t\tif (!tree) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst values = tree.flatten();\n\n\t\t\tif (values.length === 0) return null;\n\t\t\tif (values.length === 1) return values[0];\n\t\t\treturn values;\n\t\t} else {\n\t\t\t// Handle InnerTree[] (compiled format)\n\t\t\tconst innerTrees = trees as DataTree[];\n\t\t\tconst tree = innerTrees.find((t) => t.ParamName === paramName);\n\n\t\t\tif (!tree) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst innerTree = tree.InnerTree;\n\n\t\t\t// Handle missing InnerTree\n\t\t\tif (!innerTree) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Get the first path (usually \"{0}\")\n\t\t\tconst firstKey = Object.keys(innerTree)[0];\n\t\t\tif (!firstKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// @ts-expect-error - Dynamic key access on innerTree\n\t\t\tconst items = innerTree[firstKey];\n\n\t\t\t// Handle array of values\n\t\t\tif (Array.isArray(items)) {\n\t\t\t\t// Single value: unwrap the data property\n\t\t\t\tif (items.length === 1) {\n\t\t\t\t\tconst value = items[0]?.data;\n\t\t\t\t\treturn value !== undefined ? TreeBuilder.deserializeValue(value) : null;\n\t\t\t\t}\n\t\t\t\t// Multiple values: return array of deserialized values\n\t\t\t\treturn items\n\t\t\t\t\t.map((item) =>\n\t\t\t\t\t\titem?.data !== undefined ? TreeBuilder.deserializeValue(item.data) : null\n\t\t\t\t\t)\n\t\t\t\t\t.filter((v) => v !== null);\n\t\t\t}\n\n\t\t\t// Handle single object with data property\n\t\t\tif (items?.data !== undefined) {\n\t\t\t\treturn TreeBuilder.deserializeValue(items.data);\n\t\t\t}\n\n\t\t\t// Return raw value\n\t\t\treturn items;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a TreeBuilder path string like \"{0;1;2}\" into [0, 1, 2].\n\t *\n\t * @param pathStr - Path string\n\t * @returns Array of path indices\n\t */\n\tpublic static parsePathString(pathStr: string): number[] {\n\t\t// Allow the legitimate root path \"{}\" alongside \"{0;1;2}\"\n\t\tconst match = pathStr.match(/^\\{([\\d;]*)\\}$/);\n\t\tif (!match) {\n\t\t\tgetLogger().warn(`Invalid TreeBuilder path format: ${pathStr}, using [0]`);\n\t\t\treturn [0];\n\t\t}\n\t\tif (match[1] === '') return [];\n\t\treturn match[1].split(';').map(Number);\n\t}\n\n\t/**\n\t * Format a path array into TreeBuilder path string format.\n\t *\n\t * @param path - Path as number array\n\t * @returns Formatted path string like \"{0;1;2}\"\n\t */\n\tpublic static formatPathString(path: number[]): DataTreePath {\n\t\treturn `{${path.join(';')}}` as DataTreePath;\n\t}\n\n\t// ============================================================================\n\t// Private Helper Methods\n\t// ============================================================================\n\n\t/**\n\t * Apply numeric constraints to all tree values.\n\t */\n\tprivate applyNumericConstraints(\n\t\tmin: number | null | undefined,\n\t\tmax: number | null | undefined,\n\t\tinputName: string\n\t): void {\n\t\tfor (const items of Object.values(this.innerTree)) {\n\t\t\tif (!Array.isArray(items)) continue;\n\n\t\t\tfor (const item of items) {\n\t\t\t\tconst value = TreeBuilder.deserializeValue(item.data);\n\t\t\t\tif (typeof value === 'number') {\n\t\t\t\t\tconst clamped = TreeBuilder.clampValue(value, min, max, inputName);\n\t\t\t\t\titem.data = TreeBuilder.serializeValue(clamped);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Serialize a value for compute requests.\n\t * Preserves booleans and numbers as primitives for proper Grasshopper parameter handling.\n\t */\n\tprivate static serializeValue(value: DataTreeValue): string | boolean | number {\n\t\tif (typeof value === 'boolean') return value;\n\t\tif (typeof value === 'number') return value;\n\t\tif (typeof value === 'string') return value;\n\t\tif (typeof value === 'object' && value !== null) {\n\t\t\treturn JSON.stringify(value);\n\t\t}\n\t\treturn String(value);\n\t}\n\n\t/**\n\t * Deserialize a value back to its original type.\n\t * Handles both string-encoded values and primitive values.\n\t */\n\tprivate static deserializeValue(data: string | boolean | number): DataTreeValue {\n\t\t// If already a primitive type, return as-is\n\t\tif (typeof data === 'boolean') return data;\n\t\tif (typeof data === 'number') return data;\n\n\t\t// Handle string values\n\t\tif (typeof data !== 'string') return data;\n\n\t\t// Try to parse as JSON first\n\t\tif (data.startsWith('{') || data.startsWith('[')) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(data);\n\t\t\t} catch {\n\t\t\t\treturn data;\n\t\t\t}\n\t\t}\n\t\t// Try to parse as number\n\t\tif (!isNaN(Number(data))) {\n\t\t\treturn Number(data);\n\t\t}\n\t\t// Try to parse as boolean\n\t\tif (data === 'true') return true;\n\t\tif (data === 'false') return false;\n\t\treturn data;\n\t}\n\n\t/**\n\t * Check if a value is valid for inclusion in a DataTree.\n\t */\n\tprivate static hasValidValue(value: unknown): boolean {\n\t\tif (value === undefined || value === null) return false;\n\t\tif (typeof value === 'string') return true;\n\t\tif (Array.isArray(value) && value.length === 0) return false;\n\t\tif (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Check if value is a TreeBuilder structure.\n\t */\n\tprivate static isDataTreeStructure(value: unknown): value is DataTreeDefault {\n\t\tif (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\t\treturn Object.entries(value).every(\n\t\t\t([key, val]) => typeof key === 'string' && /^\\{[\\d;]+\\}$/.test(key) && Array.isArray(val)\n\t\t);\n\t}\n\n\t/**\n\t * Check if input is numeric type.\n\t */\n\tprivate static isNumericInput(input: InputParam): input is InputParam & {\n\t\tparamType: 'Number' | 'Integer';\n\t\tminimum?: number | null;\n\t\tmaximum?: number | null;\n\t} {\n\t\treturn input.paramType === 'Number' || input.paramType === 'Integer';\n\t}\n\n\t/**\n\t * Process array of values based on input type.\n\t */\n\tprivate static processValues(values: DataTreeValue[], input: InputParam): DataTreeValue[] {\n\t\treturn values\n\t\t\t.map((val) => {\n\t\t\t\t// Apply numeric constraints\n\t\t\t\tif (TreeBuilder.isNumericInput(input) && typeof val === 'number') {\n\t\t\t\t\treturn TreeBuilder.clampValue(\n\t\t\t\t\t\tval,\n\t\t\t\t\t\tinput.minimum,\n\t\t\t\t\t\tinput.maximum,\n\t\t\t\t\t\tinput.nickname || 'unnamed'\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Keep objects and strings as-is (serialization happens in append)\n\t\t\t\treturn val;\n\t\t\t})\n\t\t\t.filter((v) => v !== null && v !== undefined);\n\t}\n\n\t/**\n\t * Clamp numeric value to constraints.\n\t */\n\tprivate static clampValue(\n\t\tvalue: number,\n\t\tmin: number | null | undefined,\n\t\tmax: number | null | undefined,\n\t\tinputName: string\n\t): number {\n\t\tlet result = value;\n\n\t\tif (min !== null && min !== undefined && result < min) {\n\t\t\tgetLogger().warn(`${inputName}: ${value} below min ${min}, clamping`);\n\t\t\tresult = min;\n\t\t}\n\t\tif (max !== null && max !== undefined && result > max) {\n\t\t\tgetLogger().warn(`${inputName}: ${value} above max ${max}, clamping`);\n\t\t\tresult = max;\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"],"mappings":"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","names":["stableStringify","value","seen","stringify","v","sample","k","fnv1a","input","hash","i","hashSolveInput","definition","dataTree","defKey","SolveScheduler","executor","baseConfig","options","__publicField","cacheOpt","cacheConfig","listener","err","getLogger","definition","dataTree","RhinoComputeError","ErrorCodes","key","hashSolveInput","ctx","cached","result","resolve","reject","item","inflight","controller","externalAbortHandler","startTime","config","response","durationMs","error","next","entry","oldest","hook","args","GrasshopperClient","_GrasshopperClient","config","__publicField","ComputeServerStats","client","RhinoComputeError","ErrorCodes","definition","fetchParsedDefinitionIO","fetchDefinitionIO","dataTree","options","effectiveConfig","result","solveGrasshopperDefinition","error","getLogger","executor","SolveScheduler","extractFilesFromComputeResponse","downloadableFiles","additionalFiles","processFiles","err","RhinoComputeError","ErrorCodes","downloadFileData","fileFoldername","processedFiles","createAndDownloadZip","dataItems","item","filePath","bites","decodeBase64ToBinary","filesArray","additionalProcessed","file","response","getLogger","arrayBuffer","error","f","files","zipName","zipSync","strToU8","zipData","zipped","blob","saveFile","filename","a","decoderRegistry","registerDecoder","typeName","decoder","rhino","data","d","findDecoder","rhinoType","key","dec","extractPayload","parsedData","decodeRhinoGeometry","error","getLogger","payload","SYSTEM_TYPES","RHINO_GEOMETRY_PREFIX","EXCLUDED_TYPES","FILE_DATA_TYPE","isExcludedType","type","t","tryDecodeJSON","value","trimmed","first","decodeBySystemType","raw","rhino","decodeRhinoGeometry","extractItemValue","data","parseValues","forEachTreeItem","tree","handler","list","item","getValues","response","byId","options","stringOnly","result","param","key","extractFileData","output","parsed","getValue","parseOptions","targetParam","p","found","collected","v","GrasshopperResponseProcessor","response","debug","byId","options","getValues","paramName","getValue","paramId","mergedOptions","getThreeMeshesFromComputeResponse","error","RhinoComputeError","ErrorCodes","extractFileData","folderName","additionalFiles","files","downloadFileData","warnIfClientSide","functionName","suppress","getLogger","solveGrasshopperDefinition","dataTree","definition","config","warnIfClientSide","args","prepareGrasshopperArgs","applyOptionalComputeSettings","result","fetchRhinoCompute","_pointer","rest","base64ByteArray","isBase64","encodeStringToBase64","arglist","options","preProcessInputDefault","input","getLogger","innerTree","tree","branch","items","item","num","allValues","processInputValue","input","options","transform","setUndefinedOnEmpty","processedArray","v","transformed","createNumericTransformer","value","parsed","createBooleanTransformer","lowerValue","createTextTransformer","createColorTransformer","cleaned","processColorInput","createObjectTransformer","inputName","getLogger","err","applyRounding","decimalPlaces","tolerance","rounded","getInputStepSize","roundingTolerance","abs","decimalPart","decimals","step","s","expMatch","exp","absExp","MAX_DECIMALS","trimmed","processNumericInput","isIntegerType","val","firstValue","stepSource","stepStr","inferred","processBooleanInput","error","RhinoComputeError","processTextInput","parseToObject","processValueListInput","defaultLower","key","PARSERS","createSafeDefault","rawInput","baseInput","isList","processInput","preProcessInputDefault","parser","PARSERS","RhinoComputeError","error","getLogger","processInputs","rawInputs","fetchDefinitionIO","definition","config","args","prepareGrasshopperArgs","payload","RhinoComputeError","ErrorCodes","response","fetchRhinoCompute","camelCased","camelcaseKeys","fetchParsedDefinitionIO","warnIfClientSide","rawInputs","outputs","processInputs","TreeBuilder","_TreeBuilder","paramName","__publicField","path","items","pathKey","dataItems","item","treeData","pathStr","values","result","inputs","input","tree","value","processed","trees","newValue","dataTrees","existingIndex","t","innerTrees","newTree","innerTree","firstKey","v","match","getLogger","min","max","inputName","clamped","data","key","val"]}