"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeCodeZipPackagerSync = exports.NodeCodeZipPackager = void 0;
exports.extractNodeVersion = extractNodeVersion;
const constants_1 = require("../constants");
const types_1 = require("../errors/types");
const helpers_1 = require("./helpers");
const esbuild_1 = require("esbuild");
const fs_1 = require("fs");
const path_1 = require("path");
const NODE_RUNTIME_REGEX = /NODE_(\d+)/;
/**
 * Type guard to check if runtime version is a Node runtime
 */
function isNodeRuntimeVersion(version) {
    return (0, helpers_1.isNodeRuntime)(version);
}
/**
 * Extracts Node version from runtime constant.
 * Example: NODE_20 -> "20" (for use with node version checks)
 */
function extractNodeVersion(runtime) {
    const match = NODE_RUNTIME_REGEX.exec(runtime);
    if (!match) {
        throw new types_1.PackagingError(`Unsupported Node runtime value: ${runtime}`);
    }
    const [, major] = match;
    if (!major) {
        throw new types_1.PackagingError(`Invalid Node runtime value: ${runtime}`);
    }
    return major;
}
const DYNAMIC_REQUIRE_PACKAGES = [
    '@fastify/sse',
    '@fastify/websocket',
    'duplexify',
    'end-of-stream',
    'fastify-plugin',
    'inherits',
    'once',
    'readable-stream',
    'safe-buffer',
    'stream-shift',
    'string_decoder',
    'util-deprecate',
    'wrappy',
    'ws',
];
const DEPS_DIR = '_deps';
function copyDynamicDeps(srcDir, stagingDir) {
    const srcNodeModules = (0, path_1.join)(srcDir, 'node_modules');
    if (!(0, fs_1.existsSync)(srcNodeModules))
        return;
    for (const pkg of DYNAMIC_REQUIRE_PACKAGES) {
        const pkgPath = (0, path_1.join)(srcNodeModules, pkg);
        if ((0, fs_1.existsSync)(pkgPath)) {
            (0, fs_1.cpSync)(pkgPath, (0, path_1.join)(stagingDir, DEPS_DIR, pkg), { recursive: true });
        }
    }
}
/**
 * Async Node/TypeScript packager for CLI usage.
 * Bundles TypeScript source into a single JS file using esbuild.
 */
class NodeCodeZipPackager {
    async pack(spec, options = {}) {
        if (spec.build !== 'CodeZip') {
            throw new types_1.PackagingError('Node packager only supports CodeZip build type.');
        }
        if (!isNodeRuntimeVersion(spec.runtimeVersion)) {
            throw new types_1.PackagingError(`Node packager only supports Node runtimes. Received: ${spec.runtimeVersion}`);
        }
        const agentName = options.agentName ?? spec.name;
        const { srcDir, stagingDir, artifactsDir } = await (0, helpers_1.resolveNodeProjectPaths)(options, agentName);
        await (0, helpers_1.ensureDirClean)(stagingDir);
        const entryFile = (0, path_1.join)(srcDir, 'main.ts');
        const runtimeVersion = spec.runtimeVersion;
        const nodeTarget = `node${extractNodeVersion(runtimeVersion)}`;
        const cjsBanner = 'const importMetaUrl = require("url").pathToFileURL(__filename).href;' +
            '(function(){var M=require("module"),p=require("path"),f=require("fs"),d=p.join(__dirname,"_deps"),o=M._resolveFilename;' +
            'M._resolveFilename=function(r,P,i,O){try{return o.call(this,r,P,i,O)}catch(e){' +
            'var dp=p.join(d,r);if(f.existsSync(dp)){var pk=p.join(dp,"package.json");' +
            'if(f.existsSync(pk)){var m=JSON.parse(f.readFileSync(pk,"utf8")).main||"index.js";return p.resolve(dp,m)}' +
            'return p.resolve(dp,"index.js")}throw e}};})();';
        await (0, esbuild_1.build)({
            entryPoints: [entryFile],
            outfile: (0, path_1.join)(stagingDir, 'main.js'),
            bundle: true,
            platform: 'node',
            format: 'cjs',
            minify: true,
            target: nodeTarget,
            banner: { js: cjsBanner },
            define: { 'import.meta.url': 'importMetaUrl' },
        });
        (0, fs_1.writeFileSync)((0, path_1.join)(stagingDir, 'package.json'), '{"type":"commonjs"}');
        copyDynamicDeps(srcDir, stagingDir);
        const artifactPath = options.outputPath ?? (0, path_1.join)(artifactsDir, (0, constants_1.getArtifactZipName)(agentName));
        await (0, helpers_1.createZipFromDir)(stagingDir, artifactPath);
        const sizeBytes = await (0, helpers_1.enforceZipSizeLimit)(artifactPath);
        return {
            artifactPath,
            sizeBytes,
            stagingPath: stagingDir,
        };
    }
}
exports.NodeCodeZipPackager = NodeCodeZipPackager;
/**
 * Sync Node/TypeScript packager for CDK bundling.
 * Bundles TypeScript source into a single JS file using esbuild.
 */
