@nexart/codemode-sdk 1.5.0 → 1.6.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 (99) hide show
  1. package/CHANGELOG.md +326 -0
  2. package/CODE_MODE_PROTOCOL.md +471 -0
  3. package/LICENSE.md +62 -0
  4. package/README.md +296 -58
  5. package/builder.manifest.schema.json +62 -0
  6. package/dist/builder-manifest.d.ts +79 -0
  7. package/dist/builder-manifest.d.ts.map +1 -0
  8. package/dist/builder-manifest.js +97 -0
  9. package/dist/core-index.d.ts +21 -0
  10. package/dist/core-index.d.ts.map +1 -0
  11. package/dist/core-index.js +26 -0
  12. package/dist/engine.d.ts +17 -39
  13. package/dist/engine.d.ts.map +1 -1
  14. package/dist/engine.js +52 -253
  15. package/dist/execute.d.ts +46 -0
  16. package/dist/execute.d.ts.map +1 -0
  17. package/dist/execute.js +283 -0
  18. package/dist/execution-sandbox.d.ts +107 -0
  19. package/dist/execution-sandbox.d.ts.map +1 -0
  20. package/dist/execution-sandbox.js +207 -0
  21. package/dist/index.d.ts +24 -17
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +30 -16
  24. package/dist/loop-engine.d.ts +3 -0
  25. package/dist/loop-engine.d.ts.map +1 -1
  26. package/dist/loop-engine.js +17 -7
  27. package/dist/noise-bridge.d.ts +44 -0
  28. package/dist/noise-bridge.d.ts.map +1 -0
  29. package/dist/noise-bridge.js +68 -0
  30. package/dist/noise-engine.d.ts +74 -0
  31. package/dist/noise-engine.d.ts.map +1 -0
  32. package/dist/noise-engine.js +132 -0
  33. package/dist/noise-sketches/fractalNoise.d.ts +11 -0
  34. package/dist/noise-sketches/fractalNoise.d.ts.map +1 -0
  35. package/dist/noise-sketches/fractalNoise.js +121 -0
  36. package/dist/noise-sketches/index.d.ts +21 -0
  37. package/dist/noise-sketches/index.d.ts.map +1 -0
  38. package/dist/noise-sketches/index.js +28 -0
  39. package/dist/p5-runtime.d.ts +3 -1
  40. package/dist/p5-runtime.d.ts.map +1 -1
  41. package/dist/p5-runtime.js +2 -0
  42. package/dist/sound-bridge.d.ts +89 -0
  43. package/dist/sound-bridge.d.ts.map +1 -0
  44. package/dist/sound-bridge.js +128 -0
  45. package/dist/soundart-engine.d.ts +87 -0
  46. package/dist/soundart-engine.d.ts.map +1 -0
  47. package/dist/soundart-engine.js +173 -0
  48. package/dist/soundart-sketches/chladniBloom.d.ts +3 -0
  49. package/dist/soundart-sketches/chladniBloom.d.ts.map +1 -0
  50. package/dist/soundart-sketches/chladniBloom.js +53 -0
  51. package/dist/soundart-sketches/dualVortex.d.ts +3 -0
  52. package/dist/soundart-sketches/dualVortex.d.ts.map +1 -0
  53. package/dist/soundart-sketches/dualVortex.js +67 -0
  54. package/dist/soundart-sketches/geometryIllusion.d.ts +3 -0
  55. package/dist/soundart-sketches/geometryIllusion.d.ts.map +1 -0
  56. package/dist/soundart-sketches/geometryIllusion.js +89 -0
  57. package/dist/soundart-sketches/index.d.ts +39 -0
  58. package/dist/soundart-sketches/index.d.ts.map +1 -0
  59. package/dist/soundart-sketches/index.js +72 -0
  60. package/dist/soundart-sketches/isoflow.d.ts +3 -0
  61. package/dist/soundart-sketches/isoflow.d.ts.map +1 -0
  62. package/dist/soundart-sketches/isoflow.js +60 -0
  63. package/dist/soundart-sketches/loomWeave.d.ts +3 -0
  64. package/dist/soundart-sketches/loomWeave.d.ts.map +1 -0
  65. package/dist/soundart-sketches/loomWeave.js +59 -0
  66. package/dist/soundart-sketches/noiseTerraces.d.ts +3 -0
  67. package/dist/soundart-sketches/noiseTerraces.d.ts.map +1 -0
  68. package/dist/soundart-sketches/noiseTerraces.js +53 -0
  69. package/dist/soundart-sketches/orb.d.ts +3 -0
  70. package/dist/soundart-sketches/orb.d.ts.map +1 -0
  71. package/dist/soundart-sketches/orb.js +50 -0
  72. package/dist/soundart-sketches/pixelGlyphs.d.ts +3 -0
  73. package/dist/soundart-sketches/pixelGlyphs.d.ts.map +1 -0
  74. package/dist/soundart-sketches/pixelGlyphs.js +72 -0
  75. package/dist/soundart-sketches/prismFlowFields.d.ts +3 -0
  76. package/dist/soundart-sketches/prismFlowFields.d.ts.map +1 -0
  77. package/dist/soundart-sketches/prismFlowFields.js +51 -0
  78. package/dist/soundart-sketches/radialBurst.d.ts +3 -0
  79. package/dist/soundart-sketches/radialBurst.d.ts.map +1 -0
  80. package/dist/soundart-sketches/radialBurst.js +60 -0
  81. package/dist/soundart-sketches/resonantSoundBodies.d.ts +3 -0
  82. package/dist/soundart-sketches/resonantSoundBodies.d.ts.map +1 -0
  83. package/dist/soundart-sketches/resonantSoundBodies.js +89 -0
  84. package/dist/soundart-sketches/rings.d.ts +11 -0
  85. package/dist/soundart-sketches/rings.d.ts.map +1 -0
  86. package/dist/soundart-sketches/rings.js +89 -0
  87. package/dist/soundart-sketches/squares.d.ts +3 -0
  88. package/dist/soundart-sketches/squares.d.ts.map +1 -0
  89. package/dist/soundart-sketches/squares.js +52 -0
  90. package/dist/soundart-sketches/waveStripes.d.ts +3 -0
  91. package/dist/soundart-sketches/waveStripes.d.ts.map +1 -0
  92. package/dist/soundart-sketches/waveStripes.js +44 -0
  93. package/dist/static-engine.d.ts +7 -0
  94. package/dist/static-engine.d.ts.map +1 -1
  95. package/dist/static-engine.js +69 -14
  96. package/dist/types.d.ts +67 -5
  97. package/dist/types.d.ts.map +1 -1
  98. package/dist/types.js +1 -1
  99. package/package.json +26 -15
@@ -0,0 +1,283 @@
1
+ /**
2
+ * NexArt Code Mode Runtime SDK - Canonical Execution Entry Point
3
+ *
4
+ * ╔══════════════════════════════════════════════════════════════════════════╗
5
+ * ║ CODE MODE PROTOCOL v1.2.0 (Phase 3) — CANONICAL ENTRY POINT ║
6
+ * ║ ║
7
+ * ║ This is the ONLY official way to execute Code Mode. ║
8
+ * ║ All implementations (NexArt, ByX, external) MUST use this function. ║
9
+ * ║ ║
10
+ * ║ Authority: @nexart/codemode-sdk ║
11
+ * ╚══════════════════════════════════════════════════════════════════════════╝
12
+ */
13
+ import { runStaticMode } from './static-engine';
14
+ import { runLoopMode } from './loop-engine';
15
+ import { PROTOCOL_IDENTITY, DEFAULT_CONFIG, } from './types';
16
+ import { getBuilderManifest } from './builder-manifest';
17
+ /**
18
+ * Validate and normalize VAR array to 10 elements.
19
+ *
20
+ * Rules (SDK v1.0.2, Protocol v1.0.0):
21
+ * - VAR is OPTIONAL: omit or pass [] for empty (defaults to all zeros)
22
+ * - VAR input length MUST be 0-10 elements (protocol error if > 10)
23
+ * - VAR values MUST be finite numbers (protocol error if not)
24
+ * - VAR values MUST be in range 0-100 (protocol error if out of range, NO clamping)
25
+ * - VAR is read-only inside sketches
26
+ * - Output is ALWAYS 10 elements (padded with zeros) for protocol consistency
27
+ */
28
+ function normalizeVars(vars) {
29
+ if (!vars || !Array.isArray(vars)) {
30
+ console.log('[CodeMode] No vars provided, using defaults [0,0,0,0,0,0,0,0,0,0]');
31
+ return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
32
+ }
33
+ if (vars.length > 10) {
34
+ throw new Error(`[Code Mode Protocol Error] VAR array must have at most 10 elements, got ${vars.length}`);
35
+ }
36
+ const result = [];
37
+ for (let i = 0; i < vars.length; i++) {
38
+ const v = vars[i];
39
+ if (typeof v !== 'number' || !Number.isFinite(v)) {
40
+ throw new Error(`[Code Mode Protocol Error] VAR[${i}] must be a finite number, got ${typeof v === 'number' ? v : typeof v}`);
41
+ }
42
+ if (v < 0 || v > 100) {
43
+ throw new Error(`[Code Mode Protocol Error] VAR[${i}] = ${v} is out of range. Values must be 0-100.`);
44
+ }
45
+ result.push(v);
46
+ }
47
+ // Pad with zeros to always have 10 elements for protocol consistency
48
+ while (result.length < 10) {
49
+ result.push(0);
50
+ }
51
+ return result;
52
+ }
53
+ /**
54
+ * Validate execution input
55
+ */
56
+ function validateInput(input) {
57
+ if (!input.source || typeof input.source !== 'string') {
58
+ throw new Error('[Code Mode Protocol Error] source is required and must be a string');
59
+ }
60
+ if (typeof input.width !== 'number' || input.width <= 0) {
61
+ throw new Error('[Code Mode Protocol Error] width must be a positive number');
62
+ }
63
+ if (typeof input.height !== 'number' || input.height <= 0) {
64
+ throw new Error('[Code Mode Protocol Error] height must be a positive number');
65
+ }
66
+ if (typeof input.seed !== 'number') {
67
+ throw new Error('[Code Mode Protocol Error] seed is required and must be a number');
68
+ }
69
+ if (input.mode !== 'static' && input.mode !== 'loop') {
70
+ throw new Error('[Code Mode Protocol Error] mode must be "static" or "loop"');
71
+ }
72
+ if (input.mode === 'loop') {
73
+ if (typeof input.totalFrames !== 'number' || input.totalFrames <= 0) {
74
+ throw new Error('[Code Mode Protocol Error] totalFrames is required for loop mode and must be a positive number');
75
+ }
76
+ }
77
+ // Validate forbidden patterns per CODE_MODE_PROTOCOL.md
78
+ const forbiddenPatterns = [
79
+ // Async timing (breaks determinism)
80
+ { pattern: /setTimeout\s*\(/, name: 'setTimeout' },
81
+ { pattern: /setInterval\s*\(/, name: 'setInterval' },
82
+ { pattern: /requestAnimationFrame\s*\(/, name: 'requestAnimationFrame' },
83
+ // Time-based entropy (breaks determinism)
84
+ { pattern: /Date\.now\s*\(/, name: 'Date.now() — use time variable instead' },
85
+ { pattern: /new\s+Date\s*\(/, name: 'new Date() — use time variable instead' },
86
+ // Unseeded random (use random() instead)
87
+ { pattern: /Math\.random\s*\(/, name: 'Math.random() — use random() instead (seeded)' },
88
+ // External IO (breaks determinism)
89
+ { pattern: /fetch\s*\(/, name: 'fetch() — external IO forbidden' },
90
+ { pattern: /XMLHttpRequest/, name: 'XMLHttpRequest — external IO forbidden' },
91
+ // Canvas is pre-initialized
92
+ { pattern: /createCanvas\s*\(/, name: 'createCanvas() — canvas is pre-initialized' },
93
+ // DOM manipulation forbidden
94
+ { pattern: /document\./, name: 'DOM access — document.* forbidden' },
95
+ { pattern: /window\./, name: 'DOM access — window.* forbidden' },
96
+ // External imports forbidden
97
+ { pattern: /\bimport\s+/, name: 'import — external imports forbidden' },
98
+ { pattern: /\brequire\s*\(/, name: 'require() — external imports forbidden' },
99
+ ];
100
+ for (const { pattern, name } of forbiddenPatterns) {
101
+ if (pattern.test(input.source)) {
102
+ throw new Error(`[Code Mode Protocol Error] Forbidden pattern: ${name}`);
103
+ }
104
+ }
105
+ // Loop mode specific validation
106
+ if (input.mode === 'loop') {
107
+ if (!/function\s+draw\s*\(\s*\)/.test(input.source)) {
108
+ throw new Error('[Code Mode Protocol Error] Loop mode requires a draw() function');
109
+ }
110
+ if (/noLoop\s*\(\s*\)/.test(input.source)) {
111
+ throw new Error('[Code Mode Protocol Error] noLoop() is forbidden in Loop mode');
112
+ }
113
+ }
114
+ }
115
+ /**
116
+ * Create protocol metadata for the execution result
117
+ */
118
+ function createMetadata(input, vars) {
119
+ return {
120
+ ...PROTOCOL_IDENTITY,
121
+ seed: input.seed,
122
+ vars,
123
+ width: input.width,
124
+ height: input.height,
125
+ mode: input.mode,
126
+ ...(input.mode === 'loop' && input.totalFrames ? { totalFrames: input.totalFrames } : {}),
127
+ };
128
+ }
129
+ /**
130
+ * Execute Code Mode in Static mode - delegates to static-engine.ts
131
+ */
132
+ async function executeStatic(input, vars) {
133
+ console.log('[CodeMode] Rendered via @nexart/codemode-sdk (Protocol v1.2.0)');
134
+ console.log('[CodeMode] Execution: Static mode — delegating to static-engine');
135
+ return new Promise((resolve, reject) => {
136
+ runStaticMode({
137
+ mode: 'static',
138
+ width: input.width,
139
+ height: input.height,
140
+ }, {
141
+ code: input.source,
142
+ seed: input.seed,
143
+ vars: vars,
144
+ onComplete: (result) => {
145
+ resolve({
146
+ image: 'blob' in result ? result.blob : undefined,
147
+ frames: 'imageData' in result ? [result.imageData] : undefined,
148
+ metadata: createMetadata(input, vars),
149
+ });
150
+ },
151
+ onError: (error) => {
152
+ reject(error);
153
+ },
154
+ });
155
+ });
156
+ }
157
+ /**
158
+ * Execute Code Mode in Loop mode - delegates to loop-engine.ts
159
+ */
160
+ async function executeLoop(input, vars) {
161
+ console.log('[CodeMode] Rendered via @nexart/codemode-sdk (Protocol v1.2.0)');
162
+ console.log(`[CodeMode] Execution: Loop mode — delegating to loop-engine (${input.totalFrames} frames)`);
163
+ const fps = DEFAULT_CONFIG.fps;
164
+ const duration = (input.totalFrames || 60) / fps;
165
+ return new Promise((resolve, reject) => {
166
+ runLoopMode({
167
+ mode: 'loop',
168
+ width: input.width,
169
+ height: input.height,
170
+ duration: duration,
171
+ fps: fps,
172
+ }, {
173
+ code: input.source,
174
+ seed: input.seed,
175
+ vars: vars,
176
+ onComplete: (result) => {
177
+ resolve({
178
+ video: 'blob' in result && result.type === 'video' ? result.blob : undefined,
179
+ metadata: createMetadata(input, vars),
180
+ });
181
+ },
182
+ onError: (error) => {
183
+ reject(error);
184
+ },
185
+ });
186
+ });
187
+ }
188
+ /**
189
+ * executeCodeMode — Canonical Code Mode Execution Entry Point
190
+ *
191
+ * This is the ONLY official way to execute Code Mode.
192
+ * All implementations MUST use this function.
193
+ *
194
+ * @param input - Execution parameters
195
+ * @returns Promise<ExecuteCodeModeResult> - Execution result with protocol metadata
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * const result = await executeCodeMode({
200
+ * source: `function setup() { background(255); ellipse(width/2, height/2, 100); }`,
201
+ * width: 1950,
202
+ * height: 2400,
203
+ * seed: 12345,
204
+ * vars: [50, 75, 0, 0, 0, 0, 0, 0, 0, 0],
205
+ * mode: 'static'
206
+ * });
207
+ *
208
+ * console.log(result.metadata.protocolVersion); // '1.2.0'
209
+ * console.log(result.image); // PNG Blob
210
+ * ```
211
+ */
212
+ export async function executeCodeMode(input) {
213
+ // Validate input
214
+ validateInput(input);
215
+ // Normalize VAR values
216
+ const vars = normalizeVars(input.vars);
217
+ // ╔═══════════════════════════════════════════════════════════════════════╗
218
+ // ║ BUILDER MANIFEST CONTEXT (v1.6.0) ║
219
+ // ║ ║
220
+ // ║ Internal context for builder attribution. ║
221
+ // ║ This is NOT exposed to sketch code, NOT serialized, NOT logged. ║
222
+ // ║ Does NOT affect execution behavior or determinism. ║
223
+ // ╚═══════════════════════════════════════════════════════════════════════╝
224
+ const _executionContext = {
225
+ builderManifest: getBuilderManifest(),
226
+ };
227
+ // Note: _executionContext is intentionally unused.
228
+ // It prepares the SDK for future attribution without activating anything.
229
+ void _executionContext;
230
+ // Log protocol execution
231
+ console.log('[CodeMode] ════════════════════════════════════════════════');
232
+ console.log('[CodeMode] Protocol v1.2.0 — Phase 3 — HARD Enforcement');
233
+ console.log(`[CodeMode] Mode: ${input.mode}`);
234
+ console.log(`[CodeMode] Seed: ${input.seed}`);
235
+ console.log(`[CodeMode] VAR: [${vars.join(', ')}]`);
236
+ console.log('[CodeMode] ════════════════════════════════════════════════');
237
+ // Execute based on mode
238
+ if (input.mode === 'static') {
239
+ return executeStatic(input, vars);
240
+ }
241
+ else {
242
+ return executeLoop(input, vars);
243
+ }
244
+ }
245
+ /**
246
+ * Validate code without executing
247
+ */
248
+ export function validateCodeModeSource(source, mode) {
249
+ const errors = [];
250
+ // Same forbidden patterns as validateInput per CODE_MODE_PROTOCOL.md
251
+ const forbiddenPatterns = [
252
+ { pattern: /setTimeout\s*\(/, name: 'setTimeout' },
253
+ { pattern: /setInterval\s*\(/, name: 'setInterval' },
254
+ { pattern: /requestAnimationFrame\s*\(/, name: 'requestAnimationFrame' },
255
+ { pattern: /Date\.now\s*\(/, name: 'Date.now() — use time variable instead' },
256
+ { pattern: /new\s+Date\s*\(/, name: 'new Date() — use time variable instead' },
257
+ { pattern: /Math\.random\s*\(/, name: 'Math.random() — use random() instead (seeded)' },
258
+ { pattern: /fetch\s*\(/, name: 'fetch() — external IO forbidden' },
259
+ { pattern: /XMLHttpRequest/, name: 'XMLHttpRequest — external IO forbidden' },
260
+ { pattern: /createCanvas\s*\(/, name: 'createCanvas() — canvas is pre-initialized' },
261
+ { pattern: /document\./, name: 'DOM access — document.* forbidden' },
262
+ { pattern: /window\./, name: 'DOM access — window.* forbidden' },
263
+ { pattern: /\bimport\s+/, name: 'import — external imports forbidden' },
264
+ { pattern: /\brequire\s*\(/, name: 'require() — external imports forbidden' },
265
+ ];
266
+ for (const { pattern, name } of forbiddenPatterns) {
267
+ if (pattern.test(source)) {
268
+ errors.push(`Forbidden pattern: ${name}`);
269
+ }
270
+ }
271
+ if (mode === 'loop') {
272
+ if (!/function\s+draw\s*\(\s*\)/.test(source)) {
273
+ errors.push('Loop mode requires a draw() function');
274
+ }
275
+ if (/noLoop\s*\(\s*\)/.test(source)) {
276
+ errors.push('noLoop() is forbidden in Loop mode');
277
+ }
278
+ }
279
+ return {
280
+ valid: errors.length === 0,
281
+ errors,
282
+ };
283
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * NexArt Code Mode SDK - Execution Sandbox
3
+ * Version: 1.6.0 (Protocol v1.2.0)
4
+ *
5
+ * ╔══════════════════════════════════════════════════════════════════════════╗
6
+ * ║ EXECUTION BOUNDARY — HARD ENFORCEMENT ║
7
+ * ║ ║
8
+ * ║ This module enforces determinism by blocking all external entropy ║
9
+ * ║ sources at RUNTIME, not just via static pattern scanning. ║
10
+ * ║ ║
11
+ * ║ Blocked APIs (throw [Code Mode Protocol Error]): ║
12
+ * ║ - Date, Date.now, Date.parse, new Date() ║
13
+ * ║ - performance, performance.now ║
14
+ * ║ - process (Node.js) ║
15
+ * ║ - navigator ║
16
+ * ║ - globalThis ║
17
+ * ║ - crypto.getRandomValues ║
18
+ * ║ - Math.random (use seeded random() instead) ║
19
+ * ║ - setTimeout, setInterval, requestAnimationFrame ║
20
+ * ║ - fetch, XMLHttpRequest ║
21
+ * ║ - document, window ║
22
+ * ║ - import, require ║
23
+ * ║ ║
24
+ * ║ All blocked symbols throw immediately on access — no silent undefined. ║
25
+ * ╚══════════════════════════════════════════════════════════════════════════╝
26
+ */
27
+ /**
28
+ * Forbidden APIs - these are injected into the execution scope to override globals
29
+ */
30
+ export declare const FORBIDDEN_APIS: {
31
+ readonly Date: (...args: any[]) => never;
32
+ readonly performance: object;
33
+ readonly process: object;
34
+ readonly navigator: object;
35
+ readonly globalThis: object;
36
+ readonly crypto: object;
37
+ readonly setTimeout: (...args: any[]) => never;
38
+ readonly setInterval: (...args: any[]) => never;
39
+ readonly clearTimeout: (...args: any[]) => never;
40
+ readonly clearInterval: (...args: any[]) => never;
41
+ readonly requestAnimationFrame: (...args: any[]) => never;
42
+ readonly cancelAnimationFrame: (...args: any[]) => never;
43
+ readonly fetch: (...args: any[]) => never;
44
+ readonly XMLHttpRequest: (...args: any[]) => never;
45
+ readonly WebSocket: (...args: any[]) => never;
46
+ readonly document: object;
47
+ readonly window: object;
48
+ readonly self: object;
49
+ readonly top: object;
50
+ readonly parent: object;
51
+ readonly frames: object;
52
+ readonly location: object;
53
+ readonly history: object;
54
+ readonly localStorage: object;
55
+ readonly sessionStorage: object;
56
+ readonly indexedDB: object;
57
+ readonly caches: object;
58
+ readonly Notification: (...args: any[]) => never;
59
+ readonly Worker: (...args: any[]) => never;
60
+ readonly SharedWorker: (...args: any[]) => never;
61
+ readonly ServiceWorker: object;
62
+ readonly Blob: (...args: any[]) => never;
63
+ readonly File: (...args: any[]) => never;
64
+ readonly FileReader: (...args: any[]) => never;
65
+ readonly URL: (...args: any[]) => never;
66
+ readonly URLSearchParams: (...args: any[]) => never;
67
+ readonly Headers: (...args: any[]) => never;
68
+ readonly Request: (...args: any[]) => never;
69
+ readonly Response: (...args: any[]) => never;
70
+ readonly EventSource: (...args: any[]) => never;
71
+ readonly Image: (...args: any[]) => never;
72
+ readonly Audio: (...args: any[]) => never;
73
+ readonly Video: (...args: any[]) => never;
74
+ readonly eval: (...args: any[]) => never;
75
+ readonly Function: (...args: any[]) => never;
76
+ };
77
+ /**
78
+ * Create a safe Math object with random() blocked
79
+ */
80
+ export declare function createSafeMath(): typeof Math;
81
+ /**
82
+ * List of all forbidden API names for documentation
83
+ */
84
+ export declare const FORBIDDEN_API_NAMES: string[];
85
+ /**
86
+ * Build the complete sandbox context for sketch execution.
87
+ * This includes the p5 runtime plus all forbidden API stubs.
88
+ */
89
+ export declare function buildSandboxContext(p5Runtime: Record<string, any>): Record<string, any>;
90
+ /**
91
+ * Create a sandboxed function that executes user code with blocked globals.
92
+ *
93
+ * The function is constructed with:
94
+ * 1. All forbidden APIs as explicit parameters (override globals)
95
+ * 2. The p5 runtime as explicit parameters
96
+ * 3. A `with(context)` wrapper for additional safety
97
+ */
98
+ export declare function createSandboxedExecutor(code: string, additionalParams?: string[]): Function;
99
+ /**
100
+ * Execute user code in a sandboxed environment.
101
+ *
102
+ * @param code - The user sketch code to execute
103
+ * @param p5Runtime - The p5-like runtime object
104
+ * @param additionalContext - Additional context variables (frameCount, t, etc.)
105
+ */
106
+ export declare function executeSandboxed(code: string, p5Runtime: Record<string, any>, additionalContext?: Record<string, any>): void;
107
+ //# sourceMappingURL=execution-sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-sandbox.d.ts","sourceRoot":"","sources":["../execution-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAyDH;;GAEG;AACH,eAAO,MAAM,cAAc;6BAvD2B,GAAG,EAAE,KAAK,KAAK;;;;;;mCAAf,GAAG,EAAE,KAAK,KAAK;oCAAf,GAAG,EAAE,KAAK,KAAK;qCAAf,GAAG,EAAE,KAAK,KAAK;sCAAf,GAAG,EAAE,KAAK,KAAK;8CAAf,GAAG,EAAE,KAAK,KAAK;6CAAf,GAAG,EAAE,KAAK,KAAK;8BAAf,GAAG,EAAE,KAAK,KAAK;uCAAf,GAAG,EAAE,KAAK,KAAK;kCAAf,GAAG,EAAE,KAAK,KAAK;;;;;;;;;;;;;qCAAf,GAAG,EAAE,KAAK,KAAK;+BAAf,GAAG,EAAE,KAAK,KAAK;qCAAf,GAAG,EAAE,KAAK,KAAK;;6BAAf,GAAG,EAAE,KAAK,KAAK;6BAAf,GAAG,EAAE,KAAK,KAAK;mCAAf,GAAG,EAAE,KAAK,KAAK;4BAAf,GAAG,EAAE,KAAK,KAAK;wCAAf,GAAG,EAAE,KAAK,KAAK;gCAAf,GAAG,EAAE,KAAK,KAAK;gCAAf,GAAG,EAAE,KAAK,KAAK;iCAAf,GAAG,EAAE,KAAK,KAAK;oCAAf,GAAG,EAAE,KAAK,KAAK;8BAAf,GAAG,EAAE,KAAK,KAAK;8BAAf,GAAG,EAAE,KAAK,KAAK;8BAAf,GAAG,EAAE,KAAK,KAAK;6BAAf,GAAG,EAAE,KAAK,KAAK;iCAAf,GAAG,EAAE,KAAK,KAAK;CAqG3D,CAAC;AAEX;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,IAAI,CAU5C;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,UAA8B,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAavF;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,gBAAgB,GAAE,MAAM,EAAO,GAC9B,QAAQ,CAiBV;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9B,iBAAiB,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAC1C,IAAI,CAsBN"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * NexArt Code Mode SDK - Execution Sandbox
3
+ * Version: 1.6.0 (Protocol v1.2.0)
4
+ *
5
+ * ╔══════════════════════════════════════════════════════════════════════════╗
6
+ * ║ EXECUTION BOUNDARY — HARD ENFORCEMENT ║
7
+ * ║ ║
8
+ * ║ This module enforces determinism by blocking all external entropy ║
9
+ * ║ sources at RUNTIME, not just via static pattern scanning. ║
10
+ * ║ ║
11
+ * ║ Blocked APIs (throw [Code Mode Protocol Error]): ║
12
+ * ║ - Date, Date.now, Date.parse, new Date() ║
13
+ * ║ - performance, performance.now ║
14
+ * ║ - process (Node.js) ║
15
+ * ║ - navigator ║
16
+ * ║ - globalThis ║
17
+ * ║ - crypto.getRandomValues ║
18
+ * ║ - Math.random (use seeded random() instead) ║
19
+ * ║ - setTimeout, setInterval, requestAnimationFrame ║
20
+ * ║ - fetch, XMLHttpRequest ║
21
+ * ║ - document, window ║
22
+ * ║ - import, require ║
23
+ * ║ ║
24
+ * ║ All blocked symbols throw immediately on access — no silent undefined. ║
25
+ * ╚══════════════════════════════════════════════════════════════════════════╝
26
+ */
27
+ /**
28
+ * Create a throwing stub for a forbidden API
29
+ */
30
+ function createForbiddenStub(name) {
31
+ const stub = function () {
32
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name}`);
33
+ };
34
+ return new Proxy(stub, {
35
+ get(_target, prop) {
36
+ if (prop === Symbol.toPrimitive || prop === 'toString' || prop === 'valueOf') {
37
+ return () => { throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name}`); };
38
+ }
39
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name}.${String(prop)}`);
40
+ },
41
+ apply() {
42
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name}()`);
43
+ },
44
+ construct() {
45
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: new ${name}()`);
46
+ },
47
+ set() {
48
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name} (assignment blocked)`);
49
+ },
50
+ has() {
51
+ return true;
52
+ }
53
+ });
54
+ }
55
+ /**
56
+ * Create a frozen object that throws on any property access
57
+ */
58
+ function createForbiddenObject(name) {
59
+ return new Proxy({}, {
60
+ get(_target, prop) {
61
+ if (prop === Symbol.toPrimitive || prop === 'toString' || prop === 'valueOf') {
62
+ return () => { throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name}`); };
63
+ }
64
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name}.${String(prop)}`);
65
+ },
66
+ set() {
67
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name} (assignment blocked)`);
68
+ },
69
+ has() {
70
+ return true;
71
+ },
72
+ apply() {
73
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: ${name}()`);
74
+ },
75
+ construct() {
76
+ throw new Error(`[Code Mode Protocol Error] Forbidden API: new ${name}()`);
77
+ }
78
+ });
79
+ }
80
+ /**
81
+ * Forbidden APIs - these are injected into the execution scope to override globals
82
+ */
83
+ export const FORBIDDEN_APIS = {
84
+ Date: createForbiddenStub('Date'),
85
+ performance: createForbiddenObject('performance'),
86
+ process: createForbiddenObject('process'),
87
+ navigator: createForbiddenObject('navigator'),
88
+ globalThis: createForbiddenObject('globalThis'),
89
+ crypto: createForbiddenObject('crypto'),
90
+ setTimeout: createForbiddenStub('setTimeout'),
91
+ setInterval: createForbiddenStub('setInterval'),
92
+ clearTimeout: createForbiddenStub('clearTimeout'),
93
+ clearInterval: createForbiddenStub('clearInterval'),
94
+ requestAnimationFrame: createForbiddenStub('requestAnimationFrame'),
95
+ cancelAnimationFrame: createForbiddenStub('cancelAnimationFrame'),
96
+ fetch: createForbiddenStub('fetch'),
97
+ XMLHttpRequest: createForbiddenStub('XMLHttpRequest'),
98
+ WebSocket: createForbiddenStub('WebSocket'),
99
+ document: createForbiddenObject('document'),
100
+ window: createForbiddenObject('window'),
101
+ self: createForbiddenObject('self'),
102
+ top: createForbiddenObject('top'),
103
+ parent: createForbiddenObject('parent'),
104
+ frames: createForbiddenObject('frames'),
105
+ location: createForbiddenObject('location'),
106
+ history: createForbiddenObject('history'),
107
+ localStorage: createForbiddenObject('localStorage'),
108
+ sessionStorage: createForbiddenObject('sessionStorage'),
109
+ indexedDB: createForbiddenObject('indexedDB'),
110
+ caches: createForbiddenObject('caches'),
111
+ Notification: createForbiddenStub('Notification'),
112
+ Worker: createForbiddenStub('Worker'),
113
+ SharedWorker: createForbiddenStub('SharedWorker'),
114
+ ServiceWorker: createForbiddenObject('ServiceWorker'),
115
+ Blob: createForbiddenStub('Blob'),
116
+ File: createForbiddenStub('File'),
117
+ FileReader: createForbiddenStub('FileReader'),
118
+ URL: createForbiddenStub('URL'),
119
+ URLSearchParams: createForbiddenStub('URLSearchParams'),
120
+ Headers: createForbiddenStub('Headers'),
121
+ Request: createForbiddenStub('Request'),
122
+ Response: createForbiddenStub('Response'),
123
+ EventSource: createForbiddenStub('EventSource'),
124
+ Image: createForbiddenStub('Image'),
125
+ Audio: createForbiddenStub('Audio'),
126
+ Video: createForbiddenStub('Video'),
127
+ eval: createForbiddenStub('eval'),
128
+ Function: createForbiddenStub('Function'),
129
+ };
130
+ /**
131
+ * Create a safe Math object with random() blocked
132
+ */
133
+ export function createSafeMath() {
134
+ const safeMath = Object.create(Math);
135
+ Object.defineProperty(safeMath, 'random', {
136
+ get() {
137
+ throw new Error('[Code Mode Protocol Error] Forbidden API: Math.random() — use random() instead (seeded)');
138
+ },
139
+ configurable: false,
140
+ enumerable: true
141
+ });
142
+ return Object.freeze(safeMath);
143
+ }
144
+ /**
145
+ * List of all forbidden API names for documentation
146
+ */
147
+ export const FORBIDDEN_API_NAMES = Object.keys(FORBIDDEN_APIS);
148
+ /**
149
+ * Build the complete sandbox context for sketch execution.
150
+ * This includes the p5 runtime plus all forbidden API stubs.
151
+ */
152
+ export function buildSandboxContext(p5Runtime) {
153
+ const safeMath = createSafeMath();
154
+ const context = {
155
+ ...FORBIDDEN_APIS,
156
+ Math: safeMath,
157
+ };
158
+ for (const key of Object.keys(p5Runtime)) {
159
+ context[key] = p5Runtime[key];
160
+ }
161
+ return context;
162
+ }
163
+ /**
164
+ * Create a sandboxed function that executes user code with blocked globals.
165
+ *
166
+ * The function is constructed with:
167
+ * 1. All forbidden APIs as explicit parameters (override globals)
168
+ * 2. The p5 runtime as explicit parameters
169
+ * 3. A `with(context)` wrapper for additional safety
170
+ */
171
+ export function createSandboxedExecutor(code, additionalParams = []) {
172
+ const forbiddenParamNames = Object.keys(FORBIDDEN_APIS);
173
+ const allParams = [
174
+ 'context',
175
+ 'Math',
176
+ ...forbiddenParamNames,
177
+ ...additionalParams
178
+ ];
179
+ const wrappedCode = `
180
+ "use strict";
181
+ with(context) {
182
+ ${code}
183
+ }
184
+ `;
185
+ return new Function(...allParams, wrappedCode);
186
+ }
187
+ /**
188
+ * Execute user code in a sandboxed environment.
189
+ *
190
+ * @param code - The user sketch code to execute
191
+ * @param p5Runtime - The p5-like runtime object
192
+ * @param additionalContext - Additional context variables (frameCount, t, etc.)
193
+ */
194
+ export function executeSandboxed(code, p5Runtime, additionalContext = {}) {
195
+ const safeMath = createSafeMath();
196
+ const fullContext = {
197
+ ...p5Runtime,
198
+ ...additionalContext,
199
+ Math: safeMath,
200
+ ...FORBIDDEN_APIS,
201
+ };
202
+ const forbiddenValues = Object.keys(FORBIDDEN_APIS).map(key => FORBIDDEN_APIS[key]);
203
+ const additionalParamNames = Object.keys(additionalContext);
204
+ const additionalValues = Object.values(additionalContext);
205
+ const executor = createSandboxedExecutor(code, additionalParamNames);
206
+ executor(fullContext, safeMath, ...forbiddenValues, ...additionalValues);
207
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * NexArt Code Mode Runtime SDK
3
- * Version: 1.5.0 (Protocol v1.2.0)
3
+ * Version: 1.1.0 (Protocol v1.0.0)
4
4
  *
5
5
  * ╔══════════════════════════════════════════════════════════════════════════╗
6
6
  * ║ @nexart/codemode-sdk — Canonical Code Mode Authority ║
@@ -10,9 +10,9 @@
10
10
  * ║ ║
11
11
  * ║ Protocol: nexart ║
12
12
  * ║ Engine: codemode ║
13
- * ║ SDK Version: 1.5.0 ║
14
- * ║ Protocol Version: 1.2.0 ║
15
- * ║ Phase: 3
13
+ * ║ SDK Version: 1.1.0 ║
14
+ * ║ Protocol Version: 1.0.0 ║
15
+ * ║ Phase: 1
16
16
  * ║ Enforcement: HARD ║
17
17
  * ╚══════════════════════════════════════════════════════════════════════════╝
18
18
  *
@@ -21,23 +21,30 @@
21
21
  * import { executeCodeMode } from '@nexart/codemode-sdk';
22
22
  *
23
23
  * const result = await executeCodeMode({
24
- * source: `
25
- * function setup() {
26
- * background(255);
27
- * fill(0);
28
- * ellipse(width/2, height/2, 100);
29
- * }
30
- * `,
31
- * mode: 'static',
24
+ * source: `function setup() { background(255); ellipse(width/2, height/2, 100); }`,
32
25
  * width: 1950,
33
26
  * height: 2400,
34
27
  * seed: 12345,
35
- * vars: [50, 50, 50, 50, 50, 50, 50, 50, 50, 50]
28
+ * vars: [50, 0, 0, 0, 0, 0, 0, 0, 0, 0],
29
+ * mode: 'static'
36
30
  * });
37
- * console.log('Rendered:', result.blob.size, 'bytes');
31
+ *
32
+ * console.log(result.metadata.protocolVersion); // '1.0.0'
38
33
  * ```
39
34
  */
40
- export { executeCodeMode, validateCodeModeSource } from './engine';
41
- export type { ExecuteCodeModeInput, ExecuteCodeModeResult, ProtocolMetadata, RenderResult, TimeVariables, } from './types';
42
- export { DEFAULT_CONFIG, PROTOCOL_IDENTITY } from './types';
35
+ export { executeCodeMode, validateCodeModeSource } from './execute';
36
+ export type { ExecuteCodeModeInput, ExecuteCodeModeResult, ProtocolMetadata, } from './types';
37
+ export { PROTOCOL_IDENTITY } from './types';
38
+ export { createEngine } from './engine';
39
+ export type { Engine, EngineConfig, RunOptions, RenderResult, ProgressInfo, RenderMode, TimeVariables, } from './types';
40
+ export { DEFAULT_CONFIG } from './types';
41
+ export { renderSoundArtViaCodeMode, canRenderViaCodeMode, getCodeModeAvailableStyles, type SoundArtEngineConfig, type SoundArtRenderOptions, type SoundArtRenderResult, type SoundArtMetadata, } from './soundart-engine';
42
+ export { type SoundSnapshot, type SoundFeatures, createSoundSnapshot, createEmptySoundSnapshot, freezeSoundSnapshot, } from '../../shared/soundSnapshot';
43
+ export { injectSoundGlobals, createSoundGlobals, createEmptySoundGlobals, generateSoundPalette, inferGenreProfile, createSoundHelpers, type SoundGlobals, type GenreProfile, } from './sound-bridge';
44
+ export { getSoundArtSketch, getAvailableSoundArtSketches, isSoundArtSketchAvailable, type SoundArtSketchName, } from './soundart-sketches';
45
+ export { createP5Runtime, type P5Runtime, type P5RuntimeConfig } from './p5-runtime';
46
+ export { renderNoiseViaCodeMode, compileNoiseSystem, canRenderNoiseViaCodeMode, type NoiseEngineConfig, type NoiseRenderOptions, type NoiseRenderResult, type NoiseMetadata, } from './noise-engine';
47
+ export { type NoiseSnapshot, type NoiseParams, type NoiseBlendMode, createNoiseSnapshot, validateNoiseSnapshot, } from '../../shared/noiseSnapshot';
48
+ export { createNoiseGlobals, injectNoiseGlobals, type NoiseGlobals, } from './noise-bridge';
49
+ export { getNoiseSketch, getAvailableNoiseSketchNames, isValidNoiseSketch, type NoiseSketchName, } from './noise-sketches';
43
50
  //# sourceMappingURL=index.d.ts.map