feat(integrations): add S3 and SMTP adapters

Port the legacy server/src/lib/s3.js and mailer.js (eden.md §4/§5) into
packages/integrations behind an adapter/port pattern, isolated from
domain logic per Master Prompt §13.

- s3/client.ts: @aws-sdk/client-s3 wrapper (uploadObject, getObjectStream,
  deleteObject, getClient/getBucket for future multipart Backup uploads).
  Lazily-initialized singleton client, forcePathStyle from
  S3_FORCE_PATH_STYLE (default true). Throws a clear "S3 não configurado
  (S3_ENDPOINT ausente)" whenever S3_ENDPOINT is unset — storage failures
  must be loud, never a silent no-op.

- smtp/mailer.ts: nodemailer wrapper (sendMail). Lazily-initialized
  singleton transporter, secure:true auto-detected on port 465, from
  defaults to SMTP_FROM or SMTP_USER. Deliberately fail-soft: if
  SMTP_HOST is unset, or if sending fails, logs and returns normally —
  no business flow ever fails because of email, matching the legacy's
  behavior exactly.

@eden/config's loadEnv()/env-schema is still a placeholder in this
worktree, so both adapters read process.env directly using the exact
var names already reserved in the target schema; @eden/config is added
as a workspace dependency so this can be swapped for a real loadEnv()
call later without touching callers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 09:38:41 -03:00
parent 44510bd019
commit 95090ba24b
5 changed files with 555 additions and 4 deletions

View File

@@ -10,7 +10,13 @@
"typecheck": "tsc -p tsconfig.json --noEmit", "typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "echo 'no linter configured yet'" "lint": "echo 'no linter configured yet'"
}, },
"dependencies": {
"@aws-sdk/client-s3": "^3.1096.0",
"@eden/config": "workspace:*",
"nodemailer": "^9.1.1"
},
"devDependencies": { "devDependencies": {
"@types/nodemailer": "^8.0.1",
"typescript": "^5.7.3" "typescript": "^5.7.3"
} }
} }

View File

@@ -1,7 +1,8 @@
/** /**
* External adapters (Focus NFe, SaperX, Control iD, S3, SMTP) — each * External adapters (Focus NFe, SaperX, Control iD, S3, SMTP) — each
* isolated behind a port per Master Prompt §13. Empty placeholder; the * isolated behind a port per Master Prompt §13. S3 and SMTP adapters land
* first real adapter (S3 or SMTP) lands with the rest of Fase 1's * first (platform bootstrap); the others follow per-domain as their
* platform bootstrap. * modules are built.
*/ */
export const INTEGRATIONS_PACKAGE_VERSION = "0.1.0"; export * from "./s3/client.js";
export * from "./smtp/mailer.js";

View File

