{"version":3,"file":"storage.cjs","names":["readdir","join","stat","relative","sep","readFile","createUploadClient"],"sources":["../../../src/services/deploy/storage.ts"],"sourcesContent":["import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport { createUploadClient } from \"@everything-dev/upload-app/client\";\n\nexport interface DistFile {\n  path: string;\n  bytes: Uint8Array;\n}\n\nexport interface BundleUploadResult {\n  stored: number;\n  unchanged?: number;\n  totalBytes: number;\n  integrity: Record<string, string>;\n  storage?: \"s3\" | \"memory\";\n}\n\nasync function walkDist(dir: string, baseDir: string): Promise<DistFile[]> {\n  const entries = await readdir(dir, { withFileTypes: true });\n  const files: DistFile[] = [];\n  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n    const fullPath = join(dir, entry.name);\n    if (entry.isDirectory()) {\n      files.push(...(await walkDist(fullPath, baseDir)));\n      continue;\n    }\n    const info = await stat(fullPath);\n    if (!info.isFile()) continue;\n    files.push({\n      path: relative(baseDir, fullPath).split(sep).join(\"/\"),\n      bytes: new Uint8Array(await readFile(fullPath)),\n    });\n  }\n  return files;\n}\n\nexport async function collectDistFiles(distDir: string): Promise<DistFile[]> {\n  return walkDist(distDir, distDir);\n}\n\nexport async function uploadBundle(input: {\n  origin: string;\n  apiKey?: string;\n  account: string;\n  gateway: string;\n  workspace: string;\n  files: DistFile[];\n  fetchImpl?: typeof fetch;\n}): Promise<BundleUploadResult> {\n  const client = createUploadClient({\n    origin: input.origin,\n    apiKey: input.apiKey,\n    fetchImpl: input.fetchImpl,\n  });\n  const result = await client.uploadBundle({\n    account: input.account,\n    gateway: input.gateway,\n    workspace: input.workspace,\n    files: input.files.map((file) => ({\n      path: file.path,\n      contentBase64: Buffer.from(file.bytes).toString(\"base64\"),\n    })),\n  });\n  return result;\n}\n\n/** Per-request file-count cap for `uploadWorkspaceDist`: each file costs the\n * server a stat+put round trip against object storage, so request count — not\n * byte size — is what keeps a batch inside the CDN proxy's response timeout. */\nexport const DEFAULT_MAX_FILES_PER_REQUEST = 100;\n\nexport async function uploadWorkspaceDist(input: {\n  origin: string;\n  apiKey?: string;\n  account: string;\n  gateway: string;\n  workspace: string;\n  files: DistFile[];\n  maxRequestBytes?: number;\n  maxFilesPerRequest?: number;\n}): Promise<BundleUploadResult> {\n  const maxRequestBytes =\n    input.maxRequestBytes ?? (Number(process.env.BOS_MAX_BUNDLE_UPLOAD_BYTES) || 64 * 1024 * 1024);\n  const maxFilesPerRequest = input.maxFilesPerRequest ?? DEFAULT_MAX_FILES_PER_REQUEST;\n\n  const merged: BundleUploadResult = { stored: 0, totalBytes: 0, integrity: {} };\n  let batch: DistFile[] = [];\n  let batchBytes = 0;\n  const overheadPerFile = (file: DistFile): number =>\n    Math.ceil(file.bytes.byteLength / 3) * 4 + file.path.length + 64;\n\n  const flush = async () => {\n    if (batch.length === 0) return;\n    const result = await uploadBundle({\n      origin: input.origin,\n      apiKey: input.apiKey,\n      account: input.account,\n      gateway: input.gateway,\n      workspace: input.workspace,\n      files: batch,\n    });\n    merged.stored += result.stored;\n    merged.totalBytes += result.totalBytes;\n    merged.unchanged = (merged.unchanged ?? 0) + (result.unchanged ?? 0);\n    Object.assign(merged.integrity, result.integrity);\n    merged.storage = result.storage;\n    batch = [];\n    batchBytes = 0;\n  };\n\n  for (const file of input.files) {\n    const cost = overheadPerFile(file);\n    if (cost > maxRequestBytes) {\n      throw new Error(\n        `[publish] ${input.workspace}/${file.path} (${file.bytes.byteLength} bytes) exceeds the per-request upload ceiling`,\n      );\n    }\n    // The serving CDN in front of the upload service rejects requests whose\n    // handler time exceeds its proxy timeout — the per-file stat/put count,\n    // not the byte total, dominates that wall clock, so bound the op count too.\n    if (batchBytes + cost > maxRequestBytes || batch.length >= maxFilesPerRequest) {\n      await flush();\n    }\n    batch.push(file);\n    batchBytes += cost;\n  }\n  await flush();\n\n  return merged;\n}\n"],"mappings":";;;;;AAiBA,eAAe,SAAS,KAAa,SAAsC;CACzE,MAAM,UAAU,UAAMA,0BAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;CAC1D,MAAM,QAAoB,CAAC;CAC3B,KAAK,MAAM,SAAS,QAAQ,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC,GAAG;EACxE,MAAM,eAAWC,gBAAK,KAAK,MAAM,IAAI;EACrC,IAAI,MAAM,YAAY,GAAG;GACvB,MAAM,KAAK,GAAI,MAAM,SAAS,UAAU,OAAO,CAAE;GACjD;EACF;EAEA,IAAI,EAAC,UADcC,uBAAK,QAAQ,EACvB,CAAC,OAAO,GAAG;EACpB,MAAM,KAAK;GACT,UAAMC,oBAAS,SAAS,QAAQ,CAAC,CAAC,MAAMC,aAAG,CAAC,CAAC,KAAK,GAAG;GACrD,OAAO,IAAI,WAAW,UAAMC,2BAAS,QAAQ,CAAC;EAChD,CAAC;CACH;CACA,OAAO;AACT;AAEA,eAAsB,iBAAiB,SAAsC;CAC3E,OAAO,SAAS,SAAS,OAAO;AAClC;AAEA,eAAsB,aAAa,OAQH;CAe9B,OAAO,MAdQC,kCAAmB;EAChC,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,WAAW,MAAM;CACnB,CAC0B,CAAC,CAAC,aAAa;EACvC,SAAS,MAAM;EACf,SAAS,MAAM;EACf,WAAW,MAAM;EACjB,OAAO,MAAM,MAAM,KAAK,UAAU;GAChC,MAAM,KAAK;GACX,eAAe,OAAO,KAAK,KAAK,KAAK,CAAC,CAAC,SAAS,QAAQ;EAC1D,EAAE;CACJ,CAAC;AAEH;;;;AAKA,MAAa,gCAAgC;AAE7C,eAAsB,oBAAoB,OASV;CAC9B,MAAM,kBACJ,MAAM,oBAAoB,OAAO,QAAQ,IAAI,2BAA2B,KAAK;CAC/E,MAAM,qBAAqB,MAAM;CAEjC,MAAM,SAA6B;EAAE,QAAQ;EAAG,YAAY;EAAG,WAAW,CAAC;CAAE;CAC7E,IAAI,QAAoB,CAAC;CACzB,IAAI,aAAa;CACjB,MAAM,mBAAmB,SACvB,KAAK,KAAK,KAAK,MAAM,aAAa,CAAC,IAAI,IAAI,KAAK,KAAK,SAAS;CAEhE,MAAM,QAAQ,YAAY;EACxB,IAAI,MAAM,WAAW,GAAG;EACxB,MAAM,SAAS,MAAM,aAAa;GAChC,QAAQ,MAAM;GACd,QAAQ,MAAM;GACd,SAAS,MAAM;GACf,SAAS,MAAM;GACf,WAAW,MAAM;GACjB,OAAO;EACT,CAAC;EACD,OAAO,UAAU,OAAO;EACxB,OAAO,cAAc,OAAO;EAC5B,OAAO,aAAa,OAAO,aAAa,MAAM,OAAO,aAAa;EAClE,OAAO,OAAO,OAAO,WAAW,OAAO,SAAS;EAChD,OAAO,UAAU,OAAO;EACxB,QAAQ,CAAC;EACT,aAAa;CACf;CAEA,KAAK,MAAM,QAAQ,MAAM,OAAO;EAC9B,MAAM,OAAO,gBAAgB,IAAI;EACjC,IAAI,OAAO,iBACT,MAAM,IAAI,MACR,aAAa,MAAM,UAAU,GAAG,KAAK,KAAK,IAAI,KAAK,MAAM,WAAW,+CACtE;EAKF,IAAI,aAAa,OAAO,mBAAmB,MAAM,UAAU,oBACzD,MAAM,MAAM;EAEd,MAAM,KAAK,IAAI;EACf,cAAc;CAChB;CACA,MAAM,MAAM;CAEZ,OAAO;AACT"}