selva-compute 1.3.0 → 1.4.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.
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunkFB4LUGFJcjs = require('./chunk-FB4LUGFJ.cjs');var _chunkMTDJ3VNBcjs = require('./chunk-MTDJ3VNB.cjs');_chunkMTDJ3VNBcjs.h.call(void 0, );_chunkMTDJ3VNBcjs.f.call(void 0, );_chunkMTDJ3VNBcjs.l.call(void 0, );var T=class e{constructor(r){_chunkMTDJ3VNBcjs.c.call(void 0, this,"config");_chunkMTDJ3VNBcjs.c.call(void 0, this,"serverStats");_chunkMTDJ3VNBcjs.c.call(void 0, this,"disposed",!1);this.config=this.normalizeComputeConfig(r),this.serverStats=new (0, _chunkMTDJ3VNBcjs.n)(this.config.serverUrl,this.config.apiKey)}static async create(r){let t=new e(r);if(!await t.serverStats.isServerOnline())throw new (0, _chunkMTDJ3VNBcjs.e)("Rhino Compute server is not online",_chunkMTDJ3VNBcjs.d.NETWORK_ERROR,{context:{serverUrl:t.config.serverUrl}});return t}getConfig(){return this.ensureNotDisposed(),{...this.config}}async getIO(r){return this.ensureNotDisposed(),P(r,this.config)}async getRawIO(r){return this.ensureNotDisposed(),b(r,this.config)}async solve(r,t){this.ensureNotDisposed();try{if(typeof r=="string"&&!_optionalChain([r, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()]))throw new (0, _chunkMTDJ3VNBcjs.e)("Definition URL/content is required",_chunkMTDJ3VNBcjs.d.INVALID_INPUT,{context:{receivedUrl:r}});if(r instanceof Uint8Array&&r.length===0)throw new (0, _chunkMTDJ3VNBcjs.e)("Definition content is empty",_chunkMTDJ3VNBcjs.d.INVALID_INPUT);if(!await this.serverStats.isServerOnline())throw new (0, _chunkMTDJ3VNBcjs.e)("Rhino Compute server is not online",_chunkMTDJ3VNBcjs.d.NETWORK_ERROR,{context:{serverUrl:this.config.serverUrl}});let n=await C(t,r,this.config);if(n&&typeof n=="object"&&"message"in n&&!("fileData"in n))throw new (0, _chunkMTDJ3VNBcjs.e)(n.message||"Computation failed",_chunkMTDJ3VNBcjs.d.COMPUTATION_ERROR,{context:{definition:typeof r=="string"&&r.length<200?r:"...content...",inputs:t}});return n}catch(n){throw this.config.debug&&_chunkMTDJ3VNBcjs.i.call(void 0, ).error("Compute failed:",n),n instanceof _chunkMTDJ3VNBcjs.e?n:new (0, _chunkMTDJ3VNBcjs.e)(n instanceof Error?n.message:String(n),_chunkMTDJ3VNBcjs.d.COMPUTATION_ERROR,{context:{definition:typeof r=="string"&&r.length<200?r:"...content...",inputs:t},originalError:n instanceof Error?n:new Error(String(n))})}}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 (0, _chunkMTDJ3VNBcjs.e)("GrasshopperClient has been disposed and cannot be used",_chunkMTDJ3VNBcjs.d.INVALID_STATE)}normalizeComputeConfig(r){if(!_optionalChain([r, 'access', _4 => _4.serverUrl, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]))throw new (0, _chunkMTDJ3VNBcjs.e)("serverUrl is required",_chunkMTDJ3VNBcjs.d.INVALID_CONFIG,{context:{receivedServerUrl:r.serverUrl}});try{new URL(r.serverUrl)}catch (e2){throw new (0, _chunkMTDJ3VNBcjs.e)("serverUrl must be a valid URL",_chunkMTDJ3VNBcjs.d.INVALID_CONFIG,{context:{receivedServerUrl:r.serverUrl}})}if(r.serverUrl===""||r.serverUrl==="https://compute.rhino3d.com/")throw new (0, _chunkMTDJ3VNBcjs.e)("serverUrl must be set to your Compute server URL. The default public endpoint is not allowed.",_chunkMTDJ3VNBcjs.d.INVALID_CONFIG,{context:{receivedServerUrl:r.serverUrl}});return{...r,serverUrl:r.serverUrl.replace(/\/+$/,""),apiKey:r.apiKey,authToken:r.authToken,debug:_nullishCoalesce(r.debug, () => (!1)),suppressClientSideWarning:r.suppressClientSideWarning}}};var L=async(e,r=null)=>{try{return await K(e,r)}catch(t){throw new (0, _chunkMTDJ3VNBcjs.e)("Failed to extract files from compute response",_chunkMTDJ3VNBcjs.d.INVALID_STATE,{context:{originalError:t instanceof Error?t.message:String(t)},originalError:t instanceof Error?t:void 0})}},S= exports.c =async(e,r,t=null)=>{if(typeof document>"u"||typeof Blob>"u")throw new (0, _chunkMTDJ3VNBcjs.e)("File download functionality is only available in browser environments. This function requires the DOM API (document, Blob).",_chunkMTDJ3VNBcjs.d.BROWSER_ONLY,{context:{environment:typeof window<"u"?"browser (SSR)":"Node.js",documentAvailable:typeof document<"u",blobAvailable:typeof Blob<"u"}});try{let n=await K(e,t);await ie(n,r)}catch(n){throw n instanceof _chunkMTDJ3VNBcjs.e?n:new (0, _chunkMTDJ3VNBcjs.e)("Failed to download files from compute response",_chunkMTDJ3VNBcjs.d.INVALID_STATE,{context:{originalError:n instanceof Error?n.message:String(n)},originalError:n instanceof Error?n:void 0})}},K=async(e,r)=>{let t=[];if(e.forEach(n=>{let a=`${n.fileName}${n.fileType}`;if(n.subFolder&&n.subFolder.trim()!==""&&(a=`${n.subFolder}/${a}`),n.isBase64Encoded===!0&&n.data){let o=_chunkFB4LUGFJcjs.c.call(void 0, n.data);t.push({fileName:`${n.fileName}${n.fileType}`,content:new Uint8Array(o.buffer),path:a})}else n.isBase64Encoded===!1&&n.data&&t.push({fileName:`${n.fileName}${n.fileType}`,content:n.data,path:a})}),r){let n=Array.isArray(r)?r:[r],a=await Promise.all(n.map(async o=>{try{let s=await fetch(o.filePath);if(!s.ok)return _chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`Failed to fetch additional file from URL: ${o.filePath}`),null;let u=await(await s.blob()).arrayBuffer();return{fileName:o.fileName,content:new Uint8Array(u),path:o.fileName}}catch(s){return _chunkMTDJ3VNBcjs.i.call(void 0, ).error(`Error fetching additional file from URL: ${o.filePath}`,s),null}}));t.push(...a.filter(o=>o!==null))}return t};async function ie(e,r){let{zipSync:t,strToU8:n}=await Promise.resolve().then(() => _interopRequireWildcard(require("fflate"))),a={};e.forEach(i=>{a[i.path]=typeof i.content=="string"?n(i.content):i.content});let o=t(a,{level:6}),s=new Blob([o],{type:"application/zip"});ue(s,`${r}.zip`)}function ue(e,r){if(typeof document>"u")throw new (0, _chunkMTDJ3VNBcjs.e)("saveFile requires a browser environment with DOM API access.",_chunkMTDJ3VNBcjs.d.BROWSER_ONLY,{context:{function:"saveFile",requiredAPI:"document"}});let t=document.createElement("a");t.href=URL.createObjectURL(e),t.download=r,t.click(),URL.revokeObjectURL(t.href)}var v=new Map;function Y(e,r){v.set(e,r)}Y("Rhino.Geometry.Point3d",(e,r)=>{let t=r;return!t||typeof t.X!="number"?null:new e.Point([t.X,t.Y,t.Z])});Y("Rhino.Geometry.Line",(e,r)=>{let t=r;return!t||!t.From||!t.To?null:new e.Line([t.From.X,t.From.Y,t.From.Z],[t.To.X,t.To.Y,t.To.Z])});function le(e){if(v.has(e))return v.get(e);for(let[r,t]of v)if(e.startsWith(r))return t}function pe(e){return!e||typeof e!="object"?null:_nullishCoalesce(_nullishCoalesce(e.data, () => (e.value)), () => (null))}function J(e,r,t){let n=le(r);if(n)try{return n(t,e)}catch(a){_chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`Failed to decode Rhino type ${r}:`,a)}try{let a=pe(e);if(a)return t.CommonObject.decode(a)}catch(a){return _chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`Failed to decode ${r} with CommonObject:`,a),{__decodeError:!0,type:r,raw:e}}return e}var D={STRING:"System.String",INT:"System.Int32",DOUBLE:"System.Double",BOOL:"System.Boolean"},fe="Rhino.Geometry.",me=["WebDisplay"],ce="FileData";function de(e){return me.some(r=>e.includes(r))}function X(e){if(typeof e!="string")return e;let r=e.trim();if(!(r.startsWith("{")||r.startsWith("[")||r.startsWith('"')))return e;try{let n=JSON.parse(r);if(typeof n=="string")try{return JSON.parse(n)}catch (e3){return n}return n}catch (e4){return e}}function ye(e,r,t){switch(r){case D.STRING:return typeof e!="string"?e:e.replace(/^"(.*)"$/,"$1");case D.INT:return Number.parseInt(e,10);case D.DOUBLE:return Number.parseFloat(e);case D.BOOL:return String(e).toLowerCase()==="true";default:return t&&r.startsWith(fe)?J(e,r,t):e}}function Z(e,r,t,n){if(de(r))return null;if(typeof e!="string")return e;let a=t?X(e):e;return ye(a,r,n)}function w(e,r){for(let t of Object.values(e))if(Array.isArray(t))for(let n of t)r(n)}function H(e,r=!1,t={}){let{parseValues:n=!0,rhino:a,stringOnly:o=!1}=t,s={};for(let i of e.values)w(i.InnerTree,u=>{if(o&&u.type!==D.STRING)return;let p=r?u.id:i.ParamName;if(!p)return;let c=Z(u.data,u.type,n,a);s[p]===void 0?s[p]=c:Array.isArray(s[p])?s[p].push(c):s[p]=[s[p],c]});return{values:s}}function _(e){let r=[];for(let t of e.values)w(t.InnerTree,n=>{if(!n.type.includes(ce))return;let a=X(n.data);a&&a.fileName&&a.fileType&&a.data&&typeof a.isBase64Encoded=="boolean"&&typeof a.subFolder=="string"&&r.push(a)});return r}function B(e,r,t={}){let{parseValues:n=!0,rhino:a,stringOnly:o=!1}=t,s;if("byName"in r?s=e.values.find(u=>u.ParamName===r.byName):s=e.values.find(u=>{let p=!1;return w(u.InnerTree,c=>{c.id===r.byId&&(p=!0)}),p}),!s)return;let i=[];if(w(s.InnerTree,u=>{if("byId"in r&&u.id!==r.byId||o&&u.type!==D.STRING)return;let p=Z(u.data,u.type,n,a);i.push(p)}),i.length!==0)return i.length===1?i[0]:i}var I=class{constructor(r,t=!1){this.response=r;this.debug=t}getValues(r=!1,t={}){return H(this.response,r,t)}getValueByParamName(r,t){return B(this.response,{byName:r},t)}getValueByParamId(r,t){return B(this.response,{byId:r},t)}async extractMeshesFromResponse(r){let t={debug:this.debug,...r};try{let{getThreeMeshesFromComputeResponse:n}=await Promise.resolve().then(() => _interopRequireWildcard(require("./visualization.cjs")));return n(this.response,t)}catch(n){let{RhinoComputeError:a,ErrorCodes:o}=(_chunkMTDJ3VNBcjs.h.call(void 0, ),_chunkMTDJ3VNBcjs.b.call(void 0, _chunkMTDJ3VNBcjs.g));throw new a("Failed to load three.js visualization module. Ensure three.js is installed as a peer dependency.",o.INVALID_STATE,{context:{originalError:n instanceof Error?n.message:String(n)}})}}getFileData(){return _(this.response)}getAndDownloadFiles(r,t){let n=this.getFileData();S(n,r,t)}};_chunkMTDJ3VNBcjs.l.call(void 0, );function A(e,r){r||typeof window<"u"&&_chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`Warning: ${e} is running on the client side. For better performance and security, consider running this on the server side.`)}async function C(e,r,t){t.debug&&A("solveGrasshopperDefinition",t.suppressClientSideWarning);let n=M(r,e);he(n,t);let a=await _chunkMTDJ3VNBcjs.m.call(void 0, "grasshopper",n,t);return"pointer"in a&&delete a.pointer,a}function M(e,r){let t={algo:null,pointer:null,values:r};return e instanceof Uint8Array?t.algo=_chunkFB4LUGFJcjs.d.call(void 0, e):e.startsWith("http")?t.pointer=e:_chunkFB4LUGFJcjs.b.call(void 0, e)?t.algo=e:t.algo=_chunkFB4LUGFJcjs.a.call(void 0, e),t}function he(e,r){r.cachesolve!==null&&(e.cachesolve=r.cachesolve),r.modelunits!==null&&(e.modelunits=r.modelunits),r.angletolerance!==null&&(e.angletolerance=r.angletolerance),r.absolutetolerance!==null&&(e.absolutetolerance=r.absolutetolerance),r.dataversion!==null&&(e.dataversion=r.dataversion)}_chunkMTDJ3VNBcjs.h.call(void 0, );function Q(e){if(typeof e.default!="object"||e.default===null)return;if(!("innerTree"in e.default)){_chunkMTDJ3VNBcjs.i.call(void 0, ).warn("Unexpected structure in input.default:",e.default),e.default=null;return}let r=e.default.innerTree;if(Object.keys(r).length===0){e.default=void 0;return}if(e.treeAccess||e.atMost&&e.atMost>1){let n={};for(let[a,o]of Object.entries(r))n[a]=o.map(s=>{if(typeof s.data=="string"){if(s.type==="System.Double"||s.type==="System.Int32"){let i=Number(s.data);return Number.isNaN(i)?s.data:i}if(s.type==="System.Boolean")return s.data.toLowerCase()==="true";if(s.type.startsWith("Rhino.Geometry")||s.type==="System.String")try{return JSON.parse(s.data)}catch (e5){return s.data}}return s.data});e.default=n;return}let t=[];for(let n of Object.values(r))Array.isArray(n)&&n.forEach(a=>{a&&typeof a=="object"&&"data"in a&&t.push(a.data)});t.length===0?e.default=void 0:t.length===1?e.default=t[0]:e.default=t}_chunkMTDJ3VNBcjs.h.call(void 0, );function R(e,r){let{transform:t,setUndefinedOnEmpty:n=!0}=r;if(!(e.default===void 0||e.default===null))if(Array.isArray(e.default)){let a=e.default.map(t).filter(o=>o!==null);e.default=a.length>0?a:void 0}else{let a=t(e.default);a!==null?e.default=a:n&&(e.default=void 0)}}function ge(){return e=>{if(typeof e=="number")return e;if(typeof e=="string"){let r=Number(e.trim());return Number.isNaN(r)?null:r}return null}}function Te(){return e=>{if(typeof e=="boolean")return e;if(typeof e=="string"){let r=e.toLowerCase();if(r==="true")return!0;if(r==="false")return!1;throw new Error(`Invalid boolean string: "${e}"`)}return null}}function be(){return e=>typeof e=="string"?e.startsWith('"')&&e.endsWith('"')||e.startsWith('"')?e.slice(1,-1):e:null}function De(){return e=>{if(typeof e=="string"){let r=e.trim();return r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1).trim()),r}return null}}function Ie(e){R(e,{transform:De(),setUndefinedOnEmpty:!1})}function xe(e="unknown"){return r=>{if(typeof r=="object"&&r!==null)return r;if(typeof r=="string"&&r.trim()!=="")try{let t=JSON.parse(r);return typeof t=="object"&&t!==null?t:(_chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`Parsed value for input ${e} is not an object`),null)}catch(t){return _chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`Failed to parse object value "${r}" for input ${e}`,t),null}return null}}function ee(e,r,t){let n=Number(e.toFixed(r));return Math.abs(e-n)<t?n:e}function Ce(e,r=1e-8){if(!Number.isFinite(e)||e===0)return .1;let t=Math.abs(e);if(t>=1){let y=String(e).split(".")[1];if(y&&y.length>0){let h=Math.min(y.length,12),g=Math.pow(10,-h),U=Number(g.toFixed(h));return Math.abs(U-g)<r?U:g}return 1}let n=String(e),a=n.toLowerCase().match(/e(-?\d+)/);if(a){let G=Number(a[1]);if(G<0||n.toLowerCase().includes("e-")){let y=Math.abs(G),h=Math.pow(10,-y),g=Number(h.toFixed(y));return Math.abs(g-h)<r?g:h}return .1}let o=12,i=t.toFixed(o).replace(/0+$/,""),u=Math.min((i.split(".")[1]||"").length,o);if(u===0)return .1;let p=Math.pow(10,-u),c=Number(p.toFixed(u));return Math.abs(c-p)<r?c:p}function re(e,r=1e-8){let t=e.paramType==="Integer";if(R(e,{transform:ge()}),t){Array.isArray(e.default)?e.default=e.default.map(o=>typeof o=="number"?Math.round(o):o):typeof e.default=="number"&&(e.default=Math.round(e.default)),e.stepSize=1;return}let n=Array.isArray(e.default)?e.default[0]:e.default,a;if(typeof n=="number"&&Number.isFinite(n)&&n!==0?a=n:typeof e.minimum=="number"&&Number.isFinite(e.minimum)&&e.minimum!==0?a=e.minimum:typeof e.maximum=="number"&&Number.isFinite(e.maximum)&&e.maximum!==0&&(a=e.maximum),a!==void 0?e.stepSize=Ce(a,r):e.stepSize=.1,typeof e.stepSize=="number"){let o=0,s=String(e.stepSize),i=s.toLowerCase().match(/e(-?\d+)/);if(i?o=Math.abs(Number(i[1])):o=_nullishCoalesce(_optionalChain([s, 'access', _7 => _7.split, 'call', _8 => _8("."), 'access', _9 => _9[1], 'optionalAccess', _10 => _10.length]), () => (0)),o===0&&typeof n=="number"&&n!==0&&Math.abs(n)<1){let u=Math.ceil(-Math.log10(Math.abs(n)));Number.isFinite(u)&&u>0&&(o=u)}o=Math.min(Math.max(o,0),12),Array.isArray(e.default)?e.default=e.default.map(u=>typeof u=="number"?ee(u,o,r):u):typeof e.default=="number"&&(e.default=ee(e.default,o,r))}}function Pe(e){try{R(e,{transform:Te(),setUndefinedOnEmpty:!1})}catch(r){throw r instanceof Error?new (0, _chunkMTDJ3VNBcjs.e)(r.message):r}}function Se(e){R(e,{transform:be(),setUndefinedOnEmpty:!1})}function te(e){R(e,{transform:xe(e.nickname||"unnamed"),setUndefinedOnEmpty:!0})}function Re(e){if(!e.values||typeof e.values!="object"||Object.keys(e.values).length===0)throw _chunkMTDJ3VNBcjs.e.missingValues(e.nickname||"unnamed","ValueList");if(e.default!==void 0&&e.default!==null){let r=String(e.default).toLowerCase();Object.keys(e.values).some(n=>n.toLowerCase()===r)||_chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`ValueList input "${e.nickname||"unnamed"}" default value "${e.default}" is not in available values`)}}var ne={Number:re,Integer:re,Boolean:Pe,Text:Se,ValueList:Re,Geometry:te,File:te,Color:Ie};_chunkMTDJ3VNBcjs.l.call(void 0, );function Ne(e,r){switch(e.paramType){case"Number":case"Integer":return{...r,paramType:e.paramType,minimum:e.minimum,maximum:e.maximum,atLeast:e.atLeast,atMost:e.atMost,default:e.atMost>1?[0]:0};case"Boolean":return{...r,paramType:"Boolean",default:e.atMost>1?[!1]:!1};case"Text":return{...r,paramType:"Text",default:e.atMost>1?[""]:""};case"ValueList":return{...r,paramType:"ValueList",values:_nullishCoalesce(e.values, () => ({})),default:e.atMost>1?[e.default]:e.default};case"File":return{...r,paramType:"File",default:e.atMost>1?[null]:null};case"Color":return{...r,paramType:"Color",default:e.atMost>1?["0, 0, 0"]:"0, 0, 0"};default:return{...r,paramType:"Geometry",default:e.atMost>1?[null]:null}}}function N(e){let r={description:e.description,name:e.name,nickname:e.nickname,treeAccess:e.treeAccess,groupName:_nullishCoalesce(e.groupName, () => ("")),id:e.id};try{Q(e);let t=ne[e.paramType];if(!t)throw _chunkMTDJ3VNBcjs.e.unknownParamType(e.paramType,e.name);switch(t(e),e.paramType){case"Number":case"Integer":return{...r,paramType:e.paramType,minimum:e.minimum,maximum:e.maximum,atLeast:e.atLeast,atMost:e.atMost,stepSize:e.stepSize,default:e.default};case"Boolean":return{...r,paramType:"Boolean",default:e.default};case"Text":return{...r,paramType:"Text",default:e.default};case"ValueList":return{...r,paramType:"ValueList",values:e.values,default:e.default};case"Geometry":return{...r,paramType:e.paramType,default:e.default};case"File":return{...r,paramType:e.paramType,acceptedFormats:e.acceptedFormats,default:e.default};case"Color":return{...r,paramType:"Color",default:e.default};default:throw _chunkMTDJ3VNBcjs.e.unknownParamType(e.paramType,e.name)}}catch(t){if(t instanceof _chunkMTDJ3VNBcjs.e)return _chunkMTDJ3VNBcjs.i.call(void 0, ).error(`Validation error for input ${e.name||"unknown"}:`,t.message),Ne(e,r);throw new (0, _chunkMTDJ3VNBcjs.e)(t instanceof Error?t.message:String(t),"VALIDATION_ERROR",{context:{paramName:e.name,paramType:e.paramType},originalError:t instanceof Error?t:new Error(String(t))})}}function x(e){return e.map(r=>N(r))}async function b(e,r){let t=M(e,[]),n={};t.algo&&(n.algo=t.algo),t.pointer&&(n.pointer=t.pointer);let a=await _chunkMTDJ3VNBcjs.m.call(void 0, "io",n,r);if(!a||typeof a!="object")throw new (0, _chunkMTDJ3VNBcjs.e)("Invalid IO response structure",_chunkMTDJ3VNBcjs.d.INVALID_INPUT,{context:{response:a,definition:e}});let o=_chunkMTDJ3VNBcjs.p.call(void 0, a,{deep:!0});return{inputs:o.inputs,outputs:o.outputs}}async function P(e,r){A("fetchParsedDefinitionIO",r.suppressClientSideWarning);let{inputs:t,outputs:n}=await b(e,r);return{inputs:x(t),outputs:n}}var O=class e{constructor(r){_chunkMTDJ3VNBcjs.c.call(void 0, this,"innerTree");_chunkMTDJ3VNBcjs.c.call(void 0, this,"paramName");this.paramName=r,this.innerTree={}}append(r,t){let n=e.formatPathString(r);this.innerTree[n]||(this.innerTree[n]=[]);let a=t.map(o=>({data:e.serializeValue(o)}));return this.innerTree[n].push(...a),this}appendSingle(r,t){return this.append(r,[t])}fromDataTreeDefault(r){this.innerTree={};for(let[t,n]of Object.entries(r)){if(!Array.isArray(n))continue;let a=e.parsePathString(t);this.append(a,n)}return this}appendFlat(r){let t=Array.isArray(r)?r:[r];return this.append([0],t)}flatten(){let r=[];for(let t of Object.values(this.innerTree))if(Array.isArray(t))for(let n of t)r.push(e.deserializeValue(n.data));return r}getPaths(){return Object.keys(this.innerTree)}getPath(r){let t=e.formatPathString(r),n=this.innerTree[t];if(n)return n.map(a=>e.deserializeValue(a.data))}toComputeFormat(){return{ParamName:this.paramName,InnerTree:this.innerTree}}getInnerTree(){return this.innerTree}getParamName(){return this.paramName}static fromInputParams(r){return r.filter(t=>e.hasValidValue(t.default)).map(t=>{let n=new e(t.nickname||"unnamed"),a=t.default;if(t.treeAccess&&e.isDataTreeStructure(a))n.fromDataTreeDefault(a),e.isNumericInput(t)&&n.applyNumericConstraints(t.minimum,t.maximum,t.nickname||"unnamed");else{let o=Array.isArray(a)?a:[a],s=e.processValues(o,t);n.appendFlat(s)}return n.toComputeFormat()})}static fromInputParam(r){return e.hasValidValue(r.default)?e.fromInputParams([r])[0]:void 0}static replaceTreeValue(r,t,n){if(r.length>0&&r[0]instanceof e){let o=r,s=o.findIndex(u=>u.getParamName()===t),i=new e(t);return typeof n=="object"&&n!==null&&!Array.isArray(n)&&e.isDataTreeStructure(n)?i.fromDataTreeDefault(n):(Array.isArray(n),i.appendFlat(n)),s!==-1?o[s]=i:o.push(i),o}else{let o=r,s=o.findIndex(p=>p.ParamName===t),i=new e(t);typeof n=="object"&&n!==null&&!Array.isArray(n)&&e.isDataTreeStructure(n)?i.fromDataTreeDefault(n):(Array.isArray(n),i.appendFlat(n));let u=i.toComputeFormat();return s!==-1?o[s]=u:o.push(u),o}}static getTreeValue(r,t){if(r.length>0&&r[0]instanceof e){let o=r.find(i=>i.getParamName()===t);if(!o)return null;let s=o.flatten();return s.length===0?null:s.length===1?s[0]:s}else{let o=r.find(p=>p.ParamName===t);if(!o)return null;let s=o.InnerTree;if(!s)return null;let i=Object.keys(s)[0];if(!i)return null;let u=s[i];if(Array.isArray(u)){if(u.length===1){let p=_optionalChain([u, 'access', _11 => _11[0], 'optionalAccess', _12 => _12.data]);return p!==void 0?e.deserializeValue(p):null}return u.map(p=>_optionalChain([p, 'optionalAccess', _13 => _13.data])!==void 0?e.deserializeValue(p.data):null).filter(p=>p!==null)}return _optionalChain([u, 'optionalAccess', _14 => _14.data])!==void 0?e.deserializeValue(u.data):u}}static parsePathString(r){let t=r.match(/^\{([\d;]+)\}$/);return t?t[1].split(";").map(Number):(_chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`Invalid TreeBuilder path format: ${r}, using [0]`),[0])}static formatPathString(r){return`{${r.join(";")}}`}applyNumericConstraints(r,t,n){for(let a of Object.values(this.innerTree))if(Array.isArray(a))for(let o of a){let s=e.deserializeValue(o.data);if(typeof s=="number"){let i=e.clampValue(s,r,t,n);o.data=e.serializeValue(i)}}}static serializeValue(r){return typeof r=="boolean"||typeof r=="number"||typeof r=="string"?r:typeof r=="object"&&r!==null?JSON.stringify(r):String(r)}static deserializeValue(r){if(typeof r=="boolean"||typeof r=="number"||typeof r!="string")return r;if(r.startsWith("{")||r.startsWith("["))try{return JSON.parse(r)}catch (e6){return r}return isNaN(Number(r))?r==="true"?!0:r==="false"?!1:r:Number(r)}static hasValidValue(r){return r==null?!1:typeof r=="string"?!0:!(Array.isArray(r)&&r.length===0||typeof r=="object"&&!Array.isArray(r)&&Object.keys(r).length===0)}static isDataTreeStructure(r){return typeof r!="object"||r===null||Array.isArray(r)?!1:Object.entries(r).every(([t,n])=>typeof t=="string"&&/^\{[\d;]+\}$/.test(t)&&Array.isArray(n))}static isNumericInput(r){return r.paramType==="Number"||r.paramType==="Integer"}static processValues(r,t){return r.map(n=>e.isNumericInput(t)&&typeof n=="number"?e.clampValue(n,t.minimum,t.maximum,t.nickname||"unnamed"):n).filter(n=>n!=null)}static clampValue(r,t,n,a){let o=r;return t!=null&&o<t&&(_chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`${a}: ${r} below min ${t}, clamping`),o=t),n!=null&&o>n&&(_chunkMTDJ3VNBcjs.i.call(void 0, ).warn(`${a}: ${r} above max ${n}, clamping`),o=n),o}};exports.a = T; exports.b = L; exports.c = S; exports.d = I; exports.e = C; exports.f = N; exports.g = x; exports.h = b; exports.i = P; exports.j = O;
2
+ //# sourceMappingURL=chunk-7AD5GVQO.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/selva-compute/selva-compute/dist/chunk-TANE2MYU.cjs","../src/features/grasshopper/client/grasshopper-client.ts","../src/features/grasshopper/file-handling/handle-files.ts"],"names":["init_errors","init_base","init_logger","GrasshopperClient","_GrasshopperClient","config","__publicField","ComputeServerStats","client","RhinoComputeError","ErrorCodes","definition","fetchParsedDefinitionIO","fetchDefinitionIO","dataTree","result","solveGrasshopperDefinition","error","getLogger","extractFilesFromComputeResponse","downloadableFiles","additionalFiles","processFiles","err","downloadFileData","fileFoldername","processedFiles","createAndDownloadZip","dataItems","item","filePath"],"mappings":"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","file":"/home/runner/work/selva-compute/selva-compute/dist/chunk-TANE2MYU.cjs","sourcesContent":[null,"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 } from '@/core/types';\n\nimport { fetchDefinitionIO, fetchParsedDefinitionIO, solveGrasshopperDefinition } from '..';\nimport { GrasshopperComputeConfig, GrasshopperComputeResponse, DataTree } from '../types';\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): 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// Check server\n\t\t\tif (!(await this.serverStats.isServerOnline())) {\n\t\t\t\tthrow new RhinoComputeError(\n\t\t\t\t\t'Rhino Compute server is not online',\n\t\t\t\t\tErrorCodes.NETWORK_ERROR,\n\t\t\t\t\t{ context: { serverUrl: this.config.serverUrl } }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Run computation\n\t\t\tconst result = await solveGrasshopperDefinition(dataTree, definition, this.config);\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 * 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"]}
1
+ {"version":3,"sources":["/home/runner/work/selva-compute/selva-compute/dist/chunk-7AD5GVQO.cjs","../src/features/grasshopper/client/grasshopper-client.ts","../src/features/grasshopper/file-handling/handle-files.ts"],"names":["init_errors","init_base","init_logger","GrasshopperClient","_GrasshopperClient","config","__publicField","ComputeServerStats","client","RhinoComputeError","ErrorCodes","definition","fetchParsedDefinitionIO","fetchDefinitionIO","dataTree","result","solveGrasshopperDefinition","error","getLogger","extractFilesFromComputeResponse","downloadableFiles","additionalFiles","processFiles","err","downloadFileData","fileFoldername","processedFiles","createAndDownloadZip","dataItems","item","filePath"],"mappings":"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","file":"/home/runner/work/selva-compute/selva-compute/dist/chunk-7AD5GVQO.cjs","sourcesContent":[null,"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 } from '@/core/types';\n\nimport { fetchDefinitionIO, fetchParsedDefinitionIO, solveGrasshopperDefinition } from '..';\nimport { GrasshopperComputeConfig, GrasshopperComputeResponse, DataTree } from '../types';\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): 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// Check server\n\t\t\tif (!(await this.serverStats.isServerOnline())) {\n\t\t\t\tthrow new RhinoComputeError(\n\t\t\t\t\t'Rhino Compute server is not online',\n\t\t\t\t\tErrorCodes.NETWORK_ERROR,\n\t\t\t\t\t{ context: { serverUrl: this.config.serverUrl } }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Run computation\n\t\t\tconst result = await solveGrasshopperDefinition(dataTree, definition, this.config);\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 * 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"]}
@@ -0,0 +1,2 @@
1
+ import{a as $,b as z,c as W,d as q}from"./chunk-RGHW3SLU.js";import{b as ae,c as d,d as m,e as l,f as oe,g as se,h as V,i as f,l as E,m as F,n as k,p as j}from"./chunk-BL2RNK2F.js";V();oe();E();var T=class e{constructor(r){d(this,"config");d(this,"serverStats");d(this,"disposed",!1);this.config=this.normalizeComputeConfig(r),this.serverStats=new k(this.config.serverUrl,this.config.apiKey)}static async create(r){let t=new e(r);if(!await t.serverStats.isServerOnline())throw new l("Rhino Compute server is not online",m.NETWORK_ERROR,{context:{serverUrl:t.config.serverUrl}});return t}getConfig(){return this.ensureNotDisposed(),{...this.config}}async getIO(r){return this.ensureNotDisposed(),P(r,this.config)}async getRawIO(r){return this.ensureNotDisposed(),b(r,this.config)}async solve(r,t){this.ensureNotDisposed();try{if(typeof r=="string"&&!r?.trim())throw new l("Definition URL/content is required",m.INVALID_INPUT,{context:{receivedUrl:r}});if(r instanceof Uint8Array&&r.length===0)throw new l("Definition content is empty",m.INVALID_INPUT);if(!await this.serverStats.isServerOnline())throw new l("Rhino Compute server is not online",m.NETWORK_ERROR,{context:{serverUrl:this.config.serverUrl}});let n=await C(t,r,this.config);if(n&&typeof n=="object"&&"message"in n&&!("fileData"in n))throw new l(n.message||"Computation failed",m.COMPUTATION_ERROR,{context:{definition:typeof r=="string"&&r.length<200?r:"...content...",inputs:t}});return n}catch(n){throw this.config.debug&&f().error("Compute failed:",n),n instanceof l?n:new l(n instanceof Error?n.message:String(n),m.COMPUTATION_ERROR,{context:{definition:typeof r=="string"&&r.length<200?r:"...content...",inputs:t},originalError:n instanceof Error?n:new Error(String(n))})}}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",m.INVALID_STATE)}normalizeComputeConfig(r){if(!r.serverUrl?.trim())throw new l("serverUrl is required",m.INVALID_CONFIG,{context:{receivedServerUrl:r.serverUrl}});try{new URL(r.serverUrl)}catch{throw new l("serverUrl must be a valid URL",m.INVALID_CONFIG,{context:{receivedServerUrl:r.serverUrl}})}if(r.serverUrl===""||r.serverUrl==="https://compute.rhino3d.com/")throw new l("serverUrl must be set to your Compute server URL. The default public endpoint is not allowed.",m.INVALID_CONFIG,{context:{receivedServerUrl:r.serverUrl}});return{...r,serverUrl:r.serverUrl.replace(/\/+$/,""),apiKey:r.apiKey,authToken:r.authToken,debug:r.debug??!1,suppressClientSideWarning:r.suppressClientSideWarning}}};var L=async(e,r=null)=>{try{return await K(e,r)}catch(t){throw new l("Failed to extract files from compute response",m.INVALID_STATE,{context:{originalError:t instanceof Error?t.message:String(t)},originalError:t instanceof Error?t:void 0})}},S=async(e,r,t=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).",m.BROWSER_ONLY,{context:{environment:typeof window<"u"?"browser (SSR)":"Node.js",documentAvailable:typeof document<"u",blobAvailable:typeof Blob<"u"}});try{let n=await K(e,t);await ie(n,r)}catch(n){throw n instanceof l?n:new l("Failed to download files from compute response",m.INVALID_STATE,{context:{originalError:n instanceof Error?n.message:String(n)},originalError:n instanceof Error?n:void 0})}},K=async(e,r)=>{let t=[];if(e.forEach(n=>{let a=`${n.fileName}${n.fileType}`;if(n.subFolder&&n.subFolder.trim()!==""&&(a=`${n.subFolder}/${a}`),n.isBase64Encoded===!0&&n.data){let o=W(n.data);t.push({fileName:`${n.fileName}${n.fileType}`,content:new Uint8Array(o.buffer),path:a})}else n.isBase64Encoded===!1&&n.data&&t.push({fileName:`${n.fileName}${n.fileType}`,content:n.data,path:a})}),r){let n=Array.isArray(r)?r:[r],a=await Promise.all(n.map(async o=>{try{let s=await fetch(o.filePath);if(!s.ok)return f().warn(`Failed to fetch additional file from URL: ${o.filePath}`),null;let u=await(await s.blob()).arrayBuffer();return{fileName:o.fileName,content:new Uint8Array(u),path:o.fileName}}catch(s){return f().error(`Error fetching additional file from URL: ${o.filePath}`,s),null}}));t.push(...a.filter(o=>o!==null))}return t};async function ie(e,r){let{zipSync:t,strToU8:n}=await import("fflate"),a={};e.forEach(i=>{a[i.path]=typeof i.content=="string"?n(i.content):i.content});let o=t(a,{level:6}),s=new Blob([o],{type:"application/zip"});ue(s,`${r}.zip`)}function ue(e,r){if(typeof document>"u")throw new l("saveFile requires a browser environment with DOM API access.",m.BROWSER_ONLY,{context:{function:"saveFile",requiredAPI:"document"}});let t=document.createElement("a");t.href=URL.createObjectURL(e),t.download=r,t.click(),URL.revokeObjectURL(t.href)}var v=new Map;function Y(e,r){v.set(e,r)}Y("Rhino.Geometry.Point3d",(e,r)=>{let t=r;return!t||typeof t.X!="number"?null:new e.Point([t.X,t.Y,t.Z])});Y("Rhino.Geometry.Line",(e,r)=>{let t=r;return!t||!t.From||!t.To?null:new e.Line([t.From.X,t.From.Y,t.From.Z],[t.To.X,t.To.Y,t.To.Z])});function le(e){if(v.has(e))return v.get(e);for(let[r,t]of v)if(e.startsWith(r))return t}function pe(e){return!e||typeof e!="object"?null:e.data??e.value??null}function J(e,r,t){let n=le(r);if(n)try{return n(t,e)}catch(a){f().warn(`Failed to decode Rhino type ${r}:`,a)}try{let a=pe(e);if(a)return t.CommonObject.decode(a)}catch(a){return f().warn(`Failed to decode ${r} with CommonObject:`,a),{__decodeError:!0,type:r,raw:e}}return e}var D={STRING:"System.String",INT:"System.Int32",DOUBLE:"System.Double",BOOL:"System.Boolean"},fe="Rhino.Geometry.",me=["WebDisplay"],ce="FileData";function de(e){return me.some(r=>e.includes(r))}function X(e){if(typeof e!="string")return e;let r=e.trim();if(!(r.startsWith("{")||r.startsWith("[")||r.startsWith('"')))return e;try{let n=JSON.parse(r);if(typeof n=="string")try{return JSON.parse(n)}catch{return n}return n}catch{return e}}function ye(e,r,t){switch(r){case D.STRING:return typeof e!="string"?e:e.replace(/^"(.*)"$/,"$1");case D.INT:return Number.parseInt(e,10);case D.DOUBLE:return Number.parseFloat(e);case D.BOOL:return String(e).toLowerCase()==="true";default:return t&&r.startsWith(fe)?J(e,r,t):e}}function Z(e,r,t,n){if(de(r))return null;if(typeof e!="string")return e;let a=t?X(e):e;return ye(a,r,n)}function w(e,r){for(let t of Object.values(e))if(Array.isArray(t))for(let n of t)r(n)}function H(e,r=!1,t={}){let{parseValues:n=!0,rhino:a,stringOnly:o=!1}=t,s={};for(let i of e.values)w(i.InnerTree,u=>{if(o&&u.type!==D.STRING)return;let p=r?u.id:i.ParamName;if(!p)return;let c=Z(u.data,u.type,n,a);s[p]===void 0?s[p]=c:Array.isArray(s[p])?s[p].push(c):s[p]=[s[p],c]});return{values:s}}function _(e){let r=[];for(let t of e.values)w(t.InnerTree,n=>{if(!n.type.includes(ce))return;let a=X(n.data);a&&a.fileName&&a.fileType&&a.data&&typeof a.isBase64Encoded=="boolean"&&typeof a.subFolder=="string"&&r.push(a)});return r}function B(e,r,t={}){let{parseValues:n=!0,rhino:a,stringOnly:o=!1}=t,s;if("byName"in r?s=e.values.find(u=>u.ParamName===r.byName):s=e.values.find(u=>{let p=!1;return w(u.InnerTree,c=>{c.id===r.byId&&(p=!0)}),p}),!s)return;let i=[];if(w(s.InnerTree,u=>{if("byId"in r&&u.id!==r.byId||o&&u.type!==D.STRING)return;let p=Z(u.data,u.type,n,a);i.push(p)}),i.length!==0)return i.length===1?i[0]:i}var I=class{constructor(r,t=!1){this.response=r;this.debug=t}getValues(r=!1,t={}){return H(this.response,r,t)}getValueByParamName(r,t){return B(this.response,{byName:r},t)}getValueByParamId(r,t){return B(this.response,{byId:r},t)}async extractMeshesFromResponse(r){let t={debug:this.debug,...r};try{let{getThreeMeshesFromComputeResponse:n}=await import("./visualization.js");return n(this.response,t)}catch(n){let{RhinoComputeError:a,ErrorCodes:o}=(V(),ae(se));throw new a("Failed to load three.js visualization module. Ensure three.js is installed as a peer dependency.",o.INVALID_STATE,{context:{originalError:n instanceof Error?n.message:String(n)}})}}getFileData(){return _(this.response)}getAndDownloadFiles(r,t){let n=this.getFileData();S(n,r,t)}};E();function A(e,r){r||typeof window<"u"&&f().warn(`Warning: ${e} is running on the client side. For better performance and security, consider running this on the server side.`)}async function C(e,r,t){t.debug&&A("solveGrasshopperDefinition",t.suppressClientSideWarning);let n=M(r,e);he(n,t);let a=await F("grasshopper",n,t);return"pointer"in a&&delete a.pointer,a}function M(e,r){let t={algo:null,pointer:null,values:r};return e instanceof Uint8Array?t.algo=q(e):e.startsWith("http")?t.pointer=e:z(e)?t.algo=e:t.algo=$(e),t}function he(e,r){r.cachesolve!==null&&(e.cachesolve=r.cachesolve),r.modelunits!==null&&(e.modelunits=r.modelunits),r.angletolerance!==null&&(e.angletolerance=r.angletolerance),r.absolutetolerance!==null&&(e.absolutetolerance=r.absolutetolerance),r.dataversion!==null&&(e.dataversion=r.dataversion)}V();function Q(e){if(typeof e.default!="object"||e.default===null)return;if(!("innerTree"in e.default)){f().warn("Unexpected structure in input.default:",e.default),e.default=null;return}let r=e.default.innerTree;if(Object.keys(r).length===0){e.default=void 0;return}if(e.treeAccess||e.atMost&&e.atMost>1){let n={};for(let[a,o]of Object.entries(r))n[a]=o.map(s=>{if(typeof s.data=="string"){if(s.type==="System.Double"||s.type==="System.Int32"){let i=Number(s.data);return Number.isNaN(i)?s.data:i}if(s.type==="System.Boolean")return s.data.toLowerCase()==="true";if(s.type.startsWith("Rhino.Geometry")||s.type==="System.String")try{return JSON.parse(s.data)}catch{return s.data}}return s.data});e.default=n;return}let t=[];for(let n of Object.values(r))Array.isArray(n)&&n.forEach(a=>{a&&typeof a=="object"&&"data"in a&&t.push(a.data)});t.length===0?e.default=void 0:t.length===1?e.default=t[0]:e.default=t}V();function R(e,r){let{transform:t,setUndefinedOnEmpty:n=!0}=r;if(!(e.default===void 0||e.default===null))if(Array.isArray(e.default)){let a=e.default.map(t).filter(o=>o!==null);e.default=a.length>0?a:void 0}else{let a=t(e.default);a!==null?e.default=a:n&&(e.default=void 0)}}function ge(){return e=>{if(typeof e=="number")return e;if(typeof e=="string"){let r=Number(e.trim());return Number.isNaN(r)?null:r}return null}}function Te(){return e=>{if(typeof e=="boolean")return e;if(typeof e=="string"){let r=e.toLowerCase();if(r==="true")return!0;if(r==="false")return!1;throw new Error(`Invalid boolean string: "${e}"`)}return null}}function be(){return e=>typeof e=="string"?e.startsWith('"')&&e.endsWith('"')||e.startsWith('"')?e.slice(1,-1):e:null}function De(){return e=>{if(typeof e=="string"){let r=e.trim();return r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1).trim()),r}return null}}function Ie(e){R(e,{transform:De(),setUndefinedOnEmpty:!1})}function xe(e="unknown"){return r=>{if(typeof r=="object"&&r!==null)return r;if(typeof r=="string"&&r.trim()!=="")try{let t=JSON.parse(r);return typeof t=="object"&&t!==null?t:(f().warn(`Parsed value for input ${e} is not an object`),null)}catch(t){return f().warn(`Failed to parse object value "${r}" for input ${e}`,t),null}return null}}function ee(e,r,t){let n=Number(e.toFixed(r));return Math.abs(e-n)<t?n:e}function Ce(e,r=1e-8){if(!Number.isFinite(e)||e===0)return .1;let t=Math.abs(e);if(t>=1){let y=String(e).split(".")[1];if(y&&y.length>0){let h=Math.min(y.length,12),g=Math.pow(10,-h),U=Number(g.toFixed(h));return Math.abs(U-g)<r?U:g}return 1}let n=String(e),a=n.toLowerCase().match(/e(-?\d+)/);if(a){let G=Number(a[1]);if(G<0||n.toLowerCase().includes("e-")){let y=Math.abs(G),h=Math.pow(10,-y),g=Number(h.toFixed(y));return Math.abs(g-h)<r?g:h}return .1}let o=12,i=t.toFixed(o).replace(/0+$/,""),u=Math.min((i.split(".")[1]||"").length,o);if(u===0)return .1;let p=Math.pow(10,-u),c=Number(p.toFixed(u));return Math.abs(c-p)<r?c:p}function re(e,r=1e-8){let t=e.paramType==="Integer";if(R(e,{transform:ge()}),t){Array.isArray(e.default)?e.default=e.default.map(o=>typeof o=="number"?Math.round(o):o):typeof e.default=="number"&&(e.default=Math.round(e.default)),e.stepSize=1;return}let n=Array.isArray(e.default)?e.default[0]:e.default,a;if(typeof n=="number"&&Number.isFinite(n)&&n!==0?a=n:typeof e.minimum=="number"&&Number.isFinite(e.minimum)&&e.minimum!==0?a=e.minimum:typeof e.maximum=="number"&&Number.isFinite(e.maximum)&&e.maximum!==0&&(a=e.maximum),a!==void 0?e.stepSize=Ce(a,r):e.stepSize=.1,typeof e.stepSize=="number"){let o=0,s=String(e.stepSize),i=s.toLowerCase().match(/e(-?\d+)/);if(i?o=Math.abs(Number(i[1])):o=s.split(".")[1]?.length??0,o===0&&typeof n=="number"&&n!==0&&Math.abs(n)<1){let u=Math.ceil(-Math.log10(Math.abs(n)));Number.isFinite(u)&&u>0&&(o=u)}o=Math.min(Math.max(o,0),12),Array.isArray(e.default)?e.default=e.default.map(u=>typeof u=="number"?ee(u,o,r):u):typeof e.default=="number"&&(e.default=ee(e.default,o,r))}}function Pe(e){try{R(e,{transform:Te(),setUndefinedOnEmpty:!1})}catch(r){throw r instanceof Error?new l(r.message):r}}function Se(e){R(e,{transform:be(),setUndefinedOnEmpty:!1})}function te(e){R(e,{transform:xe(e.nickname||"unnamed"),setUndefinedOnEmpty:!0})}function Re(e){if(!e.values||typeof e.values!="object"||Object.keys(e.values).length===0)throw l.missingValues(e.nickname||"unnamed","ValueList");if(e.default!==void 0&&e.default!==null){let r=String(e.default).toLowerCase();Object.keys(e.values).some(n=>n.toLowerCase()===r)||f().warn(`ValueList input "${e.nickname||"unnamed"}" default value "${e.default}" is not in available values`)}}var ne={Number:re,Integer:re,Boolean:Pe,Text:Se,ValueList:Re,Geometry:te,File:te,Color:Ie};E();function Ne(e,r){switch(e.paramType){case"Number":case"Integer":return{...r,paramType:e.paramType,minimum:e.minimum,maximum:e.maximum,atLeast:e.atLeast,atMost:e.atMost,default:e.atMost>1?[0]:0};case"Boolean":return{...r,paramType:"Boolean",default:e.atMost>1?[!1]:!1};case"Text":return{...r,paramType:"Text",default:e.atMost>1?[""]:""};case"ValueList":return{...r,paramType:"ValueList",values:e.values??{},default:e.atMost>1?[e.default]:e.default};case"File":return{...r,paramType:"File",default:e.atMost>1?[null]:null};case"Color":return{...r,paramType:"Color",default:e.atMost>1?["0, 0, 0"]:"0, 0, 0"};default:return{...r,paramType:"Geometry",default:e.atMost>1?[null]:null}}}function N(e){let r={description:e.description,name:e.name,nickname:e.nickname,treeAccess:e.treeAccess,groupName:e.groupName??"",id:e.id};try{Q(e);let t=ne[e.paramType];if(!t)throw l.unknownParamType(e.paramType,e.name);switch(t(e),e.paramType){case"Number":case"Integer":return{...r,paramType:e.paramType,minimum:e.minimum,maximum:e.maximum,atLeast:e.atLeast,atMost:e.atMost,stepSize:e.stepSize,default:e.default};case"Boolean":return{...r,paramType:"Boolean",default:e.default};case"Text":return{...r,paramType:"Text",default:e.default};case"ValueList":return{...r,paramType:"ValueList",values:e.values,default:e.default};case"Geometry":return{...r,paramType:e.paramType,default:e.default};case"File":return{...r,paramType:e.paramType,acceptedFormats:e.acceptedFormats,default:e.default};case"Color":return{...r,paramType:"Color",default:e.default};default:throw l.unknownParamType(e.paramType,e.name)}}catch(t){if(t instanceof l)return f().error(`Validation error for input ${e.name||"unknown"}:`,t.message),Ne(e,r);throw new l(t instanceof Error?t.message:String(t),"VALIDATION_ERROR",{context:{paramName:e.name,paramType:e.paramType},originalError:t instanceof Error?t:new Error(String(t))})}}function x(e){return e.map(r=>N(r))}async function b(e,r){let t=M(e,[]),n={};t.algo&&(n.algo=t.algo),t.pointer&&(n.pointer=t.pointer);let a=await F("io",n,r);if(!a||typeof a!="object")throw new l("Invalid IO response structure",m.INVALID_INPUT,{context:{response:a,definition:e}});let o=j(a,{deep:!0});return{inputs:o.inputs,outputs:o.outputs}}async function P(e,r){A("fetchParsedDefinitionIO",r.suppressClientSideWarning);let{inputs:t,outputs:n}=await b(e,r);return{inputs:x(t),outputs:n}}var O=class e{constructor(r){d(this,"innerTree");d(this,"paramName");this.paramName=r,this.innerTree={}}append(r,t){let n=e.formatPathString(r);this.innerTree[n]||(this.innerTree[n]=[]);let a=t.map(o=>({data:e.serializeValue(o)}));return this.innerTree[n].push(...a),this}appendSingle(r,t){return this.append(r,[t])}fromDataTreeDefault(r){this.innerTree={};for(let[t,n]of Object.entries(r)){if(!Array.isArray(n))continue;let a=e.parsePathString(t);this.append(a,n)}return this}appendFlat(r){let t=Array.isArray(r)?r:[r];return this.append([0],t)}flatten(){let r=[];for(let t of Object.values(this.innerTree))if(Array.isArray(t))for(let n of t)r.push(e.deserializeValue(n.data));return r}getPaths(){return Object.keys(this.innerTree)}getPath(r){let t=e.formatPathString(r),n=this.innerTree[t];if(n)return n.map(a=>e.deserializeValue(a.data))}toComputeFormat(){return{ParamName:this.paramName,InnerTree:this.innerTree}}getInnerTree(){return this.innerTree}getParamName(){return this.paramName}static fromInputParams(r){return r.filter(t=>e.hasValidValue(t.default)).map(t=>{let n=new e(t.nickname||"unnamed"),a=t.default;if(t.treeAccess&&e.isDataTreeStructure(a))n.fromDataTreeDefault(a),e.isNumericInput(t)&&n.applyNumericConstraints(t.minimum,t.maximum,t.nickname||"unnamed");else{let o=Array.isArray(a)?a:[a],s=e.processValues(o,t);n.appendFlat(s)}return n.toComputeFormat()})}static fromInputParam(r){return e.hasValidValue(r.default)?e.fromInputParams([r])[0]:void 0}static replaceTreeValue(r,t,n){if(r.length>0&&r[0]instanceof e){let o=r,s=o.findIndex(u=>u.getParamName()===t),i=new e(t);return typeof n=="object"&&n!==null&&!Array.isArray(n)&&e.isDataTreeStructure(n)?i.fromDataTreeDefault(n):(Array.isArray(n),i.appendFlat(n)),s!==-1?o[s]=i:o.push(i),o}else{let o=r,s=o.findIndex(p=>p.ParamName===t),i=new e(t);typeof n=="object"&&n!==null&&!Array.isArray(n)&&e.isDataTreeStructure(n)?i.fromDataTreeDefault(n):(Array.isArray(n),i.appendFlat(n));let u=i.toComputeFormat();return s!==-1?o[s]=u:o.push(u),o}}static getTreeValue(r,t){if(r.length>0&&r[0]instanceof e){let o=r.find(i=>i.getParamName()===t);if(!o)return null;let s=o.flatten();return s.length===0?null:s.length===1?s[0]:s}else{let o=r.find(p=>p.ParamName===t);if(!o)return null;let s=o.InnerTree;if(!s)return null;let i=Object.keys(s)[0];if(!i)return null;let u=s[i];if(Array.isArray(u)){if(u.length===1){let p=u[0]?.data;return p!==void 0?e.deserializeValue(p):null}return u.map(p=>p?.data!==void 0?e.deserializeValue(p.data):null).filter(p=>p!==null)}return u?.data!==void 0?e.deserializeValue(u.data):u}}static parsePathString(r){let t=r.match(/^\{([\d;]+)\}$/);return t?t[1].split(";").map(Number):(f().warn(`Invalid TreeBuilder path format: ${r}, using [0]`),[0])}static formatPathString(r){return`{${r.join(";")}}`}applyNumericConstraints(r,t,n){for(let a of Object.values(this.innerTree))if(Array.isArray(a))for(let o of a){let s=e.deserializeValue(o.data);if(typeof s=="number"){let i=e.clampValue(s,r,t,n);o.data=e.serializeValue(i)}}}static serializeValue(r){return typeof r=="boolean"||typeof r=="number"||typeof r=="string"?r:typeof r=="object"&&r!==null?JSON.stringify(r):String(r)}static deserializeValue(r){if(typeof r=="boolean"||typeof r=="number"||typeof r!="string")return r;if(r.startsWith("{")||r.startsWith("["))try{return JSON.parse(r)}catch{return r}return isNaN(Number(r))?r==="true"?!0:r==="false"?!1:r:Number(r)}static hasValidValue(r){return r==null?!1:typeof r=="string"?!0:!(Array.isArray(r)&&r.length===0||typeof r=="object"&&!Array.isArray(r)&&Object.keys(r).length===0)}static isDataTreeStructure(r){return typeof r!="object"||r===null||Array.isArray(r)?!1:Object.entries(r).every(([t,n])=>typeof t=="string"&&/^\{[\d;]+\}$/.test(t)&&Array.isArray(n))}static isNumericInput(r){return r.paramType==="Number"||r.paramType==="Integer"}static processValues(r,t){return r.map(n=>e.isNumericInput(t)&&typeof n=="number"?e.clampValue(n,t.minimum,t.maximum,t.nickname||"unnamed"):n).filter(n=>n!=null)}static clampValue(r,t,n,a){let o=r;return t!=null&&o<t&&(f().warn(`${a}: ${r} below min ${t}, clamping`),o=t),n!=null&&o>n&&(f().warn(`${a}: ${r} above max ${n}, clamping`),o=n),o}};export{T as a,L as b,S as c,I as d,C as e,N as f,x as g,b as h,P as i,O as j};
2
+ //# sourceMappingURL=chunk-WYX224LA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../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-processors.ts","../src/features/grasshopper/io/input/input-validators.ts","../src/features/grasshopper/io/input/input-parsers.ts","../src/features/grasshopper/io/definition-io.ts","../src/features/grasshopper/data-tree/data-tree.ts"],"sourcesContent":["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 } from '@/core/types';\n\nimport { fetchDefinitionIO, fetchParsedDefinitionIO, solveGrasshopperDefinition } from '..';\nimport { GrasshopperComputeConfig, GrasshopperComputeResponse, DataTree } from '../types';\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): 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// Check server\n\t\t\tif (!(await this.serverStats.isServerOnline())) {\n\t\t\t\tthrow new RhinoComputeError(\n\t\t\t\t\t'Rhino Compute server is not online',\n\t\t\t\t\tErrorCodes.NETWORK_ERROR,\n\t\t\t\t\t{ context: { serverUrl: this.config.serverUrl } }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Run computation\n\t\t\tconst result = await solveGrasshopperDefinition(dataTree, definition, this.config);\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 * 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\nfunction extractItemValue(data: any, type: string, parseValues: boolean, rhino?: any): any {\n\tif (isExcludedType(type)) return null;\n\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 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\tparsed.data &&\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 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';\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\ttry {\n\t\t\tconst { getThreeMeshesFromComputeResponse } = await import('@/features/visualization');\n\t\t\treturn getThreeMeshesFromComputeResponse(this.response, mergedOptions);\n\t\t} catch (error) {\n\t\t\t// Import here to avoid circular dependencies at top level\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\t\tconst { RhinoComputeError, ErrorCodes } = require('@/core/errors');\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\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\tdelete (result as any).pointer;\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 (definition.startsWith('http')) {\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';\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\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: rawInput.atMost > 1 ? [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: rawInput.atMost > 1 ? [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: rawInput.atMost > 1 ? [''] : ''\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: rawInput.atMost > 1 ? [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: rawInput.atMost > 1 ? [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: rawInput.atMost > 1 ? ['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: rawInput.atMost > 1 ? [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 { 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 { 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\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\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\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":"qLAAAA,IACAC,KACAC,IA8BA,IAAqBC,EAArB,MAAqBC,CAAkB,CAK9B,YAAYC,EAAkC,CAJtDC,EAAA,KAAiB,UACjBA,EAAA,KAAgB,eAChBA,EAAA,KAAQ,WAAW,IAGlB,KAAK,OAAS,KAAK,uBAAuBD,CAAM,EAChD,KAAK,YAAc,IAAIE,EAAmB,KAAK,OAAO,UAAW,KAAK,OAAO,MAAM,CACpF,CAQA,aAAa,OAAOF,EAA8D,CACjF,IAAMG,EAAS,IAAIJ,EAAkBC,CAAM,EAG3C,GAAI,CAAE,MAAMG,EAAO,YAAY,eAAe,EAC7C,MAAM,IAAIC,EAAkB,qCAAsCC,EAAW,cAAe,CAC3F,QAAS,CAAE,UAAWF,EAAO,OAAO,SAAU,CAC/C,CAAC,EAGF,OAAOA,CACR,CAMO,WAAsC,CAC5C,YAAK,kBAAkB,EAChB,CAAE,GAAG,KAAK,MAAO,CACzB,CAKA,MAAa,MAAMG,EAAiC,CACnD,YAAK,kBAAkB,EAChBC,EAAwBD,EAAY,KAAK,MAAM,CACvD,CAEA,MAAa,SAASA,EAAiC,CACtD,YAAK,kBAAkB,EAChBE,EAAkBF,EAAY,KAAK,MAAM,CACjD,CASA,MAAa,MACZA,EACAG,EACsC,CACtC,KAAK,kBAAkB,EAEvB,GAAI,CAEH,GAAI,OAAOH,GAAe,UAAY,CAACA,GAAY,KAAK,EACvD,MAAM,IAAIF,EACT,qCACAC,EAAW,cACX,CACC,QAAS,CAAE,YAAaC,CAAW,CACpC,CACD,EACM,GAAIA,aAAsB,YAAcA,EAAW,SAAW,EACpE,MAAM,IAAIF,EAAkB,8BAA+BC,EAAW,aAAa,EAIpF,GAAI,CAAE,MAAM,KAAK,YAAY,eAAe,EAC3C,MAAM,IAAID,EACT,qCACAC,EAAW,cACX,CAAE,QAAS,CAAE,UAAW,KAAK,OAAO,SAAU,CAAE,CACjD,EAID,IAAMK,EAAS,MAAMC,EAA2BF,EAAUH,EAAY,KAAK,MAAM,EAGjF,GAAII,GAAU,OAAOA,GAAW,UAAY,YAAaA,GAAU,EAAE,aAAcA,GAClF,MAAM,IAAIN,EACRM,EAA+B,SAAW,qBAC3CL,EAAW,kBACX,CACC,QAAS,CACR,WACC,OAAOC,GAAe,UAAYA,EAAW,OAAS,IACnDA,EACA,gBACJ,OAAQG,CACT,CACD,CACD,EAGD,OAAOC,CACR,OAASE,EAAO,CAKf,MAJI,KAAK,OAAO,OACfC,EAAU,EAAE,MAAM,kBAAmBD,CAAK,EAGvCA,aAAiBR,EACdQ,EAGD,IAAIR,EACTQ,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACrDP,EAAW,kBACX,CACC,QAAS,CACR,WACC,OAAOC,GAAe,UAAYA,EAAW,OAAS,IACnDA,EACA,gBACJ,OAAQG,CACT,EACA,cAAeG,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,CACxE,CACD,CACD,CACD,CAMA,MAAa,SAAyB,CACjC,KAAK,WAET,KAAK,SAAW,GAGZ,YAAa,KAAK,aAAe,OAAO,KAAK,YAAY,SAAY,YACxE,MAAM,KAAK,YAAY,QAAQ,EAIjC,CAKQ,mBAA0B,CACjC,GAAI,KAAK,SACR,MAAM,IAAIR,EACT,yDACAC,EAAW,aACZ,CAEF,CAOQ,uBAA2EL,EAAc,CAChG,GAAI,CAACA,EAAO,WAAW,KAAK,EAC3B,MAAM,IAAII,EAAkB,wBAAyBC,EAAW,eAAgB,CAC/E,QAAS,CAAE,kBAAmBL,EAAO,SAAU,CAChD,CAAC,EAIF,GAAI,CACH,IAAI,IAAIA,EAAO,SAAS,CACzB,MAAQ,CACP,MAAM,IAAII,EAAkB,gCAAiCC,EAAW,eAAgB,CACvF,QAAS,CAAE,kBAAmBL,EAAO,SAAU,CAChD,CAAC,CACF,CAGA,GAAIA,EAAO,YAAc,IAAMA,EAAO,YAAc,+BACnD,MAAM,IAAII,EACT,gGACAC,EAAW,eACX,CAAE,QAAS,CAAE,kBAAmBL,EAAO,SAAU,CAAE,CACpD,EAGD,MAAO,CACN,GAAGA,EACH,UAAWA,EAAO,UAAU,QAAQ,OAAQ,EAAE,EAC9C,OAAQA,EAAO,OACf,UAAWA,EAAO,UAClB,MAAOA,EAAO,OAAS,GACvB,0BAA2BA,EAAO,yBACnC,CACD,CACD,ECtNO,IAAMc,EAAkC,MAC9CC,EACAC,EAAwD,OAC1B,CAC9B,GAAI,CACH,OAAO,MAAMC,EAAaF,EAAmBC,CAAe,CAC7D,OAASE,EAAK,CACb,MAAM,IAAIC,EACT,gDACAC,EAAW,cACX,CACC,QAAS,CAAE,cAAeF,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAE,EAC3E,cAAeA,aAAe,MAAQA,EAAM,MAC7C,CACD,CACD,CACD,EAeaG,EAAmB,MAC/BN,EACAO,EACAN,EAAwD,OACrC,CAEnB,GAAI,OAAO,SAAa,KAAe,OAAO,KAAS,IACtD,MAAM,IAAIG,EACT,8HACAC,EAAW,aACX,CACC,QAAS,CACR,YAAa,OAAO,OAAW,IAAc,gBAAkB,UAC/D,kBAAmB,OAAO,SAAa,IACvC,cAAe,OAAO,KAAS,GAChC,CACD,CACD,EAGD,GAAI,CACH,IAAMG,EAAiB,MAAMN,EAAaF,EAAmBC,CAAe,EAC5E,MAAMQ,GAAqBD,EAAgBD,CAAc,CAC1D,OAASJ,EAAK,CAEb,MAAIA,aAAeC,EACZD,EAED,IAAIC,EACT,iDACAC,EAAW,cACX,CACC,QAAS,CAAE,cAAeF,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAE,EAC3E,cAAeA,aAAe,MAAQA,EAAM,MAC7C,CACD,CACD,CACD,EAUMD,EAAe,MACpBQ,EACAT,IAC8B,CAC9B,IAAMO,EAAkC,CAAC,EA0BzC,GAvBAE,EAAU,QAASC,GAAS,CAC3B,IAAIC,EAAW,GAAGD,EAAK,QAAQ,GAAGA,EAAK,QAAQ,GAM/C,GAJIA,EAAK,WAAaA,EAAK,UAAU,KAAK,IAAM,KAC/CC,EAAW,GAAGD,EAAK,SAAS,IAAIC,CAAQ,IAGrCD,EAAK,kBAAoB,IAAQA,EAAK,KAAM,CAC/C,IAAME,EAAQC,EAAqBH,EAAK,IAAI,EAC5CH,EAAe,KAAK,CACnB,SAAU,GAAGG,EAAK,QAAQ,GAAGA,EAAK,QAAQ,GAC1C,QAAS,IAAI,WAAWE,EAAM,MAAM,EACpC,KAAMD,CACP,CAAC,CACF,MAAWD,EAAK,kBAAoB,IAASA,EAAK,MACjDH,EAAe,KAAK,CACnB,SAAU,GAAGG,EAAK,QAAQ,GAAGA,EAAK,QAAQ,GAC1C,QAASA,EAAK,KACd,KAAMC,CACP,CAAC,CAEH,CAAC,EAEGX,EAAiB,CACpB,IAAMc,EAAa,MAAM,QAAQd,CAAe,EAAIA,EAAkB,CAACA,CAAe,EAChFe,EAAsB,MAAM,QAAQ,IACzCD,EAAW,IAAI,MAAOE,GAAS,CAC9B,GAAI,CACH,IAAMC,EAAW,MAAM,MAAMD,EAAK,QAAQ,EAC1C,GAAI,CAACC,EAAS,GACb,OAAAC,EAAU,EAAE,KAAK,6CAA6CF,EAAK,QAAQ,EAAE,EACtE,KAGR,IAAMG,EAAc,MADH,MAAMF,EAAS,KAAK,GACF,YAAY,EAC/C,MAAO,CACN,SAAUD,EAAK,SACf,QAAS,IAAI,WAAWG,CAAW,EACnC,KAAMH,EAAK,QACZ,CACD,OAASI,EAAO,CACf,OAAAF,EAAU,EAAE,MAAM,4CAA4CF,EAAK,QAAQ,GAAII,CAAK,EAC7E,IACR,CACD,CAAC,CACF,EAEAb,EAAe,KAAK,GAAGQ,EAAoB,OAAQM,GAA0BA,IAAM,IAAI,CAAC,CACzF,CAEA,OAAOd,CACR,EASA,eAAeC,GAAqBc,EAAwBC,EAAgC,CAC3F,GAAM,CAAE,QAAAC,EAAS,QAAAC,CAAQ,EAAI,KAAM,QAAO,QAAQ,EAG5CC,EAAsC,CAAC,EAC7CJ,EAAM,QAASN,GAAS,CACvBU,EAAQV,EAAK,IAAI,EAAI,OAAOA,EAAK,SAAY,SAAWS,EAAQT,EAAK,OAAO,EAAIA,EAAK,OACtF,CAAC,EAED,IAAMW,EAASH,EAAQE,EAAS,CAAE,MAAO,CAAE,CAAC,EAEtCE,EAAO,IAAI,KAAK,CAACD,CAAkB,EAAG,CAAE,KAAM,iBAAkB,CAAC,EACvEE,GAASD,EAAM,GAAGL,CAAO,MAAM,CAChC,CASA,SAASM,GAASD,EAAYE,EAAkB,CAC/C,GAAI,OAAO,SAAa,IACvB,MAAM,IAAI3B,EACT,+DACAC,EAAW,aACX,CACC,QAAS,CAAE,SAAU,WAAY,YAAa,UAAW,CAC1D,CACD,EAGD,IAAM2B,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAO,IAAI,gBAAgBH,CAAI,EACjCG,EAAE,SAAWD,EACbC,EAAE,MAAM,EACR,IAAI,gBAAgBA,EAAE,IAAI,CAC3B,CClMA,IAAMC,EAAkB,IAAI,IAMrB,SAASC,EAAgBC,EAAkBC,EAA6B,CAC9EH,EAAgB,IAAIE,EAAUC,CAAO,CACtC,CAEAF,EAAgB,yBAA0B,CAACG,EAAOC,IAAS,CAC1D,IAAMC,EAAID,EACV,MAAI,CAACC,GAAK,OAAOA,EAAE,GAAM,SAAiB,KACnC,IAAIF,EAAM,MAAM,CAACE,EAAE,EAAGA,EAAE,EAAGA,EAAE,CAAC,CAAC,CACvC,CAAC,EAEDL,EAAgB,sBAAuB,CAACG,EAAOC,IAAS,CACvD,IAAMC,EAAID,EACV,MAAI,CAACC,GAAK,CAACA,EAAE,MAAQ,CAACA,EAAE,GAAW,KAC5B,IAAIF,EAAM,KAAK,CAACE,EAAE,KAAK,EAAGA,EAAE,KAAK,EAAGA,EAAE,KAAK,CAAC,EAAG,CAACA,EAAE,GAAG,EAAGA,EAAE,GAAG,EAAGA,EAAE,GAAG,CAAC,CAAC,CAC/E,CAAC,EAMD,SAASC,GAAYC,EAA6C,CACjE,GAAIR,EAAgB,IAAIQ,CAAS,EAAG,OAAOR,EAAgB,IAAIQ,CAAS,EACxE,OAAW,CAACC,EAAKC,CAAG,IAAKV,EACxB,GAAIQ,EAAU,WAAWC,CAAG,EAAG,OAAOC,CAGxC,CAEA,SAASC,GAAeC,EAAsB,CAC7C,MAAI,CAACA,GAAc,OAAOA,GAAe,SAAiB,KAClDA,EAAmB,MAASA,EAAmB,OAAS,IACjE,CAMO,SAASC,EACfD,EACAJ,EACAJ,EACU,CACV,IAAMD,EAAUI,GAAYC,CAAS,EACrC,GAAIL,EACH,GAAI,CACH,OAAOA,EAAQC,EAAOQ,CAAU,CACjC,OAASE,EAAO,CACfC,EAAU,EAAE,KAAK,+BAA+BP,CAAS,IAAKM,CAAK,CACpE,CAID,GAAI,CACH,IAAME,EAAUL,GAAeC,CAAU,EACzC,GAAII,EAAS,OAAOZ,EAAM,aAAa,OAAOY,CAAO,CACtD,OAASF,EAAO,CACf,OAAAC,EAAU,EAAE,KAAK,oBAAoBP,CAAS,sBAAuBM,CAAK,EACnE,CAAE,cAAe,GAAM,KAAMN,EAAW,IAAKI,CAAW,CAChE,CAEA,OAAOA,CACR,CClDA,IAAMK,EAAe,CACpB,OAAQ,gBACR,IAAK,eACL,OAAQ,gBACR,KAAM,gBACP,EAEMC,GAAwB,kBAGxBC,GAAiB,CAAC,YAAY,EAC9BC,GAAiB,WAavB,SAASC,GAAeC,EAAuB,CAC9C,OAAOH,GAAe,KAAMI,GAAMD,EAAK,SAASC,CAAC,CAAC,CACnD,CAEA,SAASC,EAAcC,EAAoB,CAC1C,GAAI,OAAOA,GAAU,SAAU,OAAOA,EAEtC,IAAMC,EAAUD,EAAM,KAAK,EAE3B,GAAI,EADcC,EAAQ,WAAW,GAAG,GAAKA,EAAQ,WAAW,GAAG,GAAKA,EAAQ,WAAW,GAAG,GAC9E,OAAOD,EAEvB,GAAI,CACH,IAAME,EAAQ,KAAK,MAAMD,CAAO,EAChC,GAAI,OAAOC,GAAU,SACpB,GAAI,CACH,OAAO,KAAK,MAAMA,CAAK,CACxB,MAAQ,CACP,OAAOA,CACR,CAED,OAAOA,CACR,MAAQ,CACP,OAAOF,CACR,CACD,CAEA,SAASG,GAAmBC,EAAUP,EAAcQ,EAAkB,CACrE,OAAQR,EAAM,CACb,KAAKL,EAAa,OACjB,OAAI,OAAOY,GAAQ,SAAiBA,EAC7BA,EAAI,QAAQ,WAAY,IAAI,EAEpC,KAAKZ,EAAa,IACjB,OAAO,OAAO,SAASY,EAAK,EAAE,EAE/B,KAAKZ,EAAa,OACjB,OAAO,OAAO,WAAWY,CAAG,EAE7B,KAAKZ,EAAa,KAEjB,OADY,OAAOY,CAAG,EAAE,YAAY,IACrB,OAGhB,QACC,OAAIC,GAASR,EAAK,WAAWJ,EAAqB,EAC1Ca,EAAoBF,EAAKP,EAAMQ,CAAK,EAErCD,CACT,CACD,CAGA,SAASG,EAAiBC,EAAWX,EAAcY,EAAsBJ,EAAkB,CAC1F,GAAIT,GAAeC,CAAI,EAAG,OAAO,KAEjC,GAAI,OAAOW,GAAS,SAAU,OAAOA,EAErC,IAAMJ,EAAMK,EAAcV,EAAcS,CAAI,EAAIA,EAChD,OAAOL,GAAmBC,EAAKP,EAAMQ,CAAK,CAC3C,CASA,SAASK,EACRC,EACAC,EACC,CACD,QAAWC,KAAQ,OAAO,OAAOF,CAAI,EACpC,GAAI,MAAM,QAAQE,CAAI,EACrB,QAAWC,KAAQD,EAAMD,EAAQE,CAAI,CAGxC,CAsBO,SAASC,EACfC,EACAC,EAAgB,GAChBC,EAA4B,CAAC,EACR,CACrB,GAAM,CAAE,YAAAT,EAAc,GAAM,MAAAJ,EAAO,WAAAc,EAAa,EAAM,EAAID,EACpDE,EAAwB,CAAC,EAE/B,QAAWC,KAASL,EAAS,OAC5BN,EAAgBW,EAAM,UAAYP,GAAS,CAE1C,GAAIK,GAAcL,EAAK,OAAStB,EAAa,OAAQ,OAErD,IAAM8B,EAAML,EAAOH,EAAK,GAAKO,EAAM,UACnC,GAAI,CAACC,EAAK,OAEV,IAAMtB,EAAQO,EAAiBO,EAAK,KAAMA,EAAK,KAAML,EAAaJ,CAAK,EAEnEe,EAAOE,CAAG,IAAM,OACnBF,EAAOE,CAAG,EAAItB,EACJ,MAAM,QAAQoB,EAAOE,CAAG,CAAC,EACnCF,EAAOE,CAAG,EAAE,KAAKtB,CAAK,EAEtBoB,EAAOE,CAAG,EAAI,CAACF,EAAOE,CAAG,EAAGtB,CAAK,CAEnC,CAAC,EAGF,MAAO,CAAE,OAAQoB,CAAY,CAC9B,CAYO,SAASG,EAAgBP,EAAkD,CACjF,IAAMQ,EAAqB,CAAC,EAE5B,QAAWH,KAASL,EAAS,OAC5BN,EAAgBW,EAAM,UAAYP,GAAS,CAC1C,GAAI,CAACA,EAAK,KAAK,SAASnB,EAAc,EAAG,OAEzC,IAAM8B,EAAS1B,EAAce,EAAK,IAAI,EAErCW,GACAA,EAAO,UACPA,EAAO,UACPA,EAAO,MACP,OAAOA,EAAO,iBAAoB,WAClC,OAAOA,EAAO,WAAc,UAE5BD,EAAO,KAAKC,CAAkB,CAEhC,CAAC,EAGF,OAAOD,CACR,CAqBO,SAASE,EACfV,EACAE,EACAS,EAAiC,CAAC,EAC5B,CACN,GAAM,CAAE,YAAAlB,EAAc,GAAM,MAAAJ,EAAO,WAAAc,EAAa,EAAM,EAAIQ,EAEtDC,EAcJ,GAZI,WAAYV,EACfU,EAAcZ,EAAS,OAAO,KAAMa,GAAMA,EAAE,YAAcX,EAAQ,MAAM,EAExEU,EAAcZ,EAAS,OAAO,KAAMa,GAAM,CACzC,IAAIC,EAAQ,GACZ,OAAApB,EAAgBmB,EAAE,UAAYf,GAAS,CAClCA,EAAK,KAAOI,EAAQ,OAAMY,EAAQ,GACvC,CAAC,EACMA,CACR,CAAC,EAGE,CAACF,EAAa,OAElB,IAAMG,EAAmB,CAAC,EAU1B,GARArB,EAAgBkB,EAAY,UAAYd,GAAS,CAGhD,GAFI,SAAUI,GAAWJ,EAAK,KAAOI,EAAQ,MAEzCC,GAAcL,EAAK,OAAStB,EAAa,OAAQ,OACrD,IAAMwC,EAAIzB,EAAiBO,EAAK,KAAMA,EAAK,KAAML,EAAaJ,CAAK,EACnE0B,EAAU,KAAKC,CAAC,CACjB,CAAC,EAEGD,EAAU,SAAW,EACzB,OAAIA,EAAU,SAAW,EAAUA,EAAU,CAAC,EACvCA,CACR,CCvPA,IAAqBE,EAArB,KAAkD,CAIjD,YACkBC,EACAC,EAAiB,GACjC,CAFgB,cAAAD,EACA,WAAAC,CACf,CAuBI,UACNC,EAAgB,GAChBC,EAA4B,CAAC,EACR,CACrB,OAAOC,EAAa,KAAK,SAAUF,EAAMC,CAAO,CACjD,CAcO,oBAAoBE,EAAmBF,EAAiC,CAC9E,OAAOG,EAAS,KAAK,SAAU,CAAE,OAAQD,CAAU,EAAGF,CAAO,CAC9D,CAcO,kBAAkBI,EAAiBJ,EAAiC,CAC1E,OAAOG,EAAS,KAAK,SAAU,CAAE,KAAMC,CAAQ,EAAGJ,CAAO,CAC1D,CAqCA,MAAa,0BAA0BA,EAAiC,CACvE,IAAMK,EAAuC,CAC5C,MAAO,KAAK,MACZ,GAAGL,CACJ,EAGA,GAAI,CACH,GAAM,CAAE,kCAAAM,CAAkC,EAAI,KAAM,QAAO,oBAA0B,EACrF,OAAOA,EAAkC,KAAK,SAAUD,CAAa,CACtE,OAASE,EAAO,CAGf,GAAM,CAAE,kBAAAC,EAAmB,WAAAC,CAAW,EAAI,aAC1C,MAAM,IAAID,EACT,mGACAC,EAAW,cACX,CACC,QAAS,CAAE,cAAeF,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAE,CAClF,CACD,CACD,CACD,CAWQ,aAA0B,CACjC,OAAOG,EAAgB,KAAK,QAAQ,CACrC,CAsBO,oBACNC,EACAC,EACC,CACD,IAAMC,EAAQ,KAAK,YAAY,EAC/BC,EAAiBD,EAAOF,EAAYC,CAAe,CACpD,CACD,EC9LAG,IAEO,SAASC,EAAiBC,EAAsBC,EAA0B,CAC5EA,GAIA,OAAO,OAAW,KACrBC,EAAU,EAAE,KACX,YAAYF,CAAY,gHACzB,CAEF,CCwBA,eAAsBG,EACrBC,EACAC,EACAC,EACsC,CAClCA,EAAO,OACVC,EAAiB,6BAA8BD,EAAO,yBAAyB,EAGhF,IAAME,EAAOC,EAAuBJ,EAAYD,CAAQ,EACxDM,GAA6BF,EAAMF,CAAM,EAEzC,IAAMK,EAAS,MAAMC,EAAkB,cAAeJ,EAAMF,CAAM,EAElE,MAAI,YAAaK,GAChB,OAAQA,EAAe,QAGjBA,CACR,CAcO,SAASF,EACfJ,EACAD,EAC2B,CAC3B,IAAMI,EAAiC,CACtC,KAAM,KACN,QAAS,KACT,OAAQJ,CACT,EAEA,OAAIC,aAAsB,WAEzBG,EAAK,KAAOK,EAAgBR,CAAU,EAC5BA,EAAW,WAAW,MAAM,EAEtCG,EAAK,QAAUH,EACLS,EAAST,CAAU,EAE7BG,EAAK,KAAOH,EAGZG,EAAK,KAAOO,EAAqBV,CAAU,EAGrCG,CACR,CAKO,SAASE,GACfM,EACAC,EACO,CACHA,EAAQ,aAAe,OAAMD,EAAQ,WAAaC,EAAQ,YAC1DA,EAAQ,aAAe,OAAMD,EAAQ,WAAaC,EAAQ,YAC1DA,EAAQ,iBAAmB,OAAMD,EAAQ,eAAiBC,EAAQ,gBAClEA,EAAQ,oBAAsB,OAAMD,EAAQ,kBAAoBC,EAAQ,mBACxEA,EAAQ,cAAgB,OAAMD,EAAQ,YAAcC,EAAQ,YACjE,CC5GAC,ICiOO,SAASC,EAAuBC,EAA+B,CACrE,GAAI,OAAOA,EAAM,SAAY,UAAYA,EAAM,UAAY,KAC1D,OAGD,GAAI,EAAE,cAAeA,EAAM,SAAU,CACpCC,EAAU,EAAE,KAAK,yCAA0CD,EAAM,OAAO,EACxEA,EAAM,QAAU,KAChB,MACD,CAEA,IAAME,EAAaF,EAAM,QAAgB,UAGzC,GAAI,OAAO,KAAKE,CAAS,EAAE,SAAW,EAAG,CACxCF,EAAM,QAAU,OAChB,MACD,CAGA,GAAIA,EAAM,YAAeA,EAAM,QAAUA,EAAM,OAAS,EAAI,CAE3D,IAAMG,EAA8B,CAAC,EACrC,OAAW,CAACC,EAAQC,CAAK,IAAK,OAAO,QAAQH,CAAS,EACrDC,EAAKC,CAAM,EAAKC,EAAgB,IAAKC,GAAS,CAE7C,GAAI,OAAOA,EAAK,MAAS,SAAU,CAClC,GAAIA,EAAK,OAAS,iBAAmBA,EAAK,OAAS,eAAgB,CAClE,IAAMC,EAAM,OAAOD,EAAK,IAAI,EAC5B,OAAO,OAAO,MAAMC,CAAG,EAAID,EAAK,KAAOC,CACxC,CACA,GAAID,EAAK,OAAS,iBACjB,OAAOA,EAAK,KAAK,YAAY,IAAM,OAEpC,GAAIA,EAAK,KAAK,WAAW,gBAAgB,GAAKA,EAAK,OAAS,gBAC3D,GAAI,CACH,OAAO,KAAK,MAAMA,EAAK,IAAI,CAC5B,MAAQ,CACP,OAAOA,EAAK,IACb,CAEF,CACA,OAAOA,EAAK,IACb,CAAC,EAEFN,EAAM,QAAUG,EAChB,MACD,CAGA,IAAMK,EAAmB,CAAC,EAC1B,QAAWH,KAAS,OAAO,OAAOH,CAAS,EACtC,MAAM,QAAQG,CAAK,GACtBA,EAAM,QAASC,GAAS,CACnBA,GAAQ,OAAOA,GAAS,UAAY,SAAUA,GACjDE,EAAU,KAAKF,EAAK,IAAI,CAE1B,CAAC,EAGCE,EAAU,SAAW,EACxBR,EAAM,QAAU,OACNQ,EAAU,SAAW,EAC/BR,EAAM,QAAUQ,EAAU,CAAC,EAE3BR,EAAM,QAAUQ,CAElB,CCpSAC,IA6BA,SAASC,EAAqBC,EAAyBC,EAAuC,CAC7F,GAAM,CAAE,UAAAC,EAAW,oBAAAC,EAAsB,EAAK,EAAIF,EAGlD,GAAI,EAAAD,EAAM,UAAY,QAAaA,EAAM,UAAY,MAIrD,GAAI,MAAM,QAAQA,EAAM,OAAO,EAAG,CACjC,IAAMI,EAAiBJ,EAAM,QAAQ,IAAIE,CAAS,EAAE,OAAQG,GAAcA,IAAM,IAAI,EAGpFL,EAAM,QAAUI,EAAe,OAAS,EAAIA,EAAiB,MAC9D,KAAO,CACN,IAAME,EAAcJ,EAAUF,EAAM,OAAO,EACvCM,IAAgB,KAEnBN,EAAM,QAAUM,EAGZH,IACHH,EAAM,QAAU,OAInB,CACD,CAKA,SAASO,IAAqD,CAC7D,OAAQC,GAAkC,CACzC,GAAI,OAAOA,GAAU,SACpB,OAAOA,EAER,GAAI,OAAOA,GAAU,SAAU,CAC9B,IAAMC,EAAS,OAAOD,EAAM,KAAK,CAAC,EAClC,OAAO,OAAO,MAAMC,CAAM,EAAI,KAAOA,CACtC,CACA,OAAO,IACR,CACD,CAKA,SAASC,IAAsD,CAC9D,OAAQF,GAAmC,CAC1C,GAAI,OAAOA,GAAU,UACpB,OAAOA,EAER,GAAI,OAAOA,GAAU,SAAU,CAC9B,IAAMG,EAAaH,EAAM,YAAY,EACrC,GAAIG,IAAe,OAAQ,MAAO,GAClC,GAAIA,IAAe,QAAS,MAAO,GACnC,MAAM,IAAI,MAAM,4BAA4BH,CAAK,GAAG,CACrD,CACA,OAAO,IACR,CACD,CAKA,SAASI,IAAkD,CAC1D,OAAQJ,GACH,OAAOA,GAAU,SAEhBA,EAAM,WAAW,GAAG,GAAKA,EAAM,SAAS,GAAG,GAI3CA,EAAM,WAAW,GAAG,EAChBA,EAAM,MAAM,EAAG,EAAE,EAElBA,EAED,IAET,CAKA,SAASK,IAAmD,CAC3D,OAAQL,GAAkC,CACzC,GAAI,OAAOA,GAAU,SAAU,CAE9B,IAAIM,EAAUN,EAAM,KAAK,EACzB,OAAIM,EAAQ,WAAW,GAAG,GAAKA,EAAQ,SAAS,GAAG,IAClDA,EAAUA,EAAQ,MAAM,EAAG,EAAE,EAAE,KAAK,GAG9BA,CACR,CACA,OAAO,IACR,CACD,CAKA,SAASC,GAAkBf,EAA+B,CACzDD,EAAkBC,EAAO,CACxB,UAAWa,GAAuB,EAClC,oBAAqB,EACtB,CAAC,CACF,CAKA,SAASG,GAAwBC,EAAoB,UAAqC,CACzF,OAAQT,GAAkC,CACzC,GAAI,OAAOA,GAAU,UAAYA,IAAU,KAC1C,OAAOA,EAER,GAAI,OAAOA,GAAU,UAAYA,EAAM,KAAK,IAAM,GACjD,GAAI,CACH,IAAMC,EAAS,KAAK,MAAMD,CAAK,EAC/B,OAAI,OAAOC,GAAW,UAAYA,IAAW,KACrCA,GAERS,EAAU,EAAE,KAAK,0BAA0BD,CAAS,mBAAmB,EAChE,KACR,OAASE,EAAK,CACb,OAAAD,EAAU,EAAE,KAAK,iCAAiCV,CAAK,eAAeS,CAAS,GAAIE,CAAG,EAC/E,IACR,CAED,OAAO,IACR,CACD,CAKA,SAASC,GAAcZ,EAAea,EAAuBC,EAA2B,CACvF,IAAMC,EAAU,OAAOf,EAAM,QAAQa,CAAa,CAAC,EAGnD,OAAI,KAAK,IAAIb,EAAQe,CAAO,EAAID,EACxBC,EAGDf,CACR,CAKA,SAASgB,GAAiBhB,EAAeiB,EAA4B,KAAc,CAElF,GADI,CAAC,OAAO,SAASjB,CAAK,GACtBA,IAAU,EAAG,MAAO,IAExB,IAAMkB,EAAM,KAAK,IAAIlB,CAAK,EAE1B,GAAIkB,GAAO,EAAG,CAEb,IAAMC,EADM,OAAOnB,CAAK,EACA,MAAM,GAAG,EAAE,CAAC,EACpC,GAAImB,GAAeA,EAAY,OAAS,EAAG,CAC1C,IAAMC,EAAW,KAAK,IAAID,EAAY,OAAQ,EAAE,EAC1CE,EAAO,KAAK,IAAI,GAAI,CAACD,CAAQ,EAC7BL,EAAU,OAAOM,EAAK,QAAQD,CAAQ,CAAC,EAC7C,OAAO,KAAK,IAAIL,EAAUM,CAAI,EAAIJ,EAAoBF,EAAUM,CACjE,CACA,MAAO,EACR,CAGA,IAAMC,EAAI,OAAOtB,CAAK,EAChBuB,EAAWD,EAAE,YAAY,EAAE,MAAM,UAAU,EACjD,GAAIC,EAAU,CACb,IAAMC,EAAM,OAAOD,EAAS,CAAC,CAAC,EAC9B,GAAIC,EAAM,GAAKF,EAAE,YAAY,EAAE,SAAS,IAAI,EAAG,CAC9C,IAAMG,EAAS,KAAK,IAAID,CAAG,EACrBH,EAAO,KAAK,IAAI,GAAI,CAACI,CAAM,EAC3BV,EAAU,OAAOM,EAAK,QAAQI,CAAM,CAAC,EAC3C,OAAO,KAAK,IAAIV,EAAUM,CAAI,EAAIJ,EAAoBF,EAAUM,CACjE,CACA,MAAO,GACR,CAGA,IAAMK,EAAe,GAEfC,EADQT,EAAI,QAAQQ,CAAY,EAChB,QAAQ,MAAO,EAAE,EACjCN,EAAW,KAAK,KAAKO,EAAQ,MAAM,GAAG,EAAE,CAAC,GAAK,IAAI,OAAQD,CAAY,EAE5E,GAAIN,IAAa,EAAG,MAAO,IAE3B,IAAMC,EAAO,KAAK,IAAI,GAAI,CAACD,CAAQ,EAC7BL,EAAU,OAAOM,EAAK,QAAQD,CAAQ,CAAC,EAC7C,OAAO,KAAK,IAAIL,EAAUM,CAAI,EAAIJ,EAAoBF,EAAUM,CACjE,CAKA,SAASO,GAAoBpC,EAAyByB,EAA4B,KAAY,CAC7F,IAAMY,EAAgBrC,EAAM,YAAc,UAQ1C,GALAD,EAAkBC,EAAO,CACxB,UAAWO,GAAyB,CACrC,CAAC,EAGG8B,EAAe,CACd,MAAM,QAAQrC,EAAM,OAAO,EAC9BA,EAAM,QAAUA,EAAM,QAAQ,IAAKsC,GAAS,OAAOA,GAAQ,SAAW,KAAK,MAAMA,CAAG,EAAIA,CAAI,EAClF,OAAOtC,EAAM,SAAY,WACnCA,EAAM,QAAU,KAAK,MAAMA,EAAM,OAAO,GAIzCA,EAAM,SAAW,EACjB,MACD,CAGA,IAAMuC,EAAa,MAAM,QAAQvC,EAAM,OAAO,EAAIA,EAAM,QAAQ,CAAC,EAAIA,EAAM,QAEvEwC,EAyBJ,GAvBI,OAAOD,GAAe,UAAY,OAAO,SAASA,CAAU,GAAKA,IAAe,EACnFC,EAAaD,EAEb,OAAOvC,EAAM,SAAY,UACzB,OAAO,SAASA,EAAM,OAAO,GAC7BA,EAAM,UAAY,EAElBwC,EAAaxC,EAAM,QAEnB,OAAOA,EAAM,SAAY,UACzB,OAAO,SAASA,EAAM,OAAO,GAC7BA,EAAM,UAAY,IAElBwC,EAAaxC,EAAM,SAGhBwC,IAAe,OAClBxC,EAAM,SAAWwB,GAAiBgB,EAAYf,CAAiB,EAE/DzB,EAAM,SAAW,GAId,OAAOA,EAAM,UAAa,SAAU,CACvC,IAAIqB,EAAgB,EACdoB,EAAU,OAAOzC,EAAM,QAAQ,EAE/B+B,EAAWU,EAAQ,YAAY,EAAE,MAAM,UAAU,EAQvD,GAPIV,EACHV,EAAgB,KAAK,IAAI,OAAOU,EAAS,CAAC,CAAC,CAAC,EAE5CV,EAAgBoB,EAAQ,MAAM,GAAG,EAAE,CAAC,GAAG,QAAU,EAKjDpB,IAAkB,GAClB,OAAOkB,GAAe,UACtBA,IAAe,GACf,KAAK,IAAIA,CAAU,EAAI,EACtB,CACD,IAAMG,EAAW,KAAK,KAAK,CAAC,KAAK,MAAM,KAAK,IAAIH,CAAU,CAAC,CAAC,EACxD,OAAO,SAASG,CAAQ,GAAKA,EAAW,IAC3CrB,EAAgBqB,EAElB,CAEArB,EAAgB,KAAK,IAAI,KAAK,IAAIA,EAAe,CAAC,EAAG,EAAE,EAGnD,MAAM,QAAQrB,EAAM,OAAO,EAC9BA,EAAM,QAAUA,EAAM,QAAQ,IAAKsC,GAClC,OAAOA,GAAQ,SAAWlB,GAAckB,EAAKjB,EAAeI,CAAiB,EAAIa,CAClF,EACU,OAAOtC,EAAM,SAAY,WACnCA,EAAM,QAAUoB,GAAcpB,EAAM,QAASqB,EAAeI,CAAiB,EAE/E,CACD,CAKA,SAASkB,GAAoB3C,EAA+B,CAC3D,GAAI,CACHD,EAAkBC,EAAO,CACxB,UAAWU,GAAyB,EACpC,oBAAqB,EACtB,CAAC,CACF,OAASkC,EAAO,CAEf,MAAIA,aAAiB,MACd,IAAIC,EAAkBD,EAAM,OAAO,EAEpCA,CACP,CACD,CAKA,SAASE,GAAiB9C,EAA+B,CACxDD,EAAkBC,EAAO,CACxB,UAAWY,GAAsB,EACjC,oBAAqB,EACtB,CAAC,CACF,CAKA,SAASmC,GAAc/C,EAA+B,CACrDD,EAAkBC,EAAO,CACxB,UAAWgB,GAAwBhB,EAAM,UAAY,SAAS,EAC9D,oBAAqB,EACtB,CAAC,CACF,CAMA,SAASgD,GAAsBhD,EAA+B,CAC7D,GAAI,CAACA,EAAM,QAAU,OAAOA,EAAM,QAAW,UAAY,OAAO,KAAKA,EAAM,MAAM,EAAE,SAAW,EAC7F,MAAM6C,EAAkB,cAAc7C,EAAM,UAAY,UAAW,WAAW,EAI/E,GAAIA,EAAM,UAAY,QAAaA,EAAM,UAAY,KAAM,CAE1D,IAAMiD,EAAe,OAAOjD,EAAM,OAAO,EAAE,YAAY,EACnC,OAAO,KAAKA,EAAM,MAAM,EAAE,KAAMkD,GAAQA,EAAI,YAAY,IAAMD,CAAY,GAG7F/B,EAAU,EAAE,KACX,oBAAoBlB,EAAM,UAAY,SAAS,oBAAoBA,EAAM,OAAO,8BACjF,CAEF,CACD,CAKO,IAAMmD,GAA6D,CACzE,OAAQf,GACR,QAASA,GACT,QAASO,GACT,KAAMG,GACN,UAAWE,GACX,SAAUD,GACV,KAAMA,GACN,MAAOhC,EACR,EFhYAqC,IAkBA,SAASC,GAAkBC,EAA4BC,EAAsC,CAC5F,OAAQD,EAAS,UAAW,CAC3B,IAAK,SACL,IAAK,UACJ,MAAO,CACN,GAAGC,EACH,UAAWD,EAAS,UACpB,QAASA,EAAS,QAClB,QAASA,EAAS,QAClB,QAASA,EAAS,QAClB,OAAQA,EAAS,OACjB,QAASA,EAAS,OAAS,EAAI,CAAC,CAAC,EAAI,CACtC,EACD,IAAK,UACJ,MAAO,CACN,GAAGC,EACH,UAAW,UACX,QAASD,EAAS,OAAS,EAAI,CAAC,EAAK,EAAI,EAC1C,EACD,IAAK,OACJ,MAAO,CACN,GAAGC,EACH,UAAW,OACX,QAASD,EAAS,OAAS,EAAI,CAAC,EAAE,EAAI,EACvC,EACD,IAAK,YACJ,MAAO,CACN,GAAGC,EACH,UAAW,YACX,OAAQD,EAAS,QAAU,CAAC,EAC5B,QAASA,EAAS,OAAS,EAAI,CAACA,EAAS,OAAO,EAAIA,EAAS,OAC9D,EACD,IAAK,OACJ,MAAO,CACN,GAAGC,EACH,UAAW,OACX,QAASD,EAAS,OAAS,EAAI,CAAC,IAAI,EAAI,IACzC,EACD,IAAK,QACJ,MAAO,CACN,GAAGC,EACH,UAAW,QACX,QAASD,EAAS,OAAS,EAAI,CAAC,SAAS,EAAI,SAC9C,EACD,QACC,MAAO,CACN,GAAGC,EACH,UAAW,WACX,QAASD,EAAS,OAAS,EAAI,CAAC,IAAI,EAAI,IACzC,CACF,CACD,CA4CO,SAASE,EAAaF,EAAwC,CAEpE,IAAMC,EAA2B,CAChC,YAAaD,EAAS,YACtB,KAAMA,EAAS,KACf,SAAUA,EAAS,SACnB,WAAYA,EAAS,WACrB,UAAWA,EAAS,WAAa,GACjC,GAAIA,EAAS,EACd,EAEA,GAAI,CAEHG,EAAuBH,CAAQ,EAG/B,IAAMI,EAASC,GAAQL,EAAS,SAAS,EACzC,GAAI,CAACI,EACJ,MAAME,EAAkB,iBAAiBN,EAAS,UAAWA,EAAS,IAAI,EAO3E,OAHAI,EAAOJ,CAAQ,EAGPA,EAAS,UAAW,CAC3B,IAAK,SACL,IAAK,UACJ,MAAO,CACN,GAAGC,EACH,UAAWD,EAAS,UACpB,QAASA,EAAS,QAClB,QAASA,EAAS,QAClB,QAASA,EAAS,QAClB,OAAQA,EAAS,OACjB,SAAUA,EAAS,SACnB,QAASA,EAAS,OACnB,EACD,IAAK,UACJ,MAAO,CACN,GAAGC,EACH,UAAW,UACX,QAASD,EAAS,OACnB,EACD,IAAK,OACJ,MAAO,CACN,GAAGC,EACH,UAAW,OACX,QAASD,EAAS,OACnB,EACD,IAAK,YACJ,MAAO,CACN,GAAGC,EACH,UAAW,YACX,OAAQD,EAAS,OACjB,QAASA,EAAS,OACnB,EACD,IAAK,WACJ,MAAO,CACN,GAAGC,EACH,UAAWD,EAAS,UACpB,QAASA,EAAS,OACnB,EACD,IAAK,OACJ,MAAO,CACN,GAAGC,EACH,UAAWD,EAAS,UACpB,gBAAiBA,EAAS,gBAC1B,QAASA,EAAS,OACnB,EACD,IAAK,QACJ,MAAO,CACN,GAAGC,EACH,UAAW,QACX,QAASD,EAAS,OACnB,EACD,QAEC,MAAMM,EAAkB,iBAAiBN,EAAS,UAAWA,EAAS,IAAI,CAC5E,CACD,OAASO,EAAO,CACf,GAAIA,aAAiBD,EACpB,OAAAE,EAAU,EAAE,MAAM,8BAA8BR,EAAS,MAAQ,SAAS,IAAKO,EAAM,OAAO,EAErFR,GAAkBC,EAAUC,CAAS,EAG5C,MAAM,IAAIK,EACTC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACrD,mBACA,CACC,QAAS,CAAE,UAAWP,EAAS,KAAM,UAAWA,EAAS,SAAU,EACnE,cAAeO,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,CACxE,CACD,CAEF,CACD,CA2CO,SAASE,EAAcC,EAA6C,CAC1E,OAAOA,EAAU,IAAKV,GAAaE,EAAaF,CAAQ,CAAC,CAC1D,CGzOA,eAAsBW,EACrBC,EACAC,EACkC,CAClC,IAAMC,EAAOC,EAAuBH,EAAY,CAAC,CAAC,EAC5CI,EAA6D,CAAC,EAChEF,EAAK,OAAME,EAAQ,KAAOF,EAAK,MAC/BA,EAAK,UAASE,EAAQ,QAAUF,EAAK,SAEzC,IAAMG,EAAW,MAAMC,EAAwB,KAAMF,EAASH,CAAM,EAEpE,GAAI,CAACI,GAAY,OAAOA,GAAa,SACpC,MAAM,IAAIE,EAAkB,gCAAiCC,EAAW,cAAe,CACtF,QAAS,CAAE,SAAAH,EAAU,WAAAL,CAAW,CACjC,CAAC,EAIF,IAAMS,EAAaC,EAAcL,EAAU,CAAE,KAAM,EAAK,CAAC,EAEzD,MAAO,CACN,OAAQI,EAAW,OACnB,QAASA,EAAW,OACrB,CACD,CA4BA,eAAsBE,EACrBX,EACAC,EAC+B,CAC/BW,EAAiB,0BAA2BX,EAAO,yBAAyB,EAE5E,GAAM,CAAE,OAAQY,EAAW,QAAAC,CAAQ,EAAI,MAAMf,EAAkBC,EAAYC,CAAM,EAGjF,MAAO,CAAE,OAFoBc,EAAcF,CAAS,EAEnC,QAAAC,CAAQ,CAC1B,CCrDO,IAAME,EAAN,MAAMC,CAAY,CAIxB,YAAYC,EAAmB,CAH/BC,EAAA,KAAQ,aACRA,EAAA,KAAQ,aAGP,KAAK,UAAYD,EACjB,KAAK,UAAY,CAAC,CACnB,CASO,OAAOE,EAAgBC,EAA8B,CAC3D,IAAMC,EAAUL,EAAY,iBAAiBG,CAAI,EAE5C,KAAK,UAAUE,CAAO,IAC1B,KAAK,UAAUA,CAAO,EAAI,CAAC,GAG5B,IAAMC,EAA+BF,EAAM,IAAKG,IAAU,CACzD,KAAMP,EAAY,eAAeO,CAAI,CACtC,EAAE,EAEF,YAAK,UAAUF,CAAO,EAAE,KAAK,GAAGC,CAAS,EAClC,IACR,CASO,aAAaH,EAAgBI,EAA2B,CAC9D,OAAO,KAAK,OAAOJ,EAAM,CAACI,CAAI,CAAC,CAChC,CASO,oBAAoBC,EAAiC,CAC3D,KAAK,UAAY,CAAC,EAElB,OAAW,CAACC,EAASL,CAAK,IAAK,OAAO,QAAQI,CAAQ,EAAG,CACxD,GAAI,CAAC,MAAM,QAAQJ,CAAK,EAAG,SAC3B,IAAMD,EAAOH,EAAY,gBAAgBS,CAAO,EAChD,KAAK,OAAON,EAAMC,CAAK,CACxB,CAEA,OAAO,IACR,CASO,WAAWM,EAA+C,CAChE,IAAMN,EAAQ,MAAM,QAAQM,CAAM,EAAIA,EAAS,CAACA,CAAM,EACtD,OAAO,KAAK,OAAO,CAAC,CAAC,EAAGN,CAAK,CAC9B,CAOO,SAA2B,CACjC,IAAMO,EAA0B,CAAC,EAEjC,QAAWP,KAAS,OAAO,OAAO,KAAK,SAAS,EAC/C,GAAI,MAAM,QAAQA,CAAK,EACtB,QAAWG,KAAQH,EAClBO,EAAO,KAAKX,EAAY,iBAAiBO,EAAK,IAAI,CAAC,EAKtD,OAAOI,CACR,CAOO,UAA2B,CACjC,OAAO,OAAO,KAAK,KAAK,SAAS,CAClC,CAQO,QAAQR,EAA6C,CAC3D,IAAME,EAAUL,EAAY,iBAAiBG,CAAI,EAC3CC,EAAQ,KAAK,UAAUC,CAAO,EACpC,GAAKD,EACL,OAAOA,EAAM,IAAKG,GAA0BP,EAAY,iBAAiBO,EAAK,IAAI,CAAC,CACpF,CAOO,iBAA4B,CAClC,MAAO,CACN,UAAW,KAAK,UAChB,UAAW,KAAK,SACjB,CACD,CAOO,cAAqC,CAC3C,OAAO,KAAK,SACb,CAOO,cAAuB,CAC7B,OAAO,KAAK,SACb,CAkBA,OAAc,gBAAgBK,EAAkC,CAC/D,OAAOA,EACL,OAAQC,GAAUb,EAAY,cAAca,EAAM,OAAO,CAAC,EAC1D,IAAKA,GAAU,CACf,IAAMC,EAAO,IAAId,EAAYa,EAAM,UAAY,SAAS,EAClDE,EAAQF,EAAM,QAGpB,GAAIA,EAAM,YAAcb,EAAY,oBAAoBe,CAAK,EAC5DD,EAAK,oBAAoBC,CAAwB,EAG7Cf,EAAY,eAAea,CAAK,GACnCC,EAAK,wBAAwBD,EAAM,QAASA,EAAM,QAASA,EAAM,UAAY,SAAS,MAInF,CACJ,IAAMH,EAAS,MAAM,QAAQK,CAAK,EAAIA,EAAQ,CAACA,CAAK,EAC9CC,EAAYhB,EAAY,cAAcU,EAAQG,CAAK,EACzDC,EAAK,WAAWE,CAAS,CAC1B,CAEA,OAAOF,EAAK,gBAAgB,CAC7B,CAAC,CACH,CAQA,OAAc,eAAeD,EAAyC,CACrE,OAAKb,EAAY,cAAca,EAAM,OAAO,EAE9Bb,EAAY,gBAAgB,CAACa,CAAK,CAAC,EACpC,CAAC,EAHiC,MAIhD,CAoDA,OAAc,iBACbI,EACAhB,EACAiB,EAC6B,CAI7B,GAFwBD,EAAM,OAAS,GAAKA,EAAM,CAAC,YAAajB,EAE3C,CAEpB,IAAMmB,EAAYF,EACZG,EAAgBD,EAAU,UAAWE,GAAMA,EAAE,aAAa,IAAMpB,CAAS,EACzEa,EAAO,IAAId,EAAYC,CAAS,EAGtC,OACC,OAAOiB,GAAa,UACpBA,IAAa,MACb,CAAC,MAAM,QAAQA,CAAQ,GACvBlB,EAAY,oBAAoBkB,CAAQ,EAExCJ,EAAK,oBAAoBI,CAA2B,GAC1C,MAAM,QAAQA,CAAQ,EAChCJ,EAAK,WAAWI,CAAQ,GAKrBE,IAAkB,GACrBD,EAAUC,CAAa,EAAIN,EAE3BK,EAAU,KAAKL,CAAI,EAGbK,CACR,KAAO,CAEN,IAAMG,EAAaL,EACbG,EAAgBE,EAAW,UAAWD,GAAMA,EAAE,YAAcpB,CAAS,EACrEa,EAAO,IAAId,EAAYC,CAAS,EAIrC,OAAOiB,GAAa,UACpBA,IAAa,MACb,CAAC,MAAM,QAAQA,CAAQ,GACvBlB,EAAY,oBAAoBkB,CAAQ,EAExCJ,EAAK,oBAAoBI,CAA2B,GAC1C,MAAM,QAAQA,CAAQ,EAChCJ,EAAK,WAAWI,CAAQ,GAKzB,IAAMK,EAAUT,EAAK,gBAAgB,EAErC,OAAIM,IAAkB,GACrBE,EAAWF,CAAa,EAAIG,EAE5BD,EAAW,KAAKC,CAAO,EAGjBD,CACR,CACD,CA8CA,OAAc,aACbL,EACAhB,EACuB,CAIvB,GAFwBgB,EAAM,OAAS,GAAKA,EAAM,CAAC,YAAajB,EAE3C,CAGpB,IAAMc,EADYG,EACK,KAAMI,GAAMA,EAAE,aAAa,IAAMpB,CAAS,EAEjE,GAAI,CAACa,EACJ,OAAO,KAGR,IAAMJ,EAASI,EAAK,QAAQ,EAE5B,OAAIJ,EAAO,SAAW,EAAU,KAC5BA,EAAO,SAAW,EAAUA,EAAO,CAAC,EACjCA,CACR,KAAO,CAGN,IAAMI,EADaG,EACK,KAAMI,GAAMA,EAAE,YAAcpB,CAAS,EAE7D,GAAI,CAACa,EACJ,OAAO,KAGR,IAAMU,EAAYV,EAAK,UAGvB,GAAI,CAACU,EACJ,OAAO,KAIR,IAAMC,EAAW,OAAO,KAAKD,CAAS,EAAE,CAAC,EACzC,GAAI,CAACC,EACJ,OAAO,KAIR,IAAMrB,EAAQoB,EAAUC,CAAQ,EAGhC,GAAI,MAAM,QAAQrB,CAAK,EAAG,CAEzB,GAAIA,EAAM,SAAW,EAAG,CACvB,IAAMW,EAAQX,EAAM,CAAC,GAAG,KACxB,OAAOW,IAAU,OAAYf,EAAY,iBAAiBe,CAAK,EAAI,IACpE,CAEA,OAAOX,EACL,IAAKG,GACLA,GAAM,OAAS,OAAYP,EAAY,iBAAiBO,EAAK,IAAI,EAAI,IACtE,EACC,OAAQmB,GAAMA,IAAM,IAAI,CAC3B,CAGA,OAAItB,GAAO,OAAS,OACZJ,EAAY,iBAAiBI,EAAM,IAAI,EAIxCA,CACR,CACD,CAQA,OAAc,gBAAgBK,EAA2B,CACxD,IAAMkB,EAAQlB,EAAQ,MAAM,gBAAgB,EAC5C,OAAKkB,EAIEA,EAAM,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM,GAHpCC,EAAU,EAAE,KAAK,oCAAoCnB,CAAO,aAAa,EAClE,CAAC,CAAC,EAGX,CAQA,OAAc,iBAAiBN,EAA8B,CAC5D,MAAO,IAAIA,EAAK,KAAK,GAAG,CAAC,GAC1B,CASQ,wBACP0B,EACAC,EACAC,EACO,CACP,QAAW3B,KAAS,OAAO,OAAO,KAAK,SAAS,EAC/C,GAAK,MAAM,QAAQA,CAAK,EAExB,QAAWG,KAAQH,EAAO,CACzB,IAAMW,EAAQf,EAAY,iBAAiBO,EAAK,IAAI,EACpD,GAAI,OAAOQ,GAAU,SAAU,CAC9B,IAAMiB,EAAUhC,EAAY,WAAWe,EAAOc,EAAKC,EAAKC,CAAS,EACjExB,EAAK,KAAOP,EAAY,eAAegC,CAAO,CAC/C,CACD,CAEF,CAMA,OAAe,eAAejB,EAAiD,CAG9E,OAFI,OAAOA,GAAU,WACjB,OAAOA,GAAU,UACjB,OAAOA,GAAU,SAAiBA,EAClC,OAAOA,GAAU,UAAYA,IAAU,KACnC,KAAK,UAAUA,CAAK,EAErB,OAAOA,CAAK,CACpB,CAMA,OAAe,iBAAiBkB,EAAgD,CAM/E,GAJI,OAAOA,GAAS,WAChB,OAAOA,GAAS,UAGhB,OAAOA,GAAS,SAAU,OAAOA,EAGrC,GAAIA,EAAK,WAAW,GAAG,GAAKA,EAAK,WAAW,GAAG,EAC9C,GAAI,CACH,OAAO,KAAK,MAAMA,CAAI,CACvB,MAAQ,CACP,OAAOA,CACR,CAGD,OAAK,MAAM,OAAOA,CAAI,CAAC,EAInBA,IAAS,OAAe,GACxBA,IAAS,QAAgB,GACtBA,EALC,OAAOA,CAAI,CAMpB,CAKA,OAAe,cAAclB,EAAyB,CACrD,OAA2BA,GAAU,KAAa,GAC9C,OAAOA,GAAU,SAAiB,GAClC,QAAM,QAAQA,CAAK,GAAKA,EAAM,SAAW,GACzC,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,GAAK,OAAO,KAAKA,CAAK,EAAE,SAAW,EAGzF,CAKA,OAAe,oBAAoBA,EAA0C,CAC5E,OAAI,OAAOA,GAAU,UAAYA,IAAU,MAAQ,MAAM,QAAQA,CAAK,EAAU,GACzE,OAAO,QAAQA,CAAK,EAAE,MAC5B,CAAC,CAACmB,EAAKC,CAAG,IAAM,OAAOD,GAAQ,UAAY,eAAe,KAAKA,CAAG,GAAK,MAAM,QAAQC,CAAG,CACzF,CACD,CAKA,OAAe,eAAetB,EAI5B,CACD,OAAOA,EAAM,YAAc,UAAYA,EAAM,YAAc,SAC5D,CAKA,OAAe,cAAcH,EAAyBG,EAAoC,CACzF,OAAOH,EACL,IAAKyB,GAEDnC,EAAY,eAAea,CAAK,GAAK,OAAOsB,GAAQ,SAChDnC,EAAY,WAClBmC,EACAtB,EAAM,QACNA,EAAM,QACNA,EAAM,UAAY,SACnB,EAIMsB,CACP,EACA,OAAQT,GAAMA,GAAM,IAAuB,CAC9C,CAKA,OAAe,WACdX,EACAc,EACAC,EACAC,EACS,CACT,IAAIpB,EAASI,EAEb,OAAIc,GAAQ,MAA6BlB,EAASkB,IACjDD,EAAU,EAAE,KAAK,GAAGG,CAAS,KAAKhB,CAAK,cAAcc,CAAG,YAAY,EACpElB,EAASkB,GAENC,GAAQ,MAA6BnB,EAASmB,IACjDF,EAAU,EAAE,KAAK,GAAGG,CAAS,KAAKhB,CAAK,cAAce,CAAG,YAAY,EACpEnB,EAASmB,GAGHnB,CACR,CACD","names":["init_errors","init_base","init_logger","GrasshopperClient","_GrasshopperClient","config","__publicField","ComputeServerStats","client","RhinoComputeError","ErrorCodes","definition","fetchParsedDefinitionIO","fetchDefinitionIO","dataTree","result","solveGrasshopperDefinition","error","getLogger","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","init_logger","warnIfClientSide","functionName","suppress","getLogger","solveGrasshopperDefinition","dataTree","definition","config","warnIfClientSide","args","prepareGrasshopperArgs","applyOptionalComputeSettings","result","fetchRhinoCompute","base64ByteArray","isBase64","encodeStringToBase64","arglist","options","init_errors","preProcessInputDefault","input","getLogger","innerTree","tree","branch","items","item","num","allValues","init_errors","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","init_logger","createSafeDefault","rawInput","baseInput","processInput","preProcessInputDefault","parser","PARSERS","RhinoComputeError","error","getLogger","processInputs","rawInputs","fetchDefinitionIO","definition","config","args","prepareGrasshopperArgs","payload","response","fetchRhinoCompute","RhinoComputeError","ErrorCodes","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"]}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkTANE2MYUcjs = require('./chunk-TANE2MYU.cjs');require('./chunk-FB4LUGFJ.cjs');var _chunkMTDJ3VNBcjs = require('./chunk-MTDJ3VNB.cjs');exports.GrasshopperClient = _chunkTANE2MYUcjs.a; exports.GrasshopperResponseProcessor = _chunkTANE2MYUcjs.d; exports.RhinoComputeError = _chunkMTDJ3VNBcjs.e; exports.TreeBuilder = _chunkTANE2MYUcjs.j; exports.downloadFileData = _chunkTANE2MYUcjs.c; exports.extractFilesFromComputeResponse = _chunkTANE2MYUcjs.b; exports.fetchDefinitionIO = _chunkTANE2MYUcjs.h; exports.fetchParsedDefinitionIO = _chunkTANE2MYUcjs.i; exports.processInput = _chunkTANE2MYUcjs.f; exports.processInputs = _chunkTANE2MYUcjs.g; exports.solveGrasshopperDefinition = _chunkTANE2MYUcjs.e;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunk7AD5GVQOcjs = require('./chunk-7AD5GVQO.cjs');require('./chunk-FB4LUGFJ.cjs');var _chunkMTDJ3VNBcjs = require('./chunk-MTDJ3VNB.cjs');exports.GrasshopperClient = _chunk7AD5GVQOcjs.a; exports.GrasshopperResponseProcessor = _chunk7AD5GVQOcjs.d; exports.RhinoComputeError = _chunkMTDJ3VNBcjs.e; exports.TreeBuilder = _chunk7AD5GVQOcjs.j; exports.downloadFileData = _chunk7AD5GVQOcjs.c; exports.extractFilesFromComputeResponse = _chunk7AD5GVQOcjs.b; exports.fetchDefinitionIO = _chunk7AD5GVQOcjs.h; exports.fetchParsedDefinitionIO = _chunk7AD5GVQOcjs.i; exports.processInput = _chunk7AD5GVQOcjs.f; exports.processInputs = _chunk7AD5GVQOcjs.g; exports.solveGrasshopperDefinition = _chunk7AD5GVQOcjs.e;
2
2
  //# sourceMappingURL=grasshopper.cjs.map
@@ -3,7 +3,7 @@ export { R as RhinoComputeError } from './base-dtik4Dlu.cjs';
3
3
  import { b as DataTreeDefault, O as OutputParamSchema, f as InputParamSchema, G as GrasshopperComputeConfig, a as DataTree, d as GrasshopperComputeResponse, C as ComputeConfig, c as DataTreePath } from './schemas-DeOMMmDI.cjs';
4
4
  export { D as DataItem, e as GrasshopperRequestSchema, I as InnerTreeData, R as RhinoModelUnit } from './schemas-DeOMMmDI.cjs';
5
5
  import * as THREE from 'three';
6
- import { M as MeshExtractionOptions } from './types-BARMhgxW.cjs';
6
+ import { M as MeshExtractionOptions } from './types-B24K2LG4.cjs';
7
7
 
8
8
  /**
9
9
  * Input and output parameter types
@@ -3,7 +3,7 @@ export { R as RhinoComputeError } from './base-dtik4Dlu.js';
3
3
  import { b as DataTreeDefault, O as OutputParamSchema, f as InputParamSchema, G as GrasshopperComputeConfig, a as DataTree, d as GrasshopperComputeResponse, C as ComputeConfig, c as DataTreePath } from './schemas-DeOMMmDI.js';
4
4
  export { D as DataItem, e as GrasshopperRequestSchema, I as InnerTreeData, R as RhinoModelUnit } from './schemas-DeOMMmDI.js';
5
5
  import * as THREE from 'three';
6
- import { M as MeshExtractionOptions } from './types-BARMhgxW.js';
6
+ import { M as MeshExtractionOptions } from './types-B24K2LG4.js';
7
7
 
8
8
  /**
9
9
  * Input and output parameter types
@@ -1,2 +1,2 @@
1
- import{a as b,b as c,c as d,d as e,e as f,f as g,g as h,h as i,i as j,j as k}from"./chunk-66KIJ5EK.js";import"./chunk-RGHW3SLU.js";import{e as a}from"./chunk-BL2RNK2F.js";export{b as GrasshopperClient,e as GrasshopperResponseProcessor,a as RhinoComputeError,k as TreeBuilder,d as downloadFileData,c as extractFilesFromComputeResponse,i as fetchDefinitionIO,j as fetchParsedDefinitionIO,g as processInput,h as processInputs,f as solveGrasshopperDefinition};
1
+ import{a as b,b as c,c as d,d as e,e as f,f as g,g as h,h as i,i as j,j as k}from"./chunk-WYX224LA.js";import"./chunk-RGHW3SLU.js";import{e as a}from"./chunk-BL2RNK2F.js";export{b as GrasshopperClient,e as GrasshopperResponseProcessor,a as RhinoComputeError,k as TreeBuilder,d as downloadFileData,c as extractFilesFromComputeResponse,i as fetchDefinitionIO,j as fetchParsedDefinitionIO,g as processInput,h as processInputs,f as solveGrasshopperDefinition};
2
2
  //# sourceMappingURL=grasshopper.js.map
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkTANE2MYUcjs = require('./chunk-TANE2MYU.cjs');require('./chunk-FB4LUGFJ.cjs');var _chunkMTDJ3VNBcjs = require('./chunk-MTDJ3VNB.cjs');exports.ComputeServerStats = _chunkMTDJ3VNBcjs.n; exports.ErrorCodes = _chunkMTDJ3VNBcjs.d; exports.GrasshopperClient = _chunkTANE2MYUcjs.a; exports.GrasshopperResponseProcessor = _chunkTANE2MYUcjs.d; exports.RhinoComputeError = _chunkMTDJ3VNBcjs.e; exports.TreeBuilder = _chunkTANE2MYUcjs.j; exports.camelcaseKeys = _chunkMTDJ3VNBcjs.p; exports.downloadFileData = _chunkTANE2MYUcjs.c; exports.enableDebugLogging = _chunkMTDJ3VNBcjs.k; exports.extractFilesFromComputeResponse = _chunkTANE2MYUcjs.b; exports.fetchDefinitionIO = _chunkTANE2MYUcjs.h; exports.fetchParsedDefinitionIO = _chunkTANE2MYUcjs.i; exports.fetchRhinoCompute = _chunkMTDJ3VNBcjs.m; exports.getLogger = _chunkMTDJ3VNBcjs.i; exports.processInput = _chunkTANE2MYUcjs.f; exports.processInputs = _chunkTANE2MYUcjs.g; exports.setLogger = _chunkMTDJ3VNBcjs.j; exports.solveGrasshopperDefinition = _chunkTANE2MYUcjs.e; exports.toCamelCase = _chunkMTDJ3VNBcjs.o;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunk7AD5GVQOcjs = require('./chunk-7AD5GVQO.cjs');require('./chunk-FB4LUGFJ.cjs');var _chunkMTDJ3VNBcjs = require('./chunk-MTDJ3VNB.cjs');exports.ComputeServerStats = _chunkMTDJ3VNBcjs.n; exports.ErrorCodes = _chunkMTDJ3VNBcjs.d; exports.GrasshopperClient = _chunk7AD5GVQOcjs.a; exports.GrasshopperResponseProcessor = _chunk7AD5GVQOcjs.d; exports.RhinoComputeError = _chunkMTDJ3VNBcjs.e; exports.TreeBuilder = _chunk7AD5GVQOcjs.j; exports.camelcaseKeys = _chunkMTDJ3VNBcjs.p; exports.downloadFileData = _chunk7AD5GVQOcjs.c; exports.enableDebugLogging = _chunkMTDJ3VNBcjs.k; exports.extractFilesFromComputeResponse = _chunk7AD5GVQOcjs.b; exports.fetchDefinitionIO = _chunk7AD5GVQOcjs.h; exports.fetchParsedDefinitionIO = _chunk7AD5GVQOcjs.i; exports.fetchRhinoCompute = _chunkMTDJ3VNBcjs.m; exports.getLogger = _chunkMTDJ3VNBcjs.i; exports.processInput = _chunk7AD5GVQOcjs.f; exports.processInputs = _chunk7AD5GVQOcjs.g; exports.setLogger = _chunkMTDJ3VNBcjs.j; exports.solveGrasshopperDefinition = _chunk7AD5GVQOcjs.e; exports.toCamelCase = _chunkMTDJ3VNBcjs.o;
2
2
  //# sourceMappingURL=index.cjs.map