class NodeCodeZipPackagerSync {
    packCodeZip(config, options = {}) {
        const runtimeVersion = config.runtimeVersion ?? 'NODE_20';
        if (!isNodeRuntimeVersion(runtimeVersion)) {
            throw new types_1.PackagingError(`Node packager only supports Node runtimes. Received: ${runtimeVersion}`);
        }
        const agentName = options.agentName ?? config.name ?? 'asset';
        const { srcDir, stagingDir, artifactsDir } = (0, helpers_1.resolveNodeProjectPathsSync)(options, agentName);
        (0, helpers_1.ensureDirCleanSync)(stagingDir);
        const entryFile = (0, path_1.join)(srcDir, 'main.ts');
        const nodeTarget = `node${extractNodeVersion(runtimeVersion)}`;
        const cjsBanner = 'const importMetaUrl = require("url").pathToFileURL(__filename).href;' +
            '(function(){var M=require("module"),p=require("path"),f=require("fs"),d=p.join(__dirname,"_deps"),o=M._resolveFilename;' +
            'M._resolveFilename=function(r,P,i,O){try{return o.call(this,r,P,i,O)}catch(e){' +
            'var dp=p.join(d,r);if(f.existsSync(dp)){var pk=p.join(dp,"package.json");' +
            'if(f.existsSync(pk)){var m=JSON.parse(f.readFileSync(pk,"utf8")).main||"index.js";return p.resolve(dp,m)}' +
            'return p.resolve(dp,"index.js")}throw e}};})();';
        (0, esbuild_1.buildSync)({
            entryPoints: [entryFile],
            outfile: (0, path_1.join)(stagingDir, 'main.js'),
            bundle: true,
            platform: 'node',
            format: 'cjs',
            minify: true,
            target: nodeTarget,
            banner: { js: cjsBanner },
            define: { 'import.meta.url': 'importMetaUrl' },
        });
        (0, fs_1.writeFileSync)((0, path_1.join)(stagingDir, 'package.json'), '{"type":"commonjs"}');
        copyDynamicDeps(srcDir, stagingDir);
        const artifactPath = options.outputPath ?? (0, path_1.join)(artifactsDir, (0, constants_1.getArtifactZipName)(agentName));
        (0, helpers_1.createZipFromDirSync)(stagingDir, artifactPath);
        const sizeBytes = (0, helpers_1.enforceZipSizeLimitSync)(artifactPath);
        return {
            artifactPath,
            sizeBytes,
            stagingPath: stagingDir,
        };
    }
}
exports.NodeCodeZipPackagerSync = NodeCodeZipPackagerSync;
//# sourceMappingURL=node.js.map