@holoscript/core 6.0.4 → 7.0.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.
Files changed (236) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/dist/compiler/index.d.ts +82 -0
  4. package/dist/constants.d.ts +3 -2
  5. package/dist/coordinators/index.d.ts +189 -0
  6. package/dist/index.d.ts +501 -19
  7. package/dist/paper-0c-spike/index.d.ts +29 -0
  8. package/dist/reconstruction/index.d.ts +78 -0
  9. package/dist/tools/index.d.ts +22 -1
  10. package/dist/traitDocs/traitDocs.d.ts +69 -0
  11. package/dist/traits/index.d.ts +61 -0
  12. package/package.json +105 -57
  13. package/dist/GLTFPipeline-DEN36VNK.js +0 -12
  14. package/dist/GLTFPipeline-YPCAK236.cjs +0 -33
  15. package/dist/HoloScriptPlusParser-BN6KVRCM.js +0 -692
  16. package/dist/HoloScriptPlusParser-NC5FE6AL.cjs +0 -697
  17. package/dist/USDZExporter-NTMBNTDB.js +0 -707
  18. package/dist/USDZExporter-UWGWNMMD.cjs +0 -709
  19. package/dist/chunk-27LWW5FU.cjs +0 -410
  20. package/dist/chunk-2CWOLHTE.js +0 -69
  21. package/dist/chunk-33LSUQDD.cjs +0 -835
  22. package/dist/chunk-3FJCK5XA.js +0 -2232
  23. package/dist/chunk-3FXV5S25.cjs +0 -633
  24. package/dist/chunk-3FYZOR7S.cjs +0 -69
  25. package/dist/chunk-3SAK5KFL.cjs +0 -83
  26. package/dist/chunk-4XSNJCLC.cjs +0 -1859
  27. package/dist/chunk-54FHG2MX.js +0 -655
  28. package/dist/chunk-56IF4NTA.js +0 -56
  29. package/dist/chunk-5BGSECRJ.cjs +0 -2237
  30. package/dist/chunk-5GLCTO44.js +0 -161
  31. package/dist/chunk-5O6TQC6M.cjs +0 -1871
  32. package/dist/chunk-5OEOHAAW.cjs +0 -682
  33. package/dist/chunk-5TOFIR6L.js +0 -407
  34. package/dist/chunk-5WUNN6ZN.cjs +0 -428
  35. package/dist/chunk-6TZPZCOJ.cjs +0 -1404
  36. package/dist/chunk-6UEHYZ7V.cjs +0 -773
  37. package/dist/chunk-6XSERL6L.js +0 -5678
  38. package/dist/chunk-72EQECGT.cjs +0 -908
  39. package/dist/chunk-7AGYRWKW.cjs +0 -507
  40. package/dist/chunk-7LCYLPW2.cjs +0 -663
  41. package/dist/chunk-A7PIMZGU.js +0 -263
  42. package/dist/chunk-ATSKSYVE.cjs +0 -51683
  43. package/dist/chunk-B5TCIAPQ.cjs +0 -117
  44. package/dist/chunk-BF2235SI.cjs +0 -5714
  45. package/dist/chunk-BKIGPPVM.js +0 -629
  46. package/dist/chunk-BND3ST2K.cjs +0 -662
  47. package/dist/chunk-BU7VWW2K.js +0 -2522
  48. package/dist/chunk-BWFJEM5A.js +0 -5419
  49. package/dist/chunk-CAUCGUEA.cjs +0 -130
  50. package/dist/chunk-CBJSLA2E.cjs +0 -5423
  51. package/dist/chunk-CDPGV4DN.js +0 -114
  52. package/dist/chunk-CLYEIWA5.cjs +0 -408
  53. package/dist/chunk-CS2EMTGF.js +0 -1966
  54. package/dist/chunk-DMG7C4H2.js +0 -975
  55. package/dist/chunk-DXJQDCFL.js +0 -468
  56. package/dist/chunk-E3FWRT3Z.js +0 -608
  57. package/dist/chunk-E3UALNFA.js +0 -421
  58. package/dist/chunk-EONILVMF.js +0 -762
  59. package/dist/chunk-EQV4R3EV.cjs +0 -769
  60. package/dist/chunk-F3HH56EB.cjs +0 -5538
  61. package/dist/chunk-F4IULT7N.js +0 -1488
  62. package/dist/chunk-FF3Q7ADR.js +0 -380
  63. package/dist/chunk-FFKU7BTK.cjs +0 -1046
  64. package/dist/chunk-FHQVYCH2.js +0 -70
  65. package/dist/chunk-FSF7EQVA.cjs +0 -1974
  66. package/dist/chunk-G4VZTCIB.js +0 -659
  67. package/dist/chunk-G7CT3EMP.cjs +0 -1002
  68. package/dist/chunk-GGHSW2NN.js +0 -51334
  69. package/dist/chunk-GVUR45UF.cjs +0 -777
  70. package/dist/chunk-H5Z7NASB.js +0 -9662
  71. package/dist/chunk-HE7ULERA.cjs +0 -697
  72. package/dist/chunk-HJJLD366.js +0 -1169
  73. package/dist/chunk-HPS76H7Q.js +0 -309
  74. package/dist/chunk-HQUEA5R6.cjs +0 -424
  75. package/dist/chunk-HYNTS5CP.js +0 -422
  76. package/dist/chunk-I6XZ5DZF.cjs +0 -488
  77. package/dist/chunk-IBDG74G2.cjs +0 -1219
  78. package/dist/chunk-IFNQFCTM.js +0 -3098
  79. package/dist/chunk-IHOUYQIA.js +0 -406
  80. package/dist/chunk-ILRBGFVD.cjs +0 -72
  81. package/dist/chunk-IWI6J7FX.js +0 -421
  82. package/dist/chunk-K3JDKWGI.cjs +0 -270
  83. package/dist/chunk-K6EKD26I.js +0 -630
  84. package/dist/chunk-KCQ5NDYC.cjs +0 -3172
  85. package/dist/chunk-KED34ILP.js +0 -832
  86. package/dist/chunk-KSGXLT74.cjs +0 -457
  87. package/dist/chunk-L4G4RLXX.js +0 -767
  88. package/dist/chunk-LDP5OK6G.js +0 -1216
  89. package/dist/chunk-LGGRPKTV.cjs +0 -735
  90. package/dist/chunk-LK5IAVH6.cjs +0 -1173
  91. package/dist/chunk-LSW7P7ML.js +0 -3675
  92. package/dist/chunk-LXJ4667L.cjs +0 -3874
  93. package/dist/chunk-LZ266PCM.cjs +0 -4499
  94. package/dist/chunk-MD6KDHVE.cjs +0 -237
  95. package/dist/chunk-MEASWI2Y.js +0 -126
  96. package/dist/chunk-MPXBVFHQ.js +0 -768
  97. package/dist/chunk-N5FTS757.cjs +0 -415
  98. package/dist/chunk-NCUKG4SK.cjs +0 -3075
  99. package/dist/chunk-NDQNIJEH.js +0 -1715
  100. package/dist/chunk-NOZZ46QU.js +0 -168
  101. package/dist/chunk-OFKWH2IP.js +0 -449
  102. package/dist/chunk-PHENW4MQ.js +0 -65
  103. package/dist/chunk-PMGODDJA.cjs +0 -319
  104. package/dist/chunk-Q4QX3AET.cjs +0 -1505
  105. package/dist/chunk-Q56TT7IL.js +0 -483
  106. package/dist/chunk-Q5JT3YML.cjs +0 -129
  107. package/dist/chunk-Q5SJOGHQ.cjs +0 -4256
  108. package/dist/chunk-QGKNANZ3.js +0 -3071
  109. package/dist/chunk-QLEAOI3Q.cjs +0 -424
  110. package/dist/chunk-R7MA7QWV.js +0 -732
  111. package/dist/chunk-RVYPEYPX.js +0 -678
  112. package/dist/chunk-S2N5TNMA.js +0 -1855
  113. package/dist/chunk-S565K7NK.js +0 -752
  114. package/dist/chunk-SDAMZIRE.js +0 -765
  115. package/dist/chunk-T36DDXSF.js +0 -4250
  116. package/dist/chunk-T4NKMBDL.js +0 -5474
  117. package/dist/chunk-T7LEXZUZ.cjs +0 -2526
  118. package/dist/chunk-TEWCN33Y.js +0 -694
  119. package/dist/chunk-TQSZUOW5.cjs +0 -793
  120. package/dist/chunk-TSH3MSQU.cjs +0 -129
  121. package/dist/chunk-UERJ3YJV.js +0 -504
  122. package/dist/chunk-UPJBDCVF.js +0 -1395
  123. package/dist/chunk-V3NN3HPP.js +0 -4462
  124. package/dist/chunk-VJ3L7CHT.cjs +0 -169
  125. package/dist/chunk-WB4Z63GG.js +0 -229
  126. package/dist/chunk-WDW67DZB.cjs +0 -9728
  127. package/dist/chunk-WGMEAYBG.js +0 -126
  128. package/dist/chunk-X4ZF6CNE.cjs +0 -473
  129. package/dist/chunk-X6SEAXAX.cjs +0 -3681
  130. package/dist/chunk-XCWFGZAA.js +0 -1043
  131. package/dist/chunk-XD6IYDUX.js +0 -903
  132. package/dist/chunk-XG23EUQX.cjs +0 -1717
  133. package/dist/chunk-XRKWN5PL.cjs +0 -173
  134. package/dist/chunk-XUILI4KB.cjs +0 -430
  135. package/dist/chunk-XUTX5CBW.js +0 -126
  136. package/dist/chunk-XWPNTWDN.cjs +0 -755
  137. package/dist/chunk-XXINBTZK.cjs +0 -633
  138. package/dist/chunk-YCXFCXDS.js +0 -1868
  139. package/dist/chunk-YQK5JNFK.js +0 -3725
  140. package/dist/chunk-YYXH45E2.js +0 -426
  141. package/dist/chunk-Z34RLXRA.cjs +0 -612
  142. package/dist/chunk-ZP4D3CSX.cjs +0 -72
  143. package/dist/cli/holoscript-runner.cjs +0 -2259
  144. package/dist/cli/holoscript-runner.js +0 -2234
  145. package/dist/codebase/index.cjs +0 -336
  146. package/dist/codebase/index.js +0 -331
  147. package/dist/compiler/agent-inference.cjs +0 -28
  148. package/dist/compiler/agent-inference.js +0 -5
  149. package/dist/compiler/android-xr.cjs +0 -19
  150. package/dist/compiler/android-xr.js +0 -9
  151. package/dist/compiler/android.cjs +0 -20
  152. package/dist/compiler/android.js +0 -10
  153. package/dist/compiler/ar.cjs +0 -20
  154. package/dist/compiler/ar.js +0 -8
  155. package/dist/compiler/babylon.cjs +0 -17
  156. package/dist/compiler/babylon.js +0 -11
  157. package/dist/compiler/coco.cjs +0 -27
  158. package/dist/compiler/coco.js +0 -4
  159. package/dist/compiler/domain-block-utils.cjs +0 -602
  160. package/dist/compiler/domain-block-utils.js +0 -8
  161. package/dist/compiler/dtdl.cjs +0 -24
  162. package/dist/compiler/dtdl.js +0 -8
  163. package/dist/compiler/gltf-pipeline.cjs +0 -39
  164. package/dist/compiler/gltf-pipeline.js +0 -4
  165. package/dist/compiler/godot.cjs +0 -15
  166. package/dist/compiler/godot.js +0 -9
  167. package/dist/compiler/incremental.cjs +0 -29
  168. package/dist/compiler/incremental.js +0 -4
  169. package/dist/compiler/index.cjs +0 -2578
  170. package/dist/compiler/index.js +0 -2383
  171. package/dist/compiler/ios.cjs +0 -20
  172. package/dist/compiler/ios.js +0 -10
  173. package/dist/compiler/multi-layer.cjs +0 -20
  174. package/dist/compiler/multi-layer.js +0 -11
  175. package/dist/compiler/nodetoy.cjs +0 -23
  176. package/dist/compiler/nodetoy.js +0 -4
  177. package/dist/compiler/openxr.cjs +0 -15
  178. package/dist/compiler/openxr.js +0 -9
  179. package/dist/compiler/playcanvas.cjs +0 -16
  180. package/dist/compiler/playcanvas.js +0 -10
  181. package/dist/compiler/r3f.cjs +0 -34
  182. package/dist/compiler/r3f.js +0 -12
  183. package/dist/compiler/remotion.cjs +0 -23
  184. package/dist/compiler/remotion.js +0 -4
  185. package/dist/compiler/reproducibility.cjs +0 -39
  186. package/dist/compiler/reproducibility.js +0 -4
  187. package/dist/compiler/sdf.cjs +0 -21
  188. package/dist/compiler/sdf.js +0 -9
  189. package/dist/compiler/semantic-scene.cjs +0 -31
  190. package/dist/compiler/semantic-scene.js +0 -4
  191. package/dist/compiler/state.cjs +0 -17
  192. package/dist/compiler/state.js +0 -7
  193. package/dist/compiler/trait-composition.cjs +0 -26
  194. package/dist/compiler/trait-composition.js +0 -5
  195. package/dist/compiler/unity.cjs +0 -15
  196. package/dist/compiler/unity.js +0 -9
  197. package/dist/compiler/unreal.cjs +0 -19
  198. package/dist/compiler/unreal.js +0 -9
  199. package/dist/compiler/urdf.cjs +0 -45
  200. package/dist/compiler/urdf.js +0 -9
  201. package/dist/compiler/usd-physics.cjs +0 -23
  202. package/dist/compiler/usd-physics.js +0 -6
  203. package/dist/compiler/visionos.cjs +0 -15
  204. package/dist/compiler/visionos.js +0 -9
  205. package/dist/compiler/vrchat.cjs +0 -19
  206. package/dist/compiler/vrchat.js +0 -9
  207. package/dist/compiler/vrr.cjs +0 -21
  208. package/dist/compiler/vrr.js +0 -9
  209. package/dist/compiler/wasm.cjs +0 -33
  210. package/dist/compiler/wasm.js +0 -9
  211. package/dist/compiler/webgpu.cjs +0 -15
  212. package/dist/compiler/webgpu.js +0 -9
  213. package/dist/debugger.cjs +0 -21
  214. package/dist/debugger.js +0 -8
  215. package/dist/entries/interop.cjs +0 -62
  216. package/dist/entries/interop.js +0 -5
  217. package/dist/entries/scripting.cjs +0 -68
  218. package/dist/entries/scripting.js +0 -11
  219. package/dist/index.cjs +0 -40921
  220. package/dist/index.js +0 -37763
  221. package/dist/math/vec3.cjs +0 -57
  222. package/dist/math/vec3.js +0 -4
  223. package/dist/ml-dsa-PHCWUBPX.cjs +0 -1178
  224. package/dist/ml-dsa-WYLJHJO6.js +0 -1178
  225. package/dist/parser.cjs +0 -27
  226. package/dist/parser.js +0 -10
  227. package/dist/playwright-5OSAPTNH.js +0 -98660
  228. package/dist/playwright-RL6GY4F7.cjs +0 -98673
  229. package/dist/runtime.cjs +0 -16
  230. package/dist/runtime.js +0 -7
  231. package/dist/storage/index.cjs +0 -37
  232. package/dist/storage/index.js +0 -4
  233. package/dist/traits/index.cjs +0 -14649
  234. package/dist/traits/index.js +0 -12243
  235. package/dist/type-checker.cjs +0 -18
  236. package/dist/type-checker.js +0 -5
@@ -1,1002 +0,0 @@
1
- 'use strict';
2
-
3
- var path = require('path');
4
- var crypto = require('crypto');
5
-
6
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
-
8
- var path__default = /*#__PURE__*/_interopDefault(path);
9
-
10
- // src/stdlib/StdlibActions.ts
11
- var DEFAULT_STDLIB_POLICY = {
12
- allowedPaths: ["compositions", "data", "src", "packages"],
13
- maxFileBytes: 2 * 1024 * 1024,
14
- allowShell: false,
15
- allowedShellCommands: [],
16
- maxShellOutputBytes: 100 * 1024,
17
- shellTimeoutMs: 6e4,
18
- allowNetwork: false,
19
- allowedHosts: [],
20
- rootDir: ".",
21
- allowMediaDecode: false,
22
- allowDepthInference: false,
23
- allowGpuCompute: false,
24
- maxGifFrames: 500,
25
- maxVideoDurationSec: 300,
26
- maxMediaResolution: 4096
27
- };
28
- function resolveRepoRelativePath(targetPath, rootDir) {
29
- const normalized = targetPath.replace(/\\/g, "/").replace(/^\.\//, "").trim();
30
- if (!normalized) return { ok: false, error: "Path is required" };
31
- const abs = path__default.default.resolve(rootDir, normalized);
32
- const rel = path__default.default.relative(rootDir, abs).replace(/\\/g, "/");
33
- if (!rel || rel.startsWith("..") || path__default.default.isAbsolute(rel)) {
34
- return { ok: false, error: "Path escapes repository root" };
35
- }
36
- return { ok: true, rel, abs };
37
- }
38
- function isPathAllowed(relPath, allowedRoots) {
39
- const normalized = relPath.replace(/\\/g, "/");
40
- return allowedRoots.some((root) => normalized === root || normalized.startsWith(`${root}/`));
41
- }
42
- function parseHostFromUrl(url) {
43
- try {
44
- return new URL(url).hostname.toLowerCase();
45
- } catch {
46
- return null;
47
- }
48
- }
49
- function truncateText(value, max) {
50
- const str = typeof value === "string" ? value : String(value ?? "");
51
- if (!Number.isFinite(max) || max <= 0 || str.length <= max) return str;
52
- return `${str.slice(0, max)}
53
- ...[truncated ${str.length - max} chars]`;
54
- }
55
- function toStringArray(value) {
56
- if (!Array.isArray(value)) return [];
57
- return value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
58
- }
59
- function resolveInto(params, defaultPrefix) {
60
- return typeof params.into === "string" && params.into.trim().length > 0 ? params.into.trim() : defaultPrefix;
61
- }
62
- function createStdlibActions(options) {
63
- const { policy, hostCapabilities: caps, debug } = options;
64
- const log = debug ? (msg) => console.log(` [stdlib] ${msg}`) : () => {
65
- };
66
- return {
67
- // ── File System ──────────────────────────────────────────────────────
68
- fs_read: async (params, bb) => {
69
- const prefix = resolveInto(params, "fs_read");
70
- const filePath = typeof params.path === "string" ? params.path : "";
71
- const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
72
- if (!resolved.ok) {
73
- bb[`${prefix}_error`] = resolved.error;
74
- return false;
75
- }
76
- if (!isPathAllowed(resolved.rel, policy.allowedPaths)) {
77
- bb[`${prefix}_error`] = `path "${resolved.rel}" is outside allowed roots`;
78
- return false;
79
- }
80
- if (!caps?.fileSystem) {
81
- bb[`${prefix}_error`] = "fileSystem capability not available";
82
- return false;
83
- }
84
- const exists = caps.fileSystem.exists ? await Promise.resolve(caps.fileSystem.exists(resolved.rel)) : true;
85
- if (!exists) {
86
- bb[`${prefix}_error`] = `file not found: ${resolved.rel}`;
87
- bb[`${prefix}_exists`] = false;
88
- return false;
89
- }
90
- const content = await Promise.resolve(caps.fileSystem.readFile(resolved.rel));
91
- if (Buffer.byteLength(content, "utf-8") > policy.maxFileBytes) {
92
- bb[`${prefix}_error`] = `file exceeds max size (${policy.maxFileBytes} bytes)`;
93
- return false;
94
- }
95
- bb[`${prefix}_content`] = content;
96
- bb[`${prefix}_exists`] = true;
97
- log(`fs_read: ${resolved.rel} (${Buffer.byteLength(content, "utf-8")} bytes)`);
98
- return true;
99
- },
100
- fs_write: async (params, bb) => {
101
- const prefix = resolveInto(params, "fs_write");
102
- const filePath = typeof params.path === "string" ? params.path : "";
103
- const content = typeof params.content === "string" ? params.content : null;
104
- const append = params.append === true;
105
- if (content === null) {
106
- bb[`${prefix}_error`] = "content is required";
107
- return false;
108
- }
109
- if (Buffer.byteLength(content, "utf-8") > policy.maxFileBytes) {
110
- bb[`${prefix}_error`] = `content exceeds max size (${policy.maxFileBytes} bytes)`;
111
- return false;
112
- }
113
- const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
114
- if (!resolved.ok) {
115
- bb[`${prefix}_error`] = resolved.error;
116
- return false;
117
- }
118
- if (!isPathAllowed(resolved.rel, policy.allowedPaths)) {
119
- bb[`${prefix}_error`] = `path "${resolved.rel}" is outside allowed roots`;
120
- return false;
121
- }
122
- if (!caps?.fileSystem) {
123
- bb[`${prefix}_error`] = "fileSystem capability not available";
124
- return false;
125
- }
126
- let finalContent = content;
127
- if (append && caps.fileSystem.exists) {
128
- const exists = await Promise.resolve(caps.fileSystem.exists(resolved.rel));
129
- if (exists) {
130
- const current = await Promise.resolve(caps.fileSystem.readFile(resolved.rel));
131
- finalContent = `${current}${content}`;
132
- }
133
- }
134
- await Promise.resolve(caps.fileSystem.writeFile(resolved.rel, finalContent));
135
- bb[`${prefix}_path`] = resolved.rel;
136
- bb[`${prefix}_bytes`] = Buffer.byteLength(content, "utf-8");
137
- log(`fs_write: ${resolved.rel} (${bb[`${prefix}_bytes`]} bytes, append=${append})`);
138
- return true;
139
- },
140
- fs_exists: async (params, bb) => {
141
- const prefix = resolveInto(params, "fs_exists");
142
- const filePath = typeof params.path === "string" ? params.path : "";
143
- const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
144
- if (!resolved.ok) {
145
- bb[`${prefix}_error`] = resolved.error;
146
- return false;
147
- }
148
- if (!caps?.fileSystem?.exists) {
149
- bb[`${prefix}_error`] = "fileSystem.exists capability not available";
150
- return false;
151
- }
152
- const exists = await Promise.resolve(caps.fileSystem.exists(resolved.rel));
153
- bb[`${prefix}_exists`] = exists;
154
- log(`fs_exists: ${resolved.rel} \u2192 ${exists}`);
155
- return true;
156
- },
157
- fs_delete: async (params, bb) => {
158
- const prefix = resolveInto(params, "fs_delete");
159
- const filePath = typeof params.path === "string" ? params.path : "";
160
- const resolved = resolveRepoRelativePath(filePath, policy.rootDir);
161
- if (!resolved.ok) {
162
- bb[`${prefix}_error`] = resolved.error;
163
- return false;
164
- }
165
- if (!isPathAllowed(resolved.rel, policy.allowedPaths)) {
166
- bb[`${prefix}_error`] = `path "${resolved.rel}" is outside allowed roots`;
167
- return false;
168
- }
169
- if (!caps?.fileSystem?.deleteFile) {
170
- bb[`${prefix}_error`] = "fileSystem.deleteFile capability not available";
171
- return false;
172
- }
173
- await Promise.resolve(caps.fileSystem.deleteFile(resolved.rel));
174
- log(`fs_delete: ${resolved.rel}`);
175
- return true;
176
- },
177
- // ── Process Execution ─────────────────────────────────────────────────
178
- process_exec: async (params, bb) => {
179
- const prefix = resolveInto(params, "process_exec");
180
- if (!policy.allowShell) {
181
- bb[`${prefix}_error`] = `${prefix} is disabled by policy`;
182
- return false;
183
- }
184
- const command = typeof params.cmd === "string" ? params.cmd.trim() : "";
185
- const args = toStringArray(params.args);
186
- if (!command) {
187
- bb[`${prefix}_error`] = "cmd is required";
188
- return false;
189
- }
190
- if (policy.allowedShellCommands.length > 0) {
191
- const executable = command.split(/\s+/)[0].toLowerCase();
192
- const allowed = policy.allowedShellCommands.some((c) => c.toLowerCase() === executable);
193
- if (!allowed) {
194
- bb[`${prefix}_error`] = `command "${executable}" is not allowlisted`;
195
- return false;
196
- }
197
- }
198
- if (!caps?.process?.exec) {
199
- bb[`${prefix}_error`] = "process.exec capability not available";
200
- return false;
201
- }
202
- const timeoutMs = typeof params.timeout === "number" && Number.isFinite(params.timeout) ? Math.max(1e3, Math.min(policy.shellTimeoutMs, Math.floor(params.timeout))) : policy.shellTimeoutMs;
203
- const cwd = typeof params.cwd === "string" ? params.cwd : policy.rootDir;
204
- const result = await Promise.resolve(caps.process.exec(command, args, { cwd, timeoutMs }));
205
- bb[`${prefix}_code`] = result.code ?? -1;
206
- bb[`${prefix}_stdout`] = truncateText(result.stdout, policy.maxShellOutputBytes);
207
- bb[`${prefix}_stderr`] = truncateText(result.stderr, policy.maxShellOutputBytes);
208
- log(`process_exec: ${command} ${args.join(" ")} \u2192 code ${result.code}`);
209
- return result.code === 0;
210
- },
211
- // ── Network ───────────────────────────────────────────────────────────
212
- net_fetch: async (params, bb) => {
213
- const prefix = resolveInto(params, "net_fetch");
214
- const url = typeof params.url === "string" ? params.url.trim() : "";
215
- if (!url) {
216
- bb[`${prefix}_error`] = "url is required";
217
- return false;
218
- }
219
- if (!policy.allowNetwork) {
220
- bb[`${prefix}_error`] = "network access is disabled by policy";
221
- return false;
222
- }
223
- const hostName = parseHostFromUrl(url);
224
- if (!hostName) {
225
- bb[`${prefix}_error`] = "invalid url";
226
- return false;
227
- }
228
- if (policy.allowedHosts.length > 0) {
229
- const allowed = policy.allowedHosts.includes(hostName) || policy.allowedHosts.some((h) => hostName.endsWith(`.${h}`));
230
- if (!allowed) {
231
- bb[`${prefix}_error`] = `host "${hostName}" is not allowlisted`;
232
- return false;
233
- }
234
- }
235
- if (caps?.network?.fetch) {
236
- try {
237
- const response = await Promise.resolve(
238
- caps.network.fetch(url, {
239
- method: typeof params.method === "string" ? params.method : "GET",
240
- headers: typeof params.headers === "object" && params.headers ? params.headers : void 0,
241
- body: typeof params.body === "string" ? params.body : void 0
242
- })
243
- );
244
- bb[`${prefix}_status`] = response.status;
245
- bb[`${prefix}_body`] = truncateText(response.text ?? "", policy.maxShellOutputBytes);
246
- bb[`${prefix}_ok`] = response.ok;
247
- log(`net_fetch: ${url} \u2192 ${response.status}`);
248
- return response.ok;
249
- } catch (error) {
250
- bb[`${prefix}_error`] = error.message;
251
- return false;
252
- }
253
- }
254
- try {
255
- const response = await globalThis.fetch(url, {
256
- method: typeof params.method === "string" ? params.method : "GET",
257
- headers: typeof params.headers === "object" && params.headers ? params.headers : void 0
258
- });
259
- const text = await response.text();
260
- bb[`${prefix}_status`] = response.status;
261
- bb[`${prefix}_body`] = truncateText(text, policy.maxShellOutputBytes);
262
- bb[`${prefix}_ok`] = response.ok;
263
- log(`net_fetch: ${url} \u2192 ${response.status}`);
264
- return response.ok;
265
- } catch (error) {
266
- bb[`${prefix}_error`] = error.message;
267
- return false;
268
- }
269
- }
270
- };
271
- }
272
- function registerStdlib(runtime, options) {
273
- const actions = createStdlibActions(options);
274
- for (const [name, handler] of Object.entries(actions)) {
275
- runtime.registerAction(name, handler);
276
- }
277
- }
278
-
279
- // src/traits/TestTrait.ts
280
- var CompositionTestRunner = class {
281
- constructor(initialState, computedDefs = [], config = {}) {
282
- this.initialState = { ...initialState };
283
- this.computedDefs = computedDefs;
284
- this.config = {
285
- bail: config.bail ?? false,
286
- debug: config.debug ?? false,
287
- timeout: config.timeout ?? 5e3
288
- };
289
- }
290
- /**
291
- * Extract and run all @test blocks from .hsplus source
292
- */
293
- runTestsFromSource(source) {
294
- const tests = this.extractTestBlocks(source);
295
- if (this.config.debug) {
296
- console.debug(`[composition_test] Found ${tests.length} @test blocks`);
297
- }
298
- return this.runAll(tests);
299
- }
300
- /**
301
- * Run all test blocks
302
- */
303
- runAll(tests) {
304
- const results = [];
305
- for (const test of tests) {
306
- if (test.skip) {
307
- results.push({
308
- name: test.name,
309
- status: "skipped",
310
- durationMs: 0,
311
- assertions: test.assertions.length,
312
- passedAssertions: 0
313
- });
314
- continue;
315
- }
316
- const result = this.runSingle(test);
317
- results.push(result);
318
- if (this.config.bail && result.status === "failed") {
319
- break;
320
- }
321
- }
322
- return results;
323
- }
324
- /**
325
- * Run a single test block:
326
- * 1. Clone initial state
327
- * 2. Apply setup assignments
328
- * 3. Evaluate computed values
329
- * 4. Check assertions
330
- */
331
- runSingle(test) {
332
- const start = Date.now();
333
- let passedAssertions = 0;
334
- try {
335
- const state = { ...this.initialState };
336
- for (const { variable, expression } of test.setupAssignments) {
337
- const value = this.evaluateValue(expression, state);
338
- state[variable] = value;
339
- }
340
- const computed = this.evaluateComputedValues(state);
341
- const fullState = { ...state, ...computed };
342
- if (this.config.debug) {
343
- console.debug(`[composition_test] "${test.name}" state:`, fullState);
344
- }
345
- for (const assertion of test.assertions) {
346
- const passed = this.evaluateAssertion(assertion.expression, fullState);
347
- if (passed) {
348
- passedAssertions++;
349
- } else {
350
- return {
351
- name: test.name,
352
- status: "failed",
353
- durationMs: Date.now() - start,
354
- error: `Assertion failed: ${assertion.expression}`,
355
- assertions: test.assertions.length,
356
- passedAssertions
357
- };
358
- }
359
- }
360
- return {
361
- name: test.name,
362
- status: "passed",
363
- durationMs: Date.now() - start,
364
- assertions: test.assertions.length,
365
- passedAssertions
366
- };
367
- } catch (error) {
368
- return {
369
- name: test.name,
370
- status: "failed",
371
- durationMs: Date.now() - start,
372
- error: error instanceof Error ? error.message : String(error),
373
- assertions: test.assertions.length,
374
- passedAssertions
375
- };
376
- }
377
- }
378
- // ─── Extraction ──────────────────────────────────────────────────────────────
379
- /**
380
- * Extract @test { name: "...", setup: { ... }, assert: { ... } } blocks
381
- */
382
- extractTestBlocks(source) {
383
- const blocks = [];
384
- const regex = /@test\s*\{/g;
385
- let match;
386
- while ((match = regex.exec(source)) !== null) {
387
- const startIdx = match.index + match[0].length;
388
- let depth = 1;
389
- let endIdx = startIdx;
390
- while (depth > 0 && endIdx < source.length) {
391
- if (source[endIdx] === "{") depth++;
392
- if (source[endIdx] === "}") depth--;
393
- endIdx++;
394
- }
395
- const body = source.substring(startIdx, endIdx - 1).trim();
396
- const block = this.parseTestBody(body);
397
- if (block) blocks.push(block);
398
- }
399
- return blocks;
400
- }
401
- /**
402
- * Parse the body of a @test block into structured data
403
- */
404
- parseTestBody(body) {
405
- const nameMatch = body.match(/name:\s*"([^"]+)"/);
406
- if (!nameMatch) return null;
407
- const name = nameMatch[1];
408
- const skipMatch = body.match(/skip:\s*(true|false)/);
409
- const skip = skipMatch?.[1] === "true";
410
- const setupAssignments = [];
411
- const setupMatch = body.match(/setup:\s*\{([^}]+)\}/);
412
- if (setupMatch) {
413
- const setupBody = setupMatch[1].trim();
414
- const assignRegex = /\$([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)/g;
415
- let assignMatch;
416
- while ((assignMatch = assignRegex.exec(setupBody)) !== null) {
417
- setupAssignments.push({
418
- variable: assignMatch[1],
419
- expression: assignMatch[2].trim().replace(/[,;]\s*$/, "")
420
- });
421
- }
422
- }
423
- const assertions = [];
424
- const assertRegex = /assert:\s*\{([^}]+)\}/g;
425
- let assertMatch;
426
- while ((assertMatch = assertRegex.exec(body)) !== null) {
427
- const assertBody = assertMatch[1].trim();
428
- const lines = assertBody.split(/[;\n]/).map((l) => l.trim()).filter(Boolean);
429
- for (const line of lines) {
430
- assertions.push({ expression: line });
431
- }
432
- }
433
- return { name, setupAssignments, assertions, skip };
434
- }
435
- // ─── Evaluation ──────────────────────────────────────────────────────────────
436
- /**
437
- * Evaluate a single value expression, resolving $vars from state
438
- */
439
- evaluateValue(expr, state) {
440
- const trimmed = expr.trim();
441
- if (trimmed === "true") return true;
442
- if (trimmed === "false") return false;
443
- if (trimmed === "null") return null;
444
- if (/^-?\d+(\.\d+)?$/.test(trimmed)) return Number(trimmed);
445
- if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
446
- return trimmed.slice(1, -1);
447
- }
448
- if (trimmed.startsWith("$")) {
449
- const varName = trimmed.slice(1);
450
- return state[varName];
451
- }
452
- try {
453
- const transformed = trimmed.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, varName) => varName);
454
- const keys = Object.keys(state);
455
- const values = Object.values(state);
456
- const fn = new Function(
457
- ...keys,
458
- "Math",
459
- "String",
460
- "Number",
461
- "Boolean",
462
- "Date",
463
- "JSON",
464
- `"use strict"; return (${transformed})`
465
- );
466
- return fn(...values, Math, String, Number, Boolean, Date, JSON);
467
- } catch {
468
- return trimmed;
469
- }
470
- }
471
- /**
472
- * Evaluate an assertion expression against state.
473
- * Supports: $var == value, $var != value, $var > value, etc.
474
- */
475
- evaluateAssertion(expr, state) {
476
- const trimmed = expr.trim();
477
- const transformed = trimmed.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, varName) => varName);
478
- try {
479
- const keys = Object.keys(state);
480
- const values = Object.values(state);
481
- const fn = new Function(
482
- ...keys,
483
- "Math",
484
- "String",
485
- "Number",
486
- "Boolean",
487
- "Date",
488
- "JSON",
489
- `"use strict"; return !!(${transformed})`
490
- );
491
- return fn(...values, Math, String, Number, Boolean, Date, JSON);
492
- } catch {
493
- return false;
494
- }
495
- }
496
- /**
497
- * Evaluate computed values from their definitions
498
- */
499
- evaluateComputedValues(state) {
500
- const result = {};
501
- for (const def of this.computedDefs) {
502
- try {
503
- const transformed = def.expression.replace(
504
- /\$([a-zA-Z_][a-zA-Z0-9_]*)/g,
505
- (_, varName) => varName
506
- );
507
- const keys = Object.keys(state);
508
- const values = Object.values(state);
509
- const fn = new Function(
510
- ...keys,
511
- "Math",
512
- "String",
513
- "Number",
514
- "Boolean",
515
- "Date",
516
- "JSON",
517
- `"use strict"; return (${transformed})`
518
- );
519
- result[def.name] = fn(...values, Math, String, Number, Boolean, Date, JSON);
520
- } catch {
521
- result[def.name] = void 0;
522
- }
523
- }
524
- return result;
525
- }
526
- // ─── Static helpers ──────────────────────────────────────────────────────────
527
- /**
528
- * Extract state block from .hsplus source.
529
- * Handles nested objects { ... } and arrays [ ... ].
530
- */
531
- static extractStateFromSource(source) {
532
- const result = {};
533
- const stateMatch = source.match(/\bstate\s*\{/);
534
- if (stateMatch) {
535
- const startIdx = stateMatch.index + stateMatch[0].length;
536
- const body = extractBracedBody(source, startIdx);
537
- Object.assign(result, parseNestedBlock(body));
538
- }
539
- const inlineRegex = /^\s*state\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*\w+\s*=\s*(.+)$/gm;
540
- let inlineMatch;
541
- while ((inlineMatch = inlineRegex.exec(source)) !== null) {
542
- const key = inlineMatch[1];
543
- if (!(key in result)) {
544
- result[key] = parseStateValue(inlineMatch[2].trim());
545
- }
546
- }
547
- return result;
548
- }
549
- /**
550
- * Extract computed definitions from .hsplus source
551
- */
552
- static extractComputedFromSource(source) {
553
- const defs = [];
554
- const computedMatch = source.match(/\bcomputed\s*\{/);
555
- if (!computedMatch) return defs;
556
- const startIdx = computedMatch.index + computedMatch[0].length;
557
- let depth = 1;
558
- let endIdx = startIdx;
559
- while (depth > 0 && endIdx < source.length) {
560
- if (source[endIdx] === "{") depth++;
561
- if (source[endIdx] === "}") depth--;
562
- endIdx++;
563
- }
564
- const body = source.substring(startIdx, endIdx - 1);
565
- const lines = body.split("\n");
566
- for (const line of lines) {
567
- const trimmed = line.trim();
568
- if (!trimmed || trimmed.startsWith("//")) continue;
569
- const kvMatch = trimmed.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+?)\s*$/);
570
- if (kvMatch) {
571
- defs.push({ name: kvMatch[1], expression: kvMatch[2] });
572
- }
573
- }
574
- return defs;
575
- }
576
- };
577
- function extractBracedBody(source, startIdx) {
578
- let depth = 1;
579
- let i = startIdx;
580
- while (depth > 0 && i < source.length) {
581
- if (source[i] === "{") depth++;
582
- if (source[i] === "}") depth--;
583
- i++;
584
- }
585
- return source.substring(startIdx, i - 1);
586
- }
587
- function parseNestedBlock(body) {
588
- const result = {};
589
- let i = 0;
590
- while (i < body.length) {
591
- while (i < body.length && /\s/.test(body[i])) i++;
592
- if (i >= body.length) break;
593
- if (body[i] === "/" && body[i + 1] === "/") {
594
- while (i < body.length && body[i] !== "\n") i++;
595
- continue;
596
- }
597
- const keyMatch = body.slice(i).match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*/);
598
- if (!keyMatch) {
599
- i++;
600
- continue;
601
- }
602
- const key = keyMatch[1];
603
- i += keyMatch[0].length;
604
- while (i < body.length && /\s/.test(body[i])) i++;
605
- if (body[i] === "{") {
606
- i++;
607
- const nestedBody = extractBracedBody(body, i);
608
- i += nestedBody.length + 1;
609
- result[key] = parseNestedBlock(nestedBody);
610
- } else if (body[i] === "[") {
611
- const arrStart = i;
612
- let depth = 1;
613
- i++;
614
- while (depth > 0 && i < body.length) {
615
- if (body[i] === "[") depth++;
616
- if (body[i] === "]") depth--;
617
- i++;
618
- }
619
- const arrStr = body.substring(arrStart, i).trim();
620
- try {
621
- result[key] = JSON.parse(arrStr);
622
- } catch {
623
- result[key] = arrStr;
624
- }
625
- } else {
626
- const valMatch = body.slice(i).match(/^(.+?)(?:\n|$)/);
627
- if (valMatch) {
628
- const raw = valMatch[1].trim().replace(/,\s*$/, "");
629
- result[key] = parseStateValue(raw);
630
- i += valMatch[0].length;
631
- } else {
632
- i++;
633
- }
634
- }
635
- }
636
- return result;
637
- }
638
- function parseStateValue(raw) {
639
- const v = raw.trim().replace(/,\s*$/, "");
640
- if (v === "true") return true;
641
- if (v === "false") return false;
642
- if (v === "null") return null;
643
- if (/^-?\d+(\.\d+)?$/.test(v)) return Number(v);
644
- if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
645
- return v.slice(1, -1);
646
- }
647
- return v;
648
- }
649
- var TEST_TRAIT = {
650
- name: "test",
651
- category: "testing",
652
- description: "Native composition testing with $stateVar syntax",
653
- compileTargets: ["node", "python", "ros2", "headless"],
654
- requiresRenderer: false,
655
- parameters: [
656
- { name: "name", type: "string", required: true, description: "Test name" },
657
- { name: "setup", type: "object", required: false, description: "State setup assignments" },
658
- { name: "assert", type: "object", required: true, description: "Assertion expressions" },
659
- {
660
- name: "skip",
661
- type: "boolean",
662
- required: false,
663
- default: false,
664
- description: "Skip this test"
665
- }
666
- ]
667
- };
668
- var testHandler = {
669
- name: "test",
670
- defaultConfig: { bail: false, debug: false, timeout: 5e3 },
671
- onAttach(node, config, ctx) {
672
- const instance = new CompositionTestRunner({}, [], config);
673
- node.__test_instance = instance;
674
- ctx.emit?.("test:attached", { node, config });
675
- },
676
- onDetach(node, _config, ctx) {
677
- delete node.__test_instance;
678
- ctx.emit?.("test:detached", { node });
679
- },
680
- onUpdate() {
681
- },
682
- onEvent(node, _config, ctx, event) {
683
- const instance = node.__test_instance;
684
- if (!instance) return;
685
- const eventType = typeof event === "string" ? event : event.type;
686
- if (eventType === "test:run" && event.source) {
687
- const results = instance.runTestsFromSource(event.source);
688
- ctx.emit?.("test:results", { results });
689
- }
690
- }
691
- };
692
- function computeContentHash(source) {
693
- const normalized = source.replace(/\r\n/g, "\n");
694
- return crypto.createHash("sha256").update(normalized, "utf8").digest("hex");
695
- }
696
- function classifyPublishMode(ast) {
697
- const imports = ast?.imports ?? ast?.ast?.imports ?? [];
698
- const hasImports = Array.isArray(imports) && imports.length > 0;
699
- if (!hasImports) return "original";
700
- const body = ast?.body ?? ast?.ast?.body ?? [];
701
- const hasOwnContent = Array.isArray(body) && body.some(
702
- (node) => node.type === "composition" || node.type === "ObjectDeclaration" || node.type === "scene" || node.type === "object" || node.type === "character" || node.type === "environment"
703
- );
704
- if (hasOwnContent) return "remix";
705
- return "curated";
706
- }
707
- function extractImports(ast) {
708
- const imports = ast?.imports ?? ast?.ast?.imports ?? [];
709
- if (!Array.isArray(imports)) return [];
710
- return imports.map((imp) => ({
711
- // @ts-expect-error
712
- path: imp.path ?? imp.source ?? "",
713
- // @ts-expect-error
714
- hash: imp.hash,
715
- // @ts-expect-error
716
- author: imp.author
717
- })).filter((imp) => imp.path.length > 0);
718
- }
719
- function generateProvenance(source, ast, options) {
720
- return {
721
- author: options.author,
722
- created: options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
723
- hash: computeContentHash(source),
724
- license: options.license,
725
- version: 1,
726
- publishMode: classifyPublishMode(ast),
727
- imports: extractImports(ast)
728
- };
729
- }
730
-
731
- // src/deploy/license-checker.ts
732
- var RESTRICTIVENESS = {
733
- free: 0,
734
- cc_by: 1,
735
- cc_by_sa: 2,
736
- cc_by_nc: 3,
737
- commercial: 4,
738
- exclusive: 5
739
- };
740
- function checkLicenseCompatibility(compositionLicense, importedLicenses) {
741
- const errors = [];
742
- const warnings = [];
743
- let forcedLicense;
744
- if (importedLicenses.length === 0) {
745
- return { compatible: true, errors: [], warnings: [] };
746
- }
747
- for (const imp of importedLicenses) {
748
- if (imp.license === "exclusive") {
749
- errors.push(
750
- `Cannot import "${imp.path}" \u2014 license is "exclusive" (view-only, no import allowed)`
751
- );
752
- continue;
753
- }
754
- if (imp.license === "commercial") {
755
- warnings.push(
756
- `Import "${imp.path}" has "commercial" license \u2014 ensure purchase is verified before publishing`
757
- );
758
- continue;
759
- }
760
- if (imp.license === "cc_by_sa") {
761
- const compositionLevel = RESTRICTIVENESS[compositionLicense];
762
- const requiredLevel = RESTRICTIVENESS.cc_by_sa;
763
- if (compositionLevel < requiredLevel) {
764
- if (!forcedLicense || RESTRICTIVENESS[forcedLicense] < requiredLevel) {
765
- forcedLicense = "cc_by_sa";
766
- }
767
- warnings.push(
768
- `Import "${imp.path}" is "cc_by_sa" \u2014 your composition license forced to "cc_by_sa" (share-alike)`
769
- );
770
- }
771
- }
772
- if (imp.license === "cc_by_nc") {
773
- if (compositionLicense === "free" || compositionLicense === "cc_by") {
774
- if (!forcedLicense || RESTRICTIVENESS[forcedLicense] < RESTRICTIVENESS.cc_by_nc) {
775
- forcedLicense = "cc_by_nc";
776
- }
777
- warnings.push(
778
- `Import "${imp.path}" is "cc_by_nc" \u2014 your composition license forced to "cc_by_nc" (non-commercial)`
779
- );
780
- }
781
- }
782
- if (imp.license === "cc_by") {
783
- if (compositionLicense === "free") {
784
- if (!forcedLicense || RESTRICTIVENESS[forcedLicense] < RESTRICTIVENESS.cc_by) {
785
- forcedLicense = "cc_by";
786
- }
787
- warnings.push(
788
- `Import "${imp.path}" is "cc_by" \u2014 your composition license forced to at least "cc_by" (attribution required)`
789
- );
790
- }
791
- }
792
- }
793
- const hasShareAlike = importedLicenses.some((i) => i.license === "cc_by_sa");
794
- const hasNonCommercial = importedLicenses.some((i) => i.license === "cc_by_nc");
795
- if (hasShareAlike && hasNonCommercial) {
796
- errors.push(
797
- 'License conflict: cannot mix "cc_by_sa" (share-alike) and "cc_by_nc" (non-commercial) imports \u2014 cc_by_sa requires derivatives use the same license, but cc_by_nc requires non-commercial use'
798
- );
799
- }
800
- return {
801
- compatible: errors.length === 0,
802
- errors,
803
- warnings,
804
- forcedLicense
805
- };
806
- }
807
-
808
- // src/deploy/protocol-types.ts
809
- var PROTOCOL_CONSTANTS = {
810
- /** Platform fee in basis points (2.5%) */
811
- PLATFORM_FEE_BPS: 250,
812
- /** Import royalty per level in basis points (5% per level) */
813
- IMPORT_ROYALTY_BPS: 500,
814
- /** Maximum import depth for revenue distribution */
815
- MAX_IMPORT_DEPTH: 3,
816
- /** Default referral reward in basis points (2%) */
817
- DEFAULT_REFERRAL_BPS: 200,
818
- /** Basis points denominator */
819
- BPS_DENOMINATOR: 1e4,
820
- /** Zora mint fee per edition (in wei) */
821
- ZORA_MINT_FEE_WEI: 777000000000000n,
822
- // 0.000777 ETH
823
- /** Chain configuration */
824
- CHAIN: {
825
- id: 8453,
826
- name: "base",
827
- testnet: {
828
- id: 84532,
829
- name: "base-sepolia"
830
- }
831
- },
832
- /** Protocol registry base URL */
833
- REGISTRY_BASE_URL: "https://holoscript.net",
834
- /** Zora 1155 factory address (same on all chains) */
835
- ZORA_1155_FACTORY: "0x777777C338d93e2C7adf08D102d45CA7CC4Ed021",
836
- /** Environment variable names */
837
- ENV: {
838
- WALLET_KEY: "HOLOSCRIPT_WALLET_KEY",
839
- COLLECTION_ADDRESS: "HOLOSCRIPT_COLLECTION_ADDRESS",
840
- SERVER_URL: "HOLOSCRIPT_SERVER_URL"
841
- }
842
- };
843
-
844
- // src/deploy/revenue-splitter.ts
845
- function calculateRevenueDistribution(collectPrice, creator, importChain, options = {}) {
846
- const {
847
- platformFeeBps = PROTOCOL_CONSTANTS.PLATFORM_FEE_BPS,
848
- importRoyaltyBps = PROTOCOL_CONSTANTS.IMPORT_ROYALTY_BPS,
849
- maxImportDepth = PROTOCOL_CONSTANTS.MAX_IMPORT_DEPTH,
850
- referralBps = PROTOCOL_CONSTANTS.DEFAULT_REFERRAL_BPS,
851
- referrer,
852
- platformAddress = "platform"
853
- } = options;
854
- const flows = [];
855
- if (collectPrice === 0n) {
856
- return { totalPrice: 0n, flows: [] };
857
- }
858
- const bpsDenom = BigInt(PROTOCOL_CONSTANTS.BPS_DENOMINATOR);
859
- let remaining = collectPrice;
860
- const platformFee = collectPrice * BigInt(platformFeeBps) / bpsDenom;
861
- if (platformFee > 0n) {
862
- flows.push({
863
- recipient: platformAddress,
864
- amount: platformFee,
865
- reason: "platform",
866
- bps: platformFeeBps
867
- });
868
- remaining -= platformFee;
869
- }
870
- if (referrer) {
871
- const referralAmount = collectPrice * BigInt(referralBps) / bpsDenom;
872
- if (referralAmount > 0n) {
873
- flows.push({
874
- recipient: referrer,
875
- amount: referralAmount,
876
- reason: "referral",
877
- bps: referralBps
878
- });
879
- remaining -= referralAmount;
880
- }
881
- }
882
- const flattenedByDepth = flattenImportsByDepth(importChain, maxImportDepth);
883
- for (const [depth, nodes] of flattenedByDepth.entries()) {
884
- if (nodes.length === 0) continue;
885
- const levelRoyalty = collectPrice * BigInt(importRoyaltyBps) / bpsDenom;
886
- const perImportRoyalty = levelRoyalty / BigInt(nodes.length);
887
- const dust = levelRoyalty - perImportRoyalty * BigInt(nodes.length);
888
- for (let i = 0; i < nodes.length; i++) {
889
- const amount = i === 0 ? perImportRoyalty + dust : perImportRoyalty;
890
- if (amount > 0n) {
891
- flows.push({
892
- recipient: nodes[i].author,
893
- amount,
894
- reason: "import_royalty",
895
- depth,
896
- bps: Math.floor(importRoyaltyBps / nodes.length)
897
- });
898
- remaining -= amount;
899
- }
900
- }
901
- }
902
- if (remaining > 0n) {
903
- const creatorBps = PROTOCOL_CONSTANTS.BPS_DENOMINATOR - platformFeeBps - (referrer ? referralBps : 0) - importRoyaltyBps * flattenedByDepth.size;
904
- flows.push({
905
- recipient: creator,
906
- amount: remaining,
907
- reason: "creator",
908
- bps: Math.max(creatorBps, 0)
909
- });
910
- }
911
- return { totalPrice: collectPrice, flows };
912
- }
913
- function flattenImportsByDepth(chain, maxDepth) {
914
- const byDepth = /* @__PURE__ */ new Map();
915
- const seen = /* @__PURE__ */ new Set();
916
- function walk(nodes, depth) {
917
- if (depth > maxDepth) return;
918
- for (const node of nodes) {
919
- if (seen.has(node.contentHash)) continue;
920
- seen.add(node.contentHash);
921
- const list = byDepth.get(depth) ?? [];
922
- list.push(node);
923
- byDepth.set(depth, list);
924
- if (node.children.length > 0) {
925
- walk(node.children, depth + 1);
926
- }
927
- }
928
- }
929
- walk(chain, 1);
930
- return byDepth;
931
- }
932
- async function resolveImportChain(imports, resolver, maxDepth = PROTOCOL_CONSTANTS.MAX_IMPORT_DEPTH) {
933
- const seen = /* @__PURE__ */ new Set();
934
- async function resolve(importList, depth) {
935
- if (depth > maxDepth) return [];
936
- const nodes = [];
937
- for (const imp of importList) {
938
- const hash = imp.hash;
939
- if (!hash || seen.has(hash)) continue;
940
- seen.add(hash);
941
- const record = await resolver(hash);
942
- const author = record?.author ?? imp.author ?? "unknown";
943
- const children = record && depth < maxDepth ? await resolve(
944
- record.importHashes.map((h) => ({ hash: h, path: "", author: "" })),
945
- depth + 1
946
- ) : [];
947
- nodes.push({
948
- contentHash: hash,
949
- author,
950
- depth,
951
- children
952
- });
953
- }
954
- return nodes;
955
- }
956
- return resolve(imports, 1);
957
- }
958
- function formatRevenueDistribution(dist) {
959
- if (dist.totalPrice === 0n) return ["Free collect \u2014 no revenue distribution"];
960
- return dist.flows.map((flow) => {
961
- const pct = (Number(flow.amount) / Number(dist.totalPrice) * 100).toFixed(1);
962
- const depthLabel = flow.depth ? `, depth ${flow.depth}` : "";
963
- return `${pct}% \u2192 ${flow.recipient} (${flow.reason}${depthLabel})`;
964
- });
965
- }
966
- function ethToWei(eth) {
967
- const parts = eth.split(".");
968
- const whole = parts[0] || "0";
969
- const fraction = (parts[1] || "").padEnd(18, "0").slice(0, 18);
970
- return BigInt(whole) * 10n ** 18n + BigInt(fraction);
971
- }
972
- function weiToEth(wei) {
973
- const str = wei.toString().padStart(19, "0");
974
- const whole = str.slice(0, str.length - 18) || "0";
975
- const fraction = str.slice(str.length - 18).replace(/0+$/, "") || "0";
976
- return `${whole}.${fraction}`;
977
- }
978
-
979
- exports.CompositionTestRunner = CompositionTestRunner;
980
- exports.DEFAULT_STDLIB_POLICY = DEFAULT_STDLIB_POLICY;
981
- exports.PROTOCOL_CONSTANTS = PROTOCOL_CONSTANTS;
982
- exports.TEST_TRAIT = TEST_TRAIT;
983
- exports.calculateRevenueDistribution = calculateRevenueDistribution;
984
- exports.checkLicenseCompatibility = checkLicenseCompatibility;
985
- exports.classifyPublishMode = classifyPublishMode;
986
- exports.computeContentHash = computeContentHash;
987
- exports.createStdlibActions = createStdlibActions;
988
- exports.ethToWei = ethToWei;
989
- exports.extractImports = extractImports;
990
- exports.formatRevenueDistribution = formatRevenueDistribution;
991
- exports.generateProvenance = generateProvenance;
992
- exports.isPathAllowed = isPathAllowed;
993
- exports.parseHostFromUrl = parseHostFromUrl;
994
- exports.registerStdlib = registerStdlib;
995
- exports.resolveImportChain = resolveImportChain;
996
- exports.resolveRepoRelativePath = resolveRepoRelativePath;
997
- exports.testHandler = testHandler;
998
- exports.toStringArray = toStringArray;
999
- exports.truncateText = truncateText;
1000
- exports.weiToEth = weiToEth;
1001
- //# sourceMappingURL=chunk-G7CT3EMP.cjs.map
1002
- //# sourceMappingURL=chunk-G7CT3EMP.cjs.map