OverviewFilesCommitsIssuesDocsReleasesPeers

mirall-cli / node_modules / electron-publish / out / s3 / s3UploadHelper.js

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