@field/cascade 0.11.0 → 0.13.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 +8 -5
- package/ARCHITECTURE.md +5 -4
- package/CHANGELOG.md +245 -0
- package/README.md +1 -1
- package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
- package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
- package/dist/assets/{CodeEditor-4O7FQ__R.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-Bz8JxISH.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-D5Z0nJ5-.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-Yqi0Ni61.js → core-DB-MkGjj.js} +3 -4
- package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
- package/dist/assets/{cssMode-CxUzc4vp.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-BNFb25CX.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-0ZDnWxeM.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-Cy18MoaD.js → handlebars-CcD3aMeL.js} +1 -1
- package/dist/assets/{html-B-2Dx7nq.js → html-DvZWGfqb.js} +1 -1
- package/dist/assets/{htmlMode-DUAc9B_d.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-DeQsDqP5.js → javascript-Cap2ahgh.js} +1 -1
- package/dist/assets/{jsonMode-BiFwJVSk.js → jsonMode-B0uLjp9C.js} +1 -1
- package/dist/assets/{liquid-BLoHH68a.js → liquid-CnxwhfLn.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-CNFgm1Kv.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
- package/dist/assets/math-GeULS-sk.js +1 -0
- package/dist/assets/{mdx-CFXQVNfs.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-Cf7S7p2E.js → python-CGyFk4XK.js} +1 -1
- package/dist/assets/{razor-CMHBcG-g.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-BEih0GDj.js → tsMode-BOeXzO9H.js} +1 -1
- package/dist/assets/{typescript-COEKYD_a.js → typescript-J1SnE_Tu.js} +1 -1
- package/dist/assets/{workers-BNhAhMNn.js → workers-CYwwTiVF.js} +1 -1
- package/dist/assets/{xml-CPiMpnPl.js → xml-DnPRNzK9.js} +1 -1
- package/dist/assets/{yaml-Bgp1ITLR.js → yaml-BmmYBNa9.js} +1 -1
- package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
- package/dist/cli/{Graph-ZJJTRQTM.js → Graph-OB6EWSGL.js} +12 -12
- package/dist/cli/assert-GROGQNCQ.js +25 -0
- package/dist/cli/checks-3WB44XBL.js +189 -0
- package/dist/cli/{chunk-3JTJHF7V.js → chunk-2L34ERS2.js} +4 -4
- package/dist/cli/chunk-53LGFPWX.js +138 -0
- package/dist/cli/chunk-5ORUQ6ES.js +267 -0
- package/dist/cli/{chunk-YAT5Y25U.js → chunk-7QE2ZNSN.js} +3 -3
- package/dist/cli/{chunk-SGJAET2L.js → chunk-BPODRH52.js} +8 -4
- package/dist/cli/{chunk-XWDSKG7N.js → chunk-BZ63XQ3I.js} +2 -2
- package/dist/cli/{chunk-FCDXJ6EK.js → chunk-CTPLRSWF.js} +2 -13
- package/dist/cli/{chunk-WIH4TEIS.js → chunk-EZRWJ4G2.js} +1 -1
- package/dist/cli/{chunk-BIJO5OFS.js → chunk-FWMSGKEH.js} +1 -1
- package/dist/cli/{chunk-POMMNKZZ.js → chunk-G23A2BZZ.js} +38 -5
- package/dist/cli/{chunk-35D343DC.js → chunk-GRIN2DDP.js} +19 -1
- package/dist/cli/{chunk-WKURDVYP.js → chunk-JEW5MPGI.js} +28 -331
- package/dist/cli/chunk-JVOCK5W4.js +83 -0
- package/dist/cli/chunk-KBGUO27Q.js +15 -0
- package/dist/cli/{chunk-GFS6W3C5.js → chunk-L6B6FUQP.js} +54 -32
- package/dist/cli/chunk-LTXWBXOM.js +438 -0
- package/dist/cli/chunk-MI5JLQYA.js +220 -0
- package/dist/cli/{chunk-A4OAMOZH.js → chunk-NJFMDXHR.js} +13 -3
- package/dist/cli/{chunk-DUIUFVU2.js → chunk-OBZAP3GG.js} +49 -23
- package/dist/cli/chunk-QAGATJGE.js +336 -0
- package/dist/cli/{chunk-EUIAC3U3.js → chunk-QKL7CCRS.js} +966 -132
- package/dist/cli/{chunk-RLCAJBVR.js → chunk-TJW67QSI.js} +8 -7
- package/dist/cli/{chunk-RQZ4SX5R.js → chunk-W5PJ5RMP.js} +156 -84
- package/dist/cli/chunk-W7OUAT7J.js +122 -0
- package/dist/cli/chunk-WGKPJZDY.js +364 -0
- package/dist/cli/{chunk-D6BUOHUG.js → chunk-X4WKAOQP.js} +4 -4
- package/dist/cli/{chunk-VVGSLVSF.js → chunk-X566FWBV.js} +6 -1
- package/dist/cli/chunk-YH637PDL.js +317 -0
- package/dist/cli/chunk-ZSCUZE6I.js +112 -0
- package/dist/cli/{cliCommands-UQSFGEHF.js → cliCommands-XVFRD7CF.js} +23 -17
- package/dist/cli/{commands-Q23M26QM.js → commands-M2XLTPTZ.js} +129 -47
- package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
- package/dist/cli/{definitions-HF2FTHYU.js → definitions-BPOPW52L.js} +7 -7
- package/dist/cli/{doctorCommand-B7BPQMN6.js → doctorCommand-RAEI7GVY.js} +36 -6
- package/dist/cli/{edit-JHCPTQFT.js → edit-S5KEQ5RA.js} +3 -3
- package/dist/cli/editorCommands-5BBG4S6V.js +41 -0
- package/dist/cli/{encode-HAUZTYPT.js → encode-ICPEPMH5.js} +2 -2
- package/dist/cli/file-3HTQHPYQ.js +41 -0
- package/dist/cli/filters-6ODFWYK4.js +379 -0
- package/dist/cli/generators-YU7GB4MD.js +210 -0
- package/dist/cli/{geo-4RNK3QVN.js → geo-6ZPGKZRU.js} +7 -7
- package/dist/cli/{graphCommands-6BMAKGQE.js → graphCommands-MULQ7VD2.js} +4 -4
- package/dist/cli/{graphFile-VPSQ6OF7.js → graphFile-CITF36ZM.js} +25 -19
- package/dist/cli/{headlessCanvas-5XLDZT7M.js → headlessCanvas-ENRHC7GS.js} +3 -2
- package/dist/cli/{helpCommand-3VRE3KVO.js → helpCommand-X2QDANM3.js} +9 -7
- package/dist/cli/image-TXELZZK5.js +55 -0
- package/dist/cli/index.js +14 -14
- package/dist/cli/{math-ZRMLKU2D.js → math-RSYRQ3C6.js} +5 -5
- package/dist/cli/{mcp-ZLEEMYGF.js → mcp-YRIGRLYQ.js} +4 -4
- package/dist/cli/{parity-KINARCP2.js → parity-3N3HTKWX.js} +42 -36
- package/dist/cli/{pop-USDFXB7H.js → pop-B7SIIYKN.js} +5 -5
- package/dist/cli/project-SJF5ZF3F.js +12 -0
- package/dist/cli/{projectDefinition-DMTZN2NE.js → projectDefinition-F3D7UIHJ.js} +8 -8
- package/dist/cli/{projectRuntime-Z5PJOH47.js → projectRuntime-NY4XMDFH.js} +19 -12
- package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
- package/dist/cli/{render-YURAPPUI.js → render-Y23W6MY6.js} +29 -22
- package/dist/cli/{runCommand-PI764LEG.js → runCommand-XOG7AVC5.js} +3 -3
- package/dist/cli/runner-DNJO5WO2.js +43 -0
- package/dist/cli/runtime/image.ts +27 -2
- package/dist/cli/runtime/io.ts +78 -0
- package/dist/cli/share-B7HTCOJX.js +166 -0
- package/dist/cli/stageCache-TY2BFZJR.js +15 -0
- package/dist/cli/{stageRunner-KUNIMQKJ.js → stageRunner-KY2EJP7X.js} +2 -2
- package/dist/cli/text-MB3EKR4H.js +126 -0
- package/dist/cli/{verbs-RCE3K4VQ.js → verbs-PI2JH5FI.js} +2 -2
- package/dist/cli/webBuild-2K4COCGY.js +44 -0
- package/dist/contracts/capabilities.d.ts +39 -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/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 +15 -0
- package/dist/image.js +36 -2
- package/dist/index.html +8 -2
- package/dist/io.d.ts +29 -0
- package/dist/io.js +40 -0
- package/dist/player/app.js +11 -7
- package/dist/player/editor.js +3 -2
- package/dist/player/editorEngine.js +3 -2
- package/dist/player/embed.js +2 -0
- package/dist/player/types.d.ts +6 -0
- 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 +3 -165
- package/dist/runtime/builtins/image/contactSheet.js +0 -49
- 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 +947 -4
- package/dist/runtime/builtins/image/index.js +41 -6
- 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/definition/architecture.js +89 -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/doc/CLI_REFERENCE.md +21 -3
- package/doc/EDITOR_EXPORT.md +26 -0
- package/doc/MCP.md +2 -1
- package/doc/NODE_REFERENCE.md +286 -14
- package/doc/PROJECT_AUTHORING.md +158 -4
- package/doc/WEB_PLAYER.md +9 -1
- package/package.json +4 -1
- package/dist/assets/CodePanel-BU-autmq.js +0 -2
- package/dist/assets/CustomNodeDialog-BRpDfOV5.js +0 -1
- package/dist/assets/OpenGraphDialog-BwbRlC0X.js +0 -1
- package/dist/assets/ProjectSettings-DLOXLxcA.js +0 -2
- package/dist/assets/definitions-GreEMXLV.js +0 -1
- package/dist/assets/geo-u0n_jOsD.js +0 -1
- package/dist/assets/image-cAa-Nu9O.js +0 -2062
- package/dist/assets/index-5ZtDAuy2.js +0 -220
- package/dist/assets/index-7vae6YFC.css +0 -1
- package/dist/assets/math-DioIQOPJ.js +0 -1
- package/dist/assets/pop-DC_TQG9t.js +0 -1
- package/dist/cli/chunk-36P5K3SD.js +0 -631
- package/dist/cli/chunk-4UDFYF5G.js +0 -132
- package/dist/cli/chunk-53NMBJAO.js +0 -35
- package/dist/cli/chunk-MIIEFUGG.js +0 -623
- package/dist/cli/chunk-QBBKRNGY.js +0 -90
- package/dist/cli/chunk-WPUDGEFY.js +0 -20
- package/dist/cli/editorCommands-UIF5YLUZ.js +0 -33
- package/dist/cli/project-K3QIPGBB.js +0 -12
- package/dist/cli/registerStandardNodes-S2VLMF6J.js +0 -3081
- package/dist/cli/runner-RA6UKEPD.js +0 -37
- package/dist/cli/webBuild-GT4PZT5D.js +0 -37
- package/dist/runtime/builtins/headless.d.ts +0 -19
- package/dist/runtime/builtins/headless.js +0 -25
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
browserAssetCapability
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ZSCUZE6I.js";
|
|
4
4
|
import {
|
|
5
5
|
attachDefinition
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BPODRH52.js";
|
|
7
7
|
import {
|
|
8
|
-
createGpuHost
|
|
9
|
-
|
|
8
|
+
createGpuHost,
|
|
9
|
+
requestDeviceWithAdapterLimits
|
|
10
|
+
} from "./chunk-L6B6FUQP.js";
|
|
10
11
|
import {
|
|
11
12
|
validateNodeDefinition
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-NJFMDXHR.js";
|
|
13
14
|
|
|
14
15
|
// src/nodes/definition/browserShellCapability.ts
|
|
15
16
|
var capability = null;
|
|
@@ -125,7 +126,7 @@ function createBrowserGpuHost() {
|
|
|
125
126
|
"No WebGPU adapter is available \u2014 the browser reports WebGPU but the system offers no GPU to render on."
|
|
126
127
|
);
|
|
127
128
|
}
|
|
128
|
-
const device = await adapter
|
|
129
|
+
const device = await requestDeviceWithAdapterLimits(adapter);
|
|
129
130
|
const info = adapter.info;
|
|
130
131
|
return {
|
|
131
132
|
device,
|
|
@@ -221,4 +222,4 @@ export {
|
|
|
221
222
|
moduleNodeFunction,
|
|
222
223
|
adaptModule
|
|
223
224
|
};
|
|
224
|
-
//# sourceMappingURL=chunk-
|
|
225
|
+
//# sourceMappingURL=chunk-TJW67QSI.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
validateNodeDefinition
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NJFMDXHR.js";
|
|
4
4
|
|
|
5
5
|
// server/src/project.ts
|
|
6
6
|
import fs5 from "fs/promises";
|
|
@@ -39,6 +39,19 @@ function resolveWithinRoot(root, ...segments) {
|
|
|
39
39
|
}
|
|
40
40
|
return full;
|
|
41
41
|
}
|
|
42
|
+
function canonicalPath(full) {
|
|
43
|
+
let existing = full;
|
|
44
|
+
while (!existsIncludingSymlink(existing)) {
|
|
45
|
+
const parent = path.dirname(existing);
|
|
46
|
+
if (parent === existing) return full;
|
|
47
|
+
existing = parent;
|
|
48
|
+
}
|
|
49
|
+
return path.join(canonical(existing, `path is not accessible: ${full}`), path.relative(existing, full));
|
|
50
|
+
}
|
|
51
|
+
function isWithin(base, candidate) {
|
|
52
|
+
const rel = path.relative(base, candidate);
|
|
53
|
+
return !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
54
|
+
}
|
|
42
55
|
function existsIncludingSymlink(candidate) {
|
|
43
56
|
try {
|
|
44
57
|
fs.lstatSync(candidate);
|
|
@@ -56,6 +69,101 @@ function canonical(candidate, message) {
|
|
|
56
69
|
}
|
|
57
70
|
}
|
|
58
71
|
|
|
72
|
+
// server/src/projectConfig.ts
|
|
73
|
+
import fs2 from "node:fs";
|
|
74
|
+
import path2 from "node:path";
|
|
75
|
+
var CREDENTIAL_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
76
|
+
var SECRET_KEY = /^(?:api[_-]?key|apiKey|secret|password|access[_-]?token|refresh[_-]?token|credential|credentials)$/i;
|
|
77
|
+
function readProjectManifest(root) {
|
|
78
|
+
const raw = readRaw(root);
|
|
79
|
+
return normalizeManifest(raw);
|
|
80
|
+
}
|
|
81
|
+
function writeProjectManifest(root, input) {
|
|
82
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("project manifest must be an object");
|
|
83
|
+
const value = input;
|
|
84
|
+
const current = readRaw(root);
|
|
85
|
+
const next = {
|
|
86
|
+
...current,
|
|
87
|
+
name: typeof value.name === "string" ? value.name.trim() : "",
|
|
88
|
+
commands: stringRecord(value.commands, "commands"),
|
|
89
|
+
credentials: credentialNames(value.credentials),
|
|
90
|
+
settings: settingsRecord(value.settings)
|
|
91
|
+
};
|
|
92
|
+
fs2.writeFileSync(path2.join(root, "cascade.json"), `${JSON.stringify(next, null, 2)}
|
|
93
|
+
`, "utf8");
|
|
94
|
+
return normalizeManifest(next);
|
|
95
|
+
}
|
|
96
|
+
function readRaw(root) {
|
|
97
|
+
try {
|
|
98
|
+
const value = JSON.parse(fs2.readFileSync(path2.join(root, "cascade.json"), "utf8"));
|
|
99
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("root must be an object");
|
|
100
|
+
return value;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (error.code === "ENOENT") return {};
|
|
103
|
+
throw new Error(`Cannot read cascade.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function normalizeManifest(raw) {
|
|
107
|
+
return Object.freeze({
|
|
108
|
+
name: typeof raw.name === "string" ? raw.name : "",
|
|
109
|
+
commands: Object.freeze(stringRecord(raw.commands, "commands")),
|
|
110
|
+
credentials: Object.freeze(credentialNames(raw.credentials)),
|
|
111
|
+
settings: Object.freeze(settingsRecord(raw.settings)),
|
|
112
|
+
reads: Object.freeze(relativeFolders(raw.reads, "reads", true)),
|
|
113
|
+
writes: Object.freeze(relativeFolders(raw.writes, "writes", false))
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function relativeFolders(input, label, mayLeave) {
|
|
117
|
+
if (input === void 0) return [];
|
|
118
|
+
const shape = mayLeave ? '"../other/data"' : '"renders"';
|
|
119
|
+
if (!Array.isArray(input)) throw new Error(`cascade.json ${label} must be an array of relative folders such as [${shape}]`);
|
|
120
|
+
const folders = input.map((entry) => {
|
|
121
|
+
if (typeof entry !== "string" || !entry.trim() || entry.includes("\0") || path2.isAbsolute(entry) || /^~/.test(entry))
|
|
122
|
+
throw new Error(`cascade.json ${label}: ${JSON.stringify(entry)} is not a relative folder such as ${shape}`);
|
|
123
|
+
const folder = path2.posix.normalize(entry.split("\\").join("/")).replace(/\/+$/, "");
|
|
124
|
+
const leaves = folder === ".." || folder.startsWith("../");
|
|
125
|
+
if (!mayLeave && (leaves || folder === "." || /^(?:\.git|nodes|\.cascade)(?:\/|$)/.test(folder)))
|
|
126
|
+
throw new Error(`cascade.json writes: ${JSON.stringify(entry)} must be a folder inside the project, not its root, .git, .cascade or nodes`);
|
|
127
|
+
if (mayLeave && folder === ".") throw new Error('cascade.json reads: "." is the project itself, which is always readable');
|
|
128
|
+
return folder;
|
|
129
|
+
});
|
|
130
|
+
return [...new Set(folders)];
|
|
131
|
+
}
|
|
132
|
+
function stringRecord(input, label) {
|
|
133
|
+
if (input === void 0) return {};
|
|
134
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error(`${label} must be an object of strings`);
|
|
135
|
+
const entries = Object.entries(input);
|
|
136
|
+
if (entries.some(([key, value]) => !CREDENTIAL_NAME.test(key) || typeof value !== "string" || value.includes("\0"))) {
|
|
137
|
+
throw new Error(`${label} must contain safe names and string values`);
|
|
138
|
+
}
|
|
139
|
+
return Object.fromEntries(entries);
|
|
140
|
+
}
|
|
141
|
+
function credentialNames(input) {
|
|
142
|
+
if (input === void 0) return [];
|
|
143
|
+
if (!Array.isArray(input) || input.some((name) => typeof name !== "string" || !CREDENTIAL_NAME.test(name))) {
|
|
144
|
+
throw new Error("credentials must be an array of safe names");
|
|
145
|
+
}
|
|
146
|
+
return [...new Set(input)];
|
|
147
|
+
}
|
|
148
|
+
function settingsRecord(input) {
|
|
149
|
+
if (input === void 0) return {};
|
|
150
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("settings must be an object");
|
|
151
|
+
assertSafeSettings(input, 0);
|
|
152
|
+
return structuredClone(input);
|
|
153
|
+
}
|
|
154
|
+
function assertSafeSettings(value, depth) {
|
|
155
|
+
if (depth > 12) throw new Error("settings nesting is too deep");
|
|
156
|
+
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return;
|
|
157
|
+
if (Array.isArray(value)) return value.forEach((item) => assertSafeSettings(item, depth + 1));
|
|
158
|
+
if (!value || typeof value !== "object") throw new Error("settings must contain JSON values");
|
|
159
|
+
for (const [key, item] of Object.entries(value)) {
|
|
160
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype" || SECRET_KEY.test(key)) {
|
|
161
|
+
throw new Error(`settings key ${JSON.stringify(key)} looks secret or unsafe; credentials belong outside the project`);
|
|
162
|
+
}
|
|
163
|
+
assertSafeSettings(item, depth + 1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
59
167
|
// server/src/shell/service.ts
|
|
60
168
|
import fs4 from "node:fs";
|
|
61
169
|
import os2 from "node:os";
|
|
@@ -64,11 +172,11 @@ import { execFile, spawn } from "node:child_process";
|
|
|
64
172
|
import { randomUUID } from "node:crypto";
|
|
65
173
|
|
|
66
174
|
// server/src/credentials.ts
|
|
67
|
-
import
|
|
175
|
+
import fs3 from "node:fs";
|
|
68
176
|
import os from "node:os";
|
|
69
|
-
import
|
|
177
|
+
import path3 from "node:path";
|
|
70
178
|
var CredentialStore = class {
|
|
71
|
-
constructor(file = process.env.CASCADE_CREDENTIALS ||
|
|
179
|
+
constructor(file = process.env.CASCADE_CREDENTIALS || path3.join(os.homedir(), ".cascade", "credentials.yaml")) {
|
|
72
180
|
this.file = file;
|
|
73
181
|
}
|
|
74
182
|
has(name) {
|
|
@@ -96,7 +204,7 @@ var CredentialStore = class {
|
|
|
96
204
|
read() {
|
|
97
205
|
let source;
|
|
98
206
|
try {
|
|
99
|
-
source =
|
|
207
|
+
source = fs3.readFileSync(this.file, "utf8");
|
|
100
208
|
} catch (error) {
|
|
101
209
|
if (error.code === "ENOENT") return /* @__PURE__ */ new Map();
|
|
102
210
|
throw error;
|
|
@@ -170,83 +278,6 @@ function safeEnvName(value) {
|
|
|
170
278
|
return value && /^[A-Za-z_][A-Za-z0-9_]{0,127}$/.test(value) && !/^(?:PATH|NODE_OPTIONS|PYTHONPATH|LD_.*|DYLD_.*)$/i.test(value) ? value : null;
|
|
171
279
|
}
|
|
172
280
|
|
|
173
|
-
// server/src/projectConfig.ts
|
|
174
|
-
import fs3 from "node:fs";
|
|
175
|
-
import path3 from "node:path";
|
|
176
|
-
var CREDENTIAL_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
177
|
-
var SECRET_KEY = /^(?:api[_-]?key|apiKey|secret|password|access[_-]?token|refresh[_-]?token|credential|credentials)$/i;
|
|
178
|
-
function readProjectManifest(root) {
|
|
179
|
-
const raw = readRaw(root);
|
|
180
|
-
return normalizeManifest(raw);
|
|
181
|
-
}
|
|
182
|
-
function writeProjectManifest(root, input) {
|
|
183
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("project manifest must be an object");
|
|
184
|
-
const value = input;
|
|
185
|
-
const current = readRaw(root);
|
|
186
|
-
const next = {
|
|
187
|
-
...current,
|
|
188
|
-
name: typeof value.name === "string" ? value.name.trim() : "",
|
|
189
|
-
commands: stringRecord(value.commands, "commands"),
|
|
190
|
-
credentials: credentialNames(value.credentials),
|
|
191
|
-
settings: settingsRecord(value.settings)
|
|
192
|
-
};
|
|
193
|
-
fs3.writeFileSync(path3.join(root, "cascade.json"), `${JSON.stringify(next, null, 2)}
|
|
194
|
-
`, "utf8");
|
|
195
|
-
return normalizeManifest(next);
|
|
196
|
-
}
|
|
197
|
-
function readRaw(root) {
|
|
198
|
-
try {
|
|
199
|
-
const value = JSON.parse(fs3.readFileSync(path3.join(root, "cascade.json"), "utf8"));
|
|
200
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("root must be an object");
|
|
201
|
-
return value;
|
|
202
|
-
} catch (error) {
|
|
203
|
-
if (error.code === "ENOENT") return {};
|
|
204
|
-
throw new Error(`Cannot read cascade.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
function normalizeManifest(raw) {
|
|
208
|
-
return Object.freeze({
|
|
209
|
-
name: typeof raw.name === "string" ? raw.name : "",
|
|
210
|
-
commands: Object.freeze(stringRecord(raw.commands, "commands")),
|
|
211
|
-
credentials: Object.freeze(credentialNames(raw.credentials)),
|
|
212
|
-
settings: Object.freeze(settingsRecord(raw.settings))
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
function stringRecord(input, label) {
|
|
216
|
-
if (input === void 0) return {};
|
|
217
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error(`${label} must be an object of strings`);
|
|
218
|
-
const entries = Object.entries(input);
|
|
219
|
-
if (entries.some(([key, value]) => !CREDENTIAL_NAME.test(key) || typeof value !== "string" || value.includes("\0"))) {
|
|
220
|
-
throw new Error(`${label} must contain safe names and string values`);
|
|
221
|
-
}
|
|
222
|
-
return Object.fromEntries(entries);
|
|
223
|
-
}
|
|
224
|
-
function credentialNames(input) {
|
|
225
|
-
if (input === void 0) return [];
|
|
226
|
-
if (!Array.isArray(input) || input.some((name) => typeof name !== "string" || !CREDENTIAL_NAME.test(name))) {
|
|
227
|
-
throw new Error("credentials must be an array of safe names");
|
|
228
|
-
}
|
|
229
|
-
return [...new Set(input)];
|
|
230
|
-
}
|
|
231
|
-
function settingsRecord(input) {
|
|
232
|
-
if (input === void 0) return {};
|
|
233
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("settings must be an object");
|
|
234
|
-
assertSafeSettings(input, 0);
|
|
235
|
-
return structuredClone(input);
|
|
236
|
-
}
|
|
237
|
-
function assertSafeSettings(value, depth) {
|
|
238
|
-
if (depth > 12) throw new Error("settings nesting is too deep");
|
|
239
|
-
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return;
|
|
240
|
-
if (Array.isArray(value)) return value.forEach((item) => assertSafeSettings(item, depth + 1));
|
|
241
|
-
if (!value || typeof value !== "object") throw new Error("settings must contain JSON values");
|
|
242
|
-
for (const [key, item] of Object.entries(value)) {
|
|
243
|
-
if (key === "__proto__" || key === "constructor" || key === "prototype" || SECRET_KEY.test(key)) {
|
|
244
|
-
throw new Error(`settings key ${JSON.stringify(key)} looks secret or unsafe; credentials belong outside the project`);
|
|
245
|
-
}
|
|
246
|
-
assertSafeSettings(item, depth + 1);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
281
|
// server/src/shell/types.ts
|
|
251
282
|
var ShellProcessError = class extends Error {
|
|
252
283
|
constructor(kind, result, message) {
|
|
@@ -847,7 +878,48 @@ var ProjectRoot = class _ProjectRoot {
|
|
|
847
878
|
if (normalized === "shared" || normalized.startsWith("shared/")) {
|
|
848
879
|
return this.resolveShared(...normalized.split("/").slice(1));
|
|
849
880
|
}
|
|
850
|
-
|
|
881
|
+
try {
|
|
882
|
+
return this.resolve(relativePath);
|
|
883
|
+
} catch (error) {
|
|
884
|
+
if (!(error instanceof PathSafetyError)) throw error;
|
|
885
|
+
const declared = this.resolveDeclaredRead(relativePath);
|
|
886
|
+
if (declared) return declared;
|
|
887
|
+
throw error;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* A read outside the project, allowed only into a root the project declares
|
|
892
|
+
* in cascade.json `"reads"` (`["../other/data"]`). Reached by `..` or by a
|
|
893
|
+
* symlink alike: the canonical target must lie under the canonical read
|
|
894
|
+
* root. Never used for writes — `resolve()` still refuses those.
|
|
895
|
+
*/
|
|
896
|
+
resolveDeclaredRead(relativePath) {
|
|
897
|
+
if (path5.isAbsolute(relativePath)) return null;
|
|
898
|
+
const reads = readProjectManifest(this.root).reads;
|
|
899
|
+
if (!reads.length) return null;
|
|
900
|
+
const target = canonicalPath(path5.resolve(this.root, relativePath));
|
|
901
|
+
for (const folder of reads) {
|
|
902
|
+
let base;
|
|
903
|
+
try {
|
|
904
|
+
base = fssync.realpathSync(path5.resolve(this.root, folder));
|
|
905
|
+
} catch {
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (isWithin(base, target)) return target;
|
|
909
|
+
}
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Where a node may write a file under its own name: `.cascade-cache/`, or a
|
|
914
|
+
* folder the project declares in cascade.json `"writes"` (`["renders"]`).
|
|
915
|
+
* Returns the folder the normalised path falls in, or null. Containment is
|
|
916
|
+
* still `resolve()`'s, so a symlink out of a write folder is refused.
|
|
917
|
+
*/
|
|
918
|
+
writeFolderOf(relativePath) {
|
|
919
|
+
const clean = path5.posix.normalize(relativePath.split("\\").join("/").replace(/^\.?\//, ""));
|
|
920
|
+
for (const folder of [".cascade-cache", ...readProjectManifest(this.root).writes])
|
|
921
|
+
if (clean.startsWith(`${folder}/`)) return folder;
|
|
922
|
+
return null;
|
|
851
923
|
}
|
|
852
924
|
/**
|
|
853
925
|
* Whether this project is under version control, walking **up** rather than
|
|
@@ -1122,4 +1194,4 @@ export {
|
|
|
1122
1194
|
extractNodeDefinition,
|
|
1123
1195
|
ProjectRoot
|
|
1124
1196
|
};
|
|
1125
|
-
//# sourceMappingURL=chunk-
|
|
1197
|
+
//# sourceMappingURL=chunk-W5PJ5RMP.js.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readProjectManifest
|
|
3
|
+
} from "./chunk-W5PJ5RMP.js";
|
|
4
|
+
|
|
5
|
+
// server/src/compile.ts
|
|
6
|
+
import * as esbuild from "esbuild";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
var __dirname_compile = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
function cascadeRuntimePlugin(project) {
|
|
12
|
+
return {
|
|
13
|
+
name: "cascade-runtime",
|
|
14
|
+
setup(build2) {
|
|
15
|
+
build2.onResolve({ filter: /^cascade\/(?:io|image|shell|net|config|stage)$/ }, (args) => ({
|
|
16
|
+
path: args.path,
|
|
17
|
+
namespace: "cascade-runtime"
|
|
18
|
+
}));
|
|
19
|
+
build2.onResolve({ filter: /^(?:@cascade|cascade)\/contracts$/ }, () => {
|
|
20
|
+
const candidates = [
|
|
21
|
+
path.join(__dirname_compile, "..", "contracts", "index.js"),
|
|
22
|
+
path.join(__dirname_compile, "..", "..", "packages", "contracts", "dist", "index.js")
|
|
23
|
+
];
|
|
24
|
+
const found = candidates.find((c) => fs.existsSync(c));
|
|
25
|
+
if (!found) {
|
|
26
|
+
return { errors: [{ text: `@cascade/contracts not found (looked in ${candidates.join(", ")})` }] };
|
|
27
|
+
}
|
|
28
|
+
return { path: found };
|
|
29
|
+
});
|
|
30
|
+
build2.onLoad({ filter: /.*/, namespace: "cascade-runtime" }, (args) => {
|
|
31
|
+
if (args.path === "cascade/config") {
|
|
32
|
+
return { contents: configRuntimeSource(readProjectManifest(project.root).settings), loader: "ts" };
|
|
33
|
+
}
|
|
34
|
+
const candidates = [
|
|
35
|
+
path.join(__dirname_compile, "runtime", `${args.path.slice("cascade/".length)}.ts`),
|
|
36
|
+
path.join(__dirname_compile, "..", "src", "runtime", `${args.path.slice("cascade/".length)}.ts`)
|
|
37
|
+
];
|
|
38
|
+
const found = candidates.find((c) => fs.existsSync(c));
|
|
39
|
+
if (!found) {
|
|
40
|
+
return { errors: [{ text: `${args.path} runtime not found (looked in ${candidates.join(", ")})` }] };
|
|
41
|
+
}
|
|
42
|
+
return { contents: fs.readFileSync(found, "utf-8"), loader: "ts", resolveDir: path.dirname(found) };
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function commonOptions(project) {
|
|
48
|
+
return {
|
|
49
|
+
bundle: true,
|
|
50
|
+
format: "esm",
|
|
51
|
+
platform: "browser",
|
|
52
|
+
target: "es2022",
|
|
53
|
+
write: false,
|
|
54
|
+
logLevel: "silent",
|
|
55
|
+
plugins: [cascadeRuntimePlugin(project)]
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async function compileProjectModule(project, moduleName) {
|
|
59
|
+
try {
|
|
60
|
+
await project.moduleRunsOn(moduleName);
|
|
61
|
+
return await compileEntry(project, project.resolve(`nodes/${moduleName}/index.ts`));
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return { ok: false, code: "", errors: [errorMessage(err)] };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function compileProjectPanel(project, panelName) {
|
|
67
|
+
try {
|
|
68
|
+
return await compileEntry(project, await project.resolvePanelEntry(panelName));
|
|
69
|
+
} catch (err) {
|
|
70
|
+
return { ok: false, code: "", errors: [errorMessage(err)] };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function compileEmbedded(project, code) {
|
|
74
|
+
try {
|
|
75
|
+
const result = await esbuild.build({
|
|
76
|
+
...commonOptions(project),
|
|
77
|
+
stdin: {
|
|
78
|
+
contents: code,
|
|
79
|
+
loader: "ts",
|
|
80
|
+
resolveDir: project.root,
|
|
81
|
+
sourcefile: "embedded.ts"
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
return toResult(result);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
return { ok: false, code: "", errors: [errorMessage(err)] };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function toResult(result) {
|
|
90
|
+
const errors = result.errors.map((e) => e.text);
|
|
91
|
+
const code = result.outputFiles?.[0]?.text ?? "";
|
|
92
|
+
return { ok: errors.length === 0, code, errors };
|
|
93
|
+
}
|
|
94
|
+
async function compileEntry(project, entryPath) {
|
|
95
|
+
return toResult(await esbuild.build({ ...commonOptions(project), entryPoints: [entryPath] }));
|
|
96
|
+
}
|
|
97
|
+
function configRuntimeSource(settings) {
|
|
98
|
+
return `function deepFreeze(value) { if (value && typeof value === 'object') { for (const item of Object.values(value)) deepFreeze(item); Object.freeze(value); } return value; }
|
|
99
|
+
const values = deepFreeze(${JSON.stringify(settings)});
|
|
100
|
+
function value(name) { return Object.prototype.hasOwnProperty.call(values, name) ? values[name] : undefined; }
|
|
101
|
+
export const config = Object.freeze({
|
|
102
|
+
get(name, fallback) { return value(name) ?? fallback; },
|
|
103
|
+
string(name, fallback = '') { const item = value(name); return typeof item === 'string' ? item : fallback; },
|
|
104
|
+
number(name, fallback = 0) { const item = value(name); return typeof item === 'number' && Number.isFinite(item) ? item : fallback; },
|
|
105
|
+
boolean(name, fallback = false) { const item = value(name); return typeof item === 'boolean' ? item : fallback; },
|
|
106
|
+
has(name) { return value(name) !== undefined; }
|
|
107
|
+
});`;
|
|
108
|
+
}
|
|
109
|
+
function errorMessage(err) {
|
|
110
|
+
if (err && typeof err === "object" && "errors" in err) {
|
|
111
|
+
const errors = err.errors;
|
|
112
|
+
if (errors?.length) return errors.map((e) => e.text).join("\n");
|
|
113
|
+
}
|
|
114
|
+
return err instanceof Error ? err.message : String(err);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export {
|
|
118
|
+
compileProjectModule,
|
|
119
|
+
compileProjectPanel,
|
|
120
|
+
compileEmbedded
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=chunk-W7OUAT7J.js.map
|