@@ -0,0 +1,137 @@
/**
* S3 adapter — port of the legacy `server/src/lib/s3.js` (eden.md §5
* "Armazenamento S3"). Compatible with any S3-like endpoint (MinIO, AWS S3),
* not exclusive to AWS. Storage failures are never swallowed: every
* function throws a clear error when S3 isn't configured, unlike the SMTP
* adapter (see `../smtp/mailer.ts`) which fails silently by design.
*
* NOTE: `@eden/config`'s `loadEnv()`/env-schema is still a placeholder in
* this worktree (only `CONFIG_PACKAGE_VERSION` is exported so far), so this
* module reads `process.env` directly using the exact var names already
* reserved for S3 in the target env schema (S3_ENDPOINT, S3_REGION,
* S3_FORCE_PATH_STYLE, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_BUCKET).
* `@eden/config` is still declared as a dependency so this can be swapped
* for a real `loadEnv()` call once that lands, without touching callers.
*/
import {
DeleteObjectCommand,
GetObjectCommand,
PutObjectCommand,
S3Client,
} from "@aws-sdk/client-s3";
import type { Readable } from "node:stream";
const NOT_CONFIGURED_MESSAGE = "S3 não configurado (S3_ENDPOINT ausente)";
interface S3Config {
endpoint: string;
region: string;
forcePathStyle: boolean;
accessKeyId: string | undefined;
secretAccessKey: string | undefined;
bucket: string | undefined;
}
let client: S3Client | undefined;
let config: S3Config | undefined;
function loadConfig(): S3Config | undefined {
const endpoint = process.env.S3_ENDPOINT;
if (!endpoint) {
return undefined;
}
return {
endpoint,
region: process.env.S3_REGION ?? "us-east-1",
// Path-style by default (typical of MinIO/self-hosted); set the env
// var to exactly "false" to switch to virtual-hosted style (AWS S3).
forcePathStyle: process.env.S3_FORCE_PATH_STYLE !== "false",
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
bucket: process.env.S3_BUCKET,
};
}
function requireConfig(): S3Config {
if (!config) {
config = loadConfig();
}
if (!config) {
throw new Error(NOT_CONFIGURED_MESSAGE);
}
return config;
}
/**
* Raw S3 client, exported for callers (e.g. a future Backup module) that
* need multipart streaming upload via `@aws-sdk/lib-storage`'s `Upload`
* class directly instead of `uploadObject` (which buffers the whole file
* in memory — fine for small files, not for a Postgres dump).
*/
export function getClient(): S3Client {
const cfg = requireConfig();
if (!client) {
client = new S3Client({
endpoint: cfg.endpoint,
region: cfg.region,
forcePathStyle: cfg.forcePathStyle,
...(cfg.accessKeyId && cfg.secretAccessKey
? {
credentials: {
accessKeyId: cfg.accessKeyId,
secretAccessKey: cfg.secretAccessKey,
},
}
: {}),
});
}
return client;
}
/** Single bucket used for all data (no bucket-per-data-type). */
export function getBucket(): string {
const cfg = requireConfig();
return cfg.bucket ?? "";
}
/**
* Simple PUT, whole buffer in memory — adequate for small/medium files
* (images, PDFs, attachments), not for large streaming uploads.
*/
export async function uploadObject(
key: string,
buffer: Buffer,
mimeType: string,
): Promise<void> {
const s3 = getClient();
const bucket = getBucket();
await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: buffer,
ContentType: mimeType,
}),
);
}
/**
* GET, returning the object body as a Node stream — used both to serve a
* download and to pipe directly to an HTTP response. On Node.js, the SDK
* v3 response `.Body` is already a `Readable` (with extra helper mixins);
* this just types it correctly for callers.
*/
export async function getObjectStream(key: string): Promise<Readable> {
const s3 = getClient();
const bucket = getBucket();
const response = await s3.send(
new GetObjectCommand({ Bucket: bucket, Key: key }),
);
return response.Body as Readable;
}
export async function deleteObject(key: string): Promise<void> {
const s3 = getClient();
const bucket = getBucket();
await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
}

View File

@@ -0,0 +1,82 @@
/**
* SMTP adapter — port of the legacy `server/src/lib/mailer.js` (eden.md §4
* "Envio de e-mail"). Generic SMTP via `nodemailer`, not a direct
* integration with SES/SendGrid/etc.
*
* Deliberately fail-soft, unlike the S3 adapter (`../s3/client.ts`): no
* business flow may ever fail because of email. If SMTP isn't configured,
* or if sending fails, `sendMail` logs and returns normally — it never
* throws into the caller.
*
* NOTE: `@eden/config`'s `loadEnv()`/env-schema is still a placeholder in
* this worktree, so this module reads `process.env` directly using the
* exact var names already reserved for SMTP in the target env schema
* (SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM).
*/
import nodemailer, { type Transporter } from "nodemailer";
export interface SendMailInput {
to: string;
subject: string;
html: string;
from?: string;
}
let transporter: Transporter | undefined;
let transporterBuilt = false;
function buildTransporter(): Transporter | undefined {
const host = process.env.SMTP_HOST;
if (!host) {
return undefined;
}
const port = Number(process.env.SMTP_PORT ?? "465");
const user = process.env.SMTP_USER;
const pass = process.env.SMTP_PASS;
return nodemailer.createTransport({
host,
port,
// secure: true automatically when the port is 465 (implicit SMTPS).
secure: port === 465,
...(user ? { auth: { user, pass } } : {}),
});
}
function getTransporter(): Transporter | undefined {
// Built once, lazily, on first use — not rebuilt afterwards even if env
// vars change at runtime (simplification acceptable for this MVP).
if (!transporterBuilt) {
transporter = buildTransporter();
transporterBuilt = true;
}
return transporter;
}
function defaultFrom(): string | undefined {
return process.env.SMTP_FROM ?? process.env.SMTP_USER;
}
export async function sendMail({
to,
subject,
html,
from,
}: SendMailInput): Promise<void> {
const t = getTransporter();
if (!t) {
console.log(
`[mailer] SMTP não configurado — e-mail para ${to} não enviado`,
);
return;
}
try {
await t.sendMail({
from: from ?? defaultFrom(),
to,
subject,
html,
});
} catch (err) {
console.error(`[mailer] falha ao enviar e-mail para ${to}:`, err);
}
}

325
pnpm-lock.yaml generated
View File

@@ -214,7 +214,20 @@ importers:
version: 5.9.3 version: 5.9.3
packages/integrations: packages/integrations:
dependencies:
'@aws-sdk/client-s3':
specifier: ^3.1096.0
version: 3.1096.0
'@eden/config':
specifier: workspace:*
version: link:../config
nodemailer:
specifier: ^9.1.1
version: 9.1.1
devDependencies: devDependencies:
'@types/nodemailer':
specifier: ^8.0.1
version: 8.0.1
typescript: typescript:
specifier: ^5.7.3 specifier: ^5.7.3
version: 5.9.3 version: 5.9.3
@@ -250,6 +263,78 @@ packages:
resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==}
engines: {node: '>=10'} engines: {node: '>=10'}
'@aws-sdk/checksums@3.1000.29':
resolution: {integrity: sha512-Dtu0gr4dnATZAPwEYbpCsG+MpLM7OAliy2gTepEFQwl1vZ6DL3QMH2FveMa3HLvPsOdhJsPRB3KtxVhph9T75A==}
engines: {node: '>=20.0.0'}
'@aws-sdk/client-s3@3.1096.0':
resolution: {integrity: sha512-sEx7KAEtkp1UqOoWQv2baM1rreClZG7o9YE8EfPvYpPBvGad1fQRG3sMHrOPMkIdZ9VjGRl25GiaG1MSeie2Mw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/core@3.977.9':
resolution: {integrity: sha512-reqPFEQrZxDZpeGj4PFMepBeR5LGYHRqq/L0motTzgFkCRBA4rFdaVXDSLYyGHhxVz7sT2PDnPN9CluGSfgyJA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-env@3.972.70':
resolution: {integrity: sha512-H404B7dJl2mCrBqahDEYsanB0xhdDp6tXnXcTUnXmmpy2Q3J0Ho0bUajZ2jr/RdwzCyS59Gi8xXIFwPLGBl6Uw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-http@3.972.72':
resolution: {integrity: sha512-X98zYOrVOeuosCX+6ktf29FC2N2GHPLia7qv6mzPzTc+RPAuHWCDS++Z6JK7eGYqb/v6uaW7bAXaOvDBfol+0w==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-ini@3.973.15':
resolution: {integrity: sha512-Rykg6s5ceBuynMOGWgoowO4N+27JfnqXAnVaSunZl0hOO1XodSrxGNz6sCEbnmS0lAfQZDKyb3fbr46gSuv6Sg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-login@3.972.77':
resolution: {integrity: sha512-Jb59xfEISoN5mmbnA+HYqdtrSX3CgCtJoof+V5D8/TgUI56W63GEEd5Y58WijU3Ou6+WEgaLD1feVzaRXV5IDQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-node@3.972.82':
resolution: {integrity: sha512-znDkEOGXB8W3kG1LJUKP3foBZY/9qLM0eil/DxWXSp37XsdsRLQHE/d/OaCGGVgKpA6znR38h/+INk8do1FjiA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-process@3.972.70':
resolution: {integrity: sha512-2ry03fGRJr4sV3jI+ocjj5JqALnFD6ymM5KiNCDZMvq8bX2GSbE0vji4aM43TVCl2nXqqLRZaUxdq/KeWRAY4Q==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-sso@3.973.14':
resolution: {integrity: sha512-jkhg/8ocAAoc0RFyLMhCw+/zZh7gystQgd4F4hznNa8P4Cc501PQmxd+jGLiMHodPJ+7Zv/3znM62gZojyasmA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/credential-provider-web-identity@3.972.76':
resolution: {integrity: sha512-d3AGyVu759PGr35mEB2s22xxlNEA5rpdxtSPJthfPFJvoQ8dt357iVPECqWfUxXp1toJAvKmbtcIYVGigaGsCA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-sdk-s3@3.972.75':
resolution: {integrity: sha512-wMIsNumRVKaNMKhvU/s9VrdEwE8S6gSzXp4RygFG5BEMnGkkXf8cjh8zf7cKJBpUDpqTWqwbz5isEgp9rH6Lng==}
engines: {node: '>=20.0.0'}
'@aws-sdk/nested-clients@3.997.44':
resolution: {integrity: sha512-NhEgryjlBF9w38ZXqGymQV28IhkYa1mKhlbYnqIis57AYwWGVYfUPgg/qC2rLRqOUfblxx++irvju10kVTa8Vw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/signature-v4-multi-region@3.996.46':
resolution: {integrity: sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/token-providers@3.1116.0':
resolution: {integrity: sha512-ygIivKqh8aHzNkucOCXHyIBgBpLPfrSI0mCqXF+vLBsPTUKqj0VSqAY0GFPe7lQl4HntjOcQ+KSyS7oUV2C54Q==}
engines: {node: '>=20.0.0'}
'@aws-sdk/types@3.974.5':
resolution: {integrity: sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==}
engines: {node: '>=20.0.0'}
'@aws-sdk/xml-builder@3.972.40':
resolution: {integrity: sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==}
engines: {node: '>=20.0.0'}
'@aws/lambda-invoke-store@0.3.0':
resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==}
engines: {node: '>=18.0.0'}
'@babel/code-frame@7.29.7': '@babel/code-frame@7.29.7':
resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -921,6 +1006,30 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@smithy/core@3.33.3':
resolution: {integrity: sha512-CsOeKq/9kA3y6VJHt+/+VTCtBaxJ4OTFpgrjIUhPpDIKxBci1k2bJaQASF2h/ELWrulGp+t97DZ0mevfAD8idg==}
engines: {node: '>=18.0.0'}
'@smithy/credential-provider-imds@4.5.2':
resolution: {integrity: sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==}
engines: {node: '>=18.0.0'}
'@smithy/fetch-http-handler@5.7.2':
resolution: {integrity: sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==}
engines: {node: '>=18.0.0'}
'@smithy/node-http-handler@4.12.0':
resolution: {integrity: sha512-0mq1pHadfyXCYCqm2cNpbjNIT+fbaUpNxewZb/YNr2L0IrEVMOb8gM/Fl4K6XvHCW3uSNDFwPl/+iKm0bx9jYg==}
engines: {node: '>=18.0.0'}
'@smithy/signature-v4@5.7.3':
resolution: {integrity: sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==}
engines: {node: '>=18.0.0'}
'@smithy/types@4.17.2':
resolution: {integrity: sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==}
engines: {node: '>=18.0.0'}
'@tokenizer/inflate@0.2.7': '@tokenizer/inflate@0.2.7':
resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==} resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -991,6 +1100,9 @@ packages:
'@types/node@22.20.1': '@types/node@22.20.1':
resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==}
'@types/nodemailer@8.0.1':
resolution: {integrity: sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==}
'@types/pg@8.23.1': '@types/pg@8.23.1':
resolution: {integrity: sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A==} resolution: {integrity: sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A==}
@@ -1082,6 +1194,9 @@ packages:
resolution: {integrity: sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==} resolution: {integrity: sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
bowser@2.14.1:
resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==}
boxen@5.1.2: boxen@5.1.2:
resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -1578,6 +1693,10 @@ packages:
resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==} resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
nodemailer@9.1.1:
resolution: {integrity: sha512-izw9mVKFix6YSnC9eLgV6g1opl9DUlRio9ZNcq+Wu9Ujn2UwF+8Nl0B8nz22kEC+CTZCvinkxwJ0DeFbb6NwcQ==}
engines: {node: '>=6.0.0'}
normalize-path@3.0.0: normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -2080,6 +2199,171 @@ snapshots:
'@alloc/quick-lru@5.3.0': {} '@alloc/quick-lru@5.3.0': {}
'@aws-sdk/checksums@3.1000.29':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/client-s3@3.1096.0':
dependencies:
'@aws-sdk/checksums': 3.1000.29
'@aws-sdk/core': 3.977.9
'@aws-sdk/credential-provider-node': 3.972.82
'@aws-sdk/middleware-sdk-s3': 3.972.75
'@aws-sdk/signature-v4-multi-region': 3.996.46
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/fetch-http-handler': 5.7.2
'@smithy/node-http-handler': 4.12.0
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/core@3.977.9':
dependencies:
'@aws-sdk/types': 3.974.5
'@aws-sdk/xml-builder': 3.972.40
'@aws/lambda-invoke-store': 0.3.0
'@smithy/core': 3.33.3
'@smithy/signature-v4': 5.7.3
'@smithy/types': 4.17.2
bowser: 2.14.1
tslib: 2.8.1
'@aws-sdk/credential-provider-env@3.972.70':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/credential-provider-http@3.972.72':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/fetch-http-handler': 5.7.2
'@smithy/node-http-handler': 4.12.0
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/credential-provider-ini@3.973.15':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/credential-provider-env': 3.972.70
'@aws-sdk/credential-provider-http': 3.972.72
'@aws-sdk/credential-provider-login': 3.972.77
'@aws-sdk/credential-provider-process': 3.972.70
'@aws-sdk/credential-provider-sso': 3.973.14
'@aws-sdk/credential-provider-web-identity': 3.972.76
'@aws-sdk/nested-clients': 3.997.44
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/credential-provider-imds': 4.5.2
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/credential-provider-login@3.972.77':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/nested-clients': 3.997.44
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/credential-provider-node@3.972.82':
dependencies:
'@aws-sdk/credential-provider-env': 3.972.70
'@aws-sdk/credential-provider-http': 3.972.72
'@aws-sdk/credential-provider-ini': 3.973.15
'@aws-sdk/credential-provider-process': 3.972.70
'@aws-sdk/credential-provider-sso': 3.973.14
'@aws-sdk/credential-provider-web-identity': 3.972.76
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/credential-provider-imds': 4.5.2
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/credential-provider-process@3.972.70':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/credential-provider-sso@3.973.14':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/nested-clients': 3.997.44
'@aws-sdk/token-providers': 3.1116.0
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/credential-provider-web-identity@3.972.76':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/nested-clients': 3.997.44
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/middleware-sdk-s3@3.972.75':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/signature-v4-multi-region': 3.996.46
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/nested-clients@3.997.44':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/signature-v4-multi-region': 3.996.46
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/fetch-http-handler': 5.7.2
'@smithy/node-http-handler': 4.12.0
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/signature-v4-multi-region@3.996.46':
dependencies:
'@aws-sdk/types': 3.974.5
'@smithy/signature-v4': 5.7.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/token-providers@3.1116.0':
dependencies:
'@aws-sdk/core': 3.977.9
'@aws-sdk/nested-clients': 3.997.44
'@aws-sdk/types': 3.974.5
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/types@3.974.5':
dependencies:
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws-sdk/xml-builder@3.972.40':
dependencies:
'@smithy/types': 4.17.2
tslib: 2.8.1
'@aws/lambda-invoke-store@0.3.0': {}
'@babel/code-frame@7.29.7': '@babel/code-frame@7.29.7':
dependencies: dependencies:
'@babel/helper-validator-identifier': 7.29.7 '@babel/helper-validator-identifier': 7.29.7
@@ -2521,6 +2805,39 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.63.1': '@rollup/rollup-win32-x64-msvc@4.63.1':
optional: true optional: true
'@smithy/core@3.33.3':
dependencies:
'@smithy/types': 4.17.2
tslib: 2.8.1
'@smithy/credential-provider-imds@4.5.2':
dependencies:
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@smithy/fetch-http-handler@5.7.2':
dependencies:
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@smithy/node-http-handler@4.12.0':
dependencies:
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@smithy/signature-v4@5.7.3':
dependencies:
'@smithy/core': 3.33.3
'@smithy/types': 4.17.2
tslib: 2.8.1
'@smithy/types@4.17.2':
dependencies:
tslib: 2.8.1
'@tokenizer/inflate@0.2.7(supports-color@7.2.0)': '@tokenizer/inflate@0.2.7(supports-color@7.2.0)':
dependencies: dependencies:
debug: 4.4.3(supports-color@7.2.0) debug: 4.4.3(supports-color@7.2.0)
@@ -2600,6 +2917,10 @@ snapshots:
dependencies: dependencies:
undici-types: 6.21.0 undici-types: 6.21.0
'@types/nodemailer@8.0.1':
dependencies:
'@types/node': 22.20.1
'@types/pg@8.23.1': '@types/pg@8.23.1':
dependencies: dependencies:
'@types/node': 22.20.1 '@types/node': 22.20.1
@@ -2719,6 +3040,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
bowser@2.14.1: {}
boxen@5.1.2: boxen@5.1.2:
dependencies: dependencies:
ansi-align: 3.0.1 ansi-align: 3.0.1
@@ -3268,6 +3591,8 @@ snapshots:
node-releases@2.0.54: {} node-releases@2.0.54: {}
nodemailer@9.1.1: {}
normalize-path@3.0.0: {} normalize-path@3.0.0: {}
object-assign@4.1.1: {} object-assign@4.1.1: {}