@field/cascade 0.10.0 → 0.12.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.
- package/AGENTS.md +25 -5
- package/ARCHITECTURE.md +5 -4
- package/CHANGELOG.md +382 -0
- package/README.md +1 -2
- package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
- package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
- package/dist/assets/{CodeEditor-DSZBpzdy.js → CodeEditor-C-xYG-Wn.js} +120 -120
- package/dist/assets/CodePanel-CtXd50m6.js +2 -0
- package/dist/assets/CookInfoPanel-B3NMhKJF.css +1 -0
- package/dist/assets/CookInfoPanel-DG4_TRsX.js +2 -0
- package/dist/assets/CustomNodeDialog-CHfZUs-r.js +1 -0
- package/dist/assets/DefinitionNode-CaRTXQ_b.js +1 -0
- package/dist/assets/DefinitionPanel-C3CxZY9r.js +1 -0
- package/dist/assets/DefinitionPanel-VNLnAiQD.css +1 -0
- package/dist/assets/OpenGraphDialog-BLdr6k_q.js +1 -0
- package/dist/assets/ProjectSettings-ZnvmIAir.js +2 -0
- package/dist/assets/{SettingsDialog-p25h3tj0.js → SettingsDialog-CBX3Wa87.js} +1 -1
- package/dist/assets/TimelinePanel-CDeR0arY.css +1 -0
- package/dist/assets/TimelinePanel-CWgnFH1e.js +1 -0
- package/dist/assets/{VersionHistoryDialog-DzFLUotB.js → VersionHistoryDialog-BOSoW1R-.js} +1 -1
- package/dist/assets/assert-BO2_erPD.js +1 -0
- package/dist/assets/assert-hvykGCnP.js +1 -0
- package/dist/assets/builder-BmBKcDix.js +1 -0
- package/dist/assets/camera-DFF7YA3F.js +1 -0
- package/dist/assets/checks-DAvyO9Gf.js +1 -0
- package/dist/assets/contactSheet-N1NcaWxw.js +2 -0
- package/dist/assets/{core-BICrEt0y.js → core-DB-MkGjj.js} +3 -4
- package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
- package/dist/assets/{cssMode-D7TXw57I.js → cssMode-DPVckSOc.js} +1 -1
- package/dist/assets/definitions-B227e7f_.js +1 -0
- package/dist/assets/definitions-D0WOUJd7.js +1 -0
- package/dist/assets/{editor.api-DvkCO3ko.js → editor.api-Dkutg_Z1.js} +1 -1
- package/dist/assets/expressions-X-Z-GrgW.js +5 -0
- package/dist/assets/file-DAL6IfjV.js +1 -0
- package/dist/assets/filters-D3k1LRMa.js +1 -0
- package/dist/assets/{freemarker2-BA2lxsF1.js → freemarker2-CLiLKk3B.js} +1 -1
- package/dist/assets/generators-BhDxRAFC.js +1 -0
- package/dist/assets/geo-BsMImJIJ.js +1 -0
- package/dist/assets/geo-C4YngDob.js +2 -0
- package/dist/assets/{handlebars-BcDiyPd8.js → handlebars-CcD3aMeL.js} +1 -1
- package/dist/assets/{html-C7O4TyhX.js → html-DvZWGfqb.js} +1 -1
- package/dist/assets/{htmlMode-WaDGF3Mj.js → htmlMode-DUD3VaoN.js} +1 -1
- package/dist/assets/image-0SfH-snh.js +1 -0
- package/dist/assets/image-Ck-RdGU4.js +2 -0
- package/dist/assets/index-BWnrmIB9.js +137 -0
- package/dist/assets/index-DIaxEONI.css +1 -0
- package/dist/assets/io-BGmt2g0D.js +1 -0
- package/dist/assets/{javascript-CpIEK7tz.js → javascript-Cap2ahgh.js} +1 -1
- package/dist/assets/{jsonMode-B2FltW0f.js → jsonMode-B0uLjp9C.js} +1 -1
- package/dist/assets/{liquid-CN6FFHZE.js → liquid-CnxwhfLn.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-QhV9XtLp.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
- package/dist/assets/math-GeULS-sk.js +1 -0
- package/dist/assets/{mdx-DE89pafV.js → mdx-BV3jbrVa.js} +1 -1
- package/dist/assets/pop-KMF_qloi.js +1 -0
- package/dist/assets/preload-helper-Czpn1I53.js +1 -0
- package/dist/assets/{python-ByTllTB9.js → python-CGyFk4XK.js} +1 -1
- package/dist/assets/{razor-USYlRRCE.js → razor-CQfzX3-N.js} +1 -1
- package/dist/assets/remap-5SjXQU-q.js +1 -0
- package/dist/assets/renderMarkdown-ork0Oir7.js +67 -0
- package/dist/assets/studioImages-CAyH-0Pl.js +1 -0
- package/dist/assets/text-ZpX7qNkx.js +2 -0
- package/dist/assets/time-P_OiBhcf.js +1 -0
- package/dist/assets/{tsMode-BXpN8iUz.js → tsMode-BOeXzO9H.js} +1 -1
- package/dist/assets/{typescript-DInBjGQQ.js → typescript-J1SnE_Tu.js} +1 -1
- package/dist/assets/{workers-C7Ye5B7D.js → workers-CYwwTiVF.js} +1 -1
- package/dist/assets/{xml-U0Uocqyo.js → xml-DnPRNzK9.js} +1 -1
- package/dist/assets/{yaml-CBw_PVYf.js → yaml-BmmYBNa9.js} +1 -1
- package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
- package/dist/cli/Graph-OB6EWSGL.js +2975 -0
- package/dist/cli/assert-GROGQNCQ.js +25 -0
- package/dist/cli/checks-3WB44XBL.js +189 -0
- package/dist/cli/chunk-2JEU3MGB.js +1125 -0
- package/dist/cli/chunk-2KXB47FP.js +115 -0
- package/dist/cli/chunk-3RXL5GHB.js +816 -0
- package/dist/cli/chunk-53LGFPWX.js +138 -0
- package/dist/cli/chunk-5ORUQ6ES.js +267 -0
- package/dist/cli/chunk-73S4JZXK.js +336 -0
- package/dist/cli/chunk-7QE2ZNSN.js +121 -0
- package/dist/cli/chunk-BP7UKF36.js +376 -0
- package/dist/cli/chunk-BPODRH52.js +201 -0
- package/dist/cli/chunk-BZ63XQ3I.js +1301 -0
- package/dist/cli/chunk-CKS2FQWR.js +89 -0
- package/dist/cli/chunk-CO22XHNG.js +593 -0
- package/dist/cli/chunk-CTPLRSWF.js +2197 -0
- package/dist/cli/chunk-DEQSEFFH.js +153 -0
- package/dist/cli/chunk-EU4ZFZ7Y.js +122 -0
- package/dist/cli/chunk-EZRWJ4G2.js +104 -0
- package/dist/cli/chunk-FWMSGKEH.js +71 -0
- package/dist/cli/chunk-G23A2BZZ.js +705 -0
- package/dist/cli/chunk-GRIN2DDP.js +1465 -0
- package/dist/cli/chunk-HFHWYL55.js +139 -0
- package/dist/cli/chunk-HSNOBIVT.js +263 -0
- package/dist/cli/chunk-ICH7N5PN.js +26 -0
- package/dist/cli/chunk-J7VK7MNF.js +418 -0
- package/dist/cli/chunk-JVOCK5W4.js +83 -0
- package/dist/cli/chunk-KBGUO27Q.js +15 -0
- package/dist/cli/chunk-KH4MUBKF.js +1551 -0
- package/dist/cli/chunk-L6B6FUQP.js +330 -0
- package/dist/cli/chunk-LTXWBXOM.js +438 -0
- package/dist/cli/chunk-MI5JLQYA.js +220 -0
- package/dist/cli/chunk-MP653A5O.js +3766 -0
- package/dist/cli/chunk-NJFMDXHR.js +320 -0
- package/dist/cli/chunk-OM6BEME6.js +267 -0
- package/dist/cli/chunk-OWWBYLHC.js +136 -0
- package/dist/cli/chunk-QQPA2ZHH.js +273 -0
- package/dist/cli/chunk-RUU3YWXU.js +99 -0
- package/dist/cli/chunk-RXDIMXN5.js +98 -0
- package/dist/cli/chunk-ST6LROUG.js +267 -0
- package/dist/cli/chunk-TJW67QSI.js +225 -0
- package/dist/cli/chunk-WD62JIP6.js +118 -0
- package/dist/cli/chunk-WGKPJZDY.js +364 -0
- package/dist/cli/chunk-X4WKAOQP.js +634 -0
- package/dist/cli/chunk-X566FWBV.js +156 -0
- package/dist/cli/chunk-YH637PDL.js +317 -0
- package/dist/cli/chunk-ZL4JTG5Y.js +37 -0
- package/dist/cli/chunk-ZSCUZE6I.js +112 -0
- package/dist/cli/cliCommands-JJN5Z3ZC.js +3470 -0
- package/dist/cli/commands-PHYFYA3F.js +1374 -0
- package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
- package/dist/cli/definitions-BPOPW52L.js +32 -0
- package/dist/cli/doctorCommand-ORWQRNYP.js +106 -0
- package/dist/cli/edit-S5KEQ5RA.js +28 -0
- package/dist/cli/editorCommands-NFR32JOY.js +41 -0
- package/dist/cli/encode-ICPEPMH5.js +17 -0
- package/dist/cli/file-3HTQHPYQ.js +41 -0
- package/dist/cli/filters-6ODFWYK4.js +379 -0
- package/dist/cli/frames-LSAUBZ7P.js +16 -0
- package/dist/cli/generators-YU7GB4MD.js +210 -0
- package/dist/cli/geo-6ZPGKZRU.js +43 -0
- package/dist/cli/graphCommands-EOUOBOIJ.js +184 -0
- package/dist/cli/graphFile-YTGJB5F5.js +292 -0
- package/dist/cli/headlessCanvas-ENRHC7GS.js +16 -0
- package/dist/cli/helpCommand-PULH6ZYB.js +157 -0
- package/dist/cli/image-TXELZZK5.js +55 -0
- package/dist/cli/index.js +100 -30756
- package/dist/cli/math-RSYRQ3C6.js +16 -0
- package/dist/cli/mcp-JVZFQOEX.js +164 -0
- package/dist/cli/parity-X6DEH2DV.js +334 -0
- package/dist/cli/pop-B7SIIYKN.js +39 -0
- package/dist/cli/project-VYGIA7JX.js +12 -0
- package/dist/cli/projectDefinition-F3D7UIHJ.js +27 -0
- package/dist/cli/projectRuntime-2Q4JKEH3.js +55 -0
- package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
- package/dist/cli/render-PT4MWI6U.js +438 -0
- package/dist/cli/runCommand-HNPQVZMS.js +198 -0
- package/dist/cli/runner-5XPXVW7J.js +43 -0
- package/dist/cli/runtime/image.ts +302 -0
- package/dist/cli/runtime/io.ts +78 -0
- package/dist/cli/runtime/stage.ts +4 -1
- package/dist/cli/share-MHF6TNRK.js +166 -0
- package/dist/cli/stageCache-TY2BFZJR.js +15 -0
- package/dist/cli/stageRunner-KY2EJP7X.js +10 -0
- package/dist/cli/text-MB3EKR4H.js +126 -0
- package/dist/cli/verbs-PI2JH5FI.js +19 -0
- package/dist/cli/webBuild-WPPMGGW7.js +44 -0
- package/dist/contracts/capabilities.d.ts +18 -1
- package/dist/contracts/color.d.ts +8 -0
- package/dist/contracts/color.js +23 -0
- package/dist/contracts/definition.d.ts +10 -0
- package/dist/contracts/documentFormat.d.ts +18 -0
- package/dist/contracts/documentFormat.js +195 -0
- package/dist/contracts/editor.d.ts +17 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/schema.d.ts +1 -1
- package/dist/contracts/schema.js +1 -0
- package/dist/contracts/validate.js +11 -1
- package/dist/contracts/values.d.ts +24 -0
- package/dist/image.d.ts +156 -0
- package/dist/image.js +161 -0
- package/dist/index.html +8 -2
- package/dist/io.d.ts +29 -0
- package/dist/io.js +40 -0
- package/dist/player/app.js +3 -2
- package/dist/player/editor.js +35 -9
- package/dist/player/editorEngine.js +3 -2
- package/dist/runtime/builtins/assert/checks.d.ts +18 -0
- package/dist/runtime/builtins/assert/checks.js +207 -0
- package/dist/runtime/builtins/assert/definitions.d.ts +130 -0
- package/dist/runtime/builtins/assert/definitions.js +54 -0
- package/dist/runtime/builtins/assert/index.d.ts +152 -0
- package/dist/runtime/builtins/assert/index.js +36 -0
- package/dist/runtime/builtins/image/contactSheet.d.ts +64 -0
- package/dist/runtime/builtins/image/contactSheet.js +150 -0
- package/dist/runtime/builtins/image/definitions.d.ts +950 -0
- package/dist/runtime/builtins/image/definitions.js +343 -0
- package/dist/runtime/builtins/image/file.d.ts +8 -0
- package/dist/runtime/builtins/image/file.js +37 -0
- package/dist/runtime/builtins/image/filters.d.ts +8 -0
- package/dist/runtime/builtins/image/filters.js +394 -0
- package/dist/runtime/builtins/image/generators.d.ts +7 -0
- package/dist/runtime/builtins/image/generators.js +144 -0
- package/dist/runtime/builtins/image/index.d.ts +952 -0
- package/dist/runtime/builtins/image/index.js +44 -0
- package/dist/runtime/builtins/image/io.d.ts +100 -0
- package/dist/runtime/builtins/image/io.js +142 -0
- package/dist/runtime/builtins/image/planar.d.ts +55 -0
- package/dist/runtime/builtins/image/planar.js +274 -0
- package/dist/runtime/builtins/image/simplex.d.ts +22 -0
- package/dist/runtime/builtins/image/simplex.js +92 -0
- package/dist/runtime/builtins/image/text.d.ts +4 -0
- package/dist/runtime/builtins/image/text.js +141 -0
- package/dist/runtime/builtins/index.d.ts +3 -0
- package/dist/runtime/builtins/index.js +7 -0
- package/dist/runtime/gpu.d.ts +25 -0
- package/dist/runtime/gpu.js +40 -0
- package/dist/runtime/runtime.d.ts +2 -0
- package/dist/runtime/runtime.js +268 -44
- package/dist/runtime/types.d.ts +30 -0
- package/dist/stage.js +4 -1
- package/doc/CLI_REFERENCE.md +91 -2
- package/doc/EDITOR_EXPORT.md +37 -2
- package/doc/MCP.md +18 -1
- package/doc/NODE_REFERENCE.md +424 -10
- package/doc/PROJECT_AUTHORING.md +222 -7
- package/package.json +19 -4
- package/dist/assets/CodePanel-sY6sZa7B.js +0 -2
- package/dist/assets/CustomNodeDialog-BRKnqZhp.js +0 -1
- package/dist/assets/ExportDialog-C7dVGua4.js +0 -358
- package/dist/assets/ExportDialog-DOq0flMV.css +0 -1
- package/dist/assets/OpenGraphDialog-ZsgL-iwr.js +0 -1
- package/dist/assets/ProjectSettings-Cw17nNe3.js +0 -2
- package/dist/assets/definitions-DUww2Rt-.js +0 -1
- package/dist/assets/geo-C2RHOVHC.js +0 -1
- package/dist/assets/image-DR4oeyJB.js +0 -2062
- package/dist/assets/index-7vae6YFC.css +0 -1
- package/dist/assets/index-DyvDC6pS.js +0 -219
- package/dist/assets/math-DaDEgWKt.js +0 -1
- package/dist/assets/pop-pLH7L0PW.js +0 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isGeometrySerialized
|
|
3
|
+
} from "./chunk-J7VK7MNF.js";
|
|
4
|
+
import {
|
|
5
|
+
CORE_TYPES
|
|
6
|
+
} from "./chunk-FWMSGKEH.js";
|
|
7
|
+
|
|
8
|
+
// packages/contracts/src/validate.ts
|
|
9
|
+
var IDENTIFIER = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
10
|
+
var NAMESPACED = /^[a-z][a-z0-9-]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/;
|
|
11
|
+
var RESERVED = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
12
|
+
var CORE = new Set(CORE_TYPES);
|
|
13
|
+
var CONTROLS = /* @__PURE__ */ new Set(["number", "slider", "range", "int", "boolean", "text", "textarea", "select", "vector", "matrix", "color", "image", "asset"]);
|
|
14
|
+
var CAPABILITIES_BY_ENVIRONMENT = {
|
|
15
|
+
portable: ["assets", "media", "gpu"],
|
|
16
|
+
browser: ["assets", "media", "gpu"],
|
|
17
|
+
server: ["files", "assets", "media", "python", "shell", "gpu"]
|
|
18
|
+
};
|
|
19
|
+
var ALLOWED = CAPABILITIES_BY_ENVIRONMENT;
|
|
20
|
+
var fields = (names) => new Set(names.split(" "));
|
|
21
|
+
var TOP_FIELDS = fields(
|
|
22
|
+
"apiVersion runsOn container capabilities gpuLimits source label description icon inputs outputs props"
|
|
23
|
+
);
|
|
24
|
+
var DATA_FIELDS = fields(
|
|
25
|
+
"kind type default description variadic min max step accept control options schema fields"
|
|
26
|
+
);
|
|
27
|
+
var OUTPUT_FIELDS = fields("kind type description schema fields");
|
|
28
|
+
var PROP_FIELDS = fields(
|
|
29
|
+
"type default label description min max step accept control options expression action"
|
|
30
|
+
);
|
|
31
|
+
function diagnostic(code, message, path) {
|
|
32
|
+
return { phase: "definition", code: `definition/${code}`, message, path };
|
|
33
|
+
}
|
|
34
|
+
function isRecord(value) {
|
|
35
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36
|
+
}
|
|
37
|
+
function validType(type) {
|
|
38
|
+
return typeof type === "string" && (CORE.has(type) || NAMESPACED.test(type));
|
|
39
|
+
}
|
|
40
|
+
function finiteJson(value) {
|
|
41
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
42
|
+
return true;
|
|
43
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
44
|
+
if (Array.isArray(value)) return value.every(finiteJson);
|
|
45
|
+
return isRecord(value) && Object.values(value).every(finiteJson);
|
|
46
|
+
}
|
|
47
|
+
function unknownFields(value, allowed, path) {
|
|
48
|
+
return Object.keys(value).filter((key) => !allowed.has(key)).map(
|
|
49
|
+
(key) => diagnostic(
|
|
50
|
+
"unknown-field",
|
|
51
|
+
`${path}.${key} is not allowed`,
|
|
52
|
+
`${path}.${key}`
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
function defaultMatches(type, value) {
|
|
57
|
+
if (!finiteJson(value)) return false;
|
|
58
|
+
if (type === "geometry") return isGeometrySerialized(value);
|
|
59
|
+
if (type === "float") return typeof value === "number";
|
|
60
|
+
if (type === "int") return typeof value === "number";
|
|
61
|
+
if (type === "bool") return typeof value === "boolean";
|
|
62
|
+
if (type === "string") return typeof value === "string";
|
|
63
|
+
const lengths = {
|
|
64
|
+
vec2: 2,
|
|
65
|
+
vec3: 3,
|
|
66
|
+
vec4: 4,
|
|
67
|
+
vec2i: 2,
|
|
68
|
+
vec3i: 3,
|
|
69
|
+
vec4i: 4,
|
|
70
|
+
mat2: 4,
|
|
71
|
+
mat3: 9,
|
|
72
|
+
mat4: 16,
|
|
73
|
+
color: 4
|
|
74
|
+
};
|
|
75
|
+
const length = lengths[type];
|
|
76
|
+
return length === void 0 || Array.isArray(value) && value.length === length && value.every(
|
|
77
|
+
(item) => type.endsWith("i") ? Number.isInteger(item) : typeof item === "number"
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function validateNodeDefinition(value) {
|
|
81
|
+
if (!isRecord(value))
|
|
82
|
+
return [diagnostic("not-object", "Definition must be an object")];
|
|
83
|
+
const result = unknownFields(value, TOP_FIELDS, "definition");
|
|
84
|
+
const add = (code, message, path) => result.push(diagnostic(code, message, path));
|
|
85
|
+
const environment = value.runsOn;
|
|
86
|
+
if (value.apiVersion !== 1)
|
|
87
|
+
add("api-version", "apiVersion must be 1", "apiVersion");
|
|
88
|
+
if (!Object.prototype.hasOwnProperty.call(ALLOWED, String(environment)))
|
|
89
|
+
add("environment", "runsOn must be portable, browser, or server", "runsOn");
|
|
90
|
+
if (value.container !== void 0 && value.container !== "subnet" && value.container !== "feedback")
|
|
91
|
+
add("invalid-container", "container must be subnet or feedback", "container");
|
|
92
|
+
if (value.source !== void 0 && value.source !== "live")
|
|
93
|
+
add("invalid-source", 'source must be "live" when present', "source");
|
|
94
|
+
const allowed = ALLOWED[environment] ?? [];
|
|
95
|
+
if (value.capabilities !== void 0 && !Array.isArray(value.capabilities))
|
|
96
|
+
add(
|
|
97
|
+
"invalid-capabilities",
|
|
98
|
+
"capabilities must be an array",
|
|
99
|
+
"capabilities"
|
|
100
|
+
);
|
|
101
|
+
const seen = /* @__PURE__ */ new Set();
|
|
102
|
+
for (const [index, capability] of (Array.isArray(value.capabilities) ? value.capabilities : []).entries()) {
|
|
103
|
+
const path = `capabilities.${index}`;
|
|
104
|
+
if (!seen.has(capability) && !allowed.includes(capability))
|
|
105
|
+
add(
|
|
106
|
+
"capability-not-allowed",
|
|
107
|
+
`${String(capability)} is not available on ${String(environment)}`,
|
|
108
|
+
path
|
|
109
|
+
);
|
|
110
|
+
if (seen.has(capability))
|
|
111
|
+
add("duplicate-capability", `${String(capability)} is duplicated`, path);
|
|
112
|
+
seen.add(capability);
|
|
113
|
+
}
|
|
114
|
+
if (value.gpuLimits !== void 0) {
|
|
115
|
+
if (!seen.has("gpu"))
|
|
116
|
+
add("gpu-limits-without-gpu", "gpuLimits needs the gpu capability", "gpuLimits");
|
|
117
|
+
if (!isRecord(value.gpuLimits))
|
|
118
|
+
add("invalid-gpu-limits", "gpuLimits must be an object of WebGPU limit names to numbers", "gpuLimits");
|
|
119
|
+
else
|
|
120
|
+
for (const [name, limit] of Object.entries(value.gpuLimits))
|
|
121
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit < 0)
|
|
122
|
+
add("invalid-gpu-limits", `gpuLimits.${name} must be a non-negative number`, `gpuLimits.${name}`);
|
|
123
|
+
}
|
|
124
|
+
const inward = /* @__PURE__ */ new Map();
|
|
125
|
+
const outward = /* @__PURE__ */ new Map();
|
|
126
|
+
for (const section of ["inputs", "outputs", "props"]) {
|
|
127
|
+
const entries = value[section];
|
|
128
|
+
if (entries === void 0) continue;
|
|
129
|
+
if (!isRecord(entries)) {
|
|
130
|
+
add("invalid-section", `${section} must be an object`, section);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
for (const [name, raw] of Object.entries(entries)) {
|
|
134
|
+
const path = `${section}.${name}`;
|
|
135
|
+
if (!IDENTIFIER.test(name))
|
|
136
|
+
add("invalid-name", `${name} is not a valid identifier`, path);
|
|
137
|
+
if (RESERVED.has(name)) add("reserved-name", `${name} is reserved`, path);
|
|
138
|
+
const names = section === "outputs" ? outward : inward;
|
|
139
|
+
const previous = names.get(name);
|
|
140
|
+
if (previous)
|
|
141
|
+
add(
|
|
142
|
+
"name-collision",
|
|
143
|
+
`${name} is declared in ${previous} and ${section}`,
|
|
144
|
+
path
|
|
145
|
+
);
|
|
146
|
+
else names.set(name, section);
|
|
147
|
+
if (!isRecord(raw)) {
|
|
148
|
+
add("invalid-entry", `${path} must be an object`, path);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const fields2 = section === "props" ? PROP_FIELDS : section === "outputs" ? OUTPUT_FIELDS : DATA_FIELDS;
|
|
152
|
+
if (section !== "props" && raw.kind !== "data" && raw.kind !== "trigger") {
|
|
153
|
+
add(
|
|
154
|
+
"invalid-kind",
|
|
155
|
+
`${path}.kind must be data or trigger`,
|
|
156
|
+
`${path}.kind`
|
|
157
|
+
);
|
|
158
|
+
result.push(...unknownFields(raw, fields2, path));
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (section !== "props" && raw.kind === "trigger") {
|
|
162
|
+
if (Object.keys(raw).some(
|
|
163
|
+
(key) => key !== "kind" && key !== "description"
|
|
164
|
+
))
|
|
165
|
+
add(
|
|
166
|
+
"trigger-extra",
|
|
167
|
+
"Trigger ports allow only kind and description",
|
|
168
|
+
path
|
|
169
|
+
);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
result.push(...unknownFields(raw, fields2, path));
|
|
173
|
+
if ("control" in raw && (typeof raw.control !== "string" || !CONTROLS.has(raw.control)))
|
|
174
|
+
add(
|
|
175
|
+
"invalid-control",
|
|
176
|
+
`${String(raw.control)} is not a Cascade control`,
|
|
177
|
+
`${path}.control`
|
|
178
|
+
);
|
|
179
|
+
if ("options" in raw && raw.control !== "select")
|
|
180
|
+
add(
|
|
181
|
+
"options-without-select",
|
|
182
|
+
"options require the select control",
|
|
183
|
+
`${path}.options`
|
|
184
|
+
);
|
|
185
|
+
if (Array.isArray(raw.options))
|
|
186
|
+
for (const [index, option] of raw.options.entries()) {
|
|
187
|
+
if (option === null || typeof option !== "object") continue;
|
|
188
|
+
const entry = option;
|
|
189
|
+
if (!("value" in entry))
|
|
190
|
+
add(
|
|
191
|
+
"invalid-option",
|
|
192
|
+
"a labelled option needs a value",
|
|
193
|
+
`${path}.options[${index}]`
|
|
194
|
+
);
|
|
195
|
+
if (typeof entry.label !== "string" || !entry.label)
|
|
196
|
+
add(
|
|
197
|
+
"invalid-option",
|
|
198
|
+
"a labelled option needs a non-empty label",
|
|
199
|
+
`${path}.options[${index}].label`
|
|
200
|
+
);
|
|
201
|
+
if ("disabled" in entry && typeof entry.disabled !== "boolean")
|
|
202
|
+
add(
|
|
203
|
+
"invalid-option",
|
|
204
|
+
"disabled must be a boolean",
|
|
205
|
+
`${path}.options[${index}].disabled`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
const type = raw.type;
|
|
209
|
+
if (!validType(type)) {
|
|
210
|
+
add(
|
|
211
|
+
"invalid-type",
|
|
212
|
+
`${String(type)} is not a Cascade type`,
|
|
213
|
+
`${path}.type`
|
|
214
|
+
);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (section !== "props") result.push(...bundleDiagnostics(raw, type, section, path));
|
|
218
|
+
if (type === "texture" && environment !== "browser")
|
|
219
|
+
add("texture-not-portable", "texture is browser-only", `${path}.type`);
|
|
220
|
+
if (type === "texture" && "default" in raw)
|
|
221
|
+
add(
|
|
222
|
+
"texture-default",
|
|
223
|
+
"texture cannot have a default",
|
|
224
|
+
`${path}.default`
|
|
225
|
+
);
|
|
226
|
+
if (section === "props" && !("default" in raw))
|
|
227
|
+
add("missing-default", "Props require defaults", `${path}.default`);
|
|
228
|
+
if ("default" in raw && !finiteJson(raw.default))
|
|
229
|
+
add(
|
|
230
|
+
"invalid-default",
|
|
231
|
+
"Default must be finite JSON",
|
|
232
|
+
`${path}.default`
|
|
233
|
+
);
|
|
234
|
+
else if ("default" in raw && !defaultMatches(type, raw.default))
|
|
235
|
+
add(
|
|
236
|
+
"default-type",
|
|
237
|
+
`Default does not match ${type}`,
|
|
238
|
+
`${path}.default`
|
|
239
|
+
);
|
|
240
|
+
if (type === "int" && "default" in raw && (!Number.isFinite(raw.default) || !Number.isInteger(raw.default)))
|
|
241
|
+
add(
|
|
242
|
+
"non-integer",
|
|
243
|
+
"Integer defaults must be finite integers",
|
|
244
|
+
`${path}.default`
|
|
245
|
+
);
|
|
246
|
+
if ("step" in raw && (typeof raw.step !== "number" || !Number.isFinite(raw.step) || raw.step <= 0))
|
|
247
|
+
add("invalid-step", "step must be greater than zero", `${path}.step`);
|
|
248
|
+
if (section === "props" && "expression" in raw && (typeof raw.expression !== "string" || raw.expression.length === 0))
|
|
249
|
+
add(
|
|
250
|
+
"invalid-expression",
|
|
251
|
+
"expression must be a non-empty string",
|
|
252
|
+
`${path}.expression`
|
|
253
|
+
);
|
|
254
|
+
for (const field of ["min", "max"]) {
|
|
255
|
+
if (field in raw && (typeof raw[field] !== "number" || !Number.isFinite(raw[field])))
|
|
256
|
+
add(
|
|
257
|
+
`invalid-${field}`,
|
|
258
|
+
`${field} must be a finite number`,
|
|
259
|
+
`${path}.${field}`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
if (typeof raw.min === "number" && typeof raw.max === "number" && raw.min > raw.max)
|
|
263
|
+
add("invalid-range", "min must not exceed max", path);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
function bundleDiagnostics(raw, type, section, path) {
|
|
269
|
+
const result = [];
|
|
270
|
+
const add = (code, message, at) => result.push(diagnostic(code, message, at));
|
|
271
|
+
for (const key of ["schema", "fields"])
|
|
272
|
+
if (key in raw && type !== "bundle")
|
|
273
|
+
add("bundle-metadata", `${key} is only valid on a bundle port`, `${path}.${key}`);
|
|
274
|
+
if (type !== "bundle") return result;
|
|
275
|
+
if ("schema" in raw && (typeof raw.schema !== "string" || !IDENTIFIER.test(raw.schema)))
|
|
276
|
+
add("invalid-schema", "schema must be an identifier", `${path}.schema`);
|
|
277
|
+
if (!("fields" in raw)) return result;
|
|
278
|
+
const declared = raw.fields;
|
|
279
|
+
if (section === "inputs") {
|
|
280
|
+
if (!Array.isArray(declared)) {
|
|
281
|
+
add("invalid-fields", "an input's fields list the field names it reads", `${path}.fields`);
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
const seen = /* @__PURE__ */ new Set();
|
|
285
|
+
for (const [index, field] of declared.entries()) {
|
|
286
|
+
if (typeof field !== "string" || !IDENTIFIER.test(field))
|
|
287
|
+
add("invalid-field", `${String(field)} is not a valid field name`, `${path}.fields[${index}]`);
|
|
288
|
+
else if (seen.has(field))
|
|
289
|
+
add("duplicate-field", `${field} is listed twice`, `${path}.fields[${index}]`);
|
|
290
|
+
else seen.add(field);
|
|
291
|
+
}
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
if (!isRecord(declared)) {
|
|
295
|
+
add("invalid-fields", "an output's fields map each field name to its type", `${path}.fields`);
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
298
|
+
for (const [field, definition] of Object.entries(declared)) {
|
|
299
|
+
const at = `${path}.fields.${field}`;
|
|
300
|
+
if (!IDENTIFIER.test(field) || RESERVED.has(field))
|
|
301
|
+
add("invalid-field", `${field} is not a valid field name`, at);
|
|
302
|
+
const fieldType = typeof definition === "string" ? definition : isRecord(definition) ? definition.type : void 0;
|
|
303
|
+
if (isRecord(definition)) {
|
|
304
|
+
for (const key of Object.keys(definition))
|
|
305
|
+
if (key !== "type" && key !== "description")
|
|
306
|
+
add("unknown-field", `${at}.${key} is not allowed`, `${at}.${key}`);
|
|
307
|
+
}
|
|
308
|
+
if (!validType(fieldType))
|
|
309
|
+
add("invalid-type", `${String(fieldType)} is not a Cascade type`, at);
|
|
310
|
+
else if (fieldType === "texture")
|
|
311
|
+
add("texture-not-portable", "a bundle field cannot hold a texture", at);
|
|
312
|
+
}
|
|
313
|
+
return result;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export {
|
|
317
|
+
CAPABILITIES_BY_ENVIRONMENT,
|
|
318
|
+
validateNodeDefinition
|
|
319
|
+
};
|
|
320
|
+
//# sourceMappingURL=chunk-NJFMDXHR.js.map
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createRuntime,
|
|
3
|
+
moduleId,
|
|
4
|
+
projectModuleFile,
|
|
5
|
+
validateNodeModuleArchitecture
|
|
6
|
+
} from "./chunk-MP653A5O.js";
|
|
7
|
+
import {
|
|
8
|
+
builtinNodeRegistration
|
|
9
|
+
} from "./chunk-MI5JLQYA.js";
|
|
10
|
+
import {
|
|
11
|
+
ProjectRoot,
|
|
12
|
+
extractNodeDefinition
|
|
13
|
+
} from "./chunk-2JEU3MGB.js";
|
|
14
|
+
|
|
15
|
+
// src/cli/webBuild.ts
|
|
16
|
+
import fs from "node:fs/promises";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { builtinModules } from "node:module";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
import { build } from "esbuild";
|
|
21
|
+
import ts from "typescript";
|
|
22
|
+
|
|
23
|
+
// packages/runtime/src/browser.ts
|
|
24
|
+
function createBrowserRuntimeHost(options) {
|
|
25
|
+
const {
|
|
26
|
+
modules,
|
|
27
|
+
legacyShell,
|
|
28
|
+
now = () => Date.now(),
|
|
29
|
+
report = () => {
|
|
30
|
+
},
|
|
31
|
+
...capabilities
|
|
32
|
+
} = options;
|
|
33
|
+
return {
|
|
34
|
+
environment: "browser",
|
|
35
|
+
modules,
|
|
36
|
+
legacyShell,
|
|
37
|
+
capabilities,
|
|
38
|
+
now,
|
|
39
|
+
report
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/cli/webBuild.ts
|
|
44
|
+
var installRoot = fileURLToPath(new URL("../../", import.meta.url));
|
|
45
|
+
var forbiddenModules = new Set(builtinModules.map((name) => name.replace(/^node:/, "")));
|
|
46
|
+
async function buildPlayer(file, options) {
|
|
47
|
+
if (!options.out) throw new Error("cascade build requires --out <new-directory>");
|
|
48
|
+
const project = new ProjectRoot(path.dirname(path.resolve(file)));
|
|
49
|
+
const out = path.resolve(project.root, options.out);
|
|
50
|
+
if (await exists(out)) throw new Error(`Player output already exists: ${out}. Choose a new directory.`);
|
|
51
|
+
const canonicalOut = await canonicalFuturePath(out);
|
|
52
|
+
for (const sourceDirectory of ["assets", "nodes"]) {
|
|
53
|
+
const sourceRoot = await canonicalFuturePath(path.join(project.root, sourceDirectory));
|
|
54
|
+
if (inside(sourceRoot, canonicalOut)) {
|
|
55
|
+
throw new Error(`Player output cannot be inside the project's ${sourceDirectory} directory`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const document = JSON.parse(await fs.readFile(file, "utf8"));
|
|
59
|
+
if (!Array.isArray(document.nodes)) throw new Error("Graph document must contain a nodes array");
|
|
60
|
+
const modules = [];
|
|
61
|
+
const seen = /* @__PURE__ */ new Set();
|
|
62
|
+
for (const node of document.nodes) {
|
|
63
|
+
const id = moduleId(node);
|
|
64
|
+
if (seen.has(id)) continue;
|
|
65
|
+
seen.add(id);
|
|
66
|
+
if (builtinNodeRegistration(id)) continue;
|
|
67
|
+
const resolved = await projectModuleFile(project.root, node, id);
|
|
68
|
+
if (!resolved.file) throw new Error(`${id}: no supported static project module (${resolved.tried.join(", ")})`);
|
|
69
|
+
const sourceFile = project.resolve(path.relative(project.root, resolved.file));
|
|
70
|
+
const source = await fs.readFile(sourceFile, "utf8");
|
|
71
|
+
const extracted = extractNodeDefinition(source, sourceFile, ts);
|
|
72
|
+
if (!extracted.ok) throw new Error(`${id}: static browser builds require definition-v1
|
|
73
|
+
${extracted.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")}`);
|
|
74
|
+
const diagnostics = validateNodeModuleArchitecture(source, sourceFile, ts);
|
|
75
|
+
if (diagnostics.length) throw new Error(diagnostics.map((d) => `${id}: ${d.code}: ${d.message}`).join("\n"));
|
|
76
|
+
modules.push({ id, file: sourceFile, definition: extracted.definition });
|
|
77
|
+
}
|
|
78
|
+
const registrations = modules.map((item) => ({
|
|
79
|
+
kind: "definition-v1",
|
|
80
|
+
moduleId: item.id,
|
|
81
|
+
definition: item.definition,
|
|
82
|
+
loadExecute: async () => {
|
|
83
|
+
throw new Error("Static builds never execute project code");
|
|
84
|
+
}
|
|
85
|
+
}));
|
|
86
|
+
const runtime = createRuntime({ host: createBrowserRuntimeHost({
|
|
87
|
+
modules: { resolve: async (id) => registrations.find((item) => item.moduleId === id) ?? null },
|
|
88
|
+
// Presence describes the exported player contract, not this Node process.
|
|
89
|
+
assets: {},
|
|
90
|
+
gpu: {}
|
|
91
|
+
}), nodes: registrations });
|
|
92
|
+
const assets = new Set(options.assets ?? []);
|
|
93
|
+
try {
|
|
94
|
+
const graph = await runtime.load(document);
|
|
95
|
+
const diagnostics = graph.preflight();
|
|
96
|
+
if (diagnostics.length) throw new Error(`This graph cannot be exported to the browser player:
|
|
97
|
+
${diagnostics.map((d) => `${d.path ?? ""} ${d.code}: ${d.message}`).join("\n")}`);
|
|
98
|
+
for (const node of graph.inspect().nodes) {
|
|
99
|
+
for (const port of [...Object.values(node.inputs), ...Object.values(node.props)]) {
|
|
100
|
+
if (port.type !== "image" && port.type !== "asset") continue;
|
|
101
|
+
const value = port.value;
|
|
102
|
+
const asset = typeof value === "string" ? value : value && typeof value === "object" && "path" in value ? value.path : void 0;
|
|
103
|
+
if (typeof asset === "string" && asset && !/^(https?:|data:|blob:)/.test(asset)) assets.add(asset);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} finally {
|
|
107
|
+
await runtime.dispose();
|
|
108
|
+
}
|
|
109
|
+
const sources = [];
|
|
110
|
+
for (const asset of assets) {
|
|
111
|
+
const name = asset.replace(/^\.\//, "");
|
|
112
|
+
if (!name || name.includes("\\") || name.split("/").some((part) => !part || part.startsWith(".")) || path.isAbsolute(name)) {
|
|
113
|
+
throw new Error(`Asset must be a visible project-relative file: ${asset}`);
|
|
114
|
+
}
|
|
115
|
+
const source = project.resolve(name);
|
|
116
|
+
if (!(await fs.stat(source)).isFile()) throw new Error(`Asset is not a file: ${asset}`);
|
|
117
|
+
sources.push({ name, file: source });
|
|
118
|
+
}
|
|
119
|
+
const playerApp = await playerFile("app");
|
|
120
|
+
const playerEmbed = await playerFile("embed");
|
|
121
|
+
const plugins = [await staticRuntimePlugin(project.root)];
|
|
122
|
+
const imports = modules.map((item, index) => `import { execute as execute${index} } from ${JSON.stringify(item.file)};`).join("\n");
|
|
123
|
+
const registrationSource = modules.map((item, index) => `{ kind:'definition-v1', moduleId:${JSON.stringify(item.id)}, definition:${JSON.stringify(item.definition)}, loadExecute:async()=>execute${index} }`).join(",");
|
|
124
|
+
const assetSource = sources.map((item) => `${JSON.stringify(item.name)}:new URL(${JSON.stringify(`./assets/${item.name.split("/").map(encodeURIComponent).join("/")}`)},import.meta.url).href`).join(",");
|
|
125
|
+
const appSource = `import { startPlayer } from ${JSON.stringify(playerApp)};
|
|
126
|
+
${imports}
|
|
127
|
+
window.cascadePlayerReady = startPlayer({document:${JSON.stringify(document)},registrations:[${registrationSource}],assets:{${assetSource}}});
|
|
128
|
+
window.cascadePlayerReady.catch(error=>{const message=document.createElement('pre');message.textContent=String(error?.message??error);document.body.append(message);});`;
|
|
129
|
+
const embedSource = `import { mountPlayer } from ${JSON.stringify(playerEmbed)};
|
|
130
|
+
export function mount(container,options={}) { return mountPlayer(container,{...options,url:new URL('./player.html',import.meta.url)}); }`;
|
|
131
|
+
const common = {
|
|
132
|
+
bundle: true,
|
|
133
|
+
platform: "browser",
|
|
134
|
+
format: "esm",
|
|
135
|
+
target: "es2022",
|
|
136
|
+
write: false,
|
|
137
|
+
minify: true,
|
|
138
|
+
logLevel: "silent",
|
|
139
|
+
plugins
|
|
140
|
+
};
|
|
141
|
+
const app = await build({ ...common, stdin: { contents: appSource, resolveDir: project.root, sourcefile: "player-entry.js" } });
|
|
142
|
+
const embed = await build({ ...common, stdin: { contents: embedSource, resolveDir: project.root, sourcefile: "embed-entry.js" } });
|
|
143
|
+
await fs.mkdir(path.dirname(out), { recursive: true });
|
|
144
|
+
const staging = await fs.mkdtemp(path.join(path.dirname(out), ".cascade-player-"));
|
|
145
|
+
try {
|
|
146
|
+
const html = '<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Cascade</title><style>html,body{margin:0;width:100%;height:100%;overflow:hidden}body{font:13px system-ui}pre{white-space:pre-wrap;padding:16px}</style></head><body><script type="module" src="./app.js"></script></body></html>';
|
|
147
|
+
await fs.writeFile(path.join(staging, "index.html"), html);
|
|
148
|
+
await fs.writeFile(path.join(staging, "player.html"), html);
|
|
149
|
+
await fs.writeFile(path.join(staging, "app.js"), app.outputFiles[0].contents);
|
|
150
|
+
await fs.writeFile(path.join(staging, "embed.js"), embed.outputFiles[0].contents);
|
|
151
|
+
for (const source of sources) {
|
|
152
|
+
const target = path.join(staging, "assets", source.name);
|
|
153
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
154
|
+
await fs.copyFile(source.file, target);
|
|
155
|
+
}
|
|
156
|
+
await fs.mkdir(out);
|
|
157
|
+
try {
|
|
158
|
+
for (const entry of await fs.readdir(staging)) await fs.rename(path.join(staging, entry), path.join(out, entry));
|
|
159
|
+
} catch (error) {
|
|
160
|
+
await fs.rm(out, { recursive: true, force: true });
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
} finally {
|
|
164
|
+
await fs.rm(staging, { recursive: true, force: true });
|
|
165
|
+
}
|
|
166
|
+
return { directory: out };
|
|
167
|
+
}
|
|
168
|
+
async function playerFile(name) {
|
|
169
|
+
const source = path.join(installRoot, "src", "player", `${name}.ts`);
|
|
170
|
+
return await exists(source) ? source : path.join(installRoot, "dist", "player", `${name}.js`);
|
|
171
|
+
}
|
|
172
|
+
async function staticRuntimePlugin(projectRoot) {
|
|
173
|
+
const manifest = JSON.parse(await fs.readFile(path.join(installRoot, "package.json"), "utf8"));
|
|
174
|
+
const canonicalProjectRoot = await fs.realpath(projectRoot);
|
|
175
|
+
const confinementMarker = /* @__PURE__ */ Symbol("cascade-player-confinement");
|
|
176
|
+
return { name: "cascade-static-player", setup(builder) {
|
|
177
|
+
builder.onResolve({ filter: /.*/ }, async (args) => {
|
|
178
|
+
const marked = typeof args.pluginData === "object" && args.pluginData !== null && args.pluginData[confinementMarker] === true;
|
|
179
|
+
if (!marked && isFilesystemImport(args.path) && await importerIsInProject(args.importer, canonicalProjectRoot)) {
|
|
180
|
+
const resolved = await builder.resolve(args.path, {
|
|
181
|
+
importer: args.importer,
|
|
182
|
+
resolveDir: args.resolveDir,
|
|
183
|
+
kind: args.kind,
|
|
184
|
+
pluginData: { [confinementMarker]: true }
|
|
185
|
+
});
|
|
186
|
+
if (resolved.errors.length || !resolved.path || resolved.external) return resolved;
|
|
187
|
+
const canonicalTarget = await fs.realpath(resolved.path);
|
|
188
|
+
if (!inside(canonicalProjectRoot, canonicalTarget)) {
|
|
189
|
+
return { errors: [{
|
|
190
|
+
text: `Project import escapes the project: ${args.path} resolves to ${canonicalTarget}`
|
|
191
|
+
}] };
|
|
192
|
+
}
|
|
193
|
+
return resolved;
|
|
194
|
+
}
|
|
195
|
+
if (args.path.startsWith("node:") || forbiddenModules.has(args.path)) {
|
|
196
|
+
return { errors: [{ text: `Browser player cannot import Node module ${args.path}` }] };
|
|
197
|
+
}
|
|
198
|
+
const canonical = args.path.replace(/^@field\/cascade\//, "cascade/").replace(/^@cascade\//, "cascade/");
|
|
199
|
+
if (!canonical.startsWith("cascade/")) return;
|
|
200
|
+
const subpath = canonical.slice("cascade/".length);
|
|
201
|
+
if (!(subpath === "io" || subpath === "image" || subpath === "gpu" || subpath === "contracts" || subpath.startsWith("contracts/") || subpath === "runtime" || subpath.startsWith("runtime/"))) {
|
|
202
|
+
return { errors: [{ text: `Browser player cannot import ${args.path}; server transports and configuration are not exported` }] };
|
|
203
|
+
}
|
|
204
|
+
if (subpath === "runtime/node" || subpath === "runtime/definition/extract") {
|
|
205
|
+
return { errors: [{ text: `Browser player cannot import ${args.path}` }] };
|
|
206
|
+
}
|
|
207
|
+
const entry = manifest.exports[`./${subpath}`]?.default;
|
|
208
|
+
if (!entry) return { errors: [{ text: `Unknown Cascade browser export: ${args.path}` }] };
|
|
209
|
+
const sourceShim = path.join(installRoot, "server", "src", "runtime", `${subpath}.ts`);
|
|
210
|
+
return { path: (subpath === "io" || subpath === "image" || subpath === "gpu") && await exists(sourceShim) ? sourceShim : path.resolve(installRoot, entry) };
|
|
211
|
+
});
|
|
212
|
+
} };
|
|
213
|
+
}
|
|
214
|
+
function isFilesystemImport(specifier) {
|
|
215
|
+
return specifier.startsWith(".") || path.isAbsolute(specifier);
|
|
216
|
+
}
|
|
217
|
+
async function importerIsInProject(importer, canonicalProjectRoot) {
|
|
218
|
+
if (!importer || !path.isAbsolute(importer)) return false;
|
|
219
|
+
try {
|
|
220
|
+
return inside(canonicalProjectRoot, await fs.realpath(importer));
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (error.code === "ENOENT") return false;
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function canonicalFuturePath(candidate) {
|
|
227
|
+
let existing = path.resolve(candidate);
|
|
228
|
+
const missing = [];
|
|
229
|
+
for (; ; ) {
|
|
230
|
+
try {
|
|
231
|
+
await fs.lstat(existing);
|
|
232
|
+
break;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
if (error.code !== "ENOENT") throw error;
|
|
235
|
+
const parent = path.dirname(existing);
|
|
236
|
+
if (parent === existing) throw new Error(`Output path has no accessible parent: ${candidate}`);
|
|
237
|
+
missing.unshift(path.basename(existing));
|
|
238
|
+
existing = parent;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return path.resolve(await fs.realpath(existing), ...missing);
|
|
242
|
+
}
|
|
243
|
+
function inside(root, candidate) {
|
|
244
|
+
const relative = path.relative(root, candidate);
|
|
245
|
+
return relative === "" || !relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative);
|
|
246
|
+
}
|
|
247
|
+
async function exists(file) {
|
|
248
|
+
try {
|
|
249
|
+
await fs.lstat(file);
|
|
250
|
+
return true;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (error.code === "ENOENT") return false;
|
|
253
|
+
throw error;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export {
|
|
258
|
+
createBrowserRuntimeHost,
|
|
259
|
+
installRoot,
|
|
260
|
+
buildPlayer,
|
|
261
|
+
playerFile,
|
|
262
|
+
staticRuntimePlugin,
|
|
263
|
+
canonicalFuturePath,
|
|
264
|
+
inside,
|
|
265
|
+
exists
|
|
266
|
+
};
|
|
267
|
+
//# sourceMappingURL=chunk-OM6BEME6.js.map
|