UNPKG

zephyr-agent

Version:
139 lines (138 loc) • 6.03 kB
import "node:module"; import { relative, resolve } from "node:path"; import { assertZephyrBuildTarget } from "zephyr-edge-contract"; import { ZephyrEngine } from "../zephyr-engine/index.mjs"; import { ZeErrors, ZephyrError } from "./errors/index.mjs"; import { buildAssetsMapMock } from "./transformers/ze-build-assets-map.mjs"; import { zeBuildDashData } from "./transformers/ze-build-dash-data.mjs"; import { readDirRecursiveWithContents } from "./utils/read-dir-recursive.mjs"; const DEFAULT_DEPLOY_TARGET = 'web'; const DEFAULT_DEPLOY_SSR = true; const SKIP_DEPLOY_PATTERNS = [ /\.map$/i, /node_modules\//i, /\.git\//i, /\.DS_Store$/i, /^\.zephyr\//i, /thumbs\.db$/i ]; const DEPLOY_ENTRYPOINT_CANDIDATES = [ 'server/index.js', 'server/index.mjs', 'server/server.js', 'server/server.mjs', 'server/_worker.js', 'server/_worker.mjs', 'index.mjs', 'index.js' ]; function normalizePath(filePath) { return filePath.replace(/\\/g, '/').replace(/^\.?\//, ''); } function normalizeBaseURL(baseURL) { let normalized = baseURL.trim().replace(/\\/g, '/'); while(normalized.startsWith('./'))normalized = normalized.slice(2); while(normalized.startsWith('/'))normalized = normalized.slice(1); while(normalized.endsWith('/'))normalized = normalized.slice(0, -1); return normalized; } function resolveAssetPath(file, outputDir, publicDir, baseURL = '/') { const relativePath = normalizePath(file.relativePath); if (!publicDir) return relativePath; const fullPath = normalizePath(file.fullPath); const publicRoot = normalizePath(publicDir).replace(/\/+$/, ''); const outputRoot = normalizePath(outputDir).replace(/\/+$/, ''); const publicRelativeRoot = normalizePath(relative(outputRoot, publicRoot)).replace(/\/+$/, ''); const isWithinPublicAlias = !!publicRelativeRoot && relativePath.startsWith(`${publicRelativeRoot}/`); if (fullPath.startsWith(`${publicRoot}/`) || isWithinPublicAlias) { const staticRelative = fullPath.startsWith(`${publicRoot}/`) ? fullPath.slice(publicRoot.length + 1) : relativePath.slice(publicRelativeRoot.length + 1); if (!staticRelative) return relativePath; const basePath = normalizeBaseURL(baseURL); return basePath ? `client/${basePath}/${staticRelative}` : `client/${staticRelative}`; } return relativePath; } function shouldSkipDeployAsset(filePath) { return SKIP_DEPLOY_PATTERNS.some((pattern)=>pattern.test(filePath)); } function resolveDeployEntrypoint(assets) { for (const candidate of DEPLOY_ENTRYPOINT_CANDIDATES)if (Object.prototype.hasOwnProperty.call(assets, candidate)) return candidate; } function getLegacyModuleFederationConfig(mfConfigs) { const config = mfConfigs?.length === 1 ? mfConfigs[0] : void 0; return config && 'string' == typeof config.name && 'string' == typeof config.filename ? config : void 0; } async function uploadOutputToZephyr(opts) { const target = opts.target ?? DEFAULT_DEPLOY_TARGET; assertZephyrBuildTarget(target, 'uploadOutputToZephyr({ target })'); const outputDir = resolve(opts.outputDir); const publicDir = opts.publicDir ? resolve(opts.publicDir) : void 0; const files = await readDirRecursiveWithContents(outputDir); const assets = {}; const assetSources = new Map(); for (const file of files){ const relativePath = resolveAssetPath(file, outputDir, publicDir, opts.baseURL); if (shouldSkipDeployAsset(relativePath)) continue; const existingSource = assetSources.get(relativePath); if (existingSource) throw new ZephyrError(ZeErrors.ERR_DEPLOY_LOCAL_BUILD, { message: `uploadOutputToZephyr found conflicting output files for snapshot path "${relativePath}": "${existingSource}" and "${file.fullPath}".` }); assets[relativePath] = { content: file.content }; assetSources.set(relativePath, file.fullPath); } if (0 === Object.keys(assets).length) throw new ZephyrError(ZeErrors.ERR_ASSETS_NOT_FOUND); const ssr = opts.ssr ?? DEFAULT_DEPLOY_SSR; const entrypoint = resolveDeployEntrypoint(assets); if (ssr && !entrypoint) throw new ZephyrError(ZeErrors.ERR_SSR_ENTRYPOINT_NOT_FOUND, { outputDir, candidates: DEPLOY_ENTRYPOINT_CANDIDATES.join(', ') }); const assetsMap = buildAssetsMapMock(assets, (asset)=>asset.content, ()=>'buffer'); const zephyrEngine = await ZephyrEngine.create({ builder: opts.builder ?? 'unknown', context: opts.rootDir, target }); let buildInProgress = true; try { zephyrEngine.env.target = target; zephyrEngine.env.ssr = ssr; const buildStats = await zeBuildDashData(zephyrEngine); const mfConfig = getLegacyModuleFederationConfig(opts.mfConfigs); const buildStatsWithFederation = opts.federation ? { ...buildStats, federation: opts.federation } : buildStats; let deploymentUrl = null; await zephyrEngine.upload_assets({ assetsMap, buildStats: buildStatsWithFederation, ...mfConfig ? { mfConfig } : {}, ...opts.mfConfigs ? { mfConfigs: opts.mfConfigs } : {}, snapshotType: ssr ? 'ssr' : 'csr', entrypoint: ssr ? entrypoint : void 0, hooks: { onDeployComplete: async (deploymentInfo)=>{ deploymentUrl = deploymentInfo.url; await opts.hooks?.onDeployComplete?.(deploymentInfo); } } }); buildInProgress = false; await zephyrEngine.build_finished(); return { deploymentUrl, entrypoint }; } finally{ if (buildInProgress && false !== zephyrEngine.hasActiveBuild) zephyrEngine.build_failed(); } } export { uploadOutputToZephyr }; //# sourceMappingURL=upload-output-to-zephyr.mjs.map