@selvajs/compute 4.0.0-beta.8 → 4.0.1

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.
@@ -486,6 +486,25 @@ declare const downloadFileData: (downloadableFiles: FileData[], fileFoldername:
486
486
  declare const downloadFileDataByRoot: (downloadableFiles: FileData[], fallbackName: string, additionalFiles?: FileBaseInfo[] | FileBaseInfo | null) => Promise<void>;
487
487
  //#endregion
488
488
  //#region src/core/files/sub-folder.d.ts
489
+ /**
490
+ * The `Sub Folder` convention, as authored on Selva's Grasshopper file components.
491
+ *
492
+ * `::` nests, matching Rhino's layer separator (`ROOT::Panels`), and `/` and `\` are accepted
493
+ * because people type them out of habit. The plugin normalizes to `/` before sending, so these
494
+ * helpers also cover payloads from an older plugin that still emit `::`.
495
+ *
496
+ * The first segment is the **root**, which names the archive rather than becoming a folder inside
497
+ * it: `ROOT::Panels` downloads as `ROOT.zip` containing `Panels/…`. Files sharing a root travel
498
+ * together; distinct roots produce separate archives.
499
+ */
500
+ /**
501
+ * Split a `Sub Folder` value into folder segments; `/`, `\` and `::` all separate.
502
+ *
503
+ * Exported because anything rendering a folder tree has to agree with the archive on where the
504
+ * boundaries are — splitting on `/` alone leaves `Main::Panels` as one literal segment and shows
505
+ * a folder named after the separator.
506
+ */
507
+ declare const subFolderSegments: (subFolder: string | undefined) => string[];
489
508
  /**
490
509
  * Group files by their `Sub Folder` root, preserving encounter order.
491
510
  *
@@ -498,5 +517,5 @@ declare const groupFilesByRoot: <T extends Pick<FileData, "subFolder">>(files: r
498
517
  files: T[];
499
518
  }>;
500
519
  //#endregion
501
- export { ErrorCodes as A, fetchCompute as C, ServerTiming as D, ServerErrorCodeMap as E, ComputeError as O, setResponseWireSize as S, RetryPolicy as T, Logger as _, FileBaseInfo as a, setLogger as b, DEFAULT_BLOCKED_HOST as c, DefinitionRef as d, SolveDefinition as f, readField as g, hasField as h, extractFilesFromComputeResponse as i, ErrorCode as k, ValidateServerUrlOptions as l, decodeBase64ToBinary as m, downloadFileData as n, FileData as o, isDefinitionRef as p, downloadFileDataByRoot as r, ProcessedFile as s, groupFilesByRoot as t, validateServerUrl as u, enableDebugLogging as v, ComputeConfig as w, getResponseWireSize as x, getLogger as y };
502
- //# sourceMappingURL=index-cUZsorKK.d.ts.map
520
+ export { ErrorCode as A, setResponseWireSize as C, ServerErrorCodeMap as D, RetryPolicy as E, ServerTiming as O, getResponseWireSize as S, ComputeConfig as T, readField as _, extractFilesFromComputeResponse as a, getLogger as b, ProcessedFile as c, validateServerUrl as d, DefinitionRef as f, hasField as g, decodeBase64ToBinary as h, downloadFileDataByRoot as i, ErrorCodes as j, ComputeError as k, DEFAULT_BLOCKED_HOST as l, isDefinitionRef as m, subFolderSegments as n, FileBaseInfo as o, SolveDefinition as p, downloadFileData as r, FileData as s, groupFilesByRoot as t, ValidateServerUrlOptions as u, Logger as v, fetchCompute as w, setLogger as x, enableDebugLogging as y };
521
+ //# sourceMappingURL=index-C7Olveh2.d.cts.map
@@ -486,6 +486,25 @@ declare const downloadFileData: (downloadableFiles: FileData[], fileFoldername:
486
486
  declare const downloadFileDataByRoot: (downloadableFiles: FileData[], fallbackName: string, additionalFiles?: FileBaseInfo[] | FileBaseInfo | null) => Promise<void>;
487
487
  //#endregion
488
488
  //#region src/core/files/sub-folder.d.ts
489
+ /**
490
+ * The `Sub Folder` convention, as authored on Selva's Grasshopper file components.
491
+ *
492
+ * `::` nests, matching Rhino's layer separator (`ROOT::Panels`), and `/` and `\` are accepted
493
+ * because people type them out of habit. The plugin normalizes to `/` before sending, so these
494
+ * helpers also cover payloads from an older plugin that still emit `::`.
495
+ *
496
+ * The first segment is the **root**, which names the archive rather than becoming a folder inside
497
+ * it: `ROOT::Panels` downloads as `ROOT.zip` containing `Panels/…`. Files sharing a root travel
498
+ * together; distinct roots produce separate archives.
499
+ */
500
+ /**
501
+ * Split a `Sub Folder` value into folder segments; `/`, `\` and `::` all separate.
502
+ *
503
+ * Exported because anything rendering a folder tree has to agree with the archive on where the
504
+ * boundaries are — splitting on `/` alone leaves `Main::Panels` as one literal segment and shows
505
+ * a folder named after the separator.
506
+ */
507
+ declare const subFolderSegments: (subFolder: string | undefined) => string[];
489
508
  /**
490
509
  * Group files by their `Sub Folder` root, preserving encounter order.
491
510
  *
@@ -498,5 +517,5 @@ declare const groupFilesByRoot: <T extends Pick<FileData, "subFolder">>(files: r
498
517
  files: T[];
499
518
  }>;
500
519
  //#endregion
501
- export { ErrorCodes as A, fetchCompute as C, ServerTiming as D, ServerErrorCodeMap as E, ComputeError as O, setResponseWireSize as S, RetryPolicy as T, Logger as _, FileBaseInfo as a, setLogger as b, DEFAULT_BLOCKED_HOST as c, DefinitionRef as d, SolveDefinition as f, readField as g, hasField as h, extractFilesFromComputeResponse as i, ErrorCode as k, ValidateServerUrlOptions as l, decodeBase64ToBinary as m, downloadFileData as n, FileData as o, isDefinitionRef as p, downloadFileDataByRoot as r, ProcessedFile as s, groupFilesByRoot as t, validateServerUrl as u, enableDebugLogging as v, ComputeConfig as w, getResponseWireSize as x, getLogger as y };
502
- //# sourceMappingURL=index-cUZsorKK.d.cts.map
520
+ export { ErrorCode as A, setResponseWireSize as C, ServerErrorCodeMap as D, RetryPolicy as E, ServerTiming as O, getResponseWireSize as S, ComputeConfig as T, readField as _, extractFilesFromComputeResponse as a, getLogger as b, ProcessedFile as c, validateServerUrl as d, DefinitionRef as f, hasField as g, decodeBase64ToBinary as h, downloadFileDataByRoot as i, ErrorCodes as j, ComputeError as k, DEFAULT_BLOCKED_HOST as l, isDefinitionRef as m, subFolderSegments as n, FileBaseInfo as o, SolveDefinition as p, downloadFileData as r, FileData as s, groupFilesByRoot as t, ValidateServerUrlOptions as u, Logger as v, fetchCompute as w, setLogger as x, enableDebugLogging as y };
521
+ //# sourceMappingURL=index-C7Olveh2.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selvajs/compute",
3
- "version": "4.0.0-beta.8",
3
+ "version": "4.0.1",
4
4
  "description": "TypeScript library for Rhino Compute Server - Grasshopper and RhinoCommon",
5
5
  "author": "VektorNode",
6
6
  "license": "MIT",
@@ -95,8 +95,8 @@
95
95
  "eslint": "^10.8.0",
96
96
  "eslint-config-prettier": "^10.1.8",
97
97
  "eslint-plugin-svelte": "^3.22.0",
98
- "globals": "^17.8.0",
99
- "lint-staged": "^17.2.0",
98
+ "globals": "^17.9.0",
99
+ "lint-staged": "^17.3.0",
100
100
  "prettier": "^3.9.6",
101
101
  "prettier-plugin-svelte": "^4.1.1",
102
102
  "prettier-plugin-tailwindcss": "^0.8.1",
@@ -106,10 +106,10 @@
106
106
  "typedoc-plugin-extras": "^4.0.1",
107
107
  "typedoc-plugin-missing-exports": "^4.1.2",
108
108
  "typescript": "~6.0.3",
109
- "typescript-eslint": "^8.65.0",
110
- "vite": "^8.1.5",
109
+ "typescript-eslint": "^8.66.0",
110
+ "vite": "^8.2.1",
111
111
  "vitest": "^4.1.10",
112
- "@selvajs/config": "0.0.3"
112
+ "@selvajs/config": "0.0.4"
113
113
  },
114
114
  "scripts": {
115
115
  "build": "pnpm type-check && tsdown",
@@ -1,3 +0,0 @@
1
- const e={NETWORK_ERROR:`NETWORK_ERROR`,AUTH_ERROR:`AUTH_ERROR`,VALIDATION_ERROR:`VALIDATION_ERROR`,COMPUTATION_ERROR:`COMPUTATION_ERROR`,TIMEOUT_ERROR:`TIMEOUT_ERROR`,CORS_ERROR:`CORS_ERROR`,NOT_FOUND:`NOT_FOUND`,RATE_LIMIT:`RATE_LIMIT`,INVALID_RESPONSE:`INVALID_RESPONSE`,UNKNOWN_ERROR:`UNKNOWN_ERROR`,INVALID_STATE:`INVALID_STATE`,INVALID_INPUT:`INVALID_INPUT`,INVALID_CONFIG:`INVALID_CONFIG`,BROWSER_ONLY:`BROWSER_ONLY`,ENVIRONMENT_ERROR:`ENVIRONMENT_ERROR`,ENCODING_ERROR:`ENCODING_ERROR`,MALFORMED_DEFAULT:`MALFORMED_DEFAULT`,SUPERSEDED:`SUPERSEDED`,ABORTED:`ABORTED`,QUEUE_FULL:`QUEUE_FULL`,QUEUE_TIMEOUT:`QUEUE_TIMEOUT`,DEFINITION_NOT_CACHED:`DEFINITION_NOT_CACHED`};var t=class t extends Error{code;statusCode;context;originalError;constructor(t,n=e.UNKNOWN_ERROR,r){super(t),this.name=`ComputeError`,this.code=n,this.statusCode=r?.statusCode,this.context=r?.context,this.originalError=r?.originalError,r?.originalError&&(this.cause=r.originalError)}static missingValues(n,r,i){return new t(`Input "${n}" has no values defined${r?` (expected ${r})`:``}`,e.INVALID_INPUT,{context:{inputName:n,expectedType:r,...i}})}static unknownParamType(n,r,i){return new t(`Unknown paramType: ${n}`,e.VALIDATION_ERROR,{context:{receivedParamType:n,paramName:r,...i}})}},n=class{debug(){}info(){}warn(){}error(){}},r=class{debug(e,...t){console.debug(e,...t)}info(e,...t){console.info(e,...t)}warn(e,...t){console.warn(e,...t)}error(e,...t){console.error(e,...t)}};let i=new n;function a(){return i}function o(r){if(r===null){i=new n;return}let a=[`debug`,`info`,`warn`,`error`].filter(e=>typeof r[e]!=`function`);if(a.length>0)throw new t(`Logger is missing required method(s): ${a.join(`, `)}. A logger must implement debug, info, warn and error.`,e.INVALID_CONFIG,{context:{missingMethods:a}});i=r}function s(){o(new r)}function c(e,t){if(!e||typeof e!=`object`)return;let n=e;if(l(n,t))return n[t];let r=f(n).get(t.toLowerCase());return r===void 0?void 0:n[r]}const l=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);function u(e,t){if(!e||typeof e!=`object`)return!1;let n=e;return l(n,t)?!0:f(n).has(t.toLowerCase())}const d=new WeakMap;function f(e){let t=Object.keys(e),n=d.get(e);if(n&&n.keyCount===t.length)return n.map;let r=new Map;for(let e of t){let t=e.toLowerCase();r.has(t)||r.set(t,e)}return d.set(e,{keyCount:t.length,map:r}),r}function p(n,r){let i=n?.trim()??``;if(!i)throw new t(`serverUrl is required`,e.INVALID_CONFIG,{context:{receivedServerUrl:n}});if(!/^https?:\/\//i.test(i))throw new t(`Invalid serverUrl: "${i}". Must start with "http://" or "https://". For example: "http://localhost:5000" or "https://example.com"`,e.INVALID_CONFIG,{context:{receivedServerUrl:n}});let a;try{a=new URL(i)}catch(r){throw new t(`Invalid serverUrl: "${i}". Must be a valid URL. Received error: ${r instanceof Error?r.message:String(r)}`,e.INVALID_CONFIG,{context:{receivedServerUrl:n},originalError:r instanceof Error?r:void 0})}if(a.username!==``||a.password!==``)throw new t(`Invalid serverUrl: "${i}". Must not embed credentials (user:pass@host) — fetch rejects credentialed URLs at request time. Pass the API key separately.`,e.INVALID_CONFIG,{context:{receivedServerUrl:n}});if(i.includes(`?`)||i.includes(`#`))throw new t(`Invalid serverUrl: "${i}". Must not contain a query string or fragment — endpoint paths are appended to this URL (e.g. "\${serverUrl}/version"), and a "?" or "#" suffix would corrupt every request path.`,e.INVALID_CONFIG,{context:{receivedServerUrl:n}});let o=a.hostname.toLowerCase().replace(/\.+$/,``);if((r?.blockedHosts??[`compute.rhino3d.com`]).map(e=>e.toLowerCase().replace(/\.+$/,``)).includes(o))throw new t(`serverUrl must be set to your Compute server URL. The shared public endpoint is not allowed.`,e.INVALID_CONFIG,{context:{receivedServerUrl:n}});return i.replace(/\/+$/,``)}function m(){let e=globalThis.Buffer;return typeof e==`function`?e:void 0}function h(e){let t=m();return t?t.from(e,`utf-8`).toString(`base64`):y(new TextEncoder().encode(e))}function g(e){if(!e)return null;let t=e.replace(/[\t\n\f\r ]/g,``);t.length%4==0&&(t=t.replace(/={1,2}$/,``));let n=t.length%4;if(n===1||t.length<64||!/^[A-Za-z0-9+/]*$/.test(t))return null;let r=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`.indexOf(t.charAt(t.length-1));return n===2&&r&15||n===3&&r&3?null:n===0?t:t+`==`.slice(0,4-n)}function _(n){let r=n.replace(/[\t\n\f\r ]/g,``);if(r.length%4==0&&(r=r.replace(/={1,2}$/,``)),r.length%4==1||!/^[A-Za-z0-9+/]*$/.test(r))throw new t(`Invalid base64 input.`,e.ENCODING_ERROR,{context:{inputLength:n.length}});let i=m();if(i)return new Uint8Array(i.from(r,`base64`));if(typeof globalThis.atob==`function`){let e=globalThis.atob(r),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n)&255;return t}throw new t(`Base64 decoding not supported in this environment.`,e.INVALID_STATE,{context:{environmentInfo:`atob or Buffer not available`}})}function v(e){let t=m();if(t)return t.byteLength(e,`utf-8`);let n=0;for(let t=0;t<e.length;t++){let r=e.charCodeAt(t);r<128?n+=1:r<2048?n+=2:r>=55296&&r<=56319&&t+1<e.length&&(e.charCodeAt(t+1)&64512)==56320?(n+=4,t++):n+=3}return n}function y(n){let r=m();if(r)return r.from(n).toString(`base64`);if(typeof globalThis.btoa==`function`){let e=32766,t=[];for(let r=0;r<n.length;r+=e)t.push(globalThis.btoa(String.fromCharCode.apply(null,n.subarray(r,r+e))));return t.join(``)}throw new t(`Base64 encoding not supported in this environment.`,e.INVALID_STATE,{context:{environmentInfo:`btoa or Buffer not available`}})}function b(e,t){t&&a().debug(e)}function x(e,t){return`${t.replace(/\/+$/,``)}/${e.replace(/^\/+/,``)}`}function S(e){try{let t=new URL(e).hostname.toLowerCase();return t===`localhost`||t===`127.0.0.1`||t===`[::1]`}catch{return/(localhost|127\.0\.0\.1|\[::1\])/i.test(e)}}const C=new Set;function w(e,t){let n={...t.headers,"X-Request-ID":e,"Content-Type":`application/json`,...t.authToken&&{Authorization:t.authToken},...t.apiKey&&{[t.apiKeyHeader??`RhinoComputeKey`]:t.apiKey}};return!t.apiKey&&!t.authToken&&!C.has(t.serverUrl)&&!S(t.serverUrl)&&(C.add(t.serverUrl),a().warn(`⚠️ [Compute] Request [${e}] targets remote server (${t.serverUrl}) but no API key or auth token is configured. Requests may fail or be rate-limited. (warned once per server)`)),n}function T(){return`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}function E(e){if(!e)return null;let t={raw:e},n=!1;for(let r of e.split(`,`)){let[e,...i]=r.trim().split(`;`),a=i.find(e=>e.trim().toLowerCase().startsWith(`dur`));if(!a)continue;let o=Number(a.split(`=`)[1]);if(!Number.isFinite(o))continue;let s=e.trim().toLowerCase();(s===`decode`||s===`solve`||s===`encode`)&&(t[s]=o,n=!0)}return n?t:null}function D(e,t,n,r){if(!n)return;let i=E(e.headers.get(`Server-Timing`));if(i)try{n(i,t)}catch(e){r&&b(` onServerTiming callback threw: ${e}`,!0)}}const O=new WeakMap;function k(e,t){typeof e!=`object`||!e||O.set(e,t)}function ee(e){if(!(typeof e!=`object`||!e))return O.get(e)}const A=4096;function j(e){return e.length<=A?e:`${e.slice(0,A)}… [truncated ${e.length-A} chars]`}function te(n,r,i,a,o,s,c,l,u){let{status:d,statusText:f}=n,p={};n.headers.forEach((e,t)=>{p[t]=e});let m=s.trim(),h=m?` — ${m.slice(0,200)}${m.length>200?`…`:``}`:``,g=l??s,_={url:r,requestId:i,method:`POST`,requestSize:a,serverUrl:o,responseBody:g?j(g):void 0,responseHeaders:p},v={401:{message:`HTTP ${d}: ${f}${h}`,code:e.AUTH_ERROR},403:{message:`HTTP ${d}: ${f}${h}`,code:e.AUTH_ERROR},404:{message:`Endpoint not found: ${r}`,code:e.NOT_FOUND},413:{message:`Request too large: ${(a/1024).toFixed(2)}KB`,code:e.VALIDATION_ERROR},429:{message:`Rate limit exceeded${h}`,code:e.RATE_LIMIT},500:{message:`Server error: ${f}${h}`,code:e.COMPUTATION_ERROR},502:{message:`Service unavailable: ${f}${h}`,code:e.NETWORK_ERROR},503:{message:`Service unavailable: ${f}${h}`,code:e.NETWORK_ERROR},504:{message:`Service unavailable: ${f}${h}`,code:e.NETWORK_ERROR}}[d]||{message:`HTTP ${d}: ${f}${h}`,code:e.UNKNOWN_ERROR},y=ne(c,u)??v.code;throw new t(v.message,y,{statusCode:d,context:_})}function ne(e,t){if(!(!e||!t))return t[e]}async function re(n,r,i,a,o,s,c,l,u){let d=Math.round(performance.now()-s);if(!n.ok){let e=await n.text(),t=e;c&&(b(`❌ Request [${i}] failed with HTTP ${n.status} in ${d}ms`,!0),b(` URL: ${r}`,!0),b(` Status: ${n.status} ${n.statusText}`,!0),t&&b(` Response body: ${t.substring(0,500)}${t.length>500?`...`:``}`,!0));let s;try{let e=JSON.parse(t);typeof e?.code==`string`&&(s=e.code)}catch{}if(n.status===500)try{let e=JSON.parse(t);if(e?.values&&(e.errors||e.warnings))return k(e,t.length),c&&(b(`⚠️ Request [${i}] completed with solver errors in ${d}ms`,!0),e.errors?.length>0&&b(` Errors: ${JSON.stringify(e.errors,null,2)}`,!0),e.warnings?.length>0&&b(` Warnings: ${JSON.stringify(e.warnings,null,2)}`,!0)),D(n,i,l,c),e;let r=typeof e?.message==`string`&&e.message||typeof e?.Message==`string`&&e.Message||``,a=typeof e?.ExceptionType==`string`&&e.ExceptionType||``,o=e?.stackTrace??e?.StackTrace,s=Array.isArray(o)?o.join(`
2
- `):o||``;r?t=`${a?`${a}: `:``}${r}${s?`\n${s}`:``}`:e?.error&&(t=typeof e.error==`string`?e.error:JSON.stringify(e.error,null,2))}catch(e){c&&b(` Failed to parse error body as JSON: ${e}`,!0)}te(n,r,i,a,o,t,s,e,u)}b(`✅ Request [${i}] completed in ${d}ms`,c),D(n,i,l,c);try{let e=await n.text(),t=JSON.parse(e);return k(t,e.length),t}catch(a){let o=(n.headers.get(`Content-Type`)??``).toLowerCase();throw o!==``&&!o.includes(`json`)?new t(`Server returned a non-JSON response (Content-Type: ${o}) — check the server URL / proxy configuration`,e.INVALID_RESPONSE,{statusCode:n.status,context:{url:r,requestId:i,contentType:o},originalError:a instanceof Error?a:Error(String(a))}):new t(`Failed to parse JSON response`,e.NETWORK_ERROR,{statusCode:n.status,context:{url:r,requestId:i},originalError:a instanceof Error?a:Error(String(a))})}}const M={attempts:0,baseDelayMs:500,maxDelayMs:3e4,retryOn429:!0},N=new Set([502,503,504]);function P(e){return e?{attempts:e.attempts??M.attempts,baseDelayMs:e.baseDelayMs??M.baseDelayMs,maxDelayMs:e.maxDelayMs??M.maxDelayMs,retryOn429:e.retryOn429??M.retryOn429}:M}function F(e){if(!e)return null;let t=Number(e);if(Number.isFinite(t)&&t>=0)return t*1e3;let n=Date.parse(e);if(Number.isFinite(n)){let e=n-Date.now();return e>0?e:0}return null}function I(e,t){let n=t.baseDelayMs*2**e,r=Math.random()*t.baseDelayMs;return Math.min(n+r,t.maxDelayMs)}function L(e,t){return new Promise((n,r)=>{if(t?.aborted){r(new DOMException(`Aborted`,`AbortError`));return}let i=setTimeout(()=>{t?.removeEventListener(`abort`,a),n()},e),a=()=>{clearTimeout(i),r(new DOMException(`Aborted`,`AbortError`))};t?.addEventListener(`abort`,a,{once:!0})})}function R(e,t){let n=()=>{},r=typeof t==`number`&&t>0;if(!e&&!r)return{signal:void 0,cleanup:n};if(e&&!r)return{signal:e,cleanup:n};let i=typeof AbortSignal<`u`&&typeof AbortSignal.timeout==`function`;if(!e){if(i)return{signal:AbortSignal.timeout(t),cleanup:n};let e=new AbortController,r=setTimeout(()=>e.abort(),t);return{signal:e.signal,cleanup:()=>clearTimeout(r)}}let a=new AbortController,o,s;if(i)o=AbortSignal.timeout(t);else{let e=new AbortController;s=setTimeout(()=>e.abort(),t),o=e.signal}let c=[e,o],l=function(){a.abort(this.reason)};for(let e of c){if(e.aborted){a.abort(e.reason);break}e.addEventListener(`abort`,l,{once:!0})}return{signal:a.signal,cleanup:()=>{s!==void 0&&clearTimeout(s);for(let e of c)e.removeEventListener(`abort`,l)}}}async function z(n,r,i,a){let{signal:o,cleanup:s}=R(n.config.signal,n.config.timeoutMs),c=performance.now();try{let s=await fetch(n.fullUrl,{method:`POST`,body:n.body,headers:n.headers,signal:o});if((N.has(s.status)||r.retryOn429&&s.status===429)&&i<a-1){let a=F(s.headers.get(`Retry-After`)),o=a===null?I(i,r):Math.min(a,Math.max(r.maxDelayMs,6e4));return await s.text().catch(()=>{}),{ok:!1,retry:!0,delayMs:o,cause:new t(`HTTP ${s.status} ${s.statusText} (will retry)`,s.status===429?e.RATE_LIMIT:e.NETWORK_ERROR,{statusCode:s.status,context:{requestId:n.requestId}})}}return{ok:!0,value:await re(s,n.fullUrl,n.requestId,n.requestSize,n.config.serverUrl,c,n.config.debug,n.config.onServerTiming,n.config.serverErrorCodes)}}catch(o){if(o instanceof Error&&(o.name===`AbortError`||o.name===`TimeoutError`)){if(n.config.signal?.aborted===!0)return{ok:!1,retry:!1,cause:new t(`Request aborted by caller`,e.ABORTED,{context:{endpoint:n.endpoint,requestId:n.requestId,requestSize:n.requestSize},originalError:o})};let s=typeof n.config.timeoutMs==`number`&&n.config.timeoutMs>0?new t(`Request timed out after ${n.config.timeoutMs}ms`,e.TIMEOUT_ERROR,{context:{serverUrl:n.config.serverUrl,timeoutMs:n.config.timeoutMs,url:n.fullUrl,requestId:n.requestId,endpoint:n.endpoint,requestSize:n.requestSize},originalError:o}):new t(`Request aborted by the runtime (${o.name}): ${o.message}`,e.NETWORK_ERROR,{context:{serverUrl:n.config.serverUrl,url:n.fullUrl,requestId:n.requestId,endpoint:n.endpoint,requestSize:n.requestSize},originalError:o});return i<a-1?{ok:!1,retry:!0,delayMs:I(i,r),cause:s}:{ok:!1,retry:!1,cause:s}}if(o instanceof TypeError){let s=typeof window<`u`&&window.document!==void 0,c={serverUrl:n.config.serverUrl,url:n.fullUrl,requestId:n.requestId,endpoint:n.endpoint,requestSize:n.requestSize},l=s?new t(`Request failed: ${o.message} — in a browser this usually means a CORS misconfiguration on the server (or a network failure; the browser does not distinguish them)`,e.CORS_ERROR,{context:c,originalError:o}):new t(`Network error: ${o.message}`,e.NETWORK_ERROR,{context:c,originalError:o});return i<a-1?{ok:!1,retry:!0,delayMs:I(i,r),cause:l}:{ok:!1,retry:!1,cause:l}}if(o instanceof t){let t=o.statusCode;return(o.code===e.NETWORK_ERROR&&t!==void 0&&t>=200&&t<300||t!==void 0&&(N.has(t)||r.retryOn429&&t===429))&&i<a-1?{ok:!1,retry:!0,delayMs:I(i,r),cause:o}:{ok:!1,retry:!1,cause:o}}return{ok:!1,retry:!1,cause:new t(o instanceof Error?o.message:String(o),e.UNKNOWN_ERROR,{context:{endpoint:n.endpoint,requestId:n.requestId},originalError:o instanceof Error?o:Error(String(o))})}}finally{s()}}async function B(n,r,i){let a=T(),o=JSON.stringify(r),s=v(o),c=x(n,i.serverUrl),l=w(a,i),u=P(i.retry),d=u.attempts+1;if(i.debug){let e=(s/1024).toFixed(2);b(`${s>1e5?`⚠️`:`🚀`} Starting compute request [${a}]: ${n} (${e}KB)`,!0)}let f={endpoint:n,body:o,requestSize:s,fullUrl:c,requestId:a,headers:l,config:i};for(let r=0;;r++){let o=await z(f,u,r,d);if(o.ok)return o.value;if(!o.retry)throw o.cause;i.debug&&b(`🔁 Request [${a}] retrying after ${o.delayMs}ms (attempt ${r+2}/${d}): ${o.cause.message}`,!0);try{await L(o.delayMs,i.signal)}catch{throw new t(`Request aborted by caller`,e.ABORTED,{context:{endpoint:n,requestId:a,requestSize:s},originalError:o.cause})}}}function V(e){return typeof e==`object`&&!(e instanceof Uint8Array)&&typeof e.key==`string`&&typeof e.load==`function`}const H=e=>(e??``).replace(/::/g,`/`).replace(/\\/g,`/`).split(`/`).map(e=>e.trim()).filter(e=>e!==``),U=e=>H(e.subFolder)[0]??``,W=e=>H(e.subFolder).slice(1).join(`/`),G=e=>{let t=new Map;for(let n of e){let e=U(n),r=t.get(e);r?r.push(n):t.set(e,[n])}return Array.from(t,([e,t])=>({root:e,files:t}))},K=e=>{let t=e.replace(/[/\\:*?"<>|]/g,`_`).replace(/\s+/g,` `).trim().replace(/^\.+/,``);return t===``?`files`:t},q=async(n,r=null)=>{try{return await Q(n,r)}catch(n){throw new t(`Failed to extract files from compute response`,e.INVALID_STATE,{context:{originalError:n instanceof Error?n.message:String(n)},originalError:n instanceof Error?n:void 0})}},J=async(n,r,i=null)=>{if(typeof document>`u`||typeof Blob>`u`)throw new t(`File download functionality is only available in browser environments. This function requires the DOM API (document, Blob).`,e.BROWSER_ONLY,{context:{environment:typeof window<`u`?`browser (SSR)`:`Node.js`,documentAvailable:typeof document<`u`,blobAvailable:typeof Blob<`u`}});try{await oe(await Q(n,i),r)}catch(n){throw n instanceof t?n:new t(`Failed to download files from compute response`,e.INVALID_STATE,{context:{originalError:n instanceof Error?n.message:String(n)},originalError:n instanceof Error?n:void 0})}},Y=async(e,t,n=null)=>{let r=G(e);if(r.length===0){await J([],t,n);return}let i=(r.find(e=>e.root===``)??r[0]).root;for(let{root:e,files:a}of r)await J(e===``?a:a.map(e=>({...e,subFolder:W(e)})),e===``?t:K(e),e===i?n:null)},X=e=>e.replace(/::/g,`/`).replace(/\\/g,`/`).split(`/`).map(e=>e.trim()).filter(e=>e!==``&&e!==`.`&&e!==`..`&&!/^[a-zA-Z]:$/.test(e)).join(`/`),ie=e=>e===!0||typeof e==`string`&&e.trim().toLowerCase()===`true`,Z=e=>{let t=[];return e.forEach(e=>{let n=c(e,`fileName`)??``,r=c(e,`fileType`)??``,i=X(`${n}${r}`);if(i===``){a().warn(`Skipping file with unusable name "${n}${r}": no safe archive path remains after sanitization.`);return}let o=c(e,`subFolder`),s=o?X(o):``,l=s===``?i:`${s}/${i}`,u=c(e,`data`);if(typeof u!=`string`||u===``){a().warn(`Skipping file "${l}": item carries no usable data.`);return}let d=c(e,`metadata`);if(ie(c(e,`isBase64Encoded`)))try{t.push({fileName:i,content:_(u),path:l,subFolder:s,...d?{metadata:d}:{}})}catch(e){a().warn(`Skipping file "${l}": base64 decode failed.`,e)}else t.push({fileName:i,content:u,path:l,subFolder:s,...d?{metadata:d}:{}})}),t},ae=async e=>(await Promise.all(e.map(async e=>{try{let t=typeof AbortSignal<`u`&&typeof AbortSignal.timeout==`function`?AbortSignal.timeout(3e4):void 0,n=await fetch(e.filePath,{signal:t});if(!n.ok)return a().warn(`Failed to fetch additional file from URL: ${e.filePath}`),null;let r=await n.arrayBuffer(),i=X(e.fileName);if(i===``)return a().warn(`Skipping fetched file with unusable name: ${e.fileName}`),null;let o=e.subFolder?X(e.subFolder):``;return{fileName:i,content:new Uint8Array(r),path:o===``?i:`${o}/${i}`,subFolder:o}}catch(t){return a().error(`Error fetching additional file from URL: ${e.filePath}`,t),null}}))).filter(e=>e!==null),Q=async(e,t)=>{let n=Z(e);if(t){let e=Array.isArray(t)?t:[t];n.push(...await ae(e))}let r=new Set;return n.map(e=>{let t=$(e.path,r);return r.add(t),t===e.path?e:(a().warn(`Duplicate archive path "${e.path}" — storing as "${t}".`),{...e,path:t,fileName:t.slice(t.lastIndexOf(`/`)+1)})})};async function oe(e,t){let{zip:n,strToU8:r}=await import(`fflate`),i={},o=new Set;e.forEach(e=>{let t=$(e.path,o);o.add(t),t!==e.path&&a().warn(`Duplicate archive path "${e.path}" — storing as "${t}".`),i[t]=typeof e.content==`string`?r(e.content):e.content});let s=await new Promise((e,t)=>{n(i,{level:6},(n,r)=>n?t(n):e(r))});se(new Blob([s],{type:`application/zip`}),`${t}.zip`)}function $(e,t){if(!t.has(e))return e;let n=e.lastIndexOf(`/`),r=e.lastIndexOf(`.`),i=r>n?r:e.length,a=e.slice(0,i),o=e.slice(i);for(let e=2;;e++){let n=`${a}-${e}${o}`;if(!t.has(n))return n}}function se(n,r){if(typeof document>`u`)throw new t(`saveFile requires a browser environment with DOM API access.`,e.BROWSER_ONLY,{context:{function:`saveFile`,requiredAPI:`document`}});let i=URL.createObjectURL(n),a=document.createElement(`a`);a.href=i,a.download=r,document.body.appendChild(a),a.click(),a.remove(),setTimeout(()=>URL.revokeObjectURL(i),1e4)}Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return G}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return Y}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return`compute.rhino3d.com`}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return q}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return ee}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return J}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return o}});
3
- //# sourceMappingURL=core-Bx_1_H10.cjs.map