diff --git a/frontends/nextjs/src/lib/lua/functions/sandbox/enforce-max-memory.ts b/frontends/nextjs/src/lib/lua/functions/sandbox/enforce-max-memory.ts new file mode 100644 index 000000000..8d745b266 --- /dev/null +++ b/frontends/nextjs/src/lib/lua/functions/sandbox/enforce-max-memory.ts @@ -0,0 +1,12 @@ +import type { SandboxedLuaEngineState } from './types' + +export function enforceMaxMemory(this: SandboxedLuaEngineState): void { + if (!Number.isFinite(this.maxMemory) || this.maxMemory <= 0) return + + const usageBytes = this.getLuaMemoryUsageBytes() + if (usageBytes > this.maxMemory) { + throw new Error( + `Memory limit exceeded: ${usageBytes} bytes used (max ${this.maxMemory})` + ) + } +} diff --git a/frontends/nextjs/src/lib/lua/functions/sandbox/types.ts b/frontends/nextjs/src/lib/lua/functions/sandbox/types.ts index 6e69566b8..1a6481076 100644 --- a/frontends/nextjs/src/lib/lua/functions/sandbox/types.ts +++ b/frontends/nextjs/src/lib/lua/functions/sandbox/types.ts @@ -23,4 +23,8 @@ export interface SandboxedLuaEngineState { setupSandboxedEnvironment: () => void /** Execute code with timeout */ executeWithTimeout: (code: string, context?: LuaExecutionContext) => Promise + /** Read current Lua heap usage in bytes */ + getLuaMemoryUsageBytes: () => number + /** Enforce maxMemory threshold */ + enforceMaxMemory: () => void } diff --git a/frontends/nextjs/src/lib/nerd-mode-ide/collect-file-entries.test.ts b/frontends/nextjs/src/lib/nerd-mode-ide/collect-file-entries.test.ts new file mode 100644 index 000000000..9eaa71cc2 --- /dev/null +++ b/frontends/nextjs/src/lib/nerd-mode-ide/collect-file-entries.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it } from 'vitest' +import { collectFileEntries } from './collect-file-entries' +import type { FileNode } from './types' + +describe('collectFileEntries', () => { + it('respects exportPath overrides while keeping root folder names', () => { + const tree: FileNode[] = [ + { + id: 'root', + name: 'social_hub', + type: 'folder', + children: [ + { + id: 'lua', + name: 'Lua', + type: 'folder', + exportPath: 'seed/scripts', + children: [ + { + id: 'manifest', + name: 'manifest.json', + type: 'file', + content: '{"scripts":[]}', + }, + ], + }, + { + id: 'metadata', + name: 'metadata', + type: 'folder', + exportPath: 'seed', + children: [ + { + id: 'meta-file', + name: 'metadata.json', + type: 'file', + content: '{"packageId":"social_hub"}', + }, + ], + }, + ], + }, + ] + + const entries = collectFileEntries(tree) + const paths = entries.map((entry) => entry.path) + + expect(paths).toContain('social_hub/seed/scripts/manifest.json') + expect(paths).toContain('social_hub/seed/metadata.json') + }) +})