commit 7767905706d8891812758e43c46441072d95b8be
parent c11cdfd3e51add5d181eec14995b22ae589003ae
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Mon, 6 Jul 2026 21:43:42 -0400
Upload oversize archives to R2 via S3 multipart, not wrangler
`wrangler r2 object put` caps a single upload at 300 MiB, so oversize
archives (e.g. a 480 MB live-chat zip) failed to upload and the served
manifest pointed at a missing object. Switch runArchiveUploadIntoLog to
R2's S3 API using the AWS SDK's multipart uploader (@aws-sdk/lib-storage),
which streams any size. Archives stay .zip (application/zip); Cache-Control
unchanged.
Credentials come from the env (R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY,
CLOUDFLARE_ACCOUNT_ID → S3 endpoint), not the settings JSON. If a bucket is
configured with staged files but creds are missing, the upload fails closed
(non-zero, before the Pages deploy) so a site never links to a missing file.
wrangler still handles the Pages deploy. DEPLOY_CLOUDFLARE.md documents the
new S3 credential step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat:
6 files changed, 505 insertions(+), 36 deletions(-)
diff --git a/DEPLOY_CLOUDFLARE.md b/DEPLOY_CLOUDFLARE.md
@@ -36,9 +36,15 @@ Oversize archives are staged during compose into `export/.r2-staging/<siteId>/ar
**Build & deploy** actions to `<bucket>/<siteId>/archives/<file>.zip` **before** the
Pages deploy runs, so the manifest URLs resolve immediately.
-> **Note:** only the **editor's** deploy actions upload to R2 (that's where the host
-> `wrangler` credentials live). A raw `pnpm run build` / `pnpm deploy` from the
-> `export` package only *stages* the files — it does not upload them.
+> **Note:** only the **editor's** deploy actions upload to R2 (that's where the R2
+> credentials live). A raw `pnpm run build` / `pnpm deploy` from the `export`
+> package only *stages* the files — it does not upload them.
+
+Uploads go through R2's **S3 API** (via the AWS SDK's multipart uploader), not
+`wrangler r2 object put` — wrangler caps a single upload at **300 MiB**, and real
+live-chat archives are larger (multipart has no such limit). That's why archive
+uploads need S3 credentials (step 3) in addition to the wrangler auth your Pages
+deploy already uses.
---
@@ -76,11 +82,29 @@ ways to expose it; the first needs **no domain purchase** and is the recommended
throttles `r2.dev` and gives you **no** cache / rate-limit control of your own. Fine
for a smoke test; use the Worker for a real instance.
-### 3. Authenticate `wrangler`
+### 3. Authenticate — two credentials
+
+**a) `wrangler` (for the Pages deploy).** The `wrangler pages deploy` step reuses
+whatever auth you already use. If it works today, nothing to do. Otherwise run
+`wrangler login`, or set `CLOUDFLARE_API_TOKEN`.
+
+**b) R2 S3 API keys (for the archive uploads).** Archive objects are uploaded over
+R2's S3-compatible API, which needs an Access Key ID + Secret. In the dashboard:
+**R2 → Manage R2 API Tokens → Create API token**, permission **Object Read & Write**,
+scoped to your bucket. Then set three environment variables where the editor runs:
+
+```sh
+export R2_ACCESS_KEY_ID=<access key id>
+export R2_SECRET_ACCESS_KEY=<secret access key>
+export CLOUDFLARE_ACCOUNT_ID=<your account id> # used to build the S3 endpoint
+```
-Uploads run as `wrangler r2 object put … --remote` from the host, reusing whatever
-auth your Pages deploy already uses. If `wrangler pages deploy` works today, this will
-too. Otherwise run `wrangler login`, or set `CLOUDFLARE_API_TOKEN` with R2 write scope.
+The account id is on the R2 overview page; the S3 endpoint is derived as
+`https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com`. Keep these in the
+environment (a shell profile, a systemd unit, a `.env` the editor loads) — **not** in
+the settings JSON, which isn't a place for secrets. If a deploy has oversize archives
+to upload but these are unset, it fails *before* the Pages deploy (so the site never
+links to a missing file) with a message pointing back here.
### 4. Point the editor at the bucket
diff --git a/editor/CHANGELOG.md b/editor/CHANGELOG.md
@@ -5,7 +5,7 @@
- **Search results scroll smoothly again on large result sets.** The results list windows one card per matching video (only the on-screen cards are mounted), but each visible card and every one of its hit rows was re-rendering on *every* scroll frame — and each hit row re-ran its `<mark>` highlighting, so a single video with hundreds of hits meant hundreds of redundant highlight passes per frame while scrolling. The result cards and individual hit rows are now memoized so an unchanged card/row is skipped during scroll, and opening the modal on a hit only re-renders the two rows whose highlight state actually changes. No visible/behavioral change — same DOM, same results, just far less work per frame. See `common/components/TranscriptSearch.tsx` (`ResultCard`/`HitRow` memoization, `openWithMode` stabilized via `useCallback`).
- **The monitor widget gains a needs-work channel list, more interaction buttons, and an in-place settings gear.** Three additions, all driveable from the widget builder. **(1) A "Needs work" list** (URL flag `act=1`) — a compact, per-channel worklist of videos to download (`↓ N`) or transcribe (`✎ N`), reusing the same `loadActionableSummary` that powers the `/actionable` page via a new `/api/widget/actionable` route; it polls on a 15s floor (the backlog changes on job completions, not seconds) and caps at 6 channels with a `+N more` line. **(2) More interactions** behind the existing `controls=1` switch: each needs-work row gains the same per-channel **Download missing** / **Transcribe pending** buttons as the actionable page (reusing `InlineActionButton`), and the controls row adds **Retry all failed** alongside Pause/Resume + Drain. **(3) An in-place settings gear** (on by default; URL flag `gear=0` to hide, or a **Show settings gear** builder checkbox) — clicking it opens the builder's own form *inside the widget window*, so a pinned widget can be reconfigured live without opening the builder page; edits apply immediately and mirror into the address bar via `history.replaceState`, so a reload preserves them and the link stays copyable. The builder form is extracted into a shared `WidgetConfigForm` used by both the builder and the overlay, and the widget's poller now fetches immediately on (re)subscribe instead of after one interval, so newly-enabled sections render at once. Existing links render unchanged (the two new flags default to their old behavior; the gear is the one new default-visible affordance and is read-only — it mutates no server state). See `editor/app/widget/lib/config.ts`, the new `editor/app/widget/components/WidgetConfigForm.tsx` and `editor/app/api/widget/actionable/route.ts`, `editor/app/widget/components/{MonitorWidget,WidgetControls}.tsx`, `editor/app/widget/builder/components/WidgetBuilder.tsx`, and `editor/e2e/widget.spec.ts`.
- **Every site build now bundles downloadable per-channel transcript & live-chat archive zips.** The archive builders (per-channel `<slug>.zip` / `<slug>.live_chat.zip`) previously only ran as standalone actions that wrote to a non-served directory; now `compose-site` generates them for the site's own channels straight into the served `public/archives/` and writes a `manifest.json` (sizes + counts) that the site's new **Downloads** page reads. **`zip` is now the default archive format** everywhere (was `tar.gz`), and the Build page's format help text tracks the selected format. Generation is **on by default with three opt-out levels**: a global **Generate archive zips on build** toggle in Settings, a per-site **Generate archive zips** toggle (plus an optional **Archive size cap (MB)**) on the site's page, and a per-build **Skip archive zips** checkbox on the Build and Build & Deploy controls (`BUILD_ARCHIVES=0`). See `common/bin/compose-site.ts` (`composeArchives`), `common/controller/archive{Transcripts,LiveChat}.ts` (new `outDir` option), `common/lib/archiveOptions.ts` (default + manifest types), `common/lib/{site,settings}.ts` (opt-out flags), and `editor/app/{deploy/buildDeployCore.ts,build/buildAction.ts,deploy/components/Build{Export,Deploy}Button.tsx,sites/components/SiteForm.tsx,settings/components/SettingsForm.tsx}`.
-- **Oversize archives now overflow to Cloudflare R2 instead of being dropped.** A single file over 25 MB breaks a Cloudflare Pages deploy, so a channel zip over the cap (default 25 MB; `0` = no cap) used to be removed from what's served and flagged `oversize`. Now, when **Archive overflow storage** is configured in Settings (an R2 **bucket** + its **public URL**), `compose-site` stages each oversize archive to `export/.r2-staging/<siteId>/` and records its future public URL in the manifest; the deploy step then uploads it via `wrangler r2 object put <bucket>/<siteId>/archives/<file>` (reusing the host's wrangler auth) **before** the Pages deploy, so the Downloads page links straight to R2. With no bucket configured the old drop-and-flag behavior is unchanged (uploads run only in the editor's Deploy / Build & deploy actions, not a raw `pnpm deploy`). The **combined "whole site" archives were removed** — they duplicated the per-channel content and were always the first to blow the cap. Each R2 upload also now sets `Cache-Control: public, max-age=3600` so a Cloudflare custom domain caches downloads at the edge — the main defense against download-abuse cost (R2 egress is free; only origin reads are billable, and cached hits skip the origin). New **[DEPLOY_CLOUDFLARE.md](../DEPLOY_CLOUDFLARE.md)** documents the full R2 setup plus the Cloudflare custom-domain / caching / rate-limiting / bot config for instance operators. See `common/lib/settings.ts` (`archiveStorage`), `common/bin/compose-site.ts` (staging + manifest `url`), `common/lib/archiveOptions.ts` (`ArchiveManifestEntry.url`), and `editor/app/deploy/buildDeployCore.ts` (`runArchiveUploadIntoLog`, `ARCHIVE_CACHE_CONTROL`) / `deploy/deployAction.ts` / `build/buildAction.ts`.
+- **Oversize archives now overflow to Cloudflare R2 instead of being dropped.** A single file over 25 MB breaks a Cloudflare Pages deploy, so a channel zip over the cap (default 25 MB; `0` = no cap) used to be removed from what's served and flagged `oversize`. Now, when **Archive overflow storage** is configured in Settings (an R2 **bucket** + its **public URL**), `compose-site` stages each oversize archive to `export/.r2-staging/<siteId>/` and records its future public URL in the manifest; the deploy step then uploads it to `<bucket>/<siteId>/archives/<file>` **before** the Pages deploy, so the Downloads page links straight to R2. Uploads go over R2's **S3 API** using the AWS SDK's multipart uploader (`@aws-sdk/lib-storage`) — `wrangler r2 object put` caps a single upload at 300 MiB and real live-chat archives are larger, whereas multipart streams any size. This needs R2 **S3 credentials** in the environment (`R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `CLOUDFLARE_ACCOUNT_ID`); if they're missing when there's something to upload, the deploy fails before the Pages step (so the site never links to a missing file). With no bucket configured the old drop-and-flag behavior is unchanged (uploads run only in the editor's Deploy / Build & deploy actions, not a raw `pnpm deploy`). The **combined "whole site" archives were removed** — they duplicated the per-channel content and were always the first to blow the cap. Each R2 upload also now sets `Cache-Control: public, max-age=3600` so a Cloudflare custom domain caches downloads at the edge — the main defense against download-abuse cost (R2 egress is free; only origin reads are billable, and cached hits skip the origin). New **[DEPLOY_CLOUDFLARE.md](../DEPLOY_CLOUDFLARE.md)** documents the full R2 setup plus the Cloudflare custom-domain / caching / rate-limiting / bot config for instance operators. See `common/lib/settings.ts` (`archiveStorage`), `common/bin/compose-site.ts` (staging + manifest `url`), `common/lib/archiveOptions.ts` (`ArchiveManifestEntry.url`), and `editor/app/deploy/buildDeployCore.ts` (`runArchiveUploadIntoLog`, `ARCHIVE_CACHE_CONTROL`) / `deploy/deployAction.ts` / `build/buildAction.ts`.
- **Archive downloads can now be served securely without owning a domain (`r2-proxy/` Worker).** Serving oversize R2 archives with cost/abuse protection previously implied a Cloudflare **custom domain** (for CDN caching + rate-limiting rules). New self-contained Cloudflare Worker at `r2-proxy/` serves the bucket on a free `*.workers.dev` subdomain instead — the same domain-free model as Pages' `*.pages.dev`, addressing the privacy/expense of registering a domain. It's a pure passthrough (request path `<siteId>/archives/<file>.zip` → bucket key), so **one Worker serves every site** — deploy it once, not per site. It adds edge caching (Cache API, honoring the object's `Cache-Control`), native per-IP rate limiting (free binding), path allow-listing (`*/archives/*.zip` only), and `Range`/resumable-download support. Point the editor's **Archive overflow public URL** at the `workers.dev` URL and nothing else changes (uploads/manifest are identical). `DEPLOY_CLOUDFLARE.md` now documents both paths (Worker vs custom domain), with the Worker as the recommended no-domain option. See `r2-proxy/{src/index.ts,wrangler.toml,package.json,README.md}` and `editor/app/settings/components/SettingsForm.tsx` (public-URL hint).
- **The Duplicates page is now a per-site toggle and hides itself when empty.** Each site's editor page gains a **Show the Duplicates page** checkbox (on by default). `compose-site` writes the site-filtered `duplicates.json` only when the toggle is on *and* there's at least one in-scope cluster, and the export Header keys its Duplicates nav link off a new `hasDuplicates()` — so the link and page disappear both when a site opts out and when it simply has no detected duplicates. See `common/lib/site.ts` (`duplicates` flag), `common/bin/compose-site.ts` (gated write), `export/app/lib/duplicates.ts` (new), `export/app/components/Header.tsx`, and `editor/app/sites/{components/SiteForm.tsx,actions.ts}`.
- **You can now change a channel's slug (its id) — deliberately, from the Danger zone.** A channel's slug *is* its on-disk directory name (`transcripts/channels/<slug>/`), so it used to be fixed at creation ("Slug is fixed once a channel is created"). A new **Rename** form in the channel's Danger zone lifts that: enter a new slug and **type the current slug to confirm** (same friction as delete), and the rename is blocked while the channel has running/queued jobs (the in-memory registry keys by slug). Because the slug is a directory name, the rename does a **full migration** of every slug-keyed store so nothing silently breaks: it moves the channel dir (config, data, playlist, snapshot, shards, failed lists) **and** the saved-video store dir — rewriting each `saved-video.json` pointer's absolute `dir` so persisted source videos still resolve — then retargets every site.json membership, the sync scheduler's per-channel backoff state, and any job bookmarks. The two filesystem moves run first and roll back on failure; the metadata updates that follow are atomic and best-effort (surfaced as warnings). Renaming **changes the channel's public URL** (the old one 404s), which the form warns about. The slug grammar is also now validated on create. See `common/controller/renameChannel.ts`, `common/controller/channels.ts` (`isValidChannelSlug`), `common/lib/savedVideo-server.ts` (`rewriteSavedVideoDir`), `common/jobs/bookmarks.ts` (`renameChannelInBookmarks`), `editor/app/channels/{actions.ts,components/RenameChannelForm.tsx,[slug]/page.tsx}`, and `editor/e2e/channel-rename.spec.ts`.
diff --git a/editor/app/deploy/buildDeployCore.ts b/editor/app/deploy/buildDeployCore.ts
@@ -6,6 +6,10 @@
import path from "node:path";
import { readdir } from "node:fs/promises";
+import { createReadStream } from "node:fs";
+import { stat } from "node:fs/promises";
+import { S3Client } from "@aws-sdk/client-s3";
+import { Upload } from "@aws-sdk/lib-storage";
import { runChildIntoLog } from "yt-dlp-transcript-common/jobs/runChild";
import type { Paths } from "yt-dlp-transcript-common/lib/paths";
import { getSettings } from "yt-dlp-transcript-common/lib/settings";
@@ -93,12 +97,23 @@ function archiveStagingDir(siteId: string, paths: Paths): string {
// going stale; raise it if your archives rarely change.
const ARCHIVE_CACHE_CONTROL = "public, max-age=3600";
+// MIME type stored on each uploaded archive. Archives are `.zip` bundles.
+const ARCHIVE_CONTENT_TYPE = "application/zip";
+
// Upload this site's staged oversize archives to the configured R2 bucket, so the
-// remote URLs the served manifest points at actually resolve. Reuses the host's
-// wrangler auth (process.env), same as the Pages deploy. No-op (returns 0) when
-// overflow storage isn't configured or nothing was staged. Keys match what
-// composeArchives wrote into the manifest: `<siteId>/archives/<file>`. Must run
-// BEFORE the Pages deploy so the manifest never points at a missing object.
+// remote URLs the served manifest points at actually resolve. Uploads go through
+// R2's S3 API with the AWS SDK's multipart uploader (`@aws-sdk/lib-storage`) —
+// `wrangler r2 object put` caps single-file uploads at 300 MiB, which real
+// live-chat archives blow past, whereas multipart streams any size. Keys match
+// what composeArchives wrote into the manifest: `<siteId>/archives/<file>`. Must
+// run BEFORE the Pages deploy so the manifest never points at a missing object.
+//
+// No-op (returns 0) when overflow storage isn't configured or nothing was staged.
+// Credentials come from the host env (NOT the settings JSON — secrets don't
+// belong there): R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, and CLOUDFLARE_ACCOUNT_ID
+// (for the S3 endpoint). If a bucket is configured and files are staged but the
+// credentials are missing, we fail (return non-zero) so the deploy aborts rather
+// than shipping a manifest that points at un-uploaded objects.
export async function runArchiveUploadIntoLog(
onLog: (line: string) => void,
signal: AbortSignal,
@@ -118,32 +133,64 @@ export async function runArchiveUploadIntoLog(
}
if (files.length === 0) return 0;
+ const accessKeyId = process.env.R2_ACCESS_KEY_ID?.trim();
+ const secretAccessKey = process.env.R2_SECRET_ACCESS_KEY?.trim();
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID?.trim();
+ if (!accessKeyId || !secretAccessKey || !accountId) {
+ onLog(
+ `[archives] ${files.length} oversize archive(s) need uploading to R2 bucket ` +
+ `"${bucket}", but R2 S3 credentials are missing. Set R2_ACCESS_KEY_ID, ` +
+ `R2_SECRET_ACCESS_KEY, and CLOUDFLARE_ACCOUNT_ID in the environment — see ` +
+ `DEPLOY_CLOUDFLARE.md. Aborting before deploy so the site never links to ` +
+ `missing files.\n`,
+ );
+ return 1;
+ }
+
+ const client = new S3Client({
+ region: "auto",
+ endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
+ credentials: { accessKeyId, secretAccessKey },
+ });
+
onLog(
- `[archives] uploading ${files.length} oversize archive(s) to R2 bucket "${bucket}"…\n`,
+ `[archives] uploading ${files.length} oversize archive(s) to R2 bucket "${bucket}" via the S3 API…\n`,
);
- for (const file of files) {
- const key = `${site.siteId}/archives/${file}`;
- const code = await runChildIntoLog(onLog, signal, {
- command: "pnpm",
- args: [
- "dlx",
- "wrangler",
- "r2",
- "object",
- "put",
- `${bucket}/${key}`,
- `--file=${path.join(stagingDir, file)}`,
- "--content-type=application/zip",
- `--cache-control=${ARCHIVE_CACHE_CONTROL}`,
- "--remote",
- ],
- cwd: paths.exportDir,
- env: { ...process.env, NODE_ENV: "production" },
- });
- if (code !== 0) {
- onLog(`[archives] R2 upload failed for ${key} (exit ${code}).\n`);
- return code;
+ try {
+ for (const file of files) {
+ if (signal.aborted) return 1;
+ const key = `${site.siteId}/archives/${file}`;
+ const filePath = path.join(stagingDir, file);
+ const { size } = await stat(filePath);
+ onLog(`[archives] ${key} (${(size / 1e6).toFixed(1)} MB)…\n`);
+ const upload = new Upload({
+ client,
+ params: {
+ Bucket: bucket,
+ Key: key,
+ Body: createReadStream(filePath),
+ ContentType: ARCHIVE_CONTENT_TYPE,
+ CacheControl: ARCHIVE_CACHE_CONTROL,
+ },
+ });
+ const onAbort = () => {
+ upload.abort().catch(() => {});
+ };
+ signal.addEventListener("abort", onAbort, { once: true });
+ try {
+ await upload.done();
+ } finally {
+ signal.removeEventListener("abort", onAbort);
+ }
+ onLog(`[archives] ${key} done.\n`);
}
+ } catch (err) {
+ onLog(
+ `[archives] R2 upload failed: ${err instanceof Error ? err.message : String(err)}\n`,
+ );
+ return 1;
+ } finally {
+ client.destroy();
}
onLog("[archives] R2 upload complete.\n");
return 0;
diff --git a/editor/package.json b/editor/package.json
@@ -14,6 +14,8 @@
"e2e:ui": "playwright test --ui"
},
"dependencies": {
+ "@aws-sdk/client-s3": "^3.1080.0",
+ "@aws-sdk/lib-storage": "^3.1080.0",
"@sindresorhus/slugify": "^3.0.0",
"lucide-react": "^1.16.0",
"markdown-to-jsx": "^7.7.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
@@ -111,6 +111,12 @@ importers:
editor:
dependencies:
+ '@aws-sdk/client-s3':
+ specifier: ^3.1080.0
+ version: 3.1080.0
+ '@aws-sdk/lib-storage':
+ specifier: ^3.1080.0
+ version: 3.1080.0(@aws-sdk/client-s3@3.1080.0)
'@sindresorhus/slugify':
specifier: ^3.0.0
version: 3.0.0
@@ -283,6 +289,84 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
+ '@aws-sdk/checksums@3.1000.13':
+ resolution: {integrity: sha512-USI1N1d+NbCcfjeiYLKIl94PSYykl5IIjj4X3WqdL33Ln5qktA6sjXYct0o/gG2Cte7cuzbXKkDBkzUA4VPHrg==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/client-s3@3.1080.0':
+ resolution: {integrity: sha512-erKuxbwhYLKs0ZviBeTDvXxC0E4AtugHXLbt5kFk8u9/rQMglh/QJNK5f9KuLjlMrbFSJgkBmjNSY5O03YoK4A==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/core@3.974.28':
+ resolution: {integrity: sha512-4/1DtLwgLqzIg2uFzkFaFjMQHhhhwHIZN4PfziIVqXYX7koO78omuchQlLHyzQBw80l255dtmTA/J4W5yhb7zw==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-env@3.972.54':
+ resolution: {integrity: sha512-F4WQCG8GULIt+XrMHsqUM9dZc0eTwZM3HUWByOjIKOwBqJSzUxX8CFAtbgMvWfCua52FS1oi5FXarH3+khFq8A==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-http@3.972.56':
+ resolution: {integrity: sha512-PiwHgEK2srdfi/lFveyQ+3w/qikyh6MKvuZAdlMC+dwQi4K5iVBr32oh7cugnYw+jA8iGtnQMhCGvLm/mqplmw==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-ini@3.972.61':
+ resolution: {integrity: sha512-9CZWMjhBlgfKlqJk40R7kvMOLEIoOr3HJ1J/ELjAH9H5LzR4bCxLujPVM/1PKAEjzSZKZCxWOalm7JUGZbhQqw==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-login@3.972.60':
+ resolution: {integrity: sha512-Ak6OOrCbXvACyxLFIP1mcS+JTLS9ZpW1ZqyBtqu6axvdpsbG1gVNhUlAfQq8TK/gar/h2w35LrzlQU0PcUzJpw==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-node@3.972.63':
+ resolution: {integrity: sha512-YmgWtTPZDStyT74ApSHpApD3r7W9znsc+WEZjW0vceom+NAxRx9/F3TyukOKix8kJkPaa49aIREQJdpGeLDiEw==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-process@3.972.54':
+ resolution: {integrity: sha512-UNmUjtTnp3wH3YTZcctN7yK17S2AdaJpiNIdIf0l70hHOdGuDfdMxk62P5rt64GwGm6qkFOYG0js/cU6cdZDdg==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-sso@3.972.60':
+ resolution: {integrity: sha512-zH8SvJkTRw1Kb7GARjGPjzkQPfL3jDi/OxK32I5SQq7bgwgFHJZaoDEwkEvFlfNfpByM6n4Rs20Y1mLyOdb6ag==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/credential-provider-web-identity@3.972.60':
+ resolution: {integrity: sha512-q2rJSQ/AMjemUS18OtQqczqSo2R6VjOCLmLVmLVcdrP5/AKoj632lGCrMUWQ6EgnaLMEHbq0UO4mWh/u6gjPhA==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/lib-storage@3.1080.0':
+ resolution: {integrity: sha512-Vhe1T+Of8qWRypS8sEsC24931jMUd0Q2MNhtzApZB18Re/JnRYo5NaqlMSktzvyQ3SUljHTQ/R5Bv2Cz0bRfGg==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ '@aws-sdk/client-s3': ^3.1080.0
+
+ '@aws-sdk/middleware-sdk-s3@3.972.59':
+ resolution: {integrity: sha512-KCf/UjbnzV3QIXR1C2MeE9eRUG8EUXUf0V4y65hf2bKWQXzol5f3I8wOhE6OBdEYohn8zHfnC/cyy5+s7/HwLw==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/nested-clients@3.997.28':
+ resolution: {integrity: sha512-1oG/mM3jmE2M3kad2zWJS6IKIY8hjRV4l5kAgg+xTQdLMTtehhcSucL/y4WqQpcHmQwi6+gRK8E46GYl1NBW9Q==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/signature-v4-multi-region@3.996.38':
+ resolution: {integrity: sha512-C379Sk+MiFZCfWZphKlMyLHKxV22OjoGM5KJjj5IJNJcOCWL4IGIpnEGzv1FQiRwhYXfq55SJMfxlqPE08JJ9g==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/token-providers@3.1080.0':
+ resolution: {integrity: sha512-8PufAQvncWXvdZUvODbuyXa8l3aszefEzwSMBUcgheNbZOmJMcNn388Ebt/piVrUHyxKN1MlxnR2OonzTyZaGw==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/types@3.973.15':
+ resolution: {integrity: sha512-IULn8uBV/SMtmOIANsm4WHXIOtVPBWfOWs3WGL0j/sI+KhaYehvOw0ET+9urnn8MBpiijuU/0JOpuwKOE451PQ==}
+ engines: {node: '>=20.0.0'}
+
+ '@aws-sdk/xml-builder@3.972.33':
+ resolution: {integrity: sha512-ezbwz9WpuLctm6o7P2t2naDhVVPI5jFGrVefVybhcKGjU57VIyT46pQVO0RI2RYkUdhdj2Z9uSIlAzGZE9NW9A==}
+ 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.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
@@ -1619,6 +1703,30 @@ packages:
resolution: {integrity: sha512-gVaaGtKYMYAMmI8buULVH3A2TXVJ98QiwGwI7ddrWGuGidGC2uRt4FHs22+8iROJ0QTzju9CuMjlVsrvpqsdhA==}
engines: {node: '>=20'}
+ '@smithy/core@3.29.1':
+ resolution: {integrity: sha512-qoiY4nrk5OCu1+eIR1VB8l5DmON/oKiqrd5zZFAhXJXjJlLWQusKEW/SkBDAtGDcPaz86m9kfcE1lngU0GlM6A==}
+ engines: {node: '>=18.0.0'}
+
+ '@smithy/credential-provider-imds@4.4.6':
+ resolution: {integrity: sha512-B2WQ/PV/H6Jeg3lrIq6bKUfa6Hy01mtK7CGs6lhjzHA6k4aagldH6T6eEjnzKl4HI0cJnAsxfJ19pgb5PV+CVQ==}
+ engines: {node: '>=18.0.0'}
+
+ '@smithy/fetch-http-handler@5.6.3':
+ resolution: {integrity: sha512-CwCc/7SMTj45y97MUnDTbTaxvtAsiNNRm81z3abROIuMbMsC2Iy5EKfkkVdsKrz8WExQAAMx1EJapq+9j4fFTQ==}
+ engines: {node: '>=18.0.0'}
+
+ '@smithy/node-http-handler@4.9.3':
+ resolution: {integrity: sha512-qZTa4gQFUo8RM02rk6q5UVTDLNrQ1oS20LsepBzqq1QBVc/EHJ03OOUADcqMZiXHArW+Y7+OGY0BpdTwZRq/Yg==}
+ engines: {node: '>=18.0.0'}
+
+ '@smithy/signature-v4@5.6.2':
+ resolution: {integrity: sha512-QgHflghMoPxCJ9axiCVh8KZfbC9fuP6vkXXyK//E3cq7nLaSSyyLj0GAoqVWezYeDQmXIZhmlRvLE16jsqDK6g==}
+ engines: {node: '>=18.0.0'}
+
+ '@smithy/types@4.15.1':
+ resolution: {integrity: sha512-x3L0XSACF6UYzKpa9biqiRMgvH5+wnFFew9Tm/grFYqgaupPwx/+ojDPpPJM8dZON3S9tjz5U+PQYsCBd1Mw5Q==}
+ engines: {node: '>=18.0.0'}
+
'@swc/helpers@0.5.15':
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
@@ -2062,11 +2170,17 @@ packages:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
+ base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
baseline-browser-mapping@2.10.23:
resolution: {integrity: sha512-xwVXGqevyKPsiuQdLj+dZMVjidjJV508TBqexND5HrF89cGdCYCJFB3qhcxRHSeMctdCfbR1jrxBajhDy7o29g==}
engines: {node: '>=6.0.0'}
hasBin: true
+ bowser@2.14.1:
+ resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==}
+
boxen@7.0.0:
resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==}
engines: {node: '>=14.16'}
@@ -2087,6 +2201,9 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
+ buffer@5.6.0:
+ resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==}
+
bytes@3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
@@ -2498,6 +2615,10 @@ packages:
eventemitter3@4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+ events@3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+
execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
@@ -2698,6 +2819,9 @@ packages:
resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
engines: {node: '>=18.18.0'}
+ ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -2714,6 +2838,9 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
@@ -3390,6 +3517,10 @@ packages:
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
engines: {node: '>=0.10.0'}
+ readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+
recharts-scale@0.4.5:
resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
@@ -3538,6 +3669,9 @@ packages:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
+ stream-browserify@3.0.0:
+ resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
+
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -3569,6 +3703,9 @@ packages:
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
engines: {node: '>= 0.4'}
+ string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
@@ -3745,6 +3882,9 @@ packages:
'@types/react':
optional: true
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
@@ -3816,6 +3956,181 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
+ '@aws-sdk/checksums@3.1000.13':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/client-s3@3.1080.0':
+ dependencies:
+ '@aws-sdk/checksums': 3.1000.13
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/credential-provider-node': 3.972.63
+ '@aws-sdk/middleware-sdk-s3': 3.972.59
+ '@aws-sdk/signature-v4-multi-region': 3.996.38
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/fetch-http-handler': 5.6.3
+ '@smithy/node-http-handler': 4.9.3
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/core@3.974.28':
+ dependencies:
+ '@aws-sdk/types': 3.973.15
+ '@aws-sdk/xml-builder': 3.972.33
+ '@aws/lambda-invoke-store': 0.3.0
+ '@smithy/core': 3.29.1
+ '@smithy/signature-v4': 5.6.2
+ '@smithy/types': 4.15.1
+ bowser: 2.14.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-env@3.972.54':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-http@3.972.56':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/fetch-http-handler': 5.6.3
+ '@smithy/node-http-handler': 4.9.3
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-ini@3.972.61':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/credential-provider-env': 3.972.54
+ '@aws-sdk/credential-provider-http': 3.972.56
+ '@aws-sdk/credential-provider-login': 3.972.60
+ '@aws-sdk/credential-provider-process': 3.972.54
+ '@aws-sdk/credential-provider-sso': 3.972.60
+ '@aws-sdk/credential-provider-web-identity': 3.972.60
+ '@aws-sdk/nested-clients': 3.997.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/credential-provider-imds': 4.4.6
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-login@3.972.60':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/nested-clients': 3.997.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-node@3.972.63':
+ dependencies:
+ '@aws-sdk/credential-provider-env': 3.972.54
+ '@aws-sdk/credential-provider-http': 3.972.56
+ '@aws-sdk/credential-provider-ini': 3.972.61
+ '@aws-sdk/credential-provider-process': 3.972.54
+ '@aws-sdk/credential-provider-sso': 3.972.60
+ '@aws-sdk/credential-provider-web-identity': 3.972.60
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/credential-provider-imds': 4.4.6
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-process@3.972.54':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-sso@3.972.60':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/nested-clients': 3.997.28
+ '@aws-sdk/token-providers': 3.1080.0
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/credential-provider-web-identity@3.972.60':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/nested-clients': 3.997.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/lib-storage@3.1080.0(@aws-sdk/client-s3@3.1080.0)':
+ dependencies:
+ '@aws-sdk/client-s3': 3.1080.0
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ buffer: 5.6.0
+ events: 3.3.0
+ stream-browserify: 3.0.0
+ tslib: 2.8.1
+
+ '@aws-sdk/middleware-sdk-s3@3.972.59':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/signature-v4-multi-region': 3.996.38
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/nested-clients@3.997.28':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/signature-v4-multi-region': 3.996.38
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/fetch-http-handler': 5.6.3
+ '@smithy/node-http-handler': 4.9.3
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/signature-v4-multi-region@3.996.38':
+ dependencies:
+ '@aws-sdk/types': 3.973.15
+ '@smithy/signature-v4': 5.6.2
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/token-providers@3.1080.0':
+ dependencies:
+ '@aws-sdk/core': 3.974.28
+ '@aws-sdk/nested-clients': 3.997.28
+ '@aws-sdk/types': 3.973.15
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/types@3.973.15':
+ dependencies:
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws-sdk/xml-builder@3.972.33':
+ dependencies:
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@aws/lambda-invoke-store@0.3.0': {}
+
'@babel/code-frame@7.29.0':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
@@ -5060,6 +5375,39 @@ snapshots:
'@sindresorhus/transliterate@2.3.1': {}
+ '@smithy/core@3.29.1':
+ dependencies:
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@smithy/credential-provider-imds@4.4.6':
+ dependencies:
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@smithy/fetch-http-handler@5.6.3':
+ dependencies:
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@smithy/node-http-handler@4.9.3':
+ dependencies:
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@smithy/signature-v4@5.6.2':
+ dependencies:
+ '@smithy/core': 3.29.1
+ '@smithy/types': 4.15.1
+ tslib: 2.8.1
+
+ '@smithy/types@4.15.1':
+ dependencies:
+ tslib: 2.8.1
+
'@swc/helpers@0.5.15':
dependencies:
tslib: 2.8.1
@@ -5485,8 +5833,12 @@ snapshots:
balanced-match@4.0.4: {}
+ base64-js@1.5.1: {}
+
baseline-browser-mapping@2.10.23: {}
+ bowser@2.14.1: {}
+
boxen@7.0.0:
dependencies:
ansi-align: 3.0.1
@@ -5519,6 +5871,11 @@ snapshots:
node-releases: 2.0.38
update-browserslist-db: 1.2.3(browserslist@4.28.2)
+ buffer@5.6.0:
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+
bytes@3.0.0: {}
bytes@3.1.2: {}
@@ -6133,6 +6490,8 @@ snapshots:
eventemitter3@4.0.7: {}
+ events@3.3.0: {}
+
execa@5.1.1:
dependencies:
cross-spawn: 7.0.6
@@ -6337,6 +6696,8 @@ snapshots:
human-signals@8.0.1: {}
+ ieee754@1.2.1: {}
+
ignore@5.3.2: {}
ignore@7.0.5: {}
@@ -6348,6 +6709,8 @@ snapshots:
imurmurhash@0.1.4: {}
+ inherits@2.0.4: {}
+
ini@1.3.8: {}
internal-slot@1.1.0:
@@ -7036,6 +7399,12 @@ snapshots:
react@19.2.4: {}
+ readable-stream@3.6.2:
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+
recharts-scale@0.4.5:
dependencies:
decimal.js-light: 2.5.1
@@ -7262,6 +7631,11 @@ snapshots:
es-errors: 1.3.0
internal-slot: 1.1.0
+ stream-browserify@3.0.0:
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
@@ -7324,6 +7698,10 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
+ string_decoder@1.3.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
@@ -7513,6 +7891,8 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.14
+ util-deprecate@1.0.2: {}
+
vary@1.1.2: {}
victory-vendor@36.9.2:
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
@@ -14,6 +14,22 @@ allowBuilds:
ignoredBuiltDependencies:
- sharp
- unrs-resolver
+minimumReleaseAgeExclude:
+ - '@aws-sdk/checksums@3.1000.13'
+ - '@aws-sdk/client-s3@3.1080.0'
+ - '@aws-sdk/core@3.974.28'
+ - '@aws-sdk/credential-provider-env@3.972.54'
+ - '@aws-sdk/credential-provider-http@3.972.56'
+ - '@aws-sdk/credential-provider-ini@3.972.61'
+ - '@aws-sdk/credential-provider-login@3.972.60'
+ - '@aws-sdk/credential-provider-node@3.972.63'
+ - '@aws-sdk/credential-provider-process@3.972.54'
+ - '@aws-sdk/credential-provider-sso@3.972.60'
+ - '@aws-sdk/credential-provider-web-identity@3.972.60'
+ - '@aws-sdk/lib-storage@3.1080.0'
+ - '@aws-sdk/middleware-sdk-s3@3.972.59'
+ - '@aws-sdk/nested-clients@3.997.28'
+ - '@aws-sdk/token-providers@3.1080.0'
onlyBuiltDependencies:
- cypress
- esbuild