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