UNPKG

@fgiova/aws-signature

Version:

[![NPM version](https://img.shields.io/npm/v/@fgiova/aws-signature.svg?style=flat)](https://www.npmjs.com/package/@fgiova/aws-signature) ![CI workflow](https://github.com/fgiova/aws-signature/actions/workflows/node.js.yml/badge.svg) [![TypeScript](https:/

111 lines (110 loc) 4.08 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SignerSingleton = exports.Signer = void 0; const node_os_1 = require("node:os"); const node_path_1 = __importDefault(require("node:path")); const typebox_1 = require("@sinclair/typebox"); const env_schema_1 = require("env-schema"); const lru_cache_1 = require("lru-cache"); const piscina_1 = __importDefault(require("piscina")); /* c8 ignore start */ const isTS = node_path_1.default.resolve(__filename).endsWith(".ts"); const isMjs = node_path_1.default.resolve(__filename).endsWith(".mjs"); const runEnv = { ext: isTS ? "ts" : isMjs ? "mjs" : "js", execArgv: isTS ? ["-r", "ts-node/register"] : undefined, }; /* c8 ignore end */ const keyCache = new lru_cache_1.LRUCache({ max: 50, ttl: 1000 * 60 * 60 * 24, }); const ConfigSchema = typebox_1.Type.Object({ AWS_ACCESS_KEY_ID: typebox_1.Type.Optional(typebox_1.Type.String()), AWS_SECRET_ACCESS_KEY: typebox_1.Type.Optional(typebox_1.Type.String()), AWS_REGION: typebox_1.Type.String({ default: "" }), }); class Signer { constructor(options = {}) { this.cpuCount = (() => { try { return (0, node_os_1.cpus)().length; } catch { /* istanbul ignore next */ return 1; } })(); const { minThreads, maxThreads, idleTimeout, maxQueue, concurrentTasksPerWorker, resourceLimits, credentials: credentialsOptions, } = options; const config = (0, env_schema_1.envSchema)({ schema: ConfigSchema, }); this.credentials = { region: config.AWS_REGION, accessKeyId: config.AWS_ACCESS_KEY_ID || "", secretAccessKey: config.AWS_SECRET_ACCESS_KEY || "", ...credentialsOptions, }; if (!this.credentials.accessKeyId || !this.credentials.secretAccessKey) { throw new Error("AWS credentials are required"); } this.worker = new piscina_1.default({ filename: node_path_1.default.resolve(__dirname, `./sign_worker.${runEnv.ext}`), execArgv: runEnv.execArgv, name: "generateKey", minThreads: minThreads ?? Math.max(this.cpuCount / 2, 1), maxThreads: maxThreads ?? this.cpuCount * 1.5, idleTimeout, maxQueue, concurrentTasksPerWorker, resourceLimits, }); } millsToNextDay() { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); tomorrow.setHours(0, 0, 0, 0); return Math.abs(tomorrow.getTime() - Date.now()); } async request(request, service, region, date = new Date()) { const requestCredentials = { ...this.credentials, region: region || this.credentials.region, }; if (!requestCredentials.region) { throw new Error("Region is required"); } const keyId = `${service}-${requestCredentials.region}`; let key = keyCache.get(keyId); if (!key) { key = (await this.worker.run({ credentials: requestCredentials, service, date, })); keyCache.set(keyId, key, { ttl: this.millsToNextDay(), }); } return (await this.worker.run({ credentials: requestCredentials, request, service, key, date }, { name: "signRequest" })); } async destroy() { return this.worker.destroy(); } } exports.Signer = Signer; class SignerSingleton { constructor() { throw new Error("Use SignerSingleton.getSigner()"); } static getSigner(options) { if (!SignerSingleton.signer) { SignerSingleton.signer = new Signer(options); } return SignerSingleton.signer; } } exports.SignerSingleton = SignerSingleton;