package runtime import ( "archive/zip" "bytes" "encoding/json" "fmt" ) // BuildJSDeployZip упаковывает Node.js код в zip для Fission deployment package. // // Генерируем CommonJS wrapper: так Fission/node executor не упирается в ESM export // синтаксис и может исполнять результат без package.json и type=module. // Пользовательский код остаётся CJS-стилем через new Function(module, exports). // Wrapper экспортирует main, handler и default через module.exports. 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 — CommonJS wrapper: // 1. new Function создаёт функцию в пустом модульном контексте (нет import/export) // 2. Передаём ей module, exports и require как параметры → пользовательский CJS код работает // 3. require передаётся явно, т.к. new Function выполняется в глобальном scope // и не имеет доступа к module-local require из CJS контекста main.js // 4. Экспортируем main/handler/default через module.exports wrapper := fmt.Sprintf(`const __mod = { exports: {} }; (new Function('module', 'exports', 'require', %s))(__mod, __mod.exports, require); const _fn = __mod.exports; async function __invoke(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 }; } module.exports = __invoke; module.exports.main = __invoke; module.exports.handler = __invoke; module.exports.default = __invoke; `, string(codeJSON)) var buf bytes.Buffer zw := zip.NewWriter(&buf) 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 }