package runtime import ( "archive/zip" "bytes" "encoding/json" "fmt" ) // BuildJSDeployZip упаковывает Node.js код в zip для Fission deployment package. // // Почему zip, а не просто literal-код: // Fission node-env v3 поддерживает ESM модули. Чтобы Node.js трактовал файл // как ESM, нужен package.json с {"type":"module"} рядом с main.js. // Без него `import` синтаксис вызовет "require is not defined" или SyntaxError. // // Почему new Function: // Пользовательский код пишет CJS-стиль (module.exports = ...) но мы хотим ESM wrapper. // new Function() изолирует module/exports от глобального ESM контекста и позволяет // исполнять CJS-код без изменений. // // Результат: zip с двумя файлами: // - package.json: {"type":"module"} // - main.js: ESM wrapper + инлайн пользовательский код через new Function func BuildJSDeployZip(code string) ([]byte, error) { // Сериализуем пользовательский код в JSON строку чтобы безопасно инлайнить // в JavaScript-литерал — экранирует кавычки, переводы строк, спецсимволы. codeJSON, err := json.Marshal(code) if err != nil { return nil, fmt.Errorf("marshal user code: %w", err) } // main.js — ESM wrapper: // 1. new Function создаёт функцию в пустом модульном контексте (нет import/export) // 2. Передаём ей module и exports как параметры → пользовательский CJS код работает // 3. Экспортируем default async function для Fission node-env entrypoint wrapper := fmt.Sprintf(`const __mod = { exports: {} }; (new Function('module', 'exports', %s))(__mod, __mod.exports); const _fn = __mod.exports; export default async function(ctx) { const fn = typeof _fn === 'function' ? _fn : (_fn.default || _fn.handler || _fn.main); if (!fn) throw new Error('no exported function found in user code'); const result = await fn(ctx); if (!result) return { status: 200, body: '' }; if (typeof result.status !== 'undefined') return result; return { status: 200, ...result }; } `, string(codeJSON)) var buf bytes.Buffer zw := zip.NewWriter(&buf) // package.json: включает ESM режим для всего архива pkgfw, err := zw.Create("package.json") if err != nil { return nil, err } if _, err := pkgfw.Write([]byte(`{"type":"module"}`)); err != nil { return nil, err } fw, err := zw.Create("main.js") if err != nil { return nil, err } if _, err := fw.Write([]byte(wrapper)); err != nil { return nil, err } if err := zw.Close(); err != nil { return nil, err } return buf.Bytes(), nil }