{"version":3,"file":"s3UploadHelper.js","sourceRoot":"","sources":["../../src/s3/s3UploadHelper.ts"],"names":[],"mappings":"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","sourcesContent":["import { sign } from \"aws4\"\nimport * as fs from \"fs\"\nimport * as http from \"http\"\nimport * as https from \"https\"\nimport * as mime from \"mime\"\nimport * as path from \"path\"\nimport type { AwsCredentials } from \"./awsCredentials\"\n\nexport interface S3PutObjectParams {\n  bucket: string\n  key: string\n  file: string\n  region: string\n  endpoint?: string\n  forcePathStyle?: boolean\n  contentType: string\n  acl?: string\n  storageClass?: string\n  serverSideEncryption?: string\n  credentials?: AwsCredentials\n}\n\n/**\n * Uploads a file to S3 (or S3-compatible storage) using a single PutObject request.\n * Suitable for files up to 5 GB — the S3 single-part upload limit.\n * Returns the underlying ClientRequest so callers can abort mid-flight.\n * Mirrors the behaviour of the `publish-s3` app-builder subcommand.\n */\nexport function startS3PutObject(params: S3PutObjectParams): { req: http.ClientRequest; done: Promise<void> } {\n  const stat = fs.statSync(params.file)\n  const region = params.region\n\n  let hostname: string\n  let rawPath: string\n  let isHttp = false\n\n  if (params.endpoint != null) {\n    const u = new URL(params.endpoint)\n    isHttp = u.protocol === \"http:\"\n    hostname = u.port ? `${u.hostname}:${u.port}` : u.hostname\n    // path-style for custom endpoints (handles buckets whose names contain dots)\n    rawPath = `/${params.bucket}/${params.key}`\n  } else if (params.forcePathStyle) {\n    hostname = `s3.${region}.amazonaws.com`\n    rawPath = `/${params.bucket}/${params.key}`\n  } else {\n    hostname = `${params.bucket}.s3.${region}.amazonaws.com`\n    rawPath = `/${params.key}`\n  }\n\n  // URL-encode each path segment individually so forward-slashes in keys are preserved\n  const urlPath = \"/\" + rawPath.slice(1).split(\"/\").map(encodeURIComponent).join(\"/\")\n\n  const headers: Record<string, string> = {\n    \"Content-Type\": params.contentType,\n    \"Content-Length\": String(stat.size),\n    // Declare the payload as unsigned so aws4 signs over this literal string\n    // rather than defaulting to SHA256(\"\") — which would not match the streamed body.\n    \"x-amz-content-sha256\": \"UNSIGNED-PAYLOAD\",\n  }\n  if (params.acl != null) {\n    headers[\"x-amz-acl\"] = params.acl\n  }\n  if (params.storageClass != null) {\n    headers[\"x-amz-storage-class\"] = params.storageClass\n  }\n  if (params.serverSideEncryption != null) {\n    headers[\"x-amz-server-side-encryption\"] = params.serverSideEncryption\n  }\n\n  const signed = sign(\n    {\n      service: \"s3\",\n      region,\n      method: \"PUT\",\n      host: hostname,\n      path: urlPath,\n      headers,\n    },\n    params.credentials\n  )\n\n  const transport = isHttp ? http : https\n\n  let resolvePromise!: () => void\n  let rejectPromise!: (err: Error) => void\n  const done = new Promise<void>((res, rej) => {\n    resolvePromise = res\n    rejectPromise = rej\n  })\n\n  const req = transport.request(\n    {\n      hostname: hostname.split(\":\")[0],\n      port: hostname.includes(\":\") ? Number(hostname.split(\":\")[1]) : undefined,\n      path: urlPath,\n      method: \"PUT\",\n      headers: signed.headers,\n    },\n    res => {\n      if (res.statusCode === 200) {\n        res.resume()\n        res.on(\"end\", resolvePromise)\n      } else {\n        let body = \"\"\n        let bodySize = 0\n        const MAX_ERROR_BODY = 65536\n        res.on(\"data\", (chunk: string) => {\n          bodySize += chunk.length\n          if (bodySize <= MAX_ERROR_BODY) {\n            body += chunk\n          }\n        })\n        res.on(\"end\", () => rejectPromise(new Error(`S3 PutObject failed (HTTP ${res.statusCode}): ${body.slice(0, 512)}`)))\n      }\n    }\n  )\n\n  req.on(\"error\", rejectPromise)\n  const fileStream = fs.createReadStream(params.file)\n  fileStream.on(\"error\", rejectPromise)\n  req.on(\"close\", () => fileStream.destroy())\n  fileStream.pipe(req)\n\n  return { req, done }\n}\n\n/**\n * Returns the MIME content-type for an S3 upload key, using explicit overrides\n * for formats that mime databases commonly misidentify. Mirrors the Go binary's\n * getContentType() function in pkg/publisher/s3.go.\n */\nexport function getS3ContentType(file: string): string {\n  const ext = path.extname(file).toLowerCase()\n  const overrides: Record<string, string> = {\n    \".appimage\": \"application/vnd.appimage\",\n    \".blockmap\": \"application/gzip\",\n    \".snap\": \"application/vnd.snap\",\n  }\n  return overrides[ext] ?? mime.getType(file) ?? \"application/octet-stream\"\n}\n"]}