diff --git a/README.md b/README.md index c45b222..5a5c766 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ Recurring research, cron jobs, and webhook delivery. | [**Daily Insights**](typescript-recipes/parallel-daily-insights) | Cron-triggered daily research feed — runs Tasks on a schedule, persists to KV, publishes a public data feed. Includes a `SPEC.md` showing the task spec used. | `Task` `Webhooks` `Cron` | Cloudflare Workers · KV | – | | [**Vendor Intelligence**](typescript-recipes/parallel-vendor-intelligence) | Researches vendor risk, watches the structured report for changes, and runs follow-up research only when a change crosses the review threshold. | `Task` `Deep Research` `Monitors` | TypeScript · Local scripts | – | | [**Investor Signals + Sales Enrichment**](python-recipes/parallel-investor-signals) | Track VC funds *you* choose for new AI-native rounds — one daily Monitor per fund, each detection chain-verified by a follow-up Task, scored, CRM-checked, and posted to Slack — plus a cited company-enrichment app. Bring your own watchlist and CRM; includes an `AGENTS.md` one-command setup. | `Task` `Monitors` `Webhooks` `Cron` | Python · FastAPI · React · Vercel | – | +| [**Datacenter Monitor**](typescript-recipes/parallel-datacenter-map) | Live map of ~2,700 US datacenters, each discovered, enriched across 25 fields, and AI-impact classified by the Task API, with 31 event-stream monitors plus 200 daily snapshot monitors watching the web. Per-field reasoning and citations via `output.basis`. Facility discovery uses shard-by-state plus `previous_interaction_id` pagination. | `Task` `Task Group` `Monitors` `Webhooks` `SSE` | Next.js · Vercel · Leaflet | [Live](https://datacenter-demo.app) | ### Deep Research & Notebooks diff --git a/typescript-recipes/parallel-datacenter-map/.env.local.example b/typescript-recipes/parallel-datacenter-map/.env.local.example new file mode 100644 index 0000000..b382be4 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/.env.local.example @@ -0,0 +1,14 @@ +# Parallel API key — required for monitors, facility discovery, and enrichment +# Get one at https://platform.parallel.ai +PARALLEL_API_KEY=your_parallel_api_key_here + +# Vercel Blob — stores per-facility enrichment basis (reasoning + citations) +# Set after creating a Blob store in Vercel Dashboard → Storage → Blob +ENRICHMENTS_BLOB_URL=https://your-store.private.blob.vercel-storage.com/enrichments.json +BLOB_READ_WRITE_TOKEN=vercel_blob_rw_xxx + +# Anthropic API key — used by the weekly-brief writer (Claude) +ANTHROPIC_API_KEY=your_anthropic_api_key_here + +# Optional: webhook URL for snapshot monitors (set to your deployed URL) +# WEBHOOK_URL=https://your-app.vercel.app/api/webhook diff --git a/typescript-recipes/parallel-datacenter-map/.gitignore b/typescript-recipes/parallel-datacenter-map/.gitignore new file mode 100644 index 0000000..d1caedb --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/.gitignore @@ -0,0 +1,62 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* +!.env.local.example + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# Large data files / run manifests (regenerated via scripts) +public/data/enrichments.json +src/data/backfill-results.json +src/data/enrichment-runs.json +src/data/enrichment-v2-runs.json +src/data/ai-classification-runs.json +.env*.local + +# Editor / OS +*.code-workspace + +# Generated pipeline artifacts +scripts/*.html +scripts/newsletter-*.md +scripts/newsletter-meta.json +/datacenters.json +/scripts/datacenters.json +/datacenters.runs.jsonl +/scripts/datacenters.runs.jsonl diff --git a/typescript-recipes/parallel-datacenter-map/LICENSE b/typescript-recipes/parallel-datacenter-map/LICENSE new file mode 100644 index 0000000..9ba296c --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Parallel Web Systems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/typescript-recipes/parallel-datacenter-map/README.md b/typescript-recipes/parallel-datacenter-map/README.md new file mode 100644 index 0000000..17e62d0 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/README.md @@ -0,0 +1,159 @@ +# Datacenter Monitor + +A live map of U.S. datacenter infrastructure, built end-to-end on [Parallel](https://parallel.ai)'s **Task API** and **Monitor API**. Every facility on the map was *discovered*, *enriched*, and *classified* by Parallel — and 31 monitors watch the web for new developments, with each claim traceable to its sources. + +**Live demo:** https://datacenter-demo.app + +Everything here — the facility list, the 25 fields per facility, the AI-impact classifications, the weekly brief — is generated data. Nothing is hand-curated. This README documents exactly how it was produced so you can reproduce or extend it. + +> **Note on data:** this repo ships a **51-facility sample** (one per state) in `public/data/` so the app runs immediately after cloning. The [live demo](https://datacenter-demo.app) shows the full ~2,700-facility dataset. Run the pipeline below to regenerate the full set into `public/data/`. Monitor IDs in `src/data/` ship blank on purpose — run `setup-monitors.ts` and `create-snapshots.ts` to create your own against your account. + +--- + +## How the data was built + +The whole dataset is a pipeline of Parallel Task API runs. Each stage is a script in [`scripts/`](./scripts). + +### 1. Discover the facilities — `build_datacenters_iterative.py` + +There is no clean public registry of U.S. datacenters, so we enumerate them with the Task API. The market is a long tail of ~1,800 colocation, enterprise, telecom, and edge operators, and enumerating them exhaustively is a decomposition problem: a broad, unscoped query surfaces the most prominent facilities first, so reaching the full tail takes two techniques: + +1. **Shard by geography.** Scope every query to *one state*. Enumerating a single state (reading facility directories) is the natural move, instead of dumping a global top-of-mind list. Ashburn alone goes 13 → ~90 this way. +2. **Paginate via interactions (loop-until-dry).** After the first pass for a state, keep asking for *net-new* facilities while passing `previous_interaction_id`. The model carries its own memory of what it already returned in that thread, so we never paste a list of known facilities into the prompt. Loop until a page stops adding results. + +Everything is resumable: results checkpoint after each shard, and every `run_id` / `interaction_id` is logged so work that completed server-side is always recoverable. + +```bash +export PARALLEL_API_KEY=... +python scripts/build_datacenters_iterative.py # all 50 states + DC, until dry +python scripts/build_datacenters_iterative.py --states "Texas,Ohio" --workers 8 +``` + +This produced **2,811 unique facilities** (deduped to 2,694 shown on the map) across all 50 states + DC — each with a name, operator, owner, coordinates, and a source URL. + +### 2. Enrich each facility — `run-enrichment*.ts` + +Every facility is then deep-researched with the `ultra2x` processor against a **25-field JSON schema** (verified name/operator/owner, power capacity, sqft, cooling type, tier, fiber, utility provider, tax incentives, hazard zone, construction updates, recent news, tenants, and more). Runs are submitted in parallel via **Task Groups**, and Parallel's `output.basis` gives per-field **reasoning + citations** for every value — that's what powers the basis panel behind each cell. + +```bash +npx tsx scripts/run-enrichment-v2.ts # submit enrichment task group +npx tsx scripts/collect-enrichments-v2.ts # collect results +npx tsx scripts/upload-per-facility.ts # store per-facility basis in Vercel Blob +``` + +### 3. Classify AI impact — `classify-ai.ts` + +A second Task API pass classifies each facility's AI profile and community/resource impact against a structured schema: `ai_class` (ai-training / ai-inference / ai-mixed / cloud-hyperscale / not-ai), plus water impact, grid impact, and community-pushback levels — each with its own evidence and citations. ~710 facilities classified; ~520 flagged as AI/cloud infrastructure. + +### 4. Monitor the web — `setup-monitors.ts` + `create-snapshots.ts` + +- **31 event-stream monitors** watch for datacenter developments — power-grid changes, zoning decisions, ownership transfers, community opposition, new-site discovery — returning classified, cited events. +- **200 daily snapshot monitors** re-verify facility fields once a day and surface field-level changes as diffs (with the re-verification's own reasoning + sources). + +--- + +## What the app does + +- **Interactive map** of every facility, colored by lifecycle (operational / under construction / planned / decommissioned), with scope toggles (all vs. AI datacenters) and monitor-driven highlighting. +- **Popups** with the enriched profile, AI-impact classification, and clickable primary sources loaded on demand. +- **Dataset table** with all 25 fields per facility. Click any cell to open its **basis panel** — the reasoning and citations Parallel used to produce that value. +- **Live monitor feed** with a chart-as-filter (break down by time / category / severity) and cited events. +- **Weekly brief** — a newsletter deep-researched and written by the Task API across all monitors, every claim linked to a source. + +## Parallel APIs used + +**Task API** +- Iterative facility discovery via interaction chaining (`previous_interaction_id`) +- 25-field facility enrichment (`ultra2x`, Task Groups, structured output) +- AI-impact classification (structured output) +- Weekly brief research + writing +- `output.basis` → per-field reasoning + citations everywhere + +**Monitor API** +- 31 event-stream monitors (classified events with severity + citations) +- 200 daily snapshot monitors (field-level change detection with diffs) +- Webhooks + SSE for real-time updates + +## Tech stack + +- **Next.js 16** (App Router, TypeScript) +- **react-leaflet** + Leaflet (map) +- **Tailwind CSS** (Parallel design system) +- **Vercel** (hosting, Blob storage, serverless, cron) + +--- + +## Setup + +**Prerequisites:** Node.js 18+, Python 3.9+, a [Parallel API key](https://platform.parallel.ai), and a Vercel account (Blob storage + deploy). + +```bash +git clone https://github.com/parallel-web/parallel-cookbook.git +cd parallel-cookbook/typescript-recipes/parallel-datacenter-map +npm install +cp .env.local.example .env.local # add your keys +``` + +Then run the pipeline to regenerate the full dataset (the repo ships only a 51-facility sample in `public/data/`; each stage is optional): + +```bash +# 1. discover facilities +pip install parallel-web +python scripts/build_datacenters_iterative.py + +# 2. enrich + classify +npx tsx scripts/run-enrichment-v2.ts +npx tsx scripts/collect-enrichments-v2.ts +npx tsx scripts/upload-per-facility.ts +npx tsx scripts/classify-ai.ts + +# 3. set up monitors +npx tsx scripts/setup-monitors.ts +WEBHOOK_URL=https://your-app.vercel.app/api/webhook npx tsx scripts/create-snapshots.ts + +# 4. run +npm run dev # local +vercel --prod # deploy +``` + +## Architecture + +``` +Map view Monitor panel (right rail) +- Leaflet map, 2,694 facilities - Chart-as-filter (time / category / severity) +- lifecycle + AI scope toggles - Cited event feed +- popups: profile, AI impact, - Weekly brief reader + on-demand sources + +Dataset view +- 25 enriched fields per facility +- per-cell basis panel (reasoning + citations, from Vercel Blob) +- monitor signals + snapshot diffs + +API routes + /api/monitors live events from the 31 event-stream monitors + /api/snapshots daily snapshot change detection (with basis) + /api/basis per-facility reasoning + citations (Vercel Blob) + /api/webhook receives monitor events (SSE to the client) + /api/newsletter/* weekly brief generate / preview / issue list + /api/cron/newsletter weekly brief cron +``` + +## Scripts + +| Stage | Script | Purpose | +|-------|--------|---------| +| Discover | `build_datacenters_iterative.py` | Enumerate U.S. facilities (shard-by-state + interaction pagination) | +| Enrich | `run-enrichment.ts` / `run-enrichment-v2.ts` | Submit facility enrichment task groups (`ultra2x`) | +| Enrich | `collect-enrichments*.ts` | Collect enrichment results | +| Enrich | `upload-per-facility.ts` / `upload-enrichments.ts` | Store per-facility basis in Vercel Blob | +| Enrich | `backfill-basis.ts` | Re-fetch a run's basis from its `run_id` onto a stored facility | +| Classify | `classify-ai.ts` | AI-impact classification pass | +| Monitor | `setup-monitors.ts` / `monitor-configs.ts` | Create the 31 event-stream monitors | +| Monitor | `create-snapshots.ts` / `snapshots-to-daily.ts` | Create/tune daily snapshot monitors | +| Monitor | `set-webhooks.ts` / `check-events.ts` | Register webhooks / inspect events | +| Brief | `generate-issue.ts` / `seed-issue.ts` / `regenerate-brief.ts` | Generate the weekly brief | + +## License + +MIT — see [LICENSE](./LICENSE). diff --git a/typescript-recipes/parallel-datacenter-map/eslint.config.mjs b/typescript-recipes/parallel-datacenter-map/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/typescript-recipes/parallel-datacenter-map/next.config.ts b/typescript-recipes/parallel-datacenter-map/next.config.ts new file mode 100644 index 0000000..e9ffa30 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/typescript-recipes/parallel-datacenter-map/package-lock.json b/typescript-recipes/parallel-datacenter-map/package-lock.json new file mode 100644 index 0000000..faf2974 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/package-lock.json @@ -0,0 +1,7774 @@ +{ + "name": "datacenter-map-demo", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "datacenter-map-demo", + "version": "0.1.0", + "dependencies": { + "@anthropic-ai/sdk": "^0.109.0", + "@types/leaflet": "^1.9.21", + "@types/papaparse": "^5.5.2", + "@vercel/blob": "^2.5.0", + "clsx": "^2.1.1", + "leaflet": "^1.9.4", + "lucide-react": "^1.22.0", + "next": "16.2.9", + "papaparse": "^5.5.4", + "react": "19.2.4", + "react-dom": "19.2.4", + "react-leaflet": "^5.0.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.9", + "tailwindcss": "^4", + "tsx": "^4.22.4", + "typescript": "^5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.109.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.109.0.tgz", + "integrity": "sha512-y7P4eLyW5uNut4fXpOUEHqhJwx7dnxrWAfCQE4Lcgm0hSFQuIeHa7CWEKE5dFolEjQJE/RFKkppjri05r2OK/Q==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1", + "standardwebhooks": "^1.0.0" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@next/env": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.9.tgz", + "integrity": "sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.9.tgz", + "integrity": "sha512-UZi8+YT/MLgTC9nrrn2Xd4lBYv1B7lVmtWHfPcthAI5Tt/C1LuDe6DfmtCtJ+WQod3ksY4VrKSvk3oMVAnL7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.9.tgz", + "integrity": "sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.9.tgz", + "integrity": "sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.9.tgz", + "integrity": "sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.9.tgz", + "integrity": "sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.9.tgz", + "integrity": "sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.9.tgz", + "integrity": "sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.9.tgz", + "integrity": "sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.9.tgz", + "integrity": "sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@react-leaflet/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", + "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.1" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", + "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-x64": "4.3.1", + "@tailwindcss/oxide-freebsd-x64": "4.3.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-x64-musl": "4.3.1", + "@tailwindcss/oxide-wasm32-wasi": "4.3.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", + "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", + "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", + "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", + "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", + "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", + "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", + "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", + "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", + "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", + "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", + "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", + "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.1.tgz", + "integrity": "sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.1", + "@tailwindcss/oxide": "4.3.1", + "postcss": "8.5.15", + "tailwindcss": "4.3.1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/leaflet": { + "version": "1.9.21", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.21.tgz", + "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/papaparse": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.5.2.tgz", + "integrity": "sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz", + "integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/type-utils": "8.62.0", + "@typescript-eslint/utils": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.62.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", + "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", + "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.62.0", + "@typescript-eslint/types": "^8.62.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", + "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", + "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz", + "integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/utils": "8.62.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", + "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", + "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.62.0", + "@typescript-eslint/tsconfig-utils": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz", + "integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", + "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vercel/blob": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@vercel/blob/-/blob-2.5.0.tgz", + "integrity": "sha512-ke6WnMMYlUu9nBFmyjwEkC2o03Ku2X7QIeJ3KtlOJzblS/8Xau209zt0ic76rd7IvV5nrKCH/BzP4MkFmoSLuw==", + "license": "Apache-2.0", + "dependencies": { + "@vercel/oidc": "^3.6.1", + "async-retry": "^1.3.3", + "is-buffer": "^2.0.5", + "is-node-process": "^1.2.0", + "throttleit": "^2.1.0", + "undici": "^6.23.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@vercel/cli-config": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@vercel/cli-config/-/cli-config-0.2.0.tgz", + "integrity": "sha512-fJRRRB7734BDuXZ89yBEaA2ncYhH7bWX30mk04W80J6VAfQc+4iB8lyzAdaGpFV3/vNlkt9VZt+/uoQoWX6UsQ==", + "license": "Apache-2.0", + "dependencies": { + "xdg-app-paths": "5", + "zod": "4.1.11" + } + }, + "node_modules/@vercel/cli-config/node_modules/zod": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.11.tgz", + "integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@vercel/cli-exec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@vercel/cli-exec/-/cli-exec-1.0.0.tgz", + "integrity": "sha512-kQF8LGie/Hbdq9/psJxLE7owRTcqMQMhgybU04gCeR7cbQAr5t8OrjefDNColJv1QSSucFt4pLwRiARVmlOnug==", + "license": "Apache-2.0", + "dependencies": { + "execa": "5.1.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@vercel/oidc": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.7.1.tgz", + "integrity": "sha512-RrSsVWbq3KLK5lJobyTPp3tSthNfUp+zWkXno5Wkko0oEW05rA4ngOrnVypP4+L8/Av89uPo2rWFmzL8iwnsmA==", + "license": "Apache-2.0", + "dependencies": { + "@vercel/cli-config": "0.2.0", + "@vercel/cli-exec": "1.0.0", + "jose": "^5.9.6" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "license": "MIT", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz", + "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.40", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", + "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.380", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.380.tgz", + "integrity": "sha512-W6d5AbuEoRayO447cqrg6lKJIlscgRnnxOZl/08kfV71BQDoEBC7Wwis68z87LjyK6f4kWyTaubuDbhHKrZkbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.3.tgz", + "integrity": "sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.9.tgz", + "integrity": "sha512-olGtBrs07bQchpaJWeqbk9GaMoU0oGmN/pYNEBXSbfgKngb5uHnPe37X6tVeh6DJfaWFQildvinGEOrolo5fmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "16.2.9", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "16.4.0", + "typescript-eslint": "^8.46.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-next/node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.13.0.tgz", + "integrity": "sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.22.0.tgz", + "integrity": "sha512-c9o3l0PiNcgOQDW4F31BEYHudE7kgxVt3o30qMl36ZPwTxXlGB4QnLilhERvVM4uh/pl5MDyY1/gzZSYcHDtBg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "16.2.9", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.9.tgz", + "integrity": "sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.9", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.9", + "@next/swc-darwin-x64": "16.2.9", + "@next/swc-linux-arm64-gnu": "16.2.9", + "@next/swc-linux-arm64-musl": "16.2.9", + "@next/swc-linux-x64-gnu": "16.2.9", + "@next/swc-linux-x64-musl": "16.2.9", + "@next/swc-win32-arm64-msvc": "16.2.9", + "@next/swc-win32-x64-msvc": "16.2.9", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", + "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-paths": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/os-paths/-/os-paths-4.4.0.tgz", + "integrity": "sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==", + "license": "MIT", + "engines": { + "node": ">= 6.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/papaparse": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.4.tgz", + "integrity": "sha512-SwzWD9gl/ElwYLCI0nUja1mFJzjq2D8ziShfNBa7zCHzkOozeOGDwHWQ+tvCzEZcewecWZ5U7kUopDnG+DFYEQ==", + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-leaflet": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", + "license": "Hippocratic-2.1", + "dependencies": { + "@react-leaflet/core": "^3.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", + "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.0.tgz", + "integrity": "sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.62.0", + "@typescript-eslint/parser": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/utils": "8.62.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xdg-app-paths": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/xdg-app-paths/-/xdg-app-paths-5.5.1.tgz", + "integrity": "sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ==", + "license": "MIT", + "dependencies": { + "os-paths": "^4.0.1", + "xdg-portable": "^7.2.0" + }, + "engines": { + "node": ">= 6.0" + } + }, + "node_modules/xdg-portable": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/xdg-portable/-/xdg-portable-7.3.0.tgz", + "integrity": "sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==", + "license": "MIT", + "dependencies": { + "os-paths": "^4.0.1" + }, + "engines": { + "node": ">= 6.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/typescript-recipes/parallel-datacenter-map/package.json b/typescript-recipes/parallel-datacenter-map/package.json new file mode 100644 index 0000000..b2f9a7c --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/package.json @@ -0,0 +1,36 @@ +{ + "name": "datacenter-map-demo", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "@anthropic-ai/sdk": "^0.109.0", + "@types/leaflet": "^1.9.21", + "@types/papaparse": "^5.5.2", + "@vercel/blob": "^2.5.0", + "clsx": "^2.1.1", + "leaflet": "^1.9.4", + "lucide-react": "^1.22.0", + "next": "16.2.9", + "papaparse": "^5.5.4", + "react": "19.2.4", + "react-dom": "19.2.4", + "react-leaflet": "^5.0.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.2.9", + "tailwindcss": "^4", + "tsx": "^4.22.4", + "typescript": "^5" + } +} diff --git a/typescript-recipes/parallel-datacenter-map/postcss.config.mjs b/typescript-recipes/parallel-datacenter-map/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/typescript-recipes/parallel-datacenter-map/public/data/ai-classifications.json b/typescript-recipes/parallel-datacenter-map/public/data/ai-classifications.json new file mode 100644 index 0000000..36c1c11 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/data/ai-classifications.json @@ -0,0 +1 @@ +{"1": {"community_note": "Residents in Columbiana and nearby communities raised organized opposition over water/power use, noise, and potential bill impacts at and after a Jan. 15, 2026 town hall, and the council later rejected a major property-tax abatement; no local lawsuit or moratorium was reported.", "water_impact": "moderate", "ai_evidence": "Cerebras Systems signed a 10-year, about $1.1B agreement for 40 MW at the Columbiana site, and the facility is described as supporting HPC and AI workloads.", "grid_impact": "moderate", "ai_class": "ai-mixed", "community_pushback": "active-opposition", "water_note": "Officials said the city cannot support water usage for all project phases; no gallons/day figures or aquifer/drought issues were cited.", "grid_note": "Planned 55 MW campus with a 40 MW anchor in two phases (15 MW then 25 MW), using the legacy Grede Foundry substation under an Alabama Power agreement; no quantified ratepayer impact found.", "citations": [{"title": "Columbiana Council Unanimously Rejects Major Tax ...", "url": "https://abc3340.com/news/local/columbiana-council-unanimously-rejects-major-tax-break-for-proposed-data-center"}, {"title": "Details on Columbiana data center revealed, town hall set ...", "url": "https://www.cityofcolumbiana.com/home/news/details-columbiana-data-center-revealed-town-hall-set-jan-15"}, {"title": "Columbiana updated its zoning rules to require data ...", "url": "https://www.facebook.com/aldotcom/posts/columbiana-updated-its-zoning-rules-to-require-data-centers-to-meet-new-building/1299450025563225/"}, {"title": "Details on Columbiana data center revealed, town hall set ...", "url": "https://www.cityofcolumbiana.com/home/news/details-columbiana-data-center-revealed-town-hall-set-jan-15"}, {"title": "Cerebras signs on for 40MW of capacity at Digi Power X ...", "url": "https://www.datacenterdynamics.com/en/news/cerebras-signs-on-for-40mw-of-capacity-at-digi-power-x-data-center-in-alabama/"}], "runId": "srun_c0e944bd89584b549e291e9d669a79c9", "classifiedAt": "2026-07-02T22:55:53.906Z"}, "3": {"community_note": "City-level action: Phoenix adopted 2025 zoning/special-permit rules for data centers addressing reliability, high-voltage infrastructure, fire/emergency access, noise, and water after mayoral concerns over generator noise; no site-specific litigation reported for the Union Hills campus.", "water_impact": "moderate", "ai_evidence": "The Phoenix campus is marketed as \u201cAI & Cloud\u2011Ready\u201d with support for high\u2011density GPU requirements, and Aligned is listed among NVIDIA\u2019s DGX\u2011Ready colocation partners; no public disclosures identify a deployed GPU supercluster or named AI tenant at PHX\u201101/02/03.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "some-concern", "water_note": "No gallons/day figure located; Phoenix\u2019s large\u2011water\u2011user rules trigger planning at 250,000 gpd and require at least a 30% recycled/conserved\u2011water offset for users above 500,000 gpd, and Phoenix\u2011area data center cooling water is projected to rise from 385M to over 3.7B gallons/year.", "grid_note": "Approx. 180 MW campus; APS has proposed >45% rate increases for extra\u2011large users and plans a 2 GW gas plant under a subscription model amid ~18 GW of data\u2011center requests.", "citations": [{"title": "City of Phoenix Updates Zoning to Safeguard Health and ...", "url": "https://www.phoenix.gov/newsroom/pdd-news/city-of-phoenix-updates-zoning-to-safeguard-health-and-safety-as.html"}, {"title": "Phoenix, Arizona, to clamp down on data centers - DCD", "url": "https://www.datacenterdynamics.com/en/news/phoenix-arizona-to-clamp-down-on-data-centers/"}, {"title": "Phoenix cooling lab showcases hybrid data center ...", "url": "https://www.facilitiesdive.com/news/phoenix-cooling-lab-showcases-hybrid-data-center-cooling-capabilities/757542/"}, {"title": "Phoenix unanimously passes 'large water user' ordinance", "url": "https://www.12news.com/article/news/local/valley/city-of-phoenix-passes-large-water-user-ordinance/75-a87a51e1-2e31-433f-93fc-c63439266c4d"}, {"title": "AI data center water use collides with drought in the West", "url": "https://qz.com/data-center-water-use-drought-american-west-051326"}], "runId": "srun_c0e944bd89584b54b72cc16993d1aa5d", "classifiedAt": "2026-07-02T22:55:49.366Z"}, "4": {"community_note": "No SV12x-specific lawsuit or organized opposition was found; residents and advocates in San Jos\u00e9 have raised health/environmental and fast\u2011track concerns about data centers citywide, while SV12x is already live [1][2].", "water_impact": "unknown", "ai_evidence": "SV12x is Equinix\u2019s first U.S. xScale hyperscale facility via a JV with PGIM, expected to provide more than 28 MW and launched in January 2026 [1][2]; Equinix markets \u201cAI\u2011ready hyperscale capacity,\u201d but no public reporting in the set names an AI tenant or GPU supercluster at SV12x [3].", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "some-concern", "water_note": "No SV12x-specific gallons/day, WUE, water source, aquifer/drought, or discharge figure was found in the provided materials; city environmental review exists but the quoted excerpts do not quantify water use [1][2].", "grid_note": "PG&E officially powered SV12x as the first of a dozen large\u2011load customers; the JV expects >28 MW at SV12x; and San Jos\u00e9/PG&E plan for nearly 2 GW of new demand with PG&E estimating 1\u20132% bill reductions per 1 GW [1][2][3].", "citations": [{"title": "New San Jose data center goes live under PG&E partnership", "url": "https://www.nbcbayarea.com/news/local/san-jose-data-center-pge-partnership/4018067/"}, {"title": "Advocates worry San Jose will fast track data centers", "url": "https://x.com/SJSpotlight/status/2065823649689641384"}, {"title": "Advocates worry San Jose will fast track data centers", "url": "https://sanjosespotlight.com/advocates-worry-san-jose-will-fast-track-data-centers/"}, {"title": "Equinix Data Centers (SV-12, SV-13, & SV-14)", "url": "https://www.sanjoseca.gov/your-government/departments-offices/planning-building-code-enforcement/planning-division/environmental-planning/environmental-review/negative-declaration-initial-studies/equinix-data-centers-sv-12-sv-13-sv-14"}, {"title": "SV12x", "url": "https://www.equinix.com/data-centers/americas-colocation/united-states-colocation/silicon-valley-data-centers/sv12x"}], "runId": "srun_c0e944bd89584b5449a112a3ac6933fb", "classifiedAt": "2026-07-02T22:55:50.064Z"}, "5": {"community_note": "No organized opposition or litigation has been reported for Novva\u2019s Colorado Springs data center; Rolls\u2011Royce announced emergency backup power for an expansion, but no zoning, noise, or air\u2011quality complaints were found.", "water_impact": "low", "ai_evidence": "Public materials describe the site as multi-tenant colocation with an unnamed anchor tenant and 40 MW power availability, with no verified announcements of GPU superclusters or AI tenants.", "grid_impact": "moderate", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "Reported at about 6,000 gallons/day in 2024 (including sewer discharge) with a retrofit to water\u2011free cooling underway; no aquifer or discharge disputes surfaced.", "grid_note": "Initial 6 MW with plans to expand to 30\u201340 MW; CSU\u2019s 2024 peak was 1,011 MW and its large\u2011load policy says data centers cover the full cost of service.", "citations": [{"title": "Rolls-Royce secures emergency backup power for ...", "url": "https://www.rolls-royce.com/media/press-releases/2024/06-06-2024-rr-secures-emergency-backup-power-for-co-location-data-centre-in-colorado.aspx"}, {"title": "Novva Data Centers: A different kind of data center", "url": "https://gazette.com/2023/05/31/novva-data-centers-a-different-kind-of-data-center-21986e9c-fb46-11ed-96f1-7b56e6b72f5f/"}, {"title": "Sustainable Water-Free Data Center Cooling", "url": "https://www.novva.com/data-center-services/water-free-cooling/"}, {"title": "Novva Data Centers: A different kind of data center", "url": "https://gazette.com/2023/05/31/novva-data-centers-a-different-kind-of-data-center-21986e9c-fb46-11ed-96f1-7b56e6b72f5f/"}, {"title": "Novva Colorado Springs - 650 Sybilla Lane", "url": "https://www.datacentermap.com/usa/colorado/colorado-springs/novva-colorado-springs/"}], "runId": "srun_c0e944bd89584b54d0c3b0b40dfcbbfe", "classifiedAt": "2026-07-02T22:55:54.269Z"}, "6": {"community_note": "", "water_impact": "low", "ai_evidence": "Public materials characterize NYM5 as a carrier\u2011neutral colocation site with up to 16 MW and work\u2011area recovery space, and there are no facility\u2011specific AI/GPU or liquid\u2011cooling deployment announcements [1][2].", "grid_impact": "moderate", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "Operator materials state NYM5 uses water\u2011free cooling, and no reports indicate cooling\u2011water consumption or discharge concerns [1].", "grid_note": "Up to 16 MW IT capacity is cited for NYM5, while a market listing shows ~2 MW delivered and ~4 MW additional, with no public evidence of utility upgrades or rate impacts [2][3].", "citations": [{"title": "Norwalk, CT: NYM5 | CyrusOne", "url": "https://www.cyrusone.com/data-centers/north-america/norwalk-ct"}, {"title": "Norwalk, CT: NYM5 | CyrusOne", "url": "https://www.cyrusone.com/data-centers/north-america/norwalk-ct"}, {"title": "Norwalk, CT: NYM5 | CyrusOne", "url": "https://www.cyrusone.com/data-centers/north-america/norwalk-ct"}, {"title": "Norwalk NYM5 - CyrusOne", "url": "https://www.ocolo.io/colocation/cyrusone/norwalk-nym5/"}, {"title": "AI Data Centers", "url": "https://www.cyrusone.com/solutions/ai-data-centers"}], "runId": "srun_c0e944bd89584b54b13672934664fb2b", "classifiedAt": "2026-07-02T22:55:53.609Z"}, "8": {"community_note": "Residents and Sierra Club Delaware oppose Project Washington over electric-rate impacts and pollution/noise from 516 diesel generators, and DNREC\u2019s Coastal Zone Act prohibition was upheld by the state board on March 26, 2026.", "water_impact": "low", "ai_evidence": "Reports describe a 1.2 GW, 11\u2011building hyperscale campus and note data centers powering 'ever\u2011growing AI technology,' but there are no public announcements of GPU clusters, named AI tenants, or liquid\u2011cooling deployments; the FAQ specifies closed\u2011loop air cooling.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "active-opposition", "water_note": "Closed\u2011loop air cooling with a one\u2011time ~600,000\u2011gallon fill; ongoing usage characterized as minimal by the project.", "grid_note": "Planned 1,200 MW load\u2014estimated at ~8.7 million MWh/year\u2014has spurred Delaware lawmakers to advance bills requiring large data centers to shoulder electricity costs to protect ratepayers.", "citations": [{"title": "Delaware City data center hits roadblocks", "url": "https://whyy.org/articles/delaware-city-data-center-setback-environment/"}, {"title": "Data Centers & DE", "url": "https://www.sierraclub.org/delaware/data-centers"}, {"title": "DNREC's decision to prohibit data center upheld by state ...", "url": "https://www.delawareonline.com/story/news/local/2026/03/26/delaware-largest-data-center-proposal-takes-another-blow/89287953007/"}, {"title": "Project Washington Frequently Asked Questions", "url": "https://projwashington.com/frequently-asked-questions/"}, {"title": "How much water do data centers use?", "url": "https://whyy.org/articles/data-centers-water-usage/"}], "runId": "srun_c0e944bd89584b54e3d1044a1dc443f4", "classifiedAt": "2026-07-02T22:55:53.906Z"}, "9": {"community_note": "Local residents and civil-rights advocates have raised concerns over transparency, environmental health, and community benefits; no lawsuit was identified in reporting as of 2026-07-02.", "water_impact": "unknown", "ai_evidence": "Marketed as an 'AI-ready' facility with 16MW capacity and 'GPU-ready high density' for AI deployments; no named AI tenant or deployed GPU supercluster is confirmed in public materials.", "grid_impact": "moderate", "ai_class": "ai-mixed", "community_pushback": "active-opposition", "water_note": "No facility-specific gallons/day or water-source details were found in public materials for MIA-1.", "grid_note": "Planned at 16 MW; Florida SB 484 affirms local authority over land-use planning and establishes protections relevant to large data centers, with MIA-1 below the 50 MW trigger discussed in public reporting.", "citations": [{"title": "New Miami-Dade data center sparks concerns in Black ...", "url": "https://www.wlrn.org/government-politics/2026-04-29/new-miami-dade-data-center-sparks-concerns-in-black-community"}, {"title": "Myths vs. Reality: Data Centers And Water Usage", "url": "https://www.fwpcoa.org/content.aspx?page_id=5&club_id=859275&item_id=130961"}, {"title": "Iron Mountain MIA-1 \u2014 Miami Dade, Florida", "url": "https://cleanview.co/data-centers/florida/1124/iron-mountain-mia-1"}, {"title": "Miami Data Center | Miami Colocation", "url": "https://www.ironmountain.com/data-centers/locations/miami-data-center"}, {"title": "Iron Mountain Data Centers: MIA-1 - Miami Data Center", "url": "https://www.datacenters.com/iron-mountain-mia-1-miami"}], "runId": "srun_c0e944bd89584b54b98cfe77916c476f", "classifiedAt": "2026-07-02T22:55:51.986Z"}, "10": {"community_note": "No organized local opposition identified for ATL1; the Atlanta Regional Commission\u2019s DRI review documents planning/environmental items but does not record public controversy.", "water_impact": "low", "ai_evidence": "Marketed as a hyperscale-ready, high-density campus with AI positioning, but there is no public disclosure of named AI tenants or GPU superclusters.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "none-found", "water_note": "Air-cooled cooling minimizes onsite water use; Georgia reporting notes broader concerns about data center water demand during droughts.", "grid_note": "Served by GreyStone Power in a region facing substantial data center-driven load growth; regulators and utilities are adopting measures so large users bear direct costs rather than shifting them to other ratepayers.", "citations": [{"title": "2024 DC Blox ATL West Data Center DRI 4112", "url": "http://documents.atlantaregional.com/Land%20Use/Reviews/ID5407/2024%20DC%20Blox%20ATL%20West%20Data%20Center%20DRI%204112%20-%20Final%20Report.pdf"}, {"title": "Data centers use a lot of water. Georgia counties and ...", "url": "https://www.wabe.org/data-centers-use-a-lot-of-water-georgia-counties-and-conservationists-are-looking-for-solutions/"}, {"title": "Atlanta West hyperscale Data Center Campus", "url": "https://www.dcblox.com/data-centers/atlanta-data-centers/douglas-county-ga-hyperscale-data-center-campus/"}, {"title": "DC Blox plans additional 80MW building at ...", "url": "https://www.datacenterdynamics.com/en/news/dc-blox-plans-additional-80mw-building-at-data-center-campus-in-atlanta-georgia/"}, {"title": "Data Center FAQs", "url": "https://www.greystonepower.com/datacenters"}], "runId": "srun_c0e944bd89584b540b1db2ceb0b62c00", "classifiedAt": "2026-07-02T22:55:51.032Z"}, "12": {"community_note": "No organized opposition specific to CyrusOne OCB1 was found; a local Facebook group post discussed hiring a lawyer to stop \u201c2 data centers\u201d in Council Bluffs, but no litigation or action tied to OCB1 was identified [1].", "water_impact": "low", "ai_evidence": "No public evidence of GPU superclusters, AI tenant announcements, or liquid-cooling retrofits at OCB1; the site highlights air-cooled \u201cWater\u2011Free Cooling\u201d and CRAH units, while CyrusOne\u2019s AI page is generic and not site\u2011specific [1][2].", "grid_impact": "moderate", "ai_class": "not-ai", "community_pushback": "some-concern", "water_note": "OCB1 advertises \u201cWater\u2011Free Cooling\u201d with \u201cMinimal water usage for humidification and maintenance,\u201d and notes it \u201cdoesn't consume water for cooling\u201d; no gallons/day or source-stress data reported [1][2].", "grid_note": "OCB1 is an 18 MW IT\u2011load facility served by MidAmerican Energy, reported as \u201cnow powered by 100% renewable electricity,\u201d leveraging GreenAdvantage, while MidAmerican says its agreements \u201cprotect other customers from cost shifts\u201d tied to data centers [1][2][3][4].", "citations": [{"title": "Hiring a lawyer to stop data centers in Council Bluffs, Iowa?", "url": "https://www.facebook.com/groups/saynotodatacenters/posts/1537039864894180/"}, {"title": "Council Bluffs, IA: OCB1", "url": "https://www.cyrusone.com/data-centers/north-america/council-bluffs-ia"}, {"title": "Harnessing the Wind and Sun: Council Bluffs Data Center ...", "url": "https://www.cyrusone.com/resources/blogs/harnessing-the-wind-and-sun-council-bluffs-data-center-now-powered-by-100-renewable-electricity"}, {"title": "Council Bluffs, IA: OCB1", "url": "https://www.cyrusone.com/data-centers/north-america/council-bluffs-ia"}, {"title": "AI Data Centers", "url": "https://www.cyrusone.com/solutions/ai-data-centers"}], "runId": "srun_c0e944bd89584b54721bf71d652af049", "classifiedAt": "2026-07-02T22:55:51.986Z"}, "13": {"community_note": "No organized opposition identified; BoiseDev reports city filings for ~38,000 sf initially at 9601 W Emerald and a preliminary application for ~31,000 sf more, with no site-specific lawsuits or moratoriums reported.", "water_impact": "low", "ai_evidence": "Marketing materials describe \u201cAI-ready\u201d colocation and support for AI/HPC workloads, but there are no disclosed GPU superclusters, named AI tenants, or confirmed training/inference deployments.", "grid_impact": "low", "ai_class": "cloud-hyperscale", "community_pushback": "none-found", "water_note": "No gallons/day or source data reported; materials state hybrid air/liquid cooling with a closed-loop setup to minimize water waste.", "grid_note": "Reported at 10 MW, with Idaho Power\u2019s policy indicating large users fund interconnection and are not a general rate burden for others.", "citations": [{"title": "Boise data center is set to open next year. Before ...", "url": "https://boisedev.com/news/2026/03/26/valorc3-emerald/"}, {"title": "ValorC3 Data Center", "url": "https://boisedev.com/project/valorc3-data-center/"}, {"title": "ValorC3 Boise 2 Data Center (10 MW)", "url": "https://www.datacentermap.com/usa/idaho/boise/valorc3-boise-2-data-center/"}, {"title": "Boise Data Center", "url": "https://valorc3.com/boise-data-center/"}, {"title": "Boise data center is set to open next year. Before ...", "url": "https://boisedev.com/news/2026/03/26/valorc3-emerald/"}], "runId": "srun_c0e944bd89584b541f593f1a5bd86a24", "classifiedAt": "2026-07-02T22:55:55.256Z"}, "14": {"community_note": "No organized opposition, lawsuits, or zoning fights specific to 350 E. Cermak were identified as of July 2026.", "water_impact": "unknown", "ai_evidence": "", "grid_impact": "high", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "Data Center Knowledge reported the facility\u2019s cooling includes an 8.5\u2011million\u2011gallon refrigerated brine\u2011like thermal\u2011storage tank; no gallons/day, source\u2011stress, or discharge figures were publicly reported.", "grid_note": "ORD10 is listed at 19.5 MW, while the broader 350 E. Cermak building has more than 100 MW across multiple feeds and is cited as ComEd\u2019s second\u2011largest power customer.", "citations": [{"title": "Chicago ORD10 - 350 East Cermak", "url": "https://www.digitalrealty.com/data-centers/americas/chicago/ord10"}, {"title": "Digital Realty: ORD10 Data Center", "url": "https://baxtel.com/data-center/digital-realty-ord10"}, {"title": "350 East Cermak Road in Chicago | Digital Realty (19.5 MW)", "url": "https://www.datacentermap.com/usa/illinois/chicago/350-east-cermark-road/"}, {"title": "Chicago Data Center & Colocation", "url": "https://www.digitalrealty.com/data-centers/americas/chicago"}, {"title": "Digital Realty ORD10 | 350 East Cermak Road, Chicago", "url": "https://datacenterhawk.com/marketplace/providers/digital-realty/350-east-cermak-road/ord10"}], "runId": "srun_c0e944bd89584b54e339e9e9831c1cdd", "classifiedAt": "2026-07-02T22:55:51.638Z"}, "15": {"community_note": "Residents and local groups opposed Google/Hatchworks\u2019 request for additional diesel backup generators over noise/air-pollution and environmental impacts, but IDEM approved the generators in April 2026.", "water_impact": "moderate", "ai_evidence": "Regulatory filings and reporting state the Fort Wayne data center will reduce or shift machine-learning workloads during grid stress under a demand-response program.", "grid_impact": "high", "ai_class": "ai-mixed", "community_pushback": "active-opposition", "water_note": "No site-specific GPD disclosed; the campus will use city water, with the city citing ~37 MGD average vs. 72 MGD treatment capacity, and a city\u2013Google deal could save ~182 million gallons/year.", "grid_note": "Facility profile lists 100 MW; IURC approved an I&M\u2013Google demand-response structure in April 2026 to minimize grid impact, amid I&M planning that projects a 99.5% rise in annual peak demand by 2030.", "citations": [{"title": "IDEM approves request to install additional backup diesel ...", "url": "https://www.wane.com/top-stories/idem-approves-request-to-install-additional-backup-diesel-generators-at-google-data-center-in-fort-wayne/"}, {"title": "Fort Wayne residents are getting a Google data center, but ...", "url": "https://www.wfyi.org/public-affairs/2025-12-16/googles-data-center-what-the-build-could-mean-for-fort-wayne"}, {"title": "Google Data Center | Engage Fort Wayne", "url": "https://engage.cityoffortwayne.org/data-center"}, {"title": "Geologist: More studies needed to ensure data centers use ...", "url": "https://www.wane.com/top-stories/geologist-more-studies-needed-to-ensure-data-centers-use-water-responsibly/"}, {"title": "Google goal: replenish 120% of water used in data centers", "url": "https://www.wane.com/top-stories/google-goal-replenish-120-of-water-used-in-data-centers/"}], "runId": "srun_c0e944bd89584b54780e76a1b76e8f75", "classifiedAt": "2026-07-02T22:55:54.947Z"}, "16": {"community_note": "No organized local opposition identified for QTS at 12851 Foster; items surfaced online concern other QTS projects rather than this operational Overland Park site.", "water_impact": "low", "ai_evidence": "No facility-specific AI/GPU indicators: listings show a small 0.18 MW colocation site (~2,500 sq ft), and QTS\u2019s DGX-Ready colocation certification is not linked to this address.", "grid_impact": "low", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "No facility-specific gallons/day or source/discharge data found; QTS highlights water-free/closed-loop cooling in general and has cited about 600,000 gallons annually for a closed\u2011loop data center (not specific to this site).", "grid_note": "Listed at about 0.18 MW with no reported Evergy upgrades; Evergy\u2019s plan applies higher rates to hyperscale/very large users, not a small colo like this.", "citations": [{"title": "City of Overland Park - Home", "url": "https://opkansas.civicweb.net/"}, {"title": "QTS Datacenters", "url": "http://thealliancepartners.com/qts-datacenters/"}, {"title": "Overland Park 1 DC1 - QTS Data Centers", "url": "https://www.ocolo.io/colocation/qts-data-centers/overland-park-1-dc1/"}, {"title": "Pioneering Water Efficiency and Sustainability in Data ...", "url": "https://q.com/resources/pioneering-water-efficiency-and-sustainability-in-data-center-operations/"}, {"title": "Same size. Not the same water use. A QTS closed-loop ...", "url": "https://www.facebook.com/qtsdatacenters/posts/same-size-not-the-same-water-usea-qts-closed-loop-data-center-uses-about-600000-/1461407262694610/"}], "runId": "srun_c0e944bd89584b54f050ee09283ee6bd", "classifiedAt": "2026-07-02T22:55:55.256Z"}, "17": {"community_note": "", "water_impact": "low", "ai_evidence": "No public GPU/NVIDIA cluster or AI-tenant announcements; listings describe a 4.00 MW colocation/enterprise facility rather than an AI-specialized deployment.", "grid_impact": "low", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "Operator materials indicate no water consumption for cooling at CIN6, with no published gallons/day or source-stress data; third-party listings note water- and air-cooled chillers but provide no consumption figures.", "grid_note": "Operational load served by Duke Energy Kentucky, with public listings citing 18.33 MW capacity and a 10\u201325 MW range; a PSC contract directory exists but no facility-specific transmission upgrades or ratepayer impacts were identified.", "citations": [{"title": "CyrusOne \u2014 Florence, KY", "url": "https://www.datacenter.fyi/facility/cyrusone-ky-eb81f37b"}, {"title": "Our communities are growing, and Duke Energy is prepared ...", "url": "https://www.facebook.com/duke.energy/videos/do-data-centers-impact-energy-reliability/1678687829921354/"}, {"title": "Florence, KY: CIN6 - Data centers", "url": "https://www.cyrusone.com/data-centers/north-america/florence-ky"}, {"title": "CIN6 Florence - CyrusOne", "url": "https://www.ocolo.io/colocation/cyrusone/cin6-florence/"}, {"title": "Data centers are key to fight over Duke electric rates\u2026", "url": "https://www.canarymedia.com/articles/data-centers/duke-electric-rates-north-carolina"}], "runId": "srun_c0e944bd89584b544e618c2f98ef3de7", "classifiedAt": "2026-07-02T22:55:55.256Z"}, "18": {"community_note": "Residents including Mooringsport Mayor Tyler Gordon, Michael Craft, and Mary Blakemore challenged the City\u2019s approval over transparency/impact concerns, but reporting says the legal challenge was resolved without derailing the project.", "water_impact": "high", "ai_evidence": "State announcement says Amazon\u2019s Louisiana data center campuses will \u201csupport AI and cloud computing,\u201d indicating AI workloads but without confirming GPU superclusters or specific training deployments.", "grid_impact": "moderate", "ai_class": "ai-mixed", "community_pushback": "active-opposition", "water_note": "City documents indicated roughly 7.5 million gallons/day of water use for the proposed campus.", "grid_note": "SWEPCO announced its role supporting the Amazon data center investment in Shreveport; specific MW load was not disclosed.", "citations": [{"title": "Data center legal challenge resolved without derailing project", "url": "https://www.fwbusiness.com/news/national/article_9f9f29dc-703d-5a15-97a7-f8b9e8d15088.html"}, {"title": "Documents show proposed Shreveport data center would ...", "url": "https://www.ksla.com/2025/12/12/documents-show-proposed-shreveport-data-center-would-use-75-million-gallons-water-daily/"}, {"title": "Amazon Selects Louisiana for $12 Billion Data Center ...", "url": "https://www.opportunitylouisiana.gov/news/amazon-selects-louisiana-for-12-billion-data-center-campuses-in-major-u-s-expansion"}, {"title": "Amazon's $12B data center deal signals a new era of ...", "url": "https://www.geekwire.com/2026/water-power-and-transparency-amazons-12b-data-center-deal-signals-a-new-era-of-accountability/"}, {"title": "AEP building $100 million Shreveport Transmission ...", "url": "https://www.swepco.com/company/news/view.aspx?releaseID=8365"}], "runId": "srun_c0e944bd89584b540b19e71cdd8c5836", "classifiedAt": "2026-07-02T22:55:57.574Z"}, "19": {"community_note": "Residents and councilors raised environmental/health concerns, and the Westfield City Council approved a one-year moratorium on new data centers in June 2026.", "water_impact": "low", "ai_evidence": "Reporting says Servistar is courting hyperscale developers such as Microsoft and Google; no named AI/GPU tenant or deployment has been announced in public sources.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "active-opposition", "water_note": "City/developer materials say the campus would use closed\u2011loop cooling with near\u2011zero continuous potable water needs, and local news reiterates only minimal potable water use.", "grid_note": "Proponents cite proximity to an Eversource transmission interconnect and a new substation that would boost regional reliability, implying a transmission-level interconnection for the campus.", "citations": [{"title": "Westfield council supports moratorium to halt new data ...", "url": "https://thereminder.com/local-news/hampden-county/westfield/westfield-council-supports-moratorium-to-halt-new-data-centers/"}, {"title": "Residents pack council chambers as Westfield halts new ...", "url": "https://www.masslive.com/westfieldnews/2026/06/residents-pack-council-chambers-as-westfield-halts-new-data-centers.html"}, {"title": "Community Update Proposed Servistar Data Center Project", "url": "https://www.cityofwestfield.org/CivicAlerts.aspx?AID=1724"}, {"title": "SERVISTAR DATA CENTER CAMPUS A MODEL FOR ...", "url": "https://www.cityofwestfield.org/DocumentCenter/View/17988/Servistar-Data-Center-Campus-Water-Energy-Fact-Sheet"}, {"title": "Westfield mayor reviews Servistar Data Center project's ...", "url": "https://www.wwlp.com/news/local-news/hampden-county/westfield-mayor-reviews-servistar-data-center-projects-impact/"}], "runId": "srun_c0e944bd89584b54b0046f8b76e22433", "classifiedAt": "2026-07-02T22:59:27.724Z"}, "20": {"community_note": "No organized opposition identified; Amazon told local media it has no plans to use the Owings Mills site as a data center while T. Rowe Price continues occupancy under a sale-leaseback.", "water_impact": "unknown", "ai_evidence": "Local media report Amazon said the Owings Mills property will not be used as a data center, and listings describe legacy T. Rowe Price office/technology space with no AI-specific deployments disclosed.", "grid_impact": "unknown", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "No facility-specific data on cooling method, gallons/day, water sources, or discharge issues was found in public reporting reviewed.", "grid_note": "No public evidence of MW load, BGE upgrades, new transmission, or rate impacts for this address was found.", "citations": [{"title": "Amazon says the office it purchased in Baltimore County ...", "url": "https://www.cbsnews.com/baltimore/news/owings-mills-maryland-amazon-office-purchase/"}, {"title": "Amazon Data Services Acquires Owings Mills Office ...", "url": "https://www.citybiz.co/article/841980/amazon-data-services-acquires-owings-mills-office-property-for-15-2m-plans-undisclosed/"}, {"title": "Amazon buys T. Rowe Price office building for $15.2 million", "url": "https://www.facebook.com/baltimoresun/posts/amazon-data-services-has-purchased-a-t-rowe-price-group-office-building-in-owing/1398513142323191/"}, {"title": "Amazon buys office and data center site in Maryland from T ...", "url": "https://www.datacenterdynamics.com/en/news/amazon-buys-office-and-data-center-site-in-maryland-from-t-rowe/"}, {"title": "Amazon Data Services Acquires Owings Mills Office ...", "url": "https://www.citybiz.co/article/841980/amazon-data-services-acquires-owings-mills-office-property-for-15-2m-plans-undisclosed/"}], "runId": "srun_c0e944bd89584b5451f3d1b5de510fb1", "classifiedAt": "2026-07-02T22:55:55.549Z"}, "21": {"community_note": "Local opposition over environmental/transparency and public-cost concerns culminated in the Lewiston City Council rejecting the Bates Mill No. 3 AI data center on Dec. 16, 2025.", "water_impact": "unknown", "ai_evidence": "The proposal was described as an AI data/technology center and Tier III AI data center, with the developer highlighting high\u2011density power and advanced liquid cooling.", "grid_impact": "unknown", "ai_class": "ai-mixed", "community_pushback": "active-opposition", "water_note": "No gallons/day were disclosed; a project representative said cooling water would be recycled, and Lake Auburn supplies drinking water to Lewiston/Auburn.", "grid_note": "A 24\u2011MW first phase was proposed and developers floated a 20\u201324\u2011MW natural\u2011gas co\u2011generation unit, but the project was rejected before any utility approvals or upgrades advanced.", "citations": [{"title": "Lewiston City Council shoots down data center proposal | Maine Public", "url": "http://mainepublic.org/business-and-economy/2025-12-17/lewiston-city-council-shoots-down-data-center-proposal"}, {"title": "The secretive plan for a Maine data center collapsed in 6 days", "url": "http://themainemonitor.org/secretive-plan-lewiston-data-center"}, {"title": "Lewiston says 'no' to proposed AI data and technology ...", "url": "https://mainebiz.biz/article/lewiston-says-no-to-proposed-ai-data-and-technology-center-for-bates-mill/"}, {"title": "Lewiston weighs data center proposal for vacant Bates Mill 3", "url": "https://www.newscentermaine.com/article/news/local/lewiston-weighs-data-center-proposal-vacant-bates-mill-3/97-0c0ed476-73ee-4e84-b1f4-ef3de260989c"}, {"title": "Lake Auburn | Environmental Studies", "url": "https://www.bates.edu/environmental-studies/photos/water-quality-in-lake-auburn/lake-auburn/"}], "runId": "srun_c0e944bd89584b54d6b630383c8193e2", "classifiedAt": "2026-07-02T22:55:57.006Z"}, "22": {"community_note": "", "water_impact": "unknown", "ai_evidence": "Irongate promotes \u201cnext-gen AI data centers\u201d with high-density, liquid-cooled infrastructure \u201cdesigned for AI workloads\u201d [1], and the Warren listing shows 45.00MW capacity with colocation services [4]; no public disclosures name GPU superclusters or specific AI tenants at this site.", "grid_impact": "moderate", "ai_class": "ai-mixed", "community_pushback": "none-found", "water_note": "No facility-specific cooling water volumes, source, or discharge were reported; public listings reference liquid-cooled/high-density container designs without quantifying use [2][3].", "grid_note": "Listings cite 45 MW power capacity for the Warren facility, and no IronGate-specific DTE/MPSC rate-case or contract docket for this site was found [4][5][7].", "citations": [{"title": "AI Data Centers & Infrastructure in the Midwest | Irongate", "url": "https://www.irongatedatacenters.com/"}, {"title": "Can my old gpu run Amnesia: The Bunker at all?", "url": "https://www.reddit.com/r/Amnesia/comments/1q15e2j/can_my_old_gpu_run_amnesia_the_bunker_at_all/"}, {"title": "NVIDIA's Secret German Bunker: 10000 Blackwell GPUs ...", "url": "https://www.youtube.com/watch?v=ZXeWDwWexrg"}, {"title": "IronGate Data Centers - 4 Data Centers - See Locations", "url": "https://www.datacentermap.com/c/irongate-data-centers/"}, {"title": "IronGate Data Centers", "url": "https://www.linkedin.com/company/irongate-data-centers"}], "runId": "srun_c0e944bd89584b546a5c89fae6072ac4", "classifiedAt": "2026-07-02T22:55:55.826Z"}, "23": {"community_note": "Citywide opponents pushed a moratorium over environmental/energy impacts while the Planning Commission approved a CUP formalizing data-center use at 1001 3rd Ave S; no site-specific lawsuits or complaints found [3][4].", "water_impact": "unknown", "ai_evidence": "The property is \u201cprimarily leased on a long-term basis to a leading provider of sovereign AI and cloud inferencing solutions\u201d and coverage identifies Core42 as a 20 MW primary tenant in Minneapolis [1][10].", "grid_impact": "moderate", "ai_class": "ai-mixed", "community_pushback": "some-concern", "water_note": "Listings show large chilled-water/cooling-tower capacity (10,500 tons), but no gallons/day, water source, drought/aquifer, or discharge details were published [8].", "grid_note": "Arcapita notes a 21\u2011megawatt Minneapolis data center with plans to expand, served by Xcel Energy [9].", "citations": [{"title": "Minneapolis City Council approves 5-month pause on data ...", "url": "https://www.cbsnews.com/minnesota/news/minneapolis-city-council-data-center-pause/"}, {"title": "Planning Commission approves CUP to formalize data center ...", "url": "https://citizenportal.ai/articles/7220689/minnesota/hennepin-county/minneapolis-city/Minneapolis-City/Hennepin-County/Minnesota/Planning-Commission-approves-CUP-to-formalize-data-center-use-at-1001-3rd-Ave-S"}, {"title": "T5@Minneapolis | 1001 3rd Ave S (30 MW)", "url": "https://www.datacentermap.com/usa/minnesota/minneapolis/t5-minneapolis/"}, {"title": "Cloud Capital and Arcapita Acquire a 21-megawatt Data ...", "url": "https://cloudcapital.com/cloud-capital-and-arcapita-acquire-a-21-megawatt-data-center-in-the-us-with-planned-expansion/"}, {"title": "Core42 US footprint expands, adding 20MW in Minneapolis", "url": "https://www.middleeastainews.com/p/core42-us-footprint-expands-adding"}], "runId": "srun_c0e944bd89584b54c86d27d09a740d9a", "classifiedAt": "2026-07-02T22:55:55.826Z"}, "24": {"community_note": "Residents and advocates opposed Lambda/Project Blitz over Port KC incentives and transparency, leading the developer to withdraw its Port KC bond application in June 2026 amid related legal disputes.", "water_impact": "unknown", "ai_evidence": "Lambda announced a 100MW 'AI Factory' with more than 10,000 NVIDIA GPUs, and reporting indicates an initial 24 MW launch phase with headroom to scale above 100 MW.", "grid_impact": "high", "ai_class": "ai-mixed", "community_pushback": "active-opposition", "water_note": "No site-specific gallons/day disclosed; the property listing notes 114,000-gallon thermal chilled-water storage and underground water storage, while regional reporting quantifies other KC data centers\u2019 water use (e.g., Meta up to 9.5M gpd), not this site.", "grid_note": "Planned load launches around 24 MW with potential to exceed 100 MW; local reporting described a dispute over Evergy\u2019s near\u2011term power availability as Port KC bonds were withdrawn, and Evergy discussed a new large\u2011customer rate for data centers.", "citations": [{"title": "Northland AI data center withdraws bond application with ...", "url": "https://www.kshb.com/news/local-news/data-centers/northland-ai-data-center-withdraws-bond-application-with-port-kc"}, {"title": "Lambda AI factory seeks Port KC incentives amid opposition", "url": "https://www.bizjournals.com/kansascity/news/2026/05/29/project-blitz-port-kc-data-center-ai-incentives.html"}, {"title": "Developer withdraws Port KC request for data center project", "url": "https://www.kansascity.com/news/local/article316024513.html"}, {"title": "Kansas City Data Center - Lincoln Property Company", "url": "https://lpc.com/properties/properties-search/KansasCityDataCenter/"}, {"title": "KC data centers could use millions of gallons of water per ...", "url": "https://www.kshb.com/news/local-news/kansas-city-data-centers-could-use-millions-of-gallons-of-water-per-day-records-show"}], "runId": "srun_c0e944bd89584b54e0d5dfd9d2431e4d", "classifiedAt": "2026-07-02T22:55:55.826Z"}, "25": {"community_note": "Active organized opposition: the Safe and Sound Coalition, NAACP and a large resident class-action challenge xAI\u2019s Southaven power plant/data center over allegedly unlawful gas turbines, noise, and health/property impacts, with litigation active as of June 2026.", "water_impact": "high", "ai_evidence": "Elon Musk said MACROHARDRR will take xAI training compute to almost 2 GW, and the Mississippi governor announced xAI is retrofitting the Southaven facility as MACROHARDRR for new data-center operations.", "grid_impact": "high", "ai_class": "ai-training", "community_pushback": "active-opposition", "water_note": "No official MACROHARDRR-only GPD figure was found; xAI planned an $80M wastewater-recycling facility to cool servers with treated effluent instead of drinking water, and local officials pressed for its completion amid aquifer-protection focus.", "grid_note": "Mississippi approved 41 natural-gas turbines at xAI\u2019s Southaven site, with reports of 27 temporary turbines and later 46 units lacking air permits, while Entergy indicates large data centers pay a big share of grid-upgrade costs.", "citations": [{"title": "NAACP Sues xAI for Illegal Pollution from Data Center ...", "url": "https://naacp.org/articles/naacp-sues-xai-illegal-pollution-data-center-power-plant"}, {"title": "Musk's xAI, SpaceX hit with class action over data center ' ...", "url": "https://www.reuters.com/legal/government/musks-xai-spacex-hit-with-class-action-over-data-center-nuisance-2026-06-09/"}, {"title": "As Musk's Data Centers Encroach, Southaven Residents ...", "url": "https://www.mississippifreepress.org/as-musks-xai-data-centers-encroach-on-southaven-north-mississippi-residents-push-back/"}, {"title": "Wastewater Will Cool This Memphis Data Center", "url": "https://www.governing.com/resilience/wastewater-will-cool-this-memphis-data-center"}, {"title": "Mayor, MLGW push xAI to complete water recycling facility", "url": "https://wreg.com/news/local/xai-memphis/mayor-mlgw-push-xai-to-complete-water-recycling-facility/"}], "runId": "srun_c0e944bd89584b54515cb4b0d8544ffa", "classifiedAt": "2026-07-02T22:55:53.241Z"}, "26": {"community_note": "Opposition groups are focused on the separate Bonner/Krambu proposal over water/energy impacts; no organized pushback is reported for MIS1 at 110 E Broadway.", "water_impact": "unknown", "ai_evidence": "", "grid_impact": "unknown", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "No MIS1-specific cooling-water data were found; county water-stress discussion centers on the separate Bonner proposal rather than the existing downtown Missoula site.", "grid_note": "No MIS1-specific MW load or utility-upgrade data were found; separate reporting describes Vision Net\u2019s statewide edge model (including Missoula) as reducing grid impacts and AI latency.", "citations": [{"title": "MOD Mission Critical | MOD PaaSPort\u2122", "url": "https://modmc.net/"}, {"title": "Vision Net Opens the Doors on its Newest Data Center", "url": "https://vision.net/vision-net-opens-the-doors-on-its-newest-data-center/"}, {"title": "Rack-Scale Liquid Cooling Solutions", "url": "https://www.supermicro.com/en/solutions/liquid-cooling"}, {"title": "Great Falls-based Vision Net utilizes edge data centers to ...", "url": "https://www.krtv.com/news/great-falls-news/great-falls-based-vision-net-utilizes-edge-data-centers-to-reduce-grid-impacts-and-improve-ai-latency"}, {"title": "CoreSite Delivers Customized Liquid Cooling System to ...", "url": "https://www.coresite.com/blog/coresite-delivers-customized-liquid-cooling-system-to-support-gpuaas-and-enterprise-ai"}], "runId": "srun_c0e944bd89584b54e46820ef073b2927", "classifiedAt": "2026-07-02T22:55:56.133Z"}, "27": {"community_note": "Residents and advocacy groups pressed Charlotte City Council for a pause over water, power, noise, and transparency concerns; on June 8, 2026 the Council unanimously approved a 150\u2011day moratorium on new data\u2011center applications while impacts are studied, with existing approvals unaffected.", "water_impact": "high", "ai_evidence": "Developer materials say the campus is designed for advanced hyperscale and AI-driven applications and is liquid-ready to support AI/ML and GPU clusters; no public announcements name an AI tenant or GPU supercluster at this site yet.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "active-opposition", "water_note": "City staff said a data center under construction near University Place could use up to 1.2 million gallons per day in summer, roughly equivalent to thousands of homes\u2019 use; site-specific cooling/source details for PowerHouse are not public.", "grid_note": "Planned for about 300 MW with a dedicated Duke Energy substation expected in April 2027.", "citations": [{"title": "Frequently Asked Questions: Data Centers & Moratorium", "url": "https://www.charlottenc.gov/City-News/Data-Centers-Moratorium-FAQs"}, {"title": "Charlotte Imposes 150-Day Moratorium on Data Centers", "url": "https://insidetowers.com/charlotte-imposes-150-day-moratorium-on-data-centers/"}, {"title": "Charlotte council OKs data center moratorium on new ...", "url": "https://www.charlotteobserver.com/news/politics-government/article316049525.html"}, {"title": "Charlotte City Council weighs data center moratorium amid ...", "url": "https://www.wfae.org/politics/2026-05-12/charlotte-city-council-weighs-data-center-moratorium-amid-water-power-concerns"}, {"title": "Data centers use a lot of water. What does that mean for ...", "url": "https://www.wunc.org/environment/2026-04-10/data-centers-water-quality-pfas-drought-climate-change"}], "runId": "srun_c0e944bd89584b54c27aa6ecf14a2a86", "classifiedAt": "2026-07-02T22:55:52.947Z"}, "28": {"community_note": "Local outlets report housing/rent pressure and complaints about construction-related road damage around the Ellendale campus, with no Ellendale-specific lawsuit documented in the cited coverage [7][8].", "water_impact": "low", "ai_evidence": "CoreWeave leased 250 MW at Ellendale under a long-term AI data center agreement, with Phase 1 at Polaris Forge 1 reaching ready-for-service; campus design and BASX cooling target liquid-cooled, high\u2011density AI/HPC workloads across a three\u2011building, 400\u2011MW campus [1][2][4][3].", "grid_impact": "high", "ai_class": "ai-mixed", "community_pushback": "some-concern", "water_note": "Cooling uses a closed-loop, waterless direct\u2011to\u2011chip/liquid system with BASX free\u2011cooling chillers claiming \u201czero water use,\u201d and no cited reports flag aquifer or discharge concerns [4][5].", "grid_note": "Energized on\u2011site main substation with MDU service; ELN01 at 180 MW within a three\u2011building, 400\u2011MW campus, and company materials note $5.4M in customer credits tied to service [9][10][3][11][1].", "citations": [{"title": "North Dakota town serves as an example of the promise ...", "url": "https://southdakotasearchlight.com/2026/01/30/north-dakota-town-serves-as-an-example-of-the-promise-and-perils-of-data-centers-for-south-dakota/"}, {"title": "Applied Digital responds to concerns over road damage in ...", "url": "https://kfgo.com/2026/04/21/applied-digital-responds-to-concerns-over-road-damage-in-south-central-north-dakota/"}, {"title": "BASX Powers Advanced Cooling Innovation for Applied ...", "url": "https://www.prnewswire.com/news-releases/basx-powers-advanced-cooling-innovation-for-applied-digitals-purpose-built-ai-data-center-campus-302494791.html"}, {"title": "$2.7 Billion in Data Center Savings", "url": "https://ir.applieddigital.com/news-events/press-releases/detail/124/2-7-billion-in-data-center-savings-new-applied-digital"}, {"title": "Why Modern AI Data Centers are Harnessing the Power ...", "url": "https://www.applieddigital.com/insights/why-modern-ai-data-centers-are-harnessing-the-power-of-liquid-cooling"}], "runId": "srun_c0e944bd89584b549ec03a1e150be730", "classifiedAt": "2026-07-02T22:55:56.133Z"}, "29": {"community_note": "Localized concern arose during 2023 rezoning/expansion over native prairie impacts, with a developer mitigation commitment; no lawsuits or organized opposition specific to Building 1 were found.", "water_impact": "unknown", "ai_evidence": "Google highlights AI use cases on its data center locations pages and lists Omaha as a site, and Nebraska reporting links Google\u2019s investment to growing Google Cloud demand, but no Building 1\u2013specific GPU/TPU training cluster or AI retrofit has been disclosed.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "some-concern", "water_note": "Google partnered with Omaha\u2019s MUD on a $3M leak\u2011detection program expected to save up to 1 billion gallons of water annually [12].", "grid_note": "A third\u2011party profile lists Google Omaha Building 1 (Phase 1) at 87 MW and operational in 2024 [11].", "citations": [{"title": "Google Seeks To Stretch Farther In Northwest Omaha", "url": "https://www.omahadailyrecord.com/content/google-seeks-stretch-farther-northwest-omaha"}, {"title": "Google seeks to stretch farther in northwest Omaha", "url": "https://nebraskaexaminer.com/2023/01/03/google-seeks-to-stretch-farther-in-northwest-omaha/"}, {"title": "Water and energy use is growing as data centers are built ...", "url": "https://nebraskapublicmedia.org/en/news/news-articles/water-and-energy-use-is-growing-as-data-centers-are-built-across-the-midwest-and-great-plains/"}, {"title": "Advancing responsible water use at our data centers", "url": "https://datacenters.google/water/"}, {"title": "Locations of Google Data Centers", "url": "https://datacenters.google/locations"}], "runId": "srun_c0e944bd89584b54a124460e960bcc40", "classifiedAt": "2026-07-02T22:55:51.986Z"}, "31": {"community_note": "No Secaucus-specific opposition or litigation surfaced; NJ pushback covered in the news pertains to other projects (e.g., Vineland noise lawsuit, broader political fights), not H5\u2019s Secaucus site.", "water_impact": "unknown", "ai_evidence": "No disclosures of GPU superclusters, AI-training tenants, or liquid-cooling retrofits for Secaucus; listings describe a ~38,000 sq ft colocation/enterprise site with ~2.00 MW capacity, while H5\u2019s AI page is general marketing, not site-specific.", "grid_impact": "low", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "Cooling plant includes N+1 chillers, N+1 cooling towers, N+1 CRACs, and cold-aisle containment; no gallons/day, source, or discharge details are published.", "grid_note": "Listed capacity is ~2.00 MW; utility is PSE&G; no Secaucus-specific upgrade or rate action identified, and PSE&G provides generic data center services information.", "citations": [{"title": "New Jersey Neighbors Sue Over Humming Noise From Data ...", "url": "https://www.govtech.com/artificial-intelligence/new-jersey-neighbors-sue-over-humming-noise-from-data-center"}, {"title": "Inside the battle over data center development that's quietly ...", "url": "https://newjerseyglobe.com/congress/inside-the-battle-over-data-center-development-thats-quietly-reshaping-n-j-politics/"}, {"title": "New Jersey Data Center", "url": "https://h5datacenters.com/new-jersey-data-center.html"}, {"title": "New Jersey Data Center", "url": "https://h5datacenters.com/new-jersey-data-center.html"}, {"title": "H5 Data Centers: New Jersey", "url": "https://www.ocolo.io/colocation/h5-data-centers/new-jersey/"}], "runId": "srun_c0e944bd89584b54486f0ddbca1081a3", "classifiedAt": "2026-07-02T22:55:52.262Z"}, "32": {"community_note": "No organized, facility-specific pushback was found; county-wide guardrails for data-center projects were adopted by Bernalillo County to address water, energy, community engagement, and pollution concerns and are not specific to this site.", "water_impact": "unknown", "ai_evidence": "Listings describe the site as a colocation/hosting facility (not AI-specific), with no confirmed GPU superclusters or AI tenants disclosed [3][4][6].", "grid_impact": "low", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "No gallons/day or water sourcing/discharge information is published; listings note CRAC-based cooling (air-cooled) rather than water-use figures [2].", "grid_note": "Operator materials cite 2x PNM utility feeds for 2 MW and 3x UPS available for 450 kW at 725 6th Street NW [1].", "citations": [{"title": "Data Center Project Guardrails Resolution Approved by ...", "url": "https://www.bernco.gov/blog/2026/02/11/data-center-project-guardrails-resolution-approved-by-bernalillo-county-commission/"}, {"title": "Oso Grande", "url": "https://www.osogrande.com/"}, {"title": "Oso Grande Technologies,: ABQ1 (Oso Grande Data Center)", "url": "https://www.datacenters.com/oso-grande-technologies-abq1-oso-grande"}, {"title": "Oso Grande Technologies - Albuquerque", "url": "https://www.datacentermap.com/usa/new-mexico/albuquerque/oso-secure/"}, {"title": "Albuquerque Data Centers - 18 Facilities from 5 Operators", "url": "https://www.datacentermap.com/usa/new-mexico/albuquerque/"}], "runId": "srun_c0e944bd89584b54734a2e53960fd86b", "classifiedAt": "2026-07-02T22:55:56.432Z"}, "33": {"community_note": "Henderson officials introduced Bill No. 3927 for a 180\u2011day pause on new data\u2011center conditional\u2011use applications, indicating municipal concern; no facility\u2011specific lawsuits or organized opposition groups were identified.", "water_impact": "high", "ai_evidence": "GPU resources are offered in the us\u2011west4 (Las Vegas) cloud region, and Google operates a data center in Henderson with third\u2011party listings at 560 W Warm Springs Rd; however, no public source names this site as a dedicated GPU supercluster, indicating cloud AI alongside general workloads.", "grid_impact": "moderate", "ai_class": "ai-mixed", "community_pushback": "some-concern", "water_note": "City-reported data show ~352 million gallons used in 2024 (~0.96M gpd), with Henderson sourcing about 90% of drinking water from the Colorado River amid Tier 1 shortage conditions.", "grid_note": "Approx. 60 MW facility capacity, with Google\u2019s Nevada data\u2011center load associated with up to 690 MW of solar and 380 MW of storage.", "citations": [{"title": "Henderson considers data center pause amid construction ...", "url": "https://thenevadaindependent.com/article/henderson-considers-data-center-pause-amid-construction-boom-across-clark-county"}, {"title": "Henderson City Council introduces moratorium on new ...", "url": "https://www.reviewjournal.com/local/henderson/henderson-city-council-introduces-moratorium-on-new-data-centers-3839299/"}, {"title": "Nevada's data center boom is a power, water conundrum", "url": "https://www.reviewjournal.com/local/local-nevada/nevadas-data-center-boom-is-a-power-water-conundrum-3403770/"}, {"title": "Water Source | Henderson, NV", "url": "https://www.cityofhenderson.com/government/departments/utility-services/water-quality/water-source"}, {"title": "Drought and conservation measures", "url": "https://www.lvvwd.com/conservation/measures/index.html"}], "runId": "srun_c0e944bd89584b54d587f9223994a0ec", "classifiedAt": "2026-07-02T22:55:52.657Z"}, "34": {"community_note": "", "water_impact": "unknown", "ai_evidence": "Digital Realty, OQC, and NVIDIA launched a quantum\u2011AI data center at JFK10, integrating superconducting quantum computers with NVIDIA accelerated systems, with JFK10 marketed as combining quantum and AI\u2011ready infrastructure [3][2][4].", "grid_impact": "low", "ai_class": "ai-mixed", "community_pushback": "none-found", "water_note": "", "grid_note": "Approx. 3.7 MW UPS (listing) and served by Con Edison; no facility-specific upgrade or rate-case impacts found, with a 2012 storm-time generator incident at 111 8th Ave noted historically [5][7][6].", "citations": [{"title": "New York JFK10 - 111 8th Avenue", "url": "https://www.digitalrealty.com/data-centers/americas/new-york/jfk10"}, {"title": "Digital Realty Data Center in New York NY", "url": "https://www.datacenters.com/digital-realty-new-york-jfk10"}, {"title": "New York JFK10 - 111 8th Avenue", "url": "https://www.digitalrealty.com/data-centers/americas/new-york/jfk10"}, {"title": "Temperatures Soar at Data Center Inside 111 8th Avenue", "url": "https://www.datacenterknowledge.com/cooling/temperatures-soar-at-data-center-inside-111-8th-avenue"}, {"title": "Digital Realty Data Center in New York NY", "url": "https://www.datacenters.com/digital-realty-new-york-jfk10"}], "runId": "srun_c0e944bd89584b544c014f219810f0f5", "classifiedAt": "2026-07-02T22:55:52.657Z"}, "35": {"community_note": "No COL7-specific lawsuit was found; statewide opponents have pushed protests and a moratorium over electricity, water use, and tax incentives, while Ohio approved a Cologix sales\u2011tax exemption just before pausing new data center tax breaks.", "water_impact": "unknown", "ai_evidence": "COL7 is marketed as 'AI-ready' and 'purpose-built to support both Scalelogix and Digital Edge deployments' with liquid-to-chip readiness; the only named GPU supercluster in Columbus is Lambda\u2019s NVIDIA HGX B200 at Cologix\u2019s COL4, not COL7.", "grid_impact": "high", "ai_class": "ai-inference", "community_pushback": "some-concern", "water_note": "No COL7-specific water volumes or sources are published; the facility is marketed as liquid-to-chip ready, and statewide reporting finds Ohio generally has sufficient water but faces infrastructure and used-water constraints amid growing scrutiny in Licking County.", "grid_note": "Planned as part of an up-to-800MW Johnstown campus (eight AI-ready facilities), COL7 is in AEP Ohio territory where PUCO ordered a data center\u2013specific tariff after unprecedented ~30,000 MW of data center requests to manage system impacts and cost allocation.", "citations": [{"title": "2 Ohio data centers get $42M tax break before pause", "url": "https://signalohio.org/ohio-approves-last-data-center-exemption-before-moratorium/"}, {"title": "Ohio OKs last data center sales tax break before DeWine's ...", "url": "https://www.dispatch.com/story/marketplace/jobs/2026/06/01/central-ohio-cologix-data-center-gets-last-of-sales-tax-breaks-before-pause/90358842007/"}, {"title": "Ohioans urge statewide moratorium as data center boom ...", "url": "https://www.dispatch.com/story/news/politics/2026/06/01/ohioans-pack-statehouse-to-protest-rapid-spread-of-data-centers/90316214007/"}, {"title": "COL7 Data Center Spec Sheet", "url": "https://cologix.com/resources/spec-sheets/col7-data-center-spec-sheet/"}, {"title": "Water Readiness and Data Centers: A Near-Term Study for ...", "url": "https://ohiochamberfoundation.com/projects/water-readiness-and-data-centers-a-near-term-study-for-ohio/"}], "runId": "srun_c0e944bd89584b545d4582daf3857c64", "classifiedAt": "2026-07-02T22:55:51.986Z"}, "36": {"community_note": "Some council concern: Oklahoma City council members raised favoritism concerns when amending the data\u2011center moratorium to allow certain facilities; the measure passed and no site\u2011specific lawsuits were found.", "water_impact": "low", "ai_evidence": "Cerebras announced the Oklahoma City site would house over 300 CS\u20113 systems, and separately demonstrated training a 1\u2011trillion\u2011parameter model on a single CS\u20113 system [1], [7].", "grid_impact": "low", "ai_class": "ai-mixed", "community_pushback": "some-concern", "water_note": "No public gallons/day figures were found; the site uses closed\u2011loop direct\u2011to\u2011chip liquid cooling, and Cerebras says its closed\u2011loop cooling minimizes water use and relies on outside air except on the hottest days.", "grid_note": "Reported at 10 MW with no documented site\u2011specific grid upgrades; OG&E\u2019s proposed large\u2011load agreement applies at 75 MW or more.", "citations": [{"title": "new datacenter in Oklahoma City", "url": "https://www.cerebras.ai/blog/okc"}, {"title": "Cerebras Oklahoma Data Center in Oklahoma City (10 MW)", "url": "https://www.datacentermap.com/usa/oklahoma/oklahoma-city/scale-datacenter/"}, {"title": "As data centers boom in Oklahoma, so does water demand", "url": "https://www.readfrontier.org/stories/as-data-centers-boom-in-oklahoma-so-does-water-demand/"}, {"title": "As data centers eye Oklahoma communities, residents and ...", "url": "https://www.kosu.org/energy-environment/2025-11-18/as-data-centers-eye-oklahoma-communities-residents-and-officials-weigh-in-on-water-concerns"}, {"title": "Cerebras opens 10MW data center in Oklahoma City - DCD", "url": "https://www.datacenterdynamics.com/en/news/cerebras-opens-10mw-data-center-in-oklahoma-city/"}], "runId": "srun_c0e944bd89584b544278be8555d7b121", "classifiedAt": "2026-07-02T22:55:56.432Z"}, "37": {"community_note": "Opponents including 1000 Friends of Oregon sued in June 2026 to block Hillsboro data center tax breaks, and the fight has moved into the courts.", "water_impact": "low", "ai_evidence": "", "grid_impact": "moderate", "ai_class": "not-ai", "community_pushback": "active-opposition", "water_note": "No POR01A-specific gallons/day were found; Hillsboro reports data centers used 111 million gallons in 2025 (1.76% of city demand) and predominantly employ closed-loop systems that reuse water.", "grid_note": "Served by PGE; Oregon approved changes so data centers and other large industrial users will pay more to access electricity, reflecting grid and rate impacts from large loads.", "citations": [{"title": "Opponents Sue to Block 17 Proposed Data Centers in ...", "url": "https://www.wweek.com/news/courts/2026/06/23/opponents-sue-to-block-17-proposed-data-centers-in-hillsboro/"}, {"title": "Data Center Water Use in Hillsboro | News & ...", "url": "https://www.hillsboro-oregon.gov/Home/Components/News/News/17350/"}, {"title": "Lawsuit filed against Hillsboro, Washington County over ...", "url": "https://katu.com/news/local/lawsuit-filed-against-hillsboro-washington-county-over-data-center-tax-breaks-billionaire-environment-company-fortune-500-oregon-portland-salem-politics-business-jobs-water-privacy"}, {"title": "STACK Opens New Hillsboro Data Center Campus", "url": "https://www.stackinfra.com/about/news-press/press-releases/stack-infrastructure-continues-its-u-s-expansion-with-the-groundbreaking-of-latest-hillsboro-campus/"}, {"title": "Data centers disrupting neighborhoods with noise and ...", "url": "https://www.facebook.com/ScienceNaturePage/posts/across-the-united-states-data-centers-are-transforming-peaceful-neighborhoods-in/1552446523002878/"}], "runId": "srun_c0e944bd89584b54a5e88f3cd8fdb696", "classifiedAt": "2026-07-02T22:55:50.064Z"}, "38": {"community_note": "Residents raised concerns at public meetings while the project received planning approval and a borough data\u2011center ordinance was adopted; separate litigation targets pollution from the legacy Stronghold Panther Creek power plant, not the data center.", "water_impact": "low", "ai_evidence": "Announced T5 partnership to develop an advanced AI/HPC campus at Panther Creek and $300M project financing for Phase 1 with YE\u20112026 energization, with 350 MW secured via PJM; no confirmed live GPU tenant/cluster disclosed yet.", "grid_impact": "high", "ai_class": "ai-mixed", "community_pushback": "some-concern", "water_note": "Closed\u2011loop/non\u2011evaporative cooling estimated at ~3,000 gallons/day with the initial fill trucked in by external suppliers.", "grid_note": "Expanding from ~80 MW toward a 350 MW PJM\u2011secured campus, with $300M Phase 1 financing and energization targeted by YE\u20112026.", "citations": [{"title": "Residents voice concerns over proposed data center in ...", "url": "https://www.wnep.com/article/news/local/carbon-county/nesquehoning-residents-voice-concerns-over-proposed-data-center-carbon-county-bitfarms-ltd-bitcoin/523-571bdbff-9045-4abc-9eef-5299cbdfcfc4"}, {"title": "Bitfarms Wins Local Approval to Advance Pennsylvania AI ...", "url": "https://www.theenergymag.com/news/2026-02-25/bitfarms-wins-local-approval-to-advance-pennsylvania-ai-data-center-project"}, {"title": "Data Center Ordinance", "url": "https://nesquehoning.org/wp-content/uploads/2026/03/Data-Center-Ordinance-Mar26.pdf"}, {"title": "Environmental group sues cryptocurrency plant and Gov. ...", "url": "https://www.alleghenyfront.org/pennsylvania-stronghold-digital-mining-cryptocurrency-lawsuit/"}, {"title": "Local officials greenlight Bitfarms Panther Creek AI data ...", "url": "https://finance.yahoo.com/news/local-officials-greenlight-bitfarms-panther-142555915.html"}], "runId": "srun_c0e944bd89584b545ae176aa79c87ad4", "classifiedAt": "2026-07-02T22:55:56.432Z"}, "40": {"community_note": "Organized local opposition has mounted via a petition and public meetings over environmental, water/power use, and siting concerns; the county has weighed a nine\u2011month moratorium while QTS says construction continues under existing approvals.", "water_impact": "low", "ai_evidence": "No facility\u2011specific evidence of GPU superclusters or named AI tenants was found; QTS has a corporate NVIDIA DGX colocation certification, but it is not York\u2011specific.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "active-opposition", "water_note": "Closed\u2011loop cooling is used and \u201cdoes not consume water for cooling, once operational,\u201d with the county noting newer systems that require less water.", "grid_note": "QTS pays for new power infrastructure; Duke Energy will upgrade transmission; York Electric is the retail supplier with power procured via Central Electric Power Cooperative, and the co\u2011op says member rates will not increase due to the data center.", "citations": [{"title": "Petition \u00b7 Stop the QTS data center in York County, SC", "url": "https://www.change.org/p/stop-the-qts-data-center-in-york-county-sc"}, {"title": "York County weighs 9-month moratorium on new data ...", "url": "https://www.wbtv.com/2026/06/17/york-county-weighs-9-month-moratorium-new-data-centers-what-we-know/"}, {"title": "York County considers nine-month data center moratorium", "url": "https://www.heraldonline.com/news/business/article315909645.html"}, {"title": "York County, South Carolina - Data Centers", "url": "https://q.com/data-centers/york/"}, {"title": "Data Centers | York, SC", "url": "https://www.yorkcountygov.com/1313/Data-Centers"}], "runId": "srun_c0e944bd89584b547cd2c0bf3ca45737", "classifiedAt": "2026-07-02T22:55:52.947Z"}, "42": {"community_note": "No facility-specific organized opposition, lawsuit, zoning fight, moratorium campaign, or noise/air-quality complaint was found for Data Suites at 1020 W College St.; community pushback appears absent as of July 2026.", "water_impact": "low", "ai_evidence": "Marketed as \u201cAI and HPC ready,\u201d with up to 50 kW/rack and a 2 MW, 415V powered shell for AI/HPC build-outs, but no named GPU clusters, AI tenants, or confirmed AI workloads were found in public materials [1][2][3][4].", "grid_impact": "low", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "No gallons/day reported; the operator describes a recycled chilled-water system, and Murfreesboro\u2019s drinking water comes from the East Fork of the Stones River and J. Percy Priest Lake [2][5].", "grid_note": "Powered shell of 2 MW at 415V is advertised; the local utility is Middle Tennessee Electric, with no public documentation of substation/transmission upgrades or rate cases tied to this site [3][6].", "citations": [{"title": "Data Suites: Nashville / Murfreesboro Data Center | AI ...", "url": "https://mydatasuites.com/"}, {"title": "Data Suites Data Center in Nashville | 1020 W College St", "url": "https://www.datacentermap.com/usa/tennessee/nashville/data-suites/"}, {"title": "Nashville / Murfreesboro Data Center Colocation", "url": "https://mydatasuites.com/colocation/"}, {"title": "Water Quality Report | Murfreesboro, TN - Official Website", "url": "https://www.murfreesborotn.gov/1489/Water-Quality-Report"}, {"title": "Data Suites: Nashville / Murfreesboro Data Center | AI ...", "url": "https://mydatasuites.com/"}], "runId": "srun_c0e944bd89584b5438f3fcebcf29ce13", "classifiedAt": "2026-07-02T22:55:53.241Z"}, "43": {"community_note": "No organized opposition or litigation surfaced; local coverage discussed a same-campus expansion at 2800 Summit Ave without reporting pushback.", "water_impact": "low", "ai_evidence": "Aligned markets the Dallas\u2013Fort Worth campus as powering AI and cloud workloads and supporting the highest\u2011density GPUs, but the named AI cloud deployment is Lambda at DFW\u201104, not DFW\u201101.", "grid_impact": "moderate", "ai_class": "cloud-hyperscale", "community_pushback": "none-found", "water_note": "Uses closed\u2011loop/air\u2011cooled cooling with claims of reduced water use and millions of gallons saved annually; no DFW\u201101 gallons/day, source, drought/aquifer, or discharge details found.", "grid_note": "Approximately 60 MW critical load with Oncor as provider; no DFW\u201101\u2011specific upgrades, rate cases, or curtailment identified.", "citations": [{"title": "Data Centers Expansion Set For Plano, Texas", "url": "https://www.localprofile.com/news/data-centers-expansion-set-for-plano-texas-8279396"}, {"title": "Aligned Data Centers: Adaptive Data Centers for Growth", "url": "https://aligneddc.com/"}, {"title": "Protecting Regional Water Resources", "url": "https://aligneddc.com/case-studies/case-study-protecting-regional-water-resources/"}, {"title": "Aligned Data Centers Opens Ultra-Efficient Data Center in ...", "url": "https://aligneddc.com/press-release/aligned-data-centers-opens-ultra-efficient-data-center-in-plano/"}, {"title": "Sustainable, AI-Ready Data Centers in Dallas Fort Worth", "url": "https://aligneddc.com/dallas-data-centers/"}], "runId": "srun_c0e944bd89584b545cae6659b9c502cd", "classifiedAt": "2026-07-02T22:55:49.665Z"}, "44": {"community_note": "No organized local opposition identified; only routine Utah DAQ public-comment air-permit actions for backup generation at the West Jordan data center are on file.", "water_impact": "moderate", "ai_evidence": "", "grid_impact": "moderate", "ai_class": "not-ai", "community_pushback": "none-found", "water_note": "Grist reports 47.4 million gallons used Oct 2024\u2013Sep 2025 (~130,000 gpd) for Aligned\u2019s West Jordan data center; Aligned cites closed-loop, waterless cooling that reduces ongoing water use.", "grid_note": "About 34 MW at SLC-01; Utah revised duty-to-serve rules for \u2265100 MW loads and Rocky Mountain Power is reported as lacking capacity for the surge, with no SLC-01-specific upgrades or rate actions identified.", "citations": [{"title": "{{$s }}", "url": "https://daqpermitting.utah.gov/DocViewer?IntDocID=159077&contentType=application/pdf"}, {"title": "DAQ-2026-000020 - Laserfiche WebLink - Utah.gov", "url": "https://lf-public.deq.utah.gov/WebLink/DocView.aspx?id=641110&dbid=0&repo=Public"}, {"title": "Can you build data centers in a desert without draining ... - Grist", "url": "https://grist.org/technology/utah-data-center-water-supply-meta-novva/"}, {"title": "Protecting Regional Water Resources", "url": "https://aligneddc.com/case-studies/case-study-protecting-regional-water-resources/"}, {"title": "Sustainability as a Priority", "url": "https://aligneddc.com/sustainability/"}], "runId": "srun_c0e944bd89584b5431cf769ffb2704d7", "classifiedAt": "2026-07-02T22:55:52.262Z"}, "45": {"community_note": "No site-specific opposition found; regionally, Loudoun residents are fighting Dominion\u2019s transmission routes for data centers and regulators are reviewing expanded diesel\u2011generator use, with proceedings ongoing.", "water_impact": "moderate", "ai_evidence": "Public profiles identify the site as a 113,300\u2011sq\u2011ft Digital Realty/AWS facility (~6.8 MW) with no disclosed AI GPU clusters or liquid\u2011cooling retrofits; AWS provides AI instances in us\u2011east\u20111 regionally, not tied to this address.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "active-opposition", "water_note": "No facility-specific usage disclosed; Loudoun data centers consumed ~899 million gallons of potable water in 2023 after ~250% growth since 2019, and during 2026 drought conditions they faced the same restrictions as other customers.", "grid_note": "Dominion\u2011served Northern Virginia grid upgrades for data centers are contributing to rising transmission and potential rate impacts, with PJM customers already paying billions and future allocation shifts under review.", "citations": [{"title": "Loudoun transmission line debate tees up SCC response ...", "url": "https://virginiamercury.com/2025/09/19/loudoun-transmission-line-debate-aims-scc-to-respond-to-data-center-needs-resident-concerns/"}, {"title": "State regulators weigh expanded use of data centers ...", "url": "https://www.vpm.org/news/2025-12-17/virginia-data-centers-diesel-backup-generators-deq-loudoun-turner-dowd"}, {"title": "The surging demand for data is guzzling Virginia's water | Grist", "url": "https://grist.org/technology/surging-demand-data-guzzling-water-ai/"}, {"title": "RESPONSIBLE DATA CENTER DEVELOPMENT \u2013 ...", "url": "https://vcnva.org/agenda-item/responsible-data-center-development/"}, {"title": "IAD24 Data Center | 43830 Devin Shafron Drive Bldg F", "url": "https://www.digitalrealty.com/data-centers/americas/northern-virginia/iad24"}], "runId": "srun_c0e944bd89584b5411ab1c7979e45b6d", "classifiedAt": "2026-07-02T22:55:49.365Z"}, "47": {"community_note": "No site-specific opposition surfaced; regionally, Seattle passed a one\u2011year moratorium on large data centers, indicating heightened scrutiny but not a Lynnwood-specific action.", "water_impact": "unknown", "ai_evidence": "CTP said it will refit the facility and deploy an initial 5 MW Edge installation for an AI-focused customer at the 4200 194th St SW site.", "grid_impact": "moderate", "ai_class": "ai-mixed", "community_pushback": "some-concern", "water_note": "No facility-specific water-use or discharge figures were found; the local utility provides general water service information with no site-specific details.", "grid_note": "Local utility planning includes capacity expansions via new facilities and system-specific projects, but no address-specific transmission or rate impacts were identified for this 6 MW site.", "citations": [{"title": "Seattle passes one-year data center moratorium", "url": "https://mynorthwest.com/local/data-center-moratorium/4246470"}, {"title": "Digital Fortress Data Center in Lynnwood, WA", "url": "https://www.datacenters.com/digital-fortress-north-seattle-lyn"}, {"title": "Major 150MW expansion initiatives across the USA", "url": "https://chirisatechnologyparks.com/major-150mw-expansion-initiatives-across-the-usa-3/"}, {"title": "PTC NEWS: Chirisa Technology Parks and Strategic ...", "url": "https://www.powerhousedata.com/news/ptc-news-chirisa-technology-parks-and-strategic-partner-powerhouse-data-centers-announces-major-expansion-initiatives-across-the-usa-focused-on-hyperscale-and-ai-workloads"}, {"title": "Digital Fortress: North Seattle - Lynnwood (SEA1)", "url": "https://www.ocolo.io/colocation/digital-fortress/north-seattle-lynnwood-sea1/"}], "runId": "srun_c0e944bd89584b54efb9d35414fa8b5e", "classifiedAt": "2026-07-02T22:55:52.947Z"}, "48": {"community_note": "Rock County Neighbors for Responsible Development/No Beloit Data Center is pushing an 18\u2011month moratorium citing water and power concerns, with opposition described as growing and organized.", "water_impact": "unknown", "ai_evidence": "Reported as a Meta-linked pre-development data center in Beloit with no site-specific GPU cluster or AI workload deployment announced; one outlet characterizes the plan as AI-optimized but without confirmed hardware tenants.", "grid_impact": "high", "ai_class": "cloud-hyperscale", "community_pushback": "active-opposition", "water_note": "No gallons/day disclosed; reporting says a closed-loop cooling system could use about 50% less water than current designs and water/sewer studies are part of pre-development work.", "grid_note": "Local reporting indicates potential demand in the hundreds of MW; the site is in Alliant Energy territory, where numerous large-load data center proposals are being managed via utility programs and planning.", "citations": [{"title": "Citizens push back on possible data center in Town of Beloit", "url": "https://www.wuwm.com/citizens-push-back-on-possible-data-center-in-town-of-beloit"}, {"title": "In Rock County, data center opposition is growing ...", "url": "https://www.gazettextra.com/news/in-rock-county-data-center-opposition-is-growing-becoming-more-organized/article_135a5225-a4a8-45b2-924a-8707ad1202da.html"}, {"title": "Town of Beloit has pre-development agreement with ...", "url": "https://www.wpr.org/news/town-of-beloit-pre-development-agreement-develop-data-center"}, {"title": "Meta signs pre-development agreement for data center in ...", "url": "https://www.datacenterdynamics.com/en/news/meta-signs-pre-development-agreement-for-data-center-in-beloit-wisconsin/"}, {"title": "Meta Beloit Data Center | W B R Townline Rd & I-39 ALT", "url": "https://www.datacentermap.com/usa/wisconsin/beloit/meta-beloit/"}], "runId": "srun_c0e944bd89584b54a2527f44f68eb26e", "classifiedAt": "2026-07-02T22:55:56.722Z"}, "49": {"community_note": "Active public pushback is documented: Del. Shawn Fluharty, local officials, and residents held packed Warwood/Wheeling town halls over transparency and reduced local control under HB 2014; no lawsuit, injunction, or moratorium was found, and the project remained under discussion.", "water_impact": "low", "ai_evidence": "The operator markets GPU data centers designed for AI workloads, but local reporting says the Warwood project\u2019s primary purpose is manufacturing modular components for AI data centers, with no disclosed tenants or training clusters.", "grid_impact": "high", "ai_class": "ai-mixed", "community_pushback": "active-opposition", "water_note": "Officials said the plan is to draw river water for closed-loop cooling with no discharge to the river; no gallons/day figure or drought/aquifer concerns were reported.", "grid_note": "Public reporting describes a potential build-out to 100MW at the former Centre Foundry site; no public interconnection, transmission-upgrade, or rate-case filings were identified.", "citations": [{"title": "Residents Attend Packed Town Hall on Data Center", "url": "https://www.theintelligencer.net/news/top-headlines/2026/06/residents-attend-packed-town-hall-on-data-center/"}, {"title": "Talks of a potential data center in Warwood are raising ...", "url": "https://www.facebook.com/WTOV9/posts/talks-of-a-potential-data-center-in-warwood-are-raising-questions-about-hb-2014-/1526984736123970/"}, {"title": "Warwood data center plans shrink to 50MW; company says ...", "url": "https://wtov9.com/news/local/officials-say-revised-warwood-data-center-would-draw-river-water-no-discharge-or-rate-hikes-warwood-data-center-silicon-foundation-closed-loop-river-water-no-discharge-utility-rates-shawn-fluharty"}, {"title": "Silicon Foundation", "url": "https://silicon.foundation/"}, {"title": "After a Week of Data Center Discussion in the Ohio Valley ...", "url": "https://www.timesleaderonline.com/news/local-news/2026/06/after-a-week-of-data-center-discussion-in-the-ohio-valley-heres-what-we-know/"}], "runId": "srun_c0e944bd89584b54528aee365d33c9f8", "classifiedAt": "2026-07-02T22:55:58.313Z"}, "50": {"community_note": "Residents and local groups sought a 12\u2011month moratorium over water/power/land\u2011use concerns; the City Council rejected the moratorium and the Planning Commission later failed to endorse related zoning amendments.", "water_impact": "moderate", "ai_evidence": "Listed as an Azure facility in the West Central US region, but Microsoft\u2019s H100 GPUs are noted as available in East US2 and West Europe and model availability varies by region, with no public disclosure of Cheyenne\u2011specific GPU superclusters.", "grid_impact": "moderate", "ai_class": "cloud-hyperscale", "community_pushback": "active-opposition", "water_note": "Local officials report the Cheyenne data\u2011center fleet uses about 200 acre\u2011feet/year (~1.48% of city use), while Microsoft pledges to minimize and replenish its water use amid growing drought\u2011related scrutiny.", "grid_note": "Served under Black Hills Energy\u2019s Large Power Contract Service structure approved by state regulators, with ratepayer protections and extensive permitted backup generation (128 diesel units) to mitigate constraints.", "citations": [{"title": "Cheyenne City Council rejects data center moratorium", "url": "https://capcity.news/community/city/2026/05/27/cheyenne-city-council-rejects-data-center-moratorium/"}, {"title": "Microsoft presents data center expansion plans to the public", "url": "https://www.wyomingnews.com/news/local_news/microsoft-presents-data-center-expansion-plans-to-the-public/article_3707713e-3e24-41d0-9ba4-897adf85728b.html"}, {"title": "Microsoft's data center plans fail to get Planning ...", "url": "https://capcity.news/community/city/2026/06/05/microsofts-data-center-plans-fail-to-get-planning-commission-endorsement-monday/"}, {"title": "Amid growing concern, data center developers insist they ...", "url": "https://capcity.news/wyoming/2026/05/20/amid-growing-concern-data-center-developers-insist-they-wont-stress-wyoming-water/"}, {"title": "Microsoft announces intent to expand datacenter ...", "url": "https://news.microsoft.com/source/2026/04/14/microsoft-announces-intent-to-expand-datacenter-operations-in-cheyenne-accelerating-innovation-and-economic-growth/"}], "runId": "srun_c0e944bd89584b542da2482297f1d1ec", "classifiedAt": "2026-07-02T22:55:56.432Z"}} \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/public/data/datacenters.json b/typescript-recipes/parallel-datacenter-map/public/data/datacenters.json new file mode 100644 index 0000000..2872ab2 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/data/datacenters.json @@ -0,0 +1 @@ +[{"name": "GCI Anchorage Data Center", "operator": "GCI Communication", "owner": "GCI Communication", "address": "6831 Arctic Blvd, Anchorage, AK 99518", "city": "Anchorage", "state": "AK", "zip": "99518", "lat": 61.158818605805, "lng": -149.891996218477, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "the U.S. state of Alaska"}, {"name": "Digi Power X / USDC Columbiana", "operator": "Digi Power X / US Data Centers, Inc.", "owner": "Digi Power X / US Data Centers, Inc.", "address": "130 Industrial Pkwy", "city": "Columbiana", "state": "AL", "zip": "35051", "lat": 33.182787519671, "lng": -86.618481379029, "yearOnline": "unknown", "powerMw": 55, "sqft": 160000, "type": "wholesale", "status": "planned", "region": "the U.S. state of Alabama"}, {"name": "TierPoint Little Rock (LIT)", "operator": "TierPoint", "owner": "TierPoint", "address": "15707 Chenal Parkway", "city": "Little Rock", "state": "AR", "zip": "72211", "lat": 34.756540955216, "lng": -92.443521411254, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "the U.S. state of Arkansas"}, {"name": "Aligned PHX-01/02/03 Data Center", "operator": "Aligned Data Centers", "owner": "Aligned Data Centers", "address": "2500 W Union Hills Drive", "city": "Phoenix", "state": "AZ", "zip": "85027", "lat": 33.654769152551, "lng": -112.111874291006, "yearOnline": "2017", "powerMw": 180, "sqft": 550000, "type": "wholesale", "status": "operational", "region": "Phoenix & Mesa, AZ"}, {"name": "Equinix SV12x", "operator": "Equinix", "owner": "Equinix", "address": "123 Great Oaks Boulevard", "city": "San Jose", "state": "CA", "zip": "95119", "lat": 37.232666945954, "lng": -121.780270441917, "yearOnline": "unknown", "powerMw": 1.2, "sqft": 113000, "type": "hyperscale", "status": "operational", "region": "Silicon Valley / Santa Clara, CA"}, {"name": "Novva Colorado Springs", "operator": "Novva Data Centers", "owner": "Novva Data Centers", "address": "650 Sybilla Lane", "city": "Colorado Springs", "state": "CO", "zip": "80921", "lat": 39.0130562739, "lng": -104.816630431345, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "the U.S. state of Colorado"}, {"name": "CyrusOne Norwalk", "operator": "CyrusOne", "owner": "CyrusOne", "address": "6 Norden Place", "city": "Norwalk", "state": "CT", "zip": "06855", "lat": 41.111253980749, "lng": -73.397083848386, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "the U.S. state of Connecticut"}, {"name": "Cogent Washington DC 2", "operator": "Cogent Communications", "owner": "Cogent Communications", "address": "1050 Connecticut Ave NW", "city": "Washington", "state": "DC", "zip": "20036", "lat": 38.903130269959, "lng": -77.039740962038, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "Washington, D.C."}, {"name": "Starwood Digital Ventures Project Washington campus (planned 11-building campus)", "operator": "Starwood Digital Ventures", "owner": "New Castle Campus Development LLC", "address": "825 Governor Lea Road and River Road/Hamburg Road parcels", "city": "New Castle", "state": "DE", "zip": "19720", "lat": 39.597841022263, "lng": -75.630436103088, "yearOnline": "unknown", "powerMw": 1200, "sqft": 6000000, "type": "hyperscale", "status": "planned", "region": "the U.S. state of Delaware"}, {"name": "Iron Mountain MIA-1", "operator": "Iron Mountain", "owner": "Iron Mountain", "address": "2925 NW 120th Terrace", "city": "Miami", "state": "FL", "zip": "33167", "lat": 25.88415986431, "lng": -80.247555757503, "yearOnline": "2026", "powerMw": 16, "sqft": 150000, "type": "colocation", "status": "under-construction", "region": "Miami, FL"}, {"name": "DC BLOX Atlanta West (ATL1) Hyperscale Campus", "operator": "DC BLOX", "owner": "DC BLOX", "address": "1701 North River Road, Lithia Springs, GA 30122", "city": "Lithia Springs", "state": "GA", "zip": "30122", "lat": 33.769162, "lng": -84.558172, "yearOnline": "unknown", "powerMw": 200, "sqft": 1370000, "type": "hyperscale", "status": "under-construction", "region": "Atlanta, GA"}, {"name": "AlohaNAP / HAII1", "operator": "1547 Critical Systems Realty", "owner": "1547 Critical Systems Realty and Harrison Street", "address": "91-340 Farrington Hwy, Kapolei, HI 96707", "city": "Kapolei", "state": "HI", "zip": "96707", "lat": 21.338546015063, "lng": -158.09215611219, "yearOnline": "2015", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "the U.S. state of Hawaii"}, {"name": "CyrusOne OCB1 - Council Bluffs", "operator": "CyrusOne", "owner": "CyrusOne", "address": "4700 Gifford Rd.", "city": "Council Bluffs", "state": "IA", "zip": "51501", "lat": 41, "lng": -95, "yearOnline": "unknown", "powerMw": 18, "sqft": 216000, "type": "wholesale", "status": "operational", "region": "Omaha & Council Bluffs, NE/IA"}, {"name": "ValorC3 Boise 2 Data Center", "operator": "ValorC3 Data Centers", "owner": "BOISE 2 DC LLC", "address": "9601 W Emerald St", "city": "Boise", "state": "ID", "zip": "unknown", "lat": 43.609548051867, "lng": -116.301847913929, "yearOnline": "2027", "powerMw": 10, "sqft": 38000, "type": "colocation", "status": "under-construction", "region": "the U.S. state of Idaho"}, {"name": "Digital Realty ORD10 / 350 East Cermak", "operator": "Digital Realty", "owner": "Digital Realty", "address": "350 East Cermak Road", "city": "Chicago", "state": "IL", "zip": "60616", "lat": 41.853059324473, "lng": -87.618915286339, "yearOnline": "unknown", "powerMw": 19.5, "sqft": 1133000, "type": "colocation", "status": "operational", "region": "Chicago & Elk Grove Village, IL"}, {"name": "Google Fort Wayne Data Center / Project Zodiac", "operator": "Google", "owner": "Google", "address": "6015 Adams Center Road, Fort Wayne, IN 46816", "city": "Fort Wayne", "state": "IN", "zip": "46816", "lat": 41.031166722425, "lng": -85.057769713173, "yearOnline": "unknown", "powerMw": 100, "sqft": 360000, "type": "hyperscale", "status": "under-construction", "region": "the U.S. state of Indiana"}, {"name": "QTS Overland Park Data Center", "operator": "QTS", "owner": "QTS", "address": "12851 Foster Street", "city": "Overland Park", "state": "KS", "zip": "66213", "lat": 38.9, "lng": -94.648, "yearOnline": "unknown", "powerMw": 0, "sqft": 38000, "type": "colocation", "status": "operational", "region": "the U.S. state of Kansas"}, {"name": "CyrusOne CIN6", "operator": "CyrusOne", "owner": "CyrusOne", "address": "7190-7200 Industrial Road", "city": "Florence", "state": "KY", "zip": "41042", "lat": 38.9796476707, "lng": -84.615650864258, "yearOnline": "unknown", "powerMw": 9, "sqft": 140000, "type": "colocation", "status": "operational", "region": "the U.S. state of Kentucky"}, {"name": "Stack: Resilient Tech Park Data Center Campus", "operator": "STACK Infrastructure", "owner": "STACK Infrastructure; pre-development landowner: Franks Investment Company, L.L.C.", "address": "7340 Greenwood Road, Shreveport, LA", "city": "Shreveport", "state": "LA", "zip": "unknown", "lat": 32.447749255941, "lng": -93.903141251538, "yearOnline": "unknown", "powerMw": 0, "sqft": 2800000, "type": "hyperscale", "status": "planned", "region": "continue:Louisiana"}, {"name": "Westfield Data Center Campus (Servistar)", "operator": "Servistar Realties, LLC", "owner": "Servistar Realties, LLC", "address": "199 Servistar Industrial Way, Westfield, MA 01085", "city": "Westfield", "state": "MA", "zip": "01085", "lat": 42.1373, "lng": -72.7486, "yearOnline": "unknown", "powerMw": 300, "sqft": 2700000, "type": "hyperscale", "status": "planned", "region": "the U.S. state of Massachusetts"}, {"name": "Amazon AWS - 11550 Cronridge Drive", "operator": "Amazon AWS", "owner": "Amazon Data Services", "address": "11550 Cronridge Dr", "city": "Owings Mills", "state": "MD", "zip": "21117", "lat": 39.442324067374, "lng": -76.772513122656, "yearOnline": "unknown", "powerMw": 0, "sqft": 20000, "type": "hyperscale", "status": "operational", "region": "the U.S. state of Maryland"}, {"name": "MillCompute Bates Mill No. 3 AI Data Center", "operator": "MillCompute LLC", "owner": "Twin Cities LLC (Bill Johnson)", "address": "140 Mill St", "city": "Lewiston", "state": "ME", "zip": "04240", "lat": 44.0993, "lng": -70.2115, "yearOnline": "unknown", "powerMw": 24, "sqft": 85000, "type": "colocation", "status": "planned", "region": "continue:Maine"}, {"name": "IronGate Detroit / The Bunker", "operator": "IronGate", "owner": "IronGate", "address": "28201 Van Dyke Ave", "city": "Warren", "state": "MI", "zip": "unknown", "lat": 42.500119895795, "lng": -83.028159169274, "yearOnline": "unknown", "powerMw": 45, "sqft": 0, "type": "colocation", "status": "operational", "region": "the U.S. state of Michigan"}, {"name": "T5@Minneapolis / Cloud Capital Minneapolis CBD Data Center", "operator": "T5 Data Centers", "owner": "Cloud Capital / Arcapita", "address": "1001 3rd Avenue South", "city": "Minneapolis", "state": "MN", "zip": "unknown", "lat": 44.972138443777, "lng": -93.270543573613, "yearOnline": "unknown", "powerMw": 0, "sqft": 330000, "type": "colocation", "status": "operational", "region": "the U.S. state of Minnesota"}, {"name": "Lincoln Rackhouse Kansas City / Airworld Data Center", "operator": "Lincoln Rackhouse", "owner": "Lincoln Rackhouse", "address": "11155 N Airworld Dr", "city": "Kansas City", "state": "MO", "zip": "64153", "lat": 39.296061859166, "lng": -94.676003723893, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "wholesale", "status": "operational", "region": "the U.S. state of Missouri"}, {"name": "xAI MACROHARDRR", "operator": "xAI Corp", "owner": "xAI Corp", "address": "2400 Stateline Rd W", "city": "Southaven", "state": "MS", "zip": "38671", "lat": 34.991861641286, "lng": -90.034277800904, "yearOnline": "unknown", "powerMw": 2000, "sqft": 810000, "type": "hyperscale", "status": "planned", "region": "Nashville & Memphis, TN"}, {"name": "MIS1 - VisionNet-MSO Missoula Data Center PoP", "operator": "MOD Mission Critical", "owner": "Vision Net", "address": "110 East Broadway Street", "city": "Missoula", "state": "MT", "zip": "59802", "lat": 46.872109315328, "lng": -113.993787194905, "yearOnline": "unknown", "powerMw": 0, "sqft": 24000, "type": "colocation", "status": "operational", "region": "the U.S. state of Montana"}, {"name": "PowerHouse Charlotte (campus)", "operator": "PowerHouse Data Centers", "owner": "Town Lane / PowerHouse Data Centers JV", "address": "12899 Moores Chapel Road", "city": "Charlotte", "state": "NC", "zip": "unknown", "lat": 35.251900509669, "lng": -81.001455989579, "yearOnline": "unknown", "powerMw": 0, "sqft": 2500000, "type": "hyperscale", "status": "planned", "region": "Charlotte & Raleigh, NC"}, {"name": "Applied Digital ELN01", "operator": "Applied Digital Corporation", "owner": "Applied Digital Corporation", "address": "9685 87th Ave SE", "city": "Ellendale", "state": "ND", "zip": "58436", "lat": 46.021467386509, "lng": -98.568495453602, "yearOnline": "2025", "powerMw": 180, "sqft": 0, "type": "hyperscale", "status": "operational", "region": "the U.S. state of North Dakota"}, {"name": "Google Omaha - Building 1", "operator": "Google", "owner": "Google", "address": "11110 State St", "city": "Omaha", "state": "NE", "zip": "68142", "lat": 41, "lng": -96, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "hyperscale", "status": "operational", "region": "Omaha & Council Bluffs, NE/IA"}, {"name": "FirstLight Manchester NH", "operator": "FirstLight Fiber", "owner": "FirstLight Fiber", "address": "77 Sundial Avenue", "city": "Manchester", "state": "NH", "zip": "03103", "lat": 42.972437390684, "lng": -71.468658573139, "yearOnline": "unknown", "powerMw": 0, "sqft": 14400, "type": "colocation", "status": "operational", "region": "the U.S. state of New Hampshire"}, {"name": "H5 Data Centers Secaucus Data Center", "operator": "H5 Data Centers", "owner": "H5 Data Centers", "address": "200B Meadowlands Parkway", "city": "Secaucus", "state": "NJ", "zip": "07094", "lat": 40.784740861629, "lng": -74.076232047481, "yearOnline": "unknown", "powerMw": 0, "sqft": 38000, "type": "colocation", "status": "operational", "region": "Northern New Jersey (Secaucus/Piscataway)"}, {"name": "Oso Grande Technologies / OSO Secure Data Center Complex", "operator": "Oso Grande Technologies", "owner": "Oso Grande Technologies", "address": "725 6th Street NW", "city": "Albuquerque", "state": "NM", "zip": "87102", "lat": 35.092619630101, "lng": -106.652652769081, "yearOnline": "unknown", "powerMw": 0, "sqft": 10800, "type": "colocation", "status": "operational", "region": "the U.S. state of New Mexico"}, {"name": "Google Henderson Data Center 1", "operator": "Google", "owner": "Google", "address": "560 W Warm Springs Rd", "city": "Henderson", "state": "NV", "zip": "89011", "lat": 36.055559805179, "lng": -115.01029588897, "yearOnline": "2020", "powerMw": 0, "sqft": 0, "type": "hyperscale", "status": "operational", "region": "Reno / Las Vegas, NV"}, {"name": "Digital Realty JFK10 - 111 8th Avenue", "operator": "Digital Realty", "owner": "Digital Realty Trust", "address": "111 8th Avenue", "city": "New York", "state": "NY", "zip": "10011", "lat": 40.740907242657, "lng": -74.001767860726, "yearOnline": "unknown", "powerMw": 0, "sqft": 109600, "type": "colocation", "status": "operational", "region": "New York City, NY"}, {"name": "Cologix Johnstown COL7", "operator": "Cologix", "owner": "Cologix", "address": "12017 Duncan Plains Road", "city": "Johnstown", "state": "OH", "zip": "43031", "lat": 40.137177382505, "lng": -82.715470336644, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "under-construction", "region": "Columbus & New Albany, OH"}, {"name": "Cerebras Oklahoma", "operator": "Cerebras Systems", "owner": "Scale Datacenters", "address": "512 NW 62nd St", "city": "Oklahoma City", "state": "OK", "zip": "73118", "lat": 35.535878497483, "lng": -97.521559342582, "yearOnline": "2025", "powerMw": 10, "sqft": 82000, "type": "enterprise", "status": "operational", "region": "the U.S. state of Oklahoma"}, {"name": "STACK Infrastructure POR01A", "operator": "STACK Infrastructure", "owner": "STACK Infrastructure", "address": "3145 NE Brookwood Pkwy", "city": "Hillsboro", "state": "OR", "zip": "97124", "lat": 45.550862924301, "lng": -122.926418304057, "yearOnline": "unknown", "powerMw": 5, "sqft": 0, "type": "colocation", "status": "operational", "region": "Hillsboro / Portland, OR"}, {"name": "Bitfarms / Keel Panther Creek", "operator": "Bitfarms Ltd.", "owner": "Keel Infrastructure", "address": "4 Dennison Road", "city": "Nesquehoning", "state": "PA", "zip": "18240", "lat": 40.856464122006, "lng": -75.87635307384, "yearOnline": "unknown", "powerMw": 80, "sqft": 0, "type": "crypto", "status": "operational", "region": "the U.S. state of Pennsylvania"}, {"name": "Alpha3 Cloud Providence 1", "operator": "Alpha3 Cloud", "owner": "Alpha3 Cloud", "address": "935 Westminster Street", "city": "Providence", "state": "RI", "zip": "02903", "lat": 41.817340334901, "lng": -71.424018857549, "yearOnline": "unknown", "powerMw": 0, "sqft": 4000, "type": "colocation", "status": "operational", "region": "the U.S. state of Rhode Island"}, {"name": "QTS York County (Charlotte market)", "operator": "QTS", "owner": "QTS", "address": "Hands Mill Highway and Campbell Road", "city": "York County", "state": "SC", "zip": "unknown", "lat": 35.045903166789, "lng": -81.100198191398, "yearOnline": "unknown", "powerMw": 0, "sqft": 5300000, "type": "hyperscale", "status": "planned", "region": "Charlotte & Raleigh, NC"}, {"name": "TierPoint Sioux Falls - East Data Center", "operator": "TierPoint", "owner": "TierPoint", "address": "700 East 54th Street North", "city": "Sioux Falls", "state": "SD", "zip": "57104", "lat": 43.594735746141, "lng": -96.719263134733, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "the U.S. state of South Dakota"}, {"name": "Data Suites", "operator": "Data Suites", "owner": "Data Suites", "address": "1020 W College St", "city": "Murfreesboro", "state": "TN", "zip": "37129", "lat": 35.855518870227, "lng": -86.404830987399, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "colocation", "status": "operational", "region": "Nashville & Memphis, TN"}, {"name": "Aligned DFW-01", "operator": "Aligned", "owner": "Aligned", "address": "2800 Summit Ave", "city": "Plano", "state": "TX", "zip": "75074", "lat": 33.009776426561, "lng": -96.678415144762, "yearOnline": "unknown", "powerMw": 60, "sqft": 375000, "type": "colocation", "status": "operational", "region": "Dallas-Fort Worth, TX"}, {"name": "Aligned SLC-01", "operator": "Aligned Data Centers", "owner": "Aligned Data Centers", "address": "3333 W 9000 S", "city": "West Jordan", "state": "UT", "zip": "84088", "lat": 40.58767480405, "lng": -111.970219638996, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "wholesale", "status": "operational", "region": "Salt Lake City, UT"}, {"name": "Amazon AWS IAD23 / 43830 Devin Shafron Drive (Digital Realty Bldg F)", "operator": "Amazon AWS", "owner": "Digital Realty", "address": "43830 Devin Shafron Drive", "city": "Ashburn", "state": "VA", "zip": "20147", "lat": 39.003657426363, "lng": -77.485319865947, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "hyperscale", "status": "operational", "region": "Ashburn, VA (Loudoun County / Data Center Alley)"}, {"name": "FirstLight Burlington Data Center", "operator": "FirstLight Fiber", "owner": "FirstLight Fiber", "address": "45 Krupp Drive, Williston, VT 05495", "city": "Williston", "state": "VT", "zip": "05495", "lat": 44.45019, "lng": -73.12754, "yearOnline": "unknown", "powerMw": 0, "sqft": 20000, "type": "colocation", "status": "operational", "region": "the U.S. state of Vermont"}, {"name": "Digital Fortress North Seattle / ByteGrid Seattle", "operator": "Digital Fortress", "owner": "Digital Fortress", "address": "4200 194th St SW", "city": "Lynnwood", "state": "WA", "zip": "98036", "lat": 47.822845502821, "lng": -122.289277406248, "yearOnline": "unknown", "powerMw": 6, "sqft": 0, "type": "colocation", "status": "operational", "region": "Seattle, WA"}, {"name": "Meta Beloit", "operator": "Meta", "owner": "Meta", "address": "W B R Townline Rd & I-39 ALT", "city": "Beloit", "state": "WI", "zip": "unknown", "lat": 42.583924104735, "lng": -88.981477280297, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "hyperscale", "status": "planned", "region": "the U.S. state of Wisconsin"}, {"name": "Silicon Foundation West Virginia", "operator": "Silicon Foundation Energy Inc.", "owner": "Silicon Foundation Energy Inc.", "address": "74 Warwood Avenue, Wheeling, WV 26003", "city": "Wheeling", "state": "WV", "zip": "26003", "lat": 40.101341877059, "lng": -80.70300317123, "yearOnline": "unknown", "powerMw": 100, "sqft": 60000, "type": "hyperscale", "status": "planned", "region": "continue:West Virginia"}, {"name": "Microsoft CYS - Building 1", "operator": "Microsoft", "owner": "Microsoft", "address": "644 Logistics Dr, Cheyenne, WY 82009", "city": "Cheyenne", "state": "WY", "zip": "82009", "lat": 41.125602120971, "lng": -104.896442948154, "yearOnline": "unknown", "powerMw": 0, "sqft": 0, "type": "hyperscale", "status": "operational", "region": "the U.S. state of Wyoming"}] \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/public/data/enrichments-compact.json b/typescript-recipes/parallel-datacenter-map/public/data/enrichments-compact.json new file mode 100644 index 0000000..76cd2e4 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/data/enrichments-compact.json @@ -0,0 +1 @@ +{"0": {"description": "GCI Anchorage Data Center is an operational colocation facility at 6831 Arctic Blvd in Anchorage operated by GCI Communication, marketed as Alaska\u2019s largest and most advanced with 99.9999% uptime. GCI cites a 10,000-square-foot facility.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 10000, "year_online": "unknown", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "GCI Anchorage Data Center", "verified_operator": "GCI Communication", "verified_owner": "GCI (via affiliate entity; exact real-estate holding LLC not conclusively determinable)", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "GCI", "num_buildings": 0, "campus_acres": 0, "utility_provider": "Chugach Electric Association", "tax_incentives": "", "natural_hazard_zone": "FEMA Flood Zone B and X; high seismic hazard region (Anchorage, Alaska)"}, "1": {"description": "Digi Power X / US Data Centers, Inc. is developing a 55 MW AI/HPC colocation campus at the former Grede Foundry site at 130 Industrial Pkwy in Columbiana, Alabama.", "verified_status": "under-construction", "power_capacity_mw": 55, "total_sqft": 0, "year_online": "2026 initial phase; 2027 full deployment", "construction_update": "Site development underway; Phase 1 (15 MW) targeted Ready-for-Service December 2026, with Phase 2 completing the 40 MW deployment by end of Q1 2027.", "recent_news": "Cerebras signed for 40 MW at the Columbiana campus under a 10-year deal valued around $1.1B (early May 2026); in February 2026, the city passed new zoning restrictions for data centers.", "notable_tenants": "Cerebras Systems \u2014 anchor customer for 40 MW under a 10-year agreement valued at about $1.1B.", "verified_name": "USDC Columbiana (also known as Digi Power X: Columbiana / Columbiana Data Center)", "verified_operator": "Digi Power X Inc.", "verified_owner": "Digi Power X Inc.", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 0, "campus_acres": 0, "utility_provider": "", "tax_incentives": "No active local abatement; the Council unanimously rejected initiating a tax\u2011abatement process for the project.", "natural_hazard_zone": ""}, "2": {"description": "TierPoint Little Rock (LIT) is an operational TierPoint colocation data center at 15707 Chenal Parkway, Little Rock, Arkansas, with about 30,000 sq ft and roughly 5 MW of capacity; it opened in 2012 (originally by Windstream).", "verified_status": "operational", "power_capacity_mw": 5, "total_sqft": 30000, "year_online": "2012", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "TierPoint Little Rock", "verified_operator": "TierPoint", "verified_owner": "Argo Infrastructure Partners (majority investor in TierPoint; Apollo Global Management acquired Argo in 2025)", "cooling_type": "unknown", "tier_level": "Tier III Equivalent", "fiber_providers": "", "num_buildings": 1, "campus_acres": 0, "utility_provider": "Entergy Arkansas", "tax_incentives": "Arkansas Act 548 of 2025 \u2014 expanded sales and use tax exemption for qualifying data centers.", "natural_hazard_zone": ""}, "3": {"description": "Aligned PHX-01/02/03 is Aligned Data Centers\u2019 operational wholesale/hyperscale campus at 2500 W Union Hills Drive in Phoenix, AZ. The 55-acre campus, designed to Tier III standards, opened in 2017 and comprises roughly 550,000 sq ft across three facilities.", "verified_status": "operational", "power_capacity_mw": 180, "total_sqft": 550000, "year_online": "2017", "construction_update": "Mar 22, 2022: Aligned announced PHX-05, a new hyperscale data center planned on its flagship Phoenix campus; no newer PHX-01/02/03-specific construction milestones were found.", "recent_news": "", "notable_tenants": "", "verified_name": "Aligned PHX-01/02/03 Data Center", "verified_operator": "Aligned Data Centers", "verified_owner": "", "cooling_type": "hybrid", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 3, "campus_acres": 55, "utility_provider": "Arizona Public Service (APS)", "tax_incentives": "Arizona Computer Data Center (CDC) Program provides sales/use tax exemptions; Aligned Phoenix clients can leverage a long-term (up to 20-year) sales-tax exemption on qualifying data center equipment.", "natural_hazard_zone": "low risk"}, "4": {"description": "Equinix SV12x is a hyperscale xScale data center operated by Equinix on the Great Oaks campus at 123 Great Oaks Blvd in San Jose. It is the company\u2019s first U.S. xScale project (via a JV with PGIM Real Estate) and launched in January 2026.", "verified_status": "operational", "power_capacity_mw": 28.8, "total_sqft": 82000, "year_online": "2026", "construction_update": "", "recent_news": "Jan 22, 2026: DCD reported Equinix launched/energized the SV12x data center at the Great Oaks campus in San Jose.", "notable_tenants": "", "verified_name": "Equinix SV12x", "verified_operator": "Equinix", "verified_owner": "Equinix / PGIM Real Estate Joint Venture (PGIM 80%, Equinix 20%)", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 3, "campus_acres": 18, "utility_provider": "", "tax_incentives": "", "natural_hazard_zone": "FEMA Flood Zone D; IBX elevation above 500-year base flood elevation"}, "5": {"description": "Novva Colorado Springs is an operational Novva Data Centers colocation facility at 650 Sybilla Lane in Colorado Springs, CO. It is noted as the city\u2019s first large-scale multi-tenant colocation data center.", "verified_status": "operational", "power_capacity_mw": 40, "total_sqft": 122000, "year_online": "2005", "construction_update": "Aug 31, 2021: Novva announced acquisition of the campus and planned expansion by an additional 250,000 sq ft and up to 30 MW; no newer construction milestone identified.", "recent_news": "", "notable_tenants": "Progressive (former owner/occupant); unnamed anchor tenant announced by Novva in 2021.", "verified_name": "Novva Colorado Springs", "verified_operator": "Novva Data Centers", "verified_owner": "Novva Data Centers", "cooling_type": "hybrid", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 68, "utility_provider": "Colorado Springs Utilities", "tax_incentives": "", "natural_hazard_zone": "FEMA Flood Zone B/X (moderate); community wildfire risk: very high"}, "6": {"description": "CyrusOne Norwalk (NYM5) is an operational, carrier\u2011neutral colocation data center operated by CyrusOne at 6 Norden Place in Norwalk, Connecticut, offering up to 16 MW of power and 30,000 sq ft of work\u2011area recovery space.", "verified_status": "operational", "power_capacity_mw": 16, "total_sqft": 168000, "year_online": "2014", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "CyrusOne NYM5 - Norwalk", "verified_operator": "CyrusOne", "verified_owner": "Mapletree Industrial Trust", "cooling_type": "air-cooled", "tier_level": "", "fiber_providers": "carrier-neutral; Cogent Communications; NexGen Networks", "num_buildings": 1, "campus_acres": 0, "utility_provider": "", "tax_incentives": "", "natural_hazard_zone": "Building and critical equipment above the 500-year flood zone"}, "7": {"description": "Cogent Washington DC 2 is a Cogent Communications colocation data center at 1050 Connecticut Ave NW, Washington, DC 20036, offering Internet, VPN, Transport, and Colocation services. The site has 16,763 sq ft with 42U cabinets and private cages and carrier connectivity.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 16763, "year_online": "unknown", "construction_update": "", "recent_news": "On May 26, 2026, Cogent announced a definitive agreement to sell 10 data center facilities to an entity sponsored by I Squared Capital for $225 million; no Washington DC 2\u2013specific update was announced.", "notable_tenants": "", "verified_name": "Cogent Data Center - Washington, DC 2", "verified_operator": "Cogent Communications", "verified_owner": "Lerner Enterprises and The Tower Companies", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "Cogent, CenturyLink/Level 3, Zayo, ICC, FiberLight", "num_buildings": 1, "campus_acres": 0, "utility_provider": "Pepco (Potomac Electric Power Company)", "tax_incentives": "District of Columbia: No incentive.", "natural_hazard_zone": "FEMA Zone X (minimal flood risk)"}, "8": {"description": "Project Washington is a proposed multi-building hyperscale data center campus in New Castle County, Delaware, led by Starwood Digital Ventures, with 11 two\u2011story data center buildings along Governor Lea Road and Hamburg/River Road parcels.", "verified_status": "planned", "power_capacity_mw": 1200, "total_sqft": 6000000, "year_online": "unknown", "construction_update": "As of June 2026, no construction start is verified; New Castle County lists the North (2025-0346-S) and South (2025-0347-S) campuses as Pre\u2011Exploratory Major Land Development Plans, and DNREC issued a Coastal Zone status decision denying the project.", "recent_news": "On March 26, 2026, Delaware\u2019s Coastal Zone Industrial Control Board affirmed DNREC\u2019s decision to prohibit the Project Washington data center in the Coastal Zone; Starwood was likely to appeal to Superior Court.", "notable_tenants": "", "verified_name": "Project Washington", "verified_operator": "Starwood Digital Ventures", "verified_owner": "New Castle Campus Development LLC", "cooling_type": "air-cooled", "tier_level": "", "fiber_providers": "", "num_buildings": 11, "campus_acres": 580, "utility_provider": "Delmarva Power & Light", "tax_incentives": "None identified", "natural_hazard_zone": "FEMA Flood Zone AE"}, "9": {"description": "Iron Mountain MIA-1 is Iron Mountain\u2019s purpose-built, multi-tenant colocation data center at 2925 NW 120th Terrace in Miami, designed as an AI/GPU\u2011ready facility with 150,000 sq ft and up to 16 MW of customer IT load (26 MVA redundant operational power), targeted for 2026 completion.", "verified_status": "under-construction", "power_capacity_mw": 16, "total_sqft": 150000, "year_online": "2026", "construction_update": "Feb 27, 2025: Groundbreaking for MIA-1. Aug 8, 2025: Structure topped out.", "recent_news": "Local coverage in April\u2013May 2026 reported resident opposition/concerns about the MIA-1 project in Westview, including issues around notification, noise, air quality, generators, and infrastructure impacts.", "notable_tenants": "", "verified_name": "Iron Mountain MIA-1", "verified_operator": "Iron Mountain Data Centers", "verified_owner": "Iron Mountain Incorporated (NYSE: IRM)", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 1, "campus_acres": 3.4, "utility_provider": "", "tax_incentives": "Florida\u2019s data center sales tax exemption excludes facilities under 100 MW IT load effective Aug 1, 2025; at 16 MW, MIA-1 does not qualify. Florida also requires at least $150M cumulative capital investment.", "natural_hazard_zone": "Hurricane-prone region; ZIP 33167 has minor flood risk over the next 30 years."}, "10": {"description": "DC BLOX Atlanta West (ATL1) is a hyperscale-ready data center campus operated by DC BLOX at 1701 North River Road in Lithia Springs/Douglas County, Georgia, designed for large-scale hyperscale deployments.", "verified_status": "under-construction", "power_capacity_mw": 200, "total_sqft": 1370000, "year_online": "unknown", "construction_update": "Aug 14, 2025 \u2014 DC BLOX closed a $1.15 billion green-loan financing for construction of the Douglas County (Atlanta West) hyperscale campus.", "recent_news": "", "notable_tenants": "", "verified_name": "DC BLOX Atlanta West (ATL1) Hyperscale Data Center Campus", "verified_operator": "DC BLOX", "verified_owner": "DCB Atlanta West, LLC", "cooling_type": "air-cooled", "tier_level": "Tier III basis of design", "fiber_providers": "Carrier\u2011neutral via DC BLOX dark fiber; direct dark\u2011fiber connections to 55/56 Marietta and 180 Peachtree in Atlanta, plus DC BLOX dark fiber to the Myrtle Beach CLS.", "num_buildings": 3, "campus_acres": 100, "utility_provider": "GreyStone Power", "tax_incentives": "Robust tax incentives coordinated by Elevate Douglas; local approvals include an amended tax incentive agreement for DCB Atlanta West, LLC and reporting of approximately $98M in incentives over 11 years.", "natural_hazard_zone": "FEMA flood-zone designation not confirmed; regional review emphasizes flood-damage-prevention and stream/erosion controls. Facility designed with hardened construction (e.g., 150 mph wind rating)."}, "11": {"description": "AlohaNAP (HAII1) is an operational, carrier-neutral colocation and interconnection data center at 91-340 Farrington Hwy in Kapolei, operated by 1547 Critical Systems Realty and co-owned with Harrison Street. It is notable for its resilient Oahu siting (160 feet above sea level, 2 miles inland) and for hosting an AWS Direct Connect site.", "verified_status": "operational", "power_capacity_mw": 1.2, "total_sqft": 10200, "year_online": "2015", "construction_update": "Oct 2024: Phase 1 expansion announced to begin immediately. Target after Phase 1: 22,800 sq ft and 2.7 MW total. Feb 25, 2026: operator states a 9,000 sq ft, 1.5 MW expansion is underway, set to double capacity.", "recent_news": "Feb 25, 2026: Operator video states a 9,000 sq ft, 1.5 MW expansion is underway and set to double capacity.", "notable_tenants": "No anchor tenant or major customer publicly disclosed. Publicly named on-site connectivity includes AWS Direct Connect at AlohaNAP.", "verified_name": "AlohaNAP / HAII1", "verified_operator": "fifteenfortyseven Critical Systems Realty (1547)", "verified_owner": "Harrison Street and fifteenfortyseven Critical Systems Realty (1547)", "cooling_type": "unknown", "tier_level": "Tier III (design standard; no Uptime certification cited)", "fiber_providers": "carrier-neutral; AWS Direct Connect node; connections to global and local fiber", "num_buildings": 0, "campus_acres": 0, "utility_provider": "", "tax_incentives": "", "natural_hazard_zone": "Outside flood and tsunami zones; inland and elevated (~2 miles inland, ~160 ft ASL). Regional hurricane/seismic exposure persists."}, "12": {"description": "CyrusOne OCB1 is an operational wholesale colocation data center operated by CyrusOne at 4700 Gifford Rd., Council Bluffs, Iowa, totaling 216,000 sq ft (about 120,000 sq ft of raised floor) with 18 MW of total IT capacity. The site is noted as being powered by 100% renewable electricity.", "verified_status": "operational", "power_capacity_mw": 18, "total_sqft": 216000, "year_online": "2020", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "CyrusOne OCB1 - Council Bluffs", "verified_operator": "CyrusOne", "verified_owner": "CyrusOne Inc. (privately owned by funds managed by KKR and Global Infrastructure Partners; asset-level deed owner not publicly disclosed)", "cooling_type": "air-cooled", "tier_level": "", "fiber_providers": "carrier-neutral; CyrusOne National IX / various carriers and providers", "num_buildings": 1, "campus_acres": 0, "utility_provider": "MidAmerican Energy", "tax_incentives": "No facility-specific award verified. Iowa data center sales/use tax exemptions exist for qualifying large projects; Council Bluffs offers TIF/Urban Renewal programs, but OCB1 qualification not confirmed.", "natural_hazard_zone": "FEMA Flood Zone X (protected by levee); residual Missouri River flood exposure highlighted by June 2024 voluntary evacuations covering the Gifford Road area"}, "13": {"description": "ValorC3 Boise 2 is a 10MW, carrier-neutral colocation/hyperscale data center being developed by ValorC3 Data Centers at 9601 W Emerald St in Boise, Idaho, with first-phase completion targeted for 2027. The initial building is about 37,827\u201338,000 square feet, and a preliminary application seeks roughly 31,000 additional square feet.", "verified_status": "under-construction", "power_capacity_mw": 10, "total_sqft": 37827, "year_online": "2027", "construction_update": "Apr 29\u201330, 2026: Credit facility closed with Apterra to fund continued development. Mar 26, 2026: Local report of City approval for ~38,000 SF at 9601 W Emerald St and a preliminary application to add ~31,000 SF. Jul 22, 2025: Building-permit report lists work at 9601 W Emerald St with a $20,759,339 permit value.", "recent_news": "Apr 29\u201330, 2026: ValorC3 closed a credit facility with Apterra Infrastructure Capital to fund continued development of its anchored Boise hyperscale campus; industry coverage notes the 10MW project is leased to a Fortune 50 tech company.", "notable_tenants": "", "verified_name": "ValorC3 Boise 2 Data Center", "verified_operator": "ValorC3 Data Centers", "verified_owner": "BOISE 2 DC LLC", "cooling_type": "hybrid", "tier_level": "Concurrently maintainable (Tier III equivalent design)", "fiber_providers": "Carrier-neutral; CenturyLink, Zayo, Syringa, Level3, Cogent, Lumen, Comcast, Megaport", "num_buildings": 2, "campus_acres": 3.64, "utility_provider": "Idaho Power", "tax_incentives": "Idaho data center sales tax exemption on server equipment and construction materials (Idaho Code \u00a7 63-3622TT)", "natural_hazard_zone": "Earthquake risk (Idaho ranked fifth); flood risk likely minimal (FEMA Zone X \u2013 not confirmed)"}, "14": {"description": "Digital Realty ORD10 at 350 East Cermak Road is an operational, carrier\u2011hotel/colocation facility in Chicago\u2019s historic Lakeside Technology Center, operated by Digital Realty and widely regarded as the Midwest\u2019s most interconnected multi\u2011tenant data center with a 1,133,000 ft\u00b2 building footprint.", "verified_status": "operational", "power_capacity_mw": 109, "total_sqft": 1133000, "year_online": "1999", "construction_update": "", "recent_news": "", "notable_tenants": "No publicly disclosed anchor tenant. The building hosts an extensive interconnection ecosystem; Equinix CH1 operates in the same building (5th floor), and Hivelocity\u2019s colocation business at 350 E. Cermak was acquired by Digital Realty in 2025.", "verified_name": "Digital Realty ORD10 / 350 East Cermak (Lakeside Technology Center)", "verified_operator": "Digital Realty", "verified_owner": "Digital Realty Trust, Inc.", "cooling_type": "chilled water", "tier_level": "", "fiber_providers": "carrier-neutral; 70+ network providers (e.g., AT&T, Lumen, Verizon, Zayo, Cogent, Arelion, GTT, NTT, PacketFabric, Tata, Comcast, etc.)", "num_buildings": 1, "campus_acres": 0, "utility_provider": "", "tax_incentives": "Illinois Data Center Investment Program: state/local sales & use tax exemptions for qualifying data centers (certificate-based, multi-year).", "natural_hazard_zone": "Above 500-year FEMA base flood elevation; low seismic risk"}, "15": {"description": "Google Fort Wayne Data Center (formerly Project Zodiac) is a Google-operated hyperscale campus at/near 6015 Adams Center Road in southeast Fort Wayne. The site broke ground in April 2024 and the first phase was operational by December 2025, with additional phases planned.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 0, "year_online": "2025", "construction_update": "IDEM issued a March 13, 2026 public notice for Google Data Center \u2013 Fort Wayne (Project Zodiac) Phase 3 permitting; local reporting says construction of additional buildings is planned to begin in early 2027 with mass excavation continuing thereafter.", "recent_news": "In March 2026, Indiana\u2019s environmental agency issued a public notice for Project Zodiac Phase 3 permitting, and on June 15, 2026, local news reported the city\u2019s community development director said Google was in full compliance with its taxpayer agreement amid council oversight.", "notable_tenants": "", "verified_name": "Google Fort Wayne Data Center", "verified_operator": "Google", "verified_owner": "Hatchworks LLC", "cooling_type": "evaporative", "tier_level": "", "fiber_providers": "", "num_buildings": 12, "campus_acres": 858, "utility_provider": "Indiana Michigan Power (I&M)", "tax_incentives": "10-year, 50% real property tax abatement on each building constructed on the campus.", "natural_hazard_zone": "low risk"}, "16": {"description": "QTS Overland Park Data Center is a small, operational colocation facility operated by QTS at 12851 Foster Street in Overland Park, Kansas; third\u2011party listings note it has served as QTS\u2019s corporate headquarters and provide basic specs for the site.", "verified_status": "operational", "power_capacity_mw": 0.18, "total_sqft": 33000, "year_online": "2003", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "QTS Overland Park 1 DC1", "verified_operator": "QTS Data Centers", "verified_owner": "Funds managed by Blackstone (Blackstone Infrastructure Partners and Blackstone Real Estate Income Trust) via QTS", "cooling_type": "air-cooled", "tier_level": "", "fiber_providers": "", "num_buildings": 1, "campus_acres": 0, "utility_provider": "Evergy", "tax_incentives": "", "natural_hazard_zone": "FEMA Flood Zone B and X (moderate flood hazard)"}, "17": {"description": "CyrusOne CIN6 is an operational CyrusOne colocation data center at 7190\u20137200 Industrial Road in Florence, Kentucky (Cincinnati area), featuring a 143,000\u2011sq\u2011ft facility with about 55,000 sq ft of white space and designed for production colocation, backup/recovery, and business continuity.", "verified_status": "operational", "power_capacity_mw": 4, "total_sqft": 143000, "year_online": "unknown", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "CyrusOne CIN6 (Florence, KY)", "verified_operator": "CyrusOne", "verified_owner": "CyrusOne, LLC (ultimately owned by funds managed by KKR and Global Infrastructure Partners)", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 25.79, "utility_provider": "Duke Energy Kentucky", "tax_incentives": "", "natural_hazard_zone": "FEMA Flood Zone B and X (moderate flood hazard)"}, "18": {"description": "STACK Infrastructure\u2019s Resilient Tech Park campus in west Shreveport (7340 Greenwood Road) is a planned hyperscale data center for Amazon Web Services, part of Amazon\u2019s $12 billion Louisiana expansion. Local approvals and reporting describe a multi\u2011building campus totaling about 2.8 million sq ft.", "verified_status": "planned", "power_capacity_mw": 0, "total_sqft": 2800000, "year_online": "unknown", "construction_update": "SUP approved Dec 2025; program announced Feb 2026; permit challenge dismissed Apr 2026. No public confirmation of vertical construction start.", "recent_news": "Apr 20\u201321, 2026: A Caddo Parish judge dismissed a lawsuit challenging the special-use permit for the Resilient Technology Park data center, clearing the path for the project.", "notable_tenants": "Amazon Web Services (AWS)", "verified_name": "Stack: Resilient Tech Park Data Center Campus", "verified_operator": "STACK Infrastructure", "verified_owner": "STACK Infrastructure; pre-development landowner: Franks Investment Company, L.L.C.", "cooling_type": "hybrid", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 0, "utility_provider": "SWEPCO (Southwestern Electric Power Company / AEP)", "tax_incentives": "Louisiana High Impact Jobs Program; Louisiana Data Center Sales Tax Exemption Program.", "natural_hazard_zone": ""}, "19": {"description": "Westfield Data Center Campus is a proposed hyperscale data center development by Servistar Realties, LLC at 199 Servistar Industrial Way in Westfield, MA, planned as 10 buildings totaling about 2.7 million sq ft and positioned as a multibillion\u2011dollar project.", "verified_status": "planned", "power_capacity_mw": 0, "total_sqft": 2700000, "year_online": "unknown", "construction_update": "June 15, 2026: City of Westfield reported receipt of a technical fact sheet (water, energy, cooling, and electrical-service plans) for the proposed campus and began mayoral/administrative review; no verified building construction start announced.", "recent_news": "June 2026: The Mayor of Westfield began reviewing updated technical information for the proposed Servistar campus as project backers sought more time and further city review.", "notable_tenants": "", "verified_name": "Westfield Data Center Campus", "verified_operator": "Servistar Realties, LLC", "verified_owner": "Servistar Realties, LLC", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 10, "campus_acres": 35.15, "utility_provider": "Eversource", "tax_incentives": "MGL Chapter 121A/PILOT structure (reported ~$360M over 40 years) and state-level data center tax breaks/sales-and-use tax relief enabling the project.", "natural_hazard_zone": ""}, "20": {"description": "Amazon Data Services acquired the nine\u2011acre property at 11550 Cronridge Dr, Owings Mills, MD, in 2026; the site hosts T. Rowe Price\u2019s Technology Center and an office building of about 111,000 sq ft, with occupancy continuing under a sale\u2011leaseback.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 111000, "year_online": "1996", "construction_update": "No active construction or expansion announced following the April 8, 2026 sale.", "recent_news": "Amazon Data Services purchased the 11550 Cronridge Dr property for about $15.2M; the sale closed April 8, 2026, and was widely reported in early May.", "notable_tenants": "T. Rowe Price Group (tenant under the 2026 sale\u2011leaseback); no other anchor tenants publicly disclosed.", "verified_name": "T. Rowe Price Technology Center (11550 Cronridge Drive)", "verified_operator": "T. Rowe Price", "verified_owner": "Amazon Data Services", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 1, "campus_acres": 9.32, "utility_provider": "Baltimore Gas and Electric (BGE)", "tax_incentives": "", "natural_hazard_zone": ""}, "21": {"description": "A proposed AI data and technology center by MillCompute in the historic Bates Mill No. 3 (about 85,000 sq ft on the first two floors) with a 24 MW first phase was unanimously rejected by the Lewiston City Council on Dec 16, 2025.", "verified_status": "planned", "power_capacity_mw": 24, "total_sqft": 85000, "year_online": "unknown", "construction_update": "No construction; the proposal was unanimously rejected by the city council on Dec 16, 2025.", "recent_news": "An April 6, 2026 investigative report documented how the proposal unraveled and was rejected by the city council.", "notable_tenants": "", "verified_name": "MillCompute Bates Mill No. 3 AI Data Center", "verified_operator": "MillCompute LLC", "verified_owner": "Twin Cities LLC (Bill Johnson)", "cooling_type": "unknown", "tier_level": "Tier III (proposed)", "fiber_providers": "", "num_buildings": 1, "campus_acres": 0, "utility_provider": "", "tax_incentives": "Proposed: approximately $3 million per year for 20 years; not enacted after the council\u2019s rejection.", "natural_hazard_zone": "unknown"}, "22": {"description": "IronGate Detroit \u201cThe Bunker\u201d is IronGate Data Centers\u2019 Detroit\u2011market colocation/AI facility at 28201 Van Dyke Ave in Warren, Michigan, marketed around a 45 MW on\u2011site utility/substation capacity with modular, contract\u2011driven builds. Listings indicate it opens roughly six months from contract rather than being fully live.", "verified_status": "planned", "power_capacity_mw": 45, "total_sqft": 1150792, "year_online": "unknown", "construction_update": "As of June 2026, marketplaces describe contract\u2011driven deployment: opening approximately six months after contract, with modular buildout and potential expansion up to 65 MW.", "recent_news": "", "notable_tenants": "", "verified_name": "IronGate: Detroit, The Bunker", "verified_operator": "IronGate Data Centers", "verified_owner": "", "cooling_type": "liquid cooling", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 0, "campus_acres": 53.17, "utility_provider": "DTE Energy", "tax_incentives": "Michigan Enterprise Data Center Sales & Use Tax Exemption \u2014 eliminates 6% sales and use tax on eligible data center construction and equipment purchases; extended through December 31, 2050 for qualified data centers.", "natural_hazard_zone": "FEMA Flood Zone X (area of moderate flood hazard)"}, "23": {"description": "Downtown Minneapolis colocation/AI-ready data center at 1001 3rd Ave S, owned by a Cloud Capital\u2013Arcapita JV (acquired Jan 2026) and formerly marketed as T5@Minneapolis; the building is roughly 500,000 sq ft gross, with some older listings showing about 330,000 sq ft.", "verified_status": "operational", "power_capacity_mw": 21, "total_sqft": 500000, "year_online": "unknown", "construction_update": "Jan 2026: Planned expansion of the Minneapolis facility by 10MW (from 21MW to ~31MW).", "recent_news": "Jan 2026: Cloud Capital and Arcapita acquired the Minneapolis data center and outlined a 10MW expansion plan; May 2026: Bloomberg reported Core42 (G42) took a 20MW lease at 1001 Third Ave S; Feb 2026: local press reported a $235M sale tied to the site.", "notable_tenants": "Core42 (20 MW anchor); Cogent Communications (tenant since 2021)", "verified_name": "T5@Minneapolis (Cloud Capital: Minneapolis CBD Data Center)", "verified_operator": "T5 Data Centers", "verified_owner": "Cloud Capital / Arcapita joint venture (legal entity: CLAR MINNEAPOLIS MN LLC)", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral; on-net examples include Zayo and Cogent", "num_buildings": 1, "campus_acres": 2.5, "utility_provider": "Xcel Energy", "tax_incentives": "Minnesota Qualified Data Center sales and use tax exemption (statewide program); no facility-specific abatement identified.", "natural_hazard_zone": "low risk"}, "24": {"description": "Two-building, 259,111-sq-ft former Bank of America data center campus at 11155 N Airworld Dr in Kansas City, operated by Lincoln Rackhouse and now being redeveloped with Lambda as an AI factory, with an initial 24 MW deployment and potential to exceed 100 MW.", "verified_status": "under-construction", "power_capacity_mw": 24, "total_sqft": 259111, "year_online": "2026", "construction_update": "2025-10-29: Missouri DNR issued Airworld Data Center\u2013Kansas City de minimis construction permit No. 102025-010. 2026-05-30: Port KC delayed a vote on incentives for \u201cProject Blitz.\u201d 2026-06-03: Developer withdrew its Port KC bond application.", "recent_news": "In late May\u2013early June 2026, Port KC delayed action on incentives for the Project Blitz/Lambda AI data center and the developer withdrew its Port KC bond application amid community opposition.", "notable_tenants": "Lambda Inc.", "verified_name": "Lincoln Rackhouse KC (Airworld) Data Center", "verified_operator": "Lambda, Inc.", "verified_owner": "Lincoln Property Company and Principal Real Estate Investors (joint venture)", "cooling_type": "chilled water", "tier_level": "Not Uptime-certified; Tier III-like (distributed/iso-redundant) design", "fiber_providers": "Carrier-neutral; providers include Lumen (Level 3), Unite Private Networks, and Bluebird Networks.", "num_buildings": 2, "campus_acres": 38, "utility_provider": "Evergy (formerly KCP&L)", "tax_incentives": "Missouri Data Center Sales Tax Exemption Program: state and local sales/use tax exemptions on construction/rehab materials, machinery/equipment purchases, and utility costs for qualifying data centers.", "natural_hazard_zone": "Outside FEMA 500-year floodplain; moderate tornado exposure; low seismic risk."}, "25": {"description": "MACROHARDRR is xAI Corp\u2019s AI data center project in Southaven, Mississippi, where xAI has purchased and is retrofitting a building for new data center operations, to be known as MACROHARDRR.", "verified_status": "under-construction", "power_capacity_mw": 2000, "total_sqft": 810258, "year_online": "2026", "construction_update": "Jan 8, 2026: State announced xAI\u2019s investment and retrofit plan in Southaven. Mar 10, 2026: Mississippi regulators approved an air permit for 41 gas turbines to power xAI\u2019s operations in Southaven.", "recent_news": "May 6, 2026: NAACP and partners filed for emergency court action alleging illegal air pollution from xAI\u2019s Southaven gas-turbine power plant tied to the data center.", "notable_tenants": "", "verified_name": "xAI MACROHARDRR", "verified_operator": "xAI Corp", "verified_owner": "xAI Corp", "cooling_type": "evaporative", "tier_level": "", "fiber_providers": "", "num_buildings": 1, "campus_acres": 48.6, "utility_provider": "Entergy Mississippi", "tax_incentives": "Mississippi Data Center Incentive (sales and use tax exemption for computing and equipment software). 2024 Mississippi data center incentive law exemptions for corporate income and franchise taxes for qualifying companies.", "natural_hazard_zone": "New Madrid Seismic Zone exposure; local FEMA flood zones A/AE"}, "26": {"description": "MIS1 - VisionNet-MSO Missoula Data Center PoP is a colocation facility at 110 East Broadway Street in Missoula, MT, marketed/listed by MOD Mission Critical and operated on site by Vision Net. Vision Net became the owner after acquiring iConnect Montana in 2022.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 24000, "year_online": "unknown", "construction_update": "", "recent_news": "Mar 25, 2026: Vision Net highlighted its edge data centers in Montana, including Missoula, as part of an 800 Gbps network/edge strategy to reduce grid impacts and improve AI latency.", "notable_tenants": "", "verified_name": "Vision Net Missoula", "verified_operator": "Vision Net", "verified_owner": "", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 0, "campus_acres": 0, "utility_provider": "NorthWestern Energy", "tax_incentives": "No facility-specific tax abatement/incentive found; Montana has zero sales tax and low business property tax.", "natural_hazard_zone": "Earthquake hazard: medium; FEMA flood zone for 110 E Broadway unverified (check Missoula County GIS); county highlights wildfire preparedness."}, "27": {"description": "PowerHouse Charlotte is a hyperscale data-center campus under development by PowerHouse Data Centers (a division of American Real Estate Partners) in a joint venture with Town Lane on a 122-acre site in north Charlotte, planned for up to five two-story buildings totaling about 1.5M sq ft and up to 300 MW of utility power. The listed address 12899 Moores Chapel Road refers to a separate Digital Realty rezoning/campus, not PowerHouse Charlotte.", "verified_status": "under-construction", "power_capacity_mw": 300, "total_sqft": 1500000, "year_online": "2027", "construction_update": "Grading is underway on the 122-acre site; earlier guidance targeted vertical construction beginning March 2026 and delivery of the first building in April 2027.", "recent_news": "June 4, 2026: Local news reported calls for a city moratorium on data centers citing the five-building, 122-acre PowerHouse Charlotte project; on May 11, 2026, City Council debate coverage noted the first PowerHouse Charlotte center is expected in April 2027.", "notable_tenants": "", "verified_name": "PowerHouse Charlotte (University City Boulevard campus; 12899 Moores Chapel Road is a separate Digital Realty project)", "verified_operator": "PowerHouse Data Centers", "verified_owner": "Town Lane and PowerHouse Data Centers joint venture", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral; direct access to Tier 1 carriers, local ISPs, and dark fiber providers", "num_buildings": 5, "campus_acres": 122, "utility_provider": "Duke Energy", "tax_incentives": "North Carolina statutory data-center sales and use tax exemptions may apply (qualifying data center threshold of at least $75M invested within five years, plus wage/health requirements; separate category for eligible internet data centers). No project-specific local abatement identified.", "natural_hazard_zone": "FEMA flood zone for the specific parcel is not confirmed; the University City North area has moderate flood risk at the neighborhood level."}, "28": {"description": "Applied Digital ELN01 (Polaris Forge 1) is Applied Digital Corporation\u2019s purpose-built AI/HPC data center campus in Ellendale, North Dakota, with multi-building capacity contracted for large-scale AI workloads. The company energized its on-site substation and is building out the campus under long-term agreements with CoreWeave.", "verified_status": "under-construction", "power_capacity_mw": 550, "total_sqft": 0, "year_online": "2025", "construction_update": "June 9, 2026: Proposed $1.59B senior secured notes offering to fund ELN-04, the campus\u2019s fourth 150 MW building. Earlier, Building 1\u2019s second phase was completed in late 2025, bringing it to 100 MW.", "recent_news": "June 9, 2026: Applied Digital priced $1.59 billion of 7.000% senior secured notes due 2031 to fund construction and related costs for ELN-04 (the fourth 150 MW building) at the Polaris Forge 1 campus; closing expected around June 16, 2026.", "notable_tenants": "CoreWeave (anchor tenant across the campus; 250 MW of 15-year leases signed June 2, 2025; combined 400 MW of leases at Polaris Forge 1; ELN-04\u2019s 150 MW also pre-leased to CoreWeave).", "verified_name": "Applied Digital ELN01 (Polaris Forge 1 campus, Ellendale)", "verified_operator": "Applied Digital Corporation", "verified_owner": "Applied Digital Corporation (through subsidiaries)", "cooling_type": "liquid cooling", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 0, "utility_provider": "Montana-Dakota Utilities (MDU)", "tax_incentives": "North Dakota data center sales/use tax exemption for qualifying equipment under N.D.C.C. \u00a757-39.2-04.4; annexation into Ellendale sought to expand municipal services/tax base.", "natural_hazard_zone": "FEMA Flood Zones B/X (moderate flood hazard); very low seismic risk in Dickey County."}, "29": {"description": "Google Omaha - Building 1 is a self-operated Google hyperscale data center at 11110 State St in northwest Omaha and represents the first phase of the Omaha campus, which was reported operational in 2024.", "verified_status": "operational", "power_capacity_mw": 100, "total_sqft": 700000, "year_online": "2024", "construction_update": "Jan 11, 2025: Local coverage reported Google continues to build out its campus in northwest Omaha; Phase 2 is listed as planned, following 2023 expansion filings.", "recent_news": "", "notable_tenants": "", "verified_name": "Google Omaha - Building 1", "verified_operator": "Google", "verified_owner": "Westwood Solutions LLC", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 3, "campus_acres": 460, "utility_provider": "Omaha Public Power District (OPPD)", "tax_incentives": "Nebraska data center sales/use tax exemption for qualifying tangible personal property; broader ImagiNE Nebraska Act incentives/credits remain available after repeal of one narrow data-center-specific carveout.", "natural_hazard_zone": "Tornado/severe convective storm exposure; low seismic hazard; FEMA flood zone for 11110 State St not confirmed in public docs cited."}, "30": {"description": "FirstLight Fiber operates a colocation data center on Sundial Avenue in Manchester, New Hampshire, that reopened after remodeling in May 2015. The site originated from FirstLight\u2019s 2014 acquisition of G4 Communications\u2019 facility at 77 Sundial.", "verified_status": "operational", "power_capacity_mw": 4, "total_sqft": 14400, "year_online": "2015", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "FirstLight Manchester Data Center", "verified_operator": "FirstLight Fiber", "verified_owner": "SMC Management", "cooling_type": "unknown", "tier_level": "Tier II standard", "fiber_providers": "Access to multiple carriers, including FirstLight Fiber", "num_buildings": 1, "campus_acres": 0, "utility_provider": "Eversource Energy", "tax_incentives": "", "natural_hazard_zone": "Elevated flood risk (Realtor.com 'Flood factor: Major'); FEMA flood zone not determined"}, "31": {"description": "H5 Data Centers operates a carrier-neutral Tier III colocation facility at 200B Meadowlands Parkway in Secaucus, NJ, offering 38,000+ sq ft and industry compliance certifications near New York City.", "verified_status": "operational", "power_capacity_mw": 5, "total_sqft": 47000, "year_online": "2011", "construction_update": "", "recent_news": "", "notable_tenants": "On The Spot Media; no large anchor/hyperscale tenant publicly disclosed.", "verified_name": "H5 Data Centers New Jersey Data Center", "verified_operator": "H5 Data Centers", "verified_owner": "H5 Data Centers", "cooling_type": "unknown", "tier_level": "Tier III design", "fiber_providers": "Carrier-neutral; on-net examples include Cogent, InterServer, and Metanet.", "num_buildings": 1, "campus_acres": 4.5, "utility_provider": "Public Service Electric & Gas (PSE&G)", "tax_incentives": "No site-specific award found. New Jersey created AI-related credits in 2024, but no evidence that this facility has received them.", "natural_hazard_zone": "Flood exposure: Meadowlands/Secaucus area with documented Meadowlands Parkway flooding; exact FEMA zone at 200B Meadowlands Pkwy not confirmed."}, "32": {"description": "Oso Grande Technologies operates the OSO Secure/ABQ1 colocation data center at 725 6th Street NW in Albuquerque, a carrier\u2011neutral facility housed in a single\u2011story ~60,000 sq ft building with multiple secure vaults and redundant infrastructure, offering shared colocation and a build\u2011to\u2011suit data floor.", "verified_status": "operational", "power_capacity_mw": 2, "total_sqft": 60000, "year_online": "unknown", "construction_update": "Apr 7, 2026: ABQ1\u2011DF3 is marketed as premium build\u2011to\u2011suit white space with pre\u2011approved utility power and ready plans for a 5 MW AI facility; other areas remain in shared colocation service.", "recent_news": "Apr 7, 2026: The operator updated its data\u2011centers page to market ABQ1\u2011DF3 as build\u2011to\u2011suit white space, noting pre\u2011approved utility power and ready plans for a 5 MW AI facility.", "notable_tenants": "", "verified_name": "Oso Grande Technologies \u2013 725 6th Street NW Data Center Campus", "verified_operator": "Oso Grande Technologies, Inc.", "verified_owner": "", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral; Hurricane Electric, Cogent", "num_buildings": 3, "campus_acres": 3.65, "utility_provider": "Public Service Company of New Mexico (PNM)", "tax_incentives": "", "natural_hazard_zone": "low risk"}, "33": {"description": "Google Henderson Data Center 1 is an owned-and-operated hyperscale data center at 560 W Warm Springs Rd in Henderson, Nevada. Public reports describe a roughly $600 million, ~750,000\u2011sq\u2011ft facility that came online in 2020.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 750000, "year_online": "2020", "construction_update": "", "recent_news": "June 2026: Henderson officials considered a 180\u2011day pause on accepting new data\u2011center applications (temporary moratorium) to study impacts, affecting future approvals citywide.", "notable_tenants": "", "verified_name": "Google Henderson data center", "verified_operator": "Google", "verified_owner": "Design LLC (Google subsidiary). Land acquired/developer-of-record: Jasmine Development LLC.", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 64, "utility_provider": "NV Energy", "tax_incentives": "Nevada state abatements of about $25\u201325.2 million over 20 years for the Henderson data center project.", "natural_hazard_zone": "Likely FEMA Zone X (minimal flood hazard)"}, "34": {"description": "Digital Realty\u2019s JFK10 is a live colocation and interconnection facility at 111 8th Avenue in Manhattan, serving as a central hub for hundreds of carriers and home to New York City\u2019s first Quantum\u2011AI data center.", "verified_status": "operational", "power_capacity_mw": 5.5, "total_sqft": 109600, "year_online": "unknown", "construction_update": "", "recent_news": "", "notable_tenants": "Oxford Quantum Circuits (OQC); NVIDIA", "verified_name": "Digital Realty New York JFK10 - 111 8th Avenue", "verified_operator": "Digital Realty", "verified_owner": "Google (Alphabet Inc.)", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral; hub for domestic and international carriers along the Hudson Street/Ninth Avenue fiber highway", "num_buildings": 1, "campus_acres": 0, "utility_provider": "Con Edison / Consolidated Edison Company of New York", "tax_incentives": "New York State Internet Data Center sales/use-tax exemption for qualifying data-center machinery and equipment", "natural_hazard_zone": "FEMA Flood Zones B and X (area of moderate flood hazard, between 100-year and 500-year flood limits)"}, "35": {"description": "Cologix Johnstown COL7 is an AI-ready colocation facility operated by Cologix at 12017 Duncan Plains Road, Johnstown, OH, designed to support both Scalelogix and Digital Edge deployments as part of the company\u2019s Johnstown campus.", "verified_status": "under-construction", "power_capacity_mw": 36, "total_sqft": 120000, "year_online": "2027 (planned)", "construction_update": "June 2026: Ohio approved a sales-tax exemption/incentive supporting Cologix\u2019s Central Ohio build-out (including Johnstown). Earlier milestone: June 23, 2025 groundbreaking for Central Ohio expansion.", "recent_news": "June 2026: Ohio approved a sales-tax exemption/incentive package supporting Cologix\u2019s Central Ohio expansion, including the Johnstown campus where COL7 is located.", "notable_tenants": "", "verified_name": "Cologix COL7 Data Center", "verified_operator": "Cologix", "verified_owner": "COLOGIX JOHNSTOWN LLC", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 8, "campus_acres": 154, "utility_provider": "AEP Ohio (American Electric Power)", "tax_incentives": "State of Ohio data center sales-tax exemption approved for Cologix at the June 2026 Ohio Tax Credit Authority meeting; statewide pause on new exemptions announced immediately thereafter.", "natural_hazard_zone": "low risk"}, "36": {"description": "Cerebras Oklahoma is an enterprise AI data center in Oklahoma City owned by Scale Datacenter and operated by Cerebras Systems, launched in 2025. It houses over 300 Cerebras CS-3 systems delivering more than 44 exaflops of AI compute.", "verified_status": "operational", "power_capacity_mw": 10, "total_sqft": 82000, "year_online": "2025", "construction_update": "", "recent_news": "", "notable_tenants": "Cerebras Systems is the anchor/user; no third-party tenants are publicly disclosed.", "verified_name": "Cerebras Oklahoma City", "verified_operator": "Cerebras Systems", "verified_owner": "Argosy Real Estate Partners", "cooling_type": "liquid cooling", "tier_level": "Level 3+ (Tier III\u2013equivalent; not Uptime-certified)", "fiber_providers": "", "num_buildings": 1, "campus_acres": 2.17, "utility_provider": "OG&E", "tax_incentives": "Statewide incentives available: sales/use tax exemption for qualifying data center equipment and inputs; five-year ad valorem (property) tax exemption for qualifying new/expanded/acquired data processing facilities.", "natural_hazard_zone": ""}, "37": {"description": "STACK Infrastructure POR01A is an operational colocation data center at 3145 NE Brookwood Pkwy in Hillsboro, Oregon, within STACK\u2019s POR01 campus. It serves enterprise and cloud workloads as part of the broader Hillsboro ecosystem.", "verified_status": "operational", "power_capacity_mw": 5, "total_sqft": 65000, "year_online": "unknown", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "STACK Infrastructure POR01A", "verified_operator": "STACK Infrastructure", "verified_owner": "IPI Partners", "cooling_type": "air-cooled", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 6, "utility_provider": "Portland General Electric (PGE)", "tax_incentives": "Hillsboro Enterprise Zone: 100% property tax abatement on new qualified capital assets (typically 3\u20135 years).", "natural_hazard_zone": "Minor flood risk (not within FEMA Special Flood Hazard Area per local mapping guidance; neighborhood-level risk rated as minor)."}, "38": {"description": "Panther Creek is an operating waste\u2011coal power plant and bitcoin\u2011mining site at 4 Dennison Road in Nesquehoning, PA that Keel Infrastructure (parent of Bitfarms) is redeveloping into a large AI/HPC data\u2011center campus. The campus is positioned as a flagship site with contracted firm power, including 350 MW secured for expansion.", "verified_status": "operational", "power_capacity_mw": 80, "total_sqft": 0, "year_online": "2022", "construction_update": "Apr 22, 2026: Carbon County officials said the proposed Nesquehoning data center plan needs more work before moving forward; Feb 2026: local officials authorized a crucial zoning permit for the project; May 11, 2026: Keel reported zoning secured and site development on track at Panther Creek.", "recent_news": "June 9, 2026: Keel closed $458M of 1.250% convertible senior notes to help develop Panther Creek (along with Sharon and Moses Lake); on May 11, 2026, Keel reported zoning secured and site development on track at Panther Creek.", "notable_tenants": "", "verified_name": "Panther Creek Campus - Keel Infrastructure", "verified_operator": "Keel Infrastructure", "verified_owner": "Panther Creek Power Operating LLC", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 336, "utility_provider": "", "tax_incentives": "", "natural_hazard_zone": ""}, "39": {"description": "Alpha3 Cloud Providence 1 is an operational colocation data center at 935 Westminster Street in Providence, RI, identified on industry listings as an Alpha3/Prov.net site and noted at about 4,000 sq ft with 2,000 sq ft of raised floor.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 4000, "year_online": "unknown", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "Alpha3 Cloud Providence 1", "verified_operator": "Alpha3 Cloud", "verified_owner": "", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral; access to over 100 carriers; AWS Direct Connect and Microsoft Azure ExpressRoute available", "num_buildings": 1, "campus_acres": 0, "utility_provider": "Rhode Island Energy", "tax_incentives": "", "natural_hazard_zone": "unknown"}, "40": {"description": "QTS York County is a multi-building data center campus under development by QTS in York County (Charlotte market), located at 2143 Hands Mill Hwy near Hands Mill Highway and Campbell Road. County and local reporting describe a phased project with more than $8 billion in long-term investment and an approximate 5.3 million-square-foot buildout.", "verified_status": "under-construction", "power_capacity_mw": 0, "total_sqft": 5300000, "year_online": "unknown", "construction_update": "Construction began in 2025 and is ongoing as of May 14, 2026, with multi-year buildout continuing.", "recent_news": "June 2026: York County advanced a nine-month moratorium on new data-center applications (first approval June 15), while reports noted QTS said it continues to advance its permitted York County campus.", "notable_tenants": "", "verified_name": "QTS York County", "verified_operator": "QTS Data Centers", "verified_owner": "Blackstone (via Blackstone Infrastructure Partners and Blackstone Real Estate Income Trust/BREIT)", "cooling_type": "air-cooled", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 0, "campus_acres": 800, "utility_provider": "York Electric Cooperative (power sourced from Duke Energy via Central Electric Power Cooperative)", "tax_incentives": "Fee in Lieu of Taxes (FILOT) approved by York County in 2023; $200,000 Set\u2011Aside grant from the S.C. Coordinating Council for Economic Development for site preparation.", "natural_hazard_zone": "Elevated hurricane/storm risk (York County storm events risk score 42.14%)."}, "41": {"description": "TierPoint Sioux Falls - East is an operational TierPoint colocation data center in Sioux Falls, South Dakota, noted for enterprise-grade building, security, and reliability features.", "verified_status": "operational", "power_capacity_mw": 2, "total_sqft": 16000, "year_online": "2005", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "TierPoint Sioux Falls - East Data Center (SFE)", "verified_operator": "TierPoint", "verified_owner": "", "cooling_type": "chilled water", "tier_level": "N+1 redundancy (no Uptime Institute Tier certification published)", "fiber_providers": "carrier-neutral; SDN Communications", "num_buildings": 1, "campus_acres": 8.47, "utility_provider": "", "tax_incentives": "", "natural_hazard_zone": "Outside 500-year FEMA floodplain"}, "42": {"description": "Colocation data center at 1020 W. College St., Murfreesboro, TN, operated by Data Suites; locally owned and positioned for AI/HPC workloads. Opened in 2018 and listed among operating Middle Tennessee facilities as of 2026.", "verified_status": "operational", "power_capacity_mw": 2, "total_sqft": 10000, "year_online": "2018", "construction_update": "January 2026: Facility announced a major integration to expand power and cooling across the Data Suites AI Colo Datacenter; powered-shell space with 2 MW at 415V is available for AI/HPC build-outs.", "recent_news": "January 2026: Announced a major upgrade to expand power and cooling across the Data Suites AI Colo Datacenter.", "notable_tenants": "", "verified_name": "Data Suites Murfreesboro", "verified_operator": "Data Suites", "verified_owner": "", "cooling_type": "chilled water", "tier_level": "Tier III-ready (not Uptime-certified)", "fiber_providers": "carrier-neutral", "num_buildings": 1, "campus_acres": 0, "utility_provider": "Middle Tennessee Electric", "tax_incentives": "Zero tax dollars and zero incentives reported by the operator.", "natural_hazard_zone": "FEMA flood zone undetermined; regional tornado/wind exposure (Middle Tennessee)."}, "43": {"description": "Aligned DFW-01 is Aligned\u2019s operational colocation data center at 2800 Summit Ave in Plano, Texas, on a 19\u2011acre campus. The facility provides around 60 MW across roughly 375,000 sq ft and was retrofitted in 2015 with a later expansion in 2019.", "verified_status": "operational", "power_capacity_mw": 60, "total_sqft": 375000, "year_online": "2015", "construction_update": "", "recent_news": "", "notable_tenants": "Evocative (DAL1)", "verified_name": "Aligned DFW-01 Data Center", "verified_operator": "Aligned Data Centers", "verified_owner": "Aligned Data Centers (DFW) Propco LLC", "cooling_type": "hybrid", "tier_level": "", "fiber_providers": "carrier-neutral; multiple carriers present (PeeringDB shows Networks 5, Local Exchanges 1)", "num_buildings": 2, "campus_acres": 19, "utility_provider": "Oncor Electric Delivery", "tax_incentives": "", "natural_hazard_zone": "low risk"}, "44": {"description": "Aligned SLC-01 is an operational wholesale/colocation data center operated by Aligned Data Centers at 3333 W 9000 S, West Jordan, Utah, on its Salt Lake City campus. The facility is about 300,000 sq ft with roughly 34 MW of capacity.", "verified_status": "operational", "power_capacity_mw": 34, "total_sqft": 300000, "year_online": "2018", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "Aligned SLC-01 Data Center", "verified_operator": "Aligned Data Centers", "verified_owner": "ALIGNED ENERGY DATA CENTERS (SLC) PROPCO, LLC", "cooling_type": "air-cooled", "tier_level": "Designed to Tier III standards", "fiber_providers": "", "num_buildings": 3, "campus_acres": 55, "utility_provider": "", "tax_incentives": "Utah sales and use tax exemptions for large data centers (\u2265150,000 sq ft); Aligned notes Salt Lake City customers can leverage incentives for significant savings.", "natural_hazard_zone": "Seismic: outside city\u2019s noted moderate-to-high liquefaction corridor (between Jordan River and ~2200 W); FEMA flood zone: not determined from provided excerpts."}, "45": {"description": "Digital Realty\u2019s IAD24 is an operational colocation data center at 43830 Devin Shafron Drive (Building F) on the company\u2019s Northern Virginia campus, totaling 113,300 sq ft. Third\u2011party facility profiles list approximately 6.8 MW of fully built\u2011out power.", "verified_status": "operational", "power_capacity_mw": 6.8, "total_sqft": 113300, "year_online": "unknown", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "Digital Realty IAD24 (Building F), 43830 Devin Shafron Drive, Ashburn, VA 20147; also listed as Amazon AWS IAD23 Ashburn at the same address", "verified_operator": "Digital Realty (operator); Amazon Web Services is a tenant at this address (AWS IAD23).", "verified_owner": "Digital Realty Trust", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral; Zayo; AT&T; Cogent Communications; Verizon", "num_buildings": 6, "campus_acres": 98, "utility_provider": "", "tax_incentives": "Virginia Data Center Retail Sales & Use Tax Exemption for qualifying purchases; facility-specific qualification not confirmed.", "natural_hazard_zone": ""}, "46": {"description": "A 20,000 sq ft colocation data center operated by FirstLight Fiber at 45 Krupp Drive in Williston, VT, offering A/B power and UPS-backed infrastructure.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 20000, "year_online": "unknown", "construction_update": "", "recent_news": "", "notable_tenants": "", "verified_name": "FirstLight Burlington Data Center (Williston, VT)", "verified_operator": "FirstLight Fiber", "verified_owner": "KRUPP DRIVE PROPERTIES LLC", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "carrier-neutral", "num_buildings": 1, "campus_acres": 3.48, "utility_provider": "Green Mountain Power", "tax_incentives": "", "natural_hazard_zone": "unknown"}, "47": {"description": "Operational colocation data center at 4200 194th St SW in Lynnwood, WA, long marketed by Digital Fortress as the North Seattle site (6 MW N+1, 34,600 sq ft), and now a 10MW standalone facility under Chirisa Technology Parks ownership.", "verified_status": "operational", "power_capacity_mw": 10, "total_sqft": 47820, "year_online": "2006", "construction_update": "Jan 22, 2024: CTP announced acquisition and refit for AI workloads with an initial edge deployment; a 2025 refit/edge installation is later noted.", "recent_news": "", "notable_tenants": "HostPapa SEA1 is listed at 4200 194th St SW; Megaport connectivity is available at the facility; Chirisa/CTP disclosed an unnamed AI-focused customer for an initial edge deployment and noted a former unnamed hyperscale tenant.", "verified_name": "Digital Fortress: North Seattle - Lynnwood (SEA1)", "verified_operator": "Digital Fortress", "verified_owner": "Chirisa Investments (via Chirisa Technology Parks)", "cooling_type": "unknown", "tier_level": "Tier III (equivalent design)", "fiber_providers": "AWS Direct Connect; Seattle Internet Exchange peering", "num_buildings": 1, "campus_acres": 1.54, "utility_provider": "Snohomish County PUD", "tax_incentives": "Washington State sales and use tax exemption may be available to qualifying data center businesses/tenants.", "natural_hazard_zone": ""}, "48": {"description": "Project Cornmaze (often linked to Meta in reporting) is a proposed large-scale data center campus led by Panattoni on roughly 430 acres in the Towns of Beloit and Turtle, WI, near W B R Townline Rd & I-39 ALT. Concept plans presented in June 2026 show four buildings totaling about 2 million square feet, pending studies and approvals.", "verified_status": "planned", "power_capacity_mw": 0, "total_sqft": 2000000, "year_online": "unknown", "construction_update": "June 2026: Panattoni hosted a private briefing and public open house presenting Project Cornmaze concept plans; the project remains in early planning and under consideration pending studies and local approvals.", "recent_news": "June 2026: Panattoni held a private briefing and public open house for Project Cornmaze, presenting conceptual plans (4 buildings across >430 acres; imagery of a ~2M sq ft campus), prompting community discussion.", "notable_tenants": "Meta (reported/backing; not officially confirmed by developer). No other tenants publicly listed.", "verified_name": "Project Cornmaze (Beloit and Turtle Data Center Project)", "verified_operator": "Panattoni Data Centers (developer; end-operator not yet confirmed)", "verified_owner": "", "cooling_type": "liquid cooling", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 600, "utility_provider": "Alliant Energy", "tax_incentives": "State program available: Wisconsin Data Center Sales and Use Tax Exemption (eligibility requires WEDC certification); no project-specific award identified.", "natural_hazard_zone": "Potential flood risk near Rock River; specific FEMA flood zone undetermined"}, "49": {"description": "Planned Silicon Foundation West Virginia data center and modular data-center production campus at the former Centre Foundry site, 74 Warwood Ave, Wheeling, WV. Reports indicate an initial 10 MW phase and a longer-term ambition up to 100 MW on a ~15-acre property with about 60,000 sq ft of existing buildings.", "verified_status": "planned", "power_capacity_mw": 100, "total_sqft": 60000, "year_online": "unknown", "construction_update": "Property acquired for about $1.5 million; early-stage planning and phasing discussions, no active construction reported.", "recent_news": "June 2026: Officials clarified the Warwood facility will build modules for data centers and confirmed the $1.5M property purchase; plans for a phased rollout were discussed.", "notable_tenants": "", "verified_name": "Silicon Foundation West Virginia", "verified_operator": "Silicon Foundation Energy Inc.", "verified_owner": "Silicon Foundation Energy Inc.", "cooling_type": "unknown", "tier_level": "", "fiber_providers": "", "num_buildings": 0, "campus_acres": 15, "utility_provider": "Appalachian Power", "tax_incentives": "West Virginia High Impact Data Center Program (HB 2014); special property tax treatment for qualifying data centers (salvage value basis).", "natural_hazard_zone": "FEMA flood zone unknown; riverine flood exposure in Wheeling (Ohio River)."}, "50": {"description": "Microsoft CYS - Building 1 is a Microsoft-operated hyperscale/Azure data center at 644 Logistics Dr in Cheyenne, Wyoming, serving the Azure West Central US region. Wyoming DEQ identifies the Microsoft Cheyenne Data Center at this address.", "verified_status": "operational", "power_capacity_mw": 0, "total_sqft": 267555, "year_online": "unknown", "construction_update": "Apr 2026: campus permitting activity for generators at the Logistics Drive site; July 2025: authorization for 128 diesel-fired units (campus-level).", "recent_news": "Apr 14, 2026: Microsoft announced intent to expand datacenter operations in Cheyenne (two parcels ~200 acres in Bison Business Park); late May 2026 reports said Microsoft added two more parcels totaling ~420 acres amid community concerns; Jan 15, 2026: WYDEQ posted a Title V draft permit for the 644 Logistics Drive campus.", "notable_tenants": "Microsoft Azure (self-operated by Microsoft); no third-party/colocation tenants are publicly disclosed.", "verified_name": "Microsoft CYS - Building 1", "verified_operator": "Microsoft", "verified_owner": "Microsoft Corporation", "cooling_type": "evaporative", "tier_level": "", "fiber_providers": "", "num_buildings": 7, "campus_acres": 0, "utility_provider": "Black Hills Energy / Cheyenne Light, Fuel and Power", "tax_incentives": "Wyoming statewide data center incentives apply: sales/use tax exemptions for qualifying data center investments and the Managed Data Center Cost Reduction Grant under the Business Ready Community program.", "natural_hazard_zone": "FEMA Flood Zone B and X \u2014 moderate flood hazard"}} \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/public/file.svg b/typescript-recipes/parallel-datacenter-map/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/public/globe.svg b/typescript-recipes/parallel-datacenter-map/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/public/next.svg b/typescript-recipes/parallel-datacenter-map/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/public/vercel.svg b/typescript-recipes/parallel-datacenter-map/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/public/window.svg b/typescript-recipes/parallel-datacenter-map/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/typescript-recipes/parallel-datacenter-map/scripts/add-new-facilities.ts b/typescript-recipes/parallel-datacenter-map/scripts/add-new-facilities.ts new file mode 100644 index 0000000..90c7b4d --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/add-new-facilities.ts @@ -0,0 +1,111 @@ +/** + * Adds new facilities from an enriched CSV to the existing dataset. + * Only adds rows that don't already exist (by lat/lng coordinate match). + * Preserves all existing data untouched. + * + * Usage: npx tsx scripts/add-new-facilities.ts /path/to/enriched.csv + */ + +import * as fs from "fs"; +import Papa from "papaparse"; + +const csvPath = process.argv[2]; +if (!csvPath) { console.error("Usage: npx tsx scripts/add-new-facilities.ts /path/to/enriched.csv"); process.exit(1); } + +// Load existing data +const dcPath = "./public/data/datacenters.json"; +const compactPath = "./public/data/enrichments-compact.json"; + +const existing: Record[] = JSON.parse(fs.readFileSync(dcPath, "utf-8")); +const compact: Record> = fs.existsSync(compactPath) + ? JSON.parse(fs.readFileSync(compactPath, "utf-8")) + : {}; + +console.log(`Existing: ${existing.length} facilities, ${Object.keys(compact).length} enrichments`); + +// Build index of existing coords +const existingCoords = new Set(); +for (const dc of existing) { + existingCoords.add(`${(dc as { lat: number }).lat.toFixed(6)},${(dc as { lng: number }).lng.toFixed(6)}`); +} + +// Parse new CSV +const raw = fs.readFileSync(csvPath, "utf-8"); +const { data } = Papa.parse(raw, { header: true, skipEmptyLines: true }); +const rows = data as Record[]; + +console.log(`CSV: ${rows.length} rows`); + +let added = 0; +let skipped = 0; + +for (const row of rows) { + const lat = parseFloat(row.latitude) || 0; + const lng = parseFloat(row.longitude) || 0; + if (lat === 0 && lng === 0) { skipped++; continue; } + + const coordKey = `${lat.toFixed(6)},${lng.toFixed(6)}`; + if (existingCoords.has(coordKey)) { skipped++; continue; } + + // Filter out unknown/empty status + const status = (row.verified_status || row.status || "").trim(); + if (!status || status === "unknown") { skipped++; continue; } + + existingCoords.add(coordKey); // prevent dupes within new data + + const newIndex = existing.length; + + // Add to datacenters.json (base fields only) + const dc = { + name: (row.verified_name || row.name || "").trim(), + operator: (row.verified_operator || row.operator_company || "").trim(), + owner: (row.verified_owner || row.owner_company || "").trim(), + address: (row.address || "").trim(), + city: (row.city || "").trim(), + state: (row.state || "").trim(), + zip: (row.zip_code || "").trim(), + lat, + lng, + yearOnline: (row.year_online || "unknown").trim(), + powerMw: Math.min(parseFloat(row.power_capacity_mw) || 0, 5000), + sqft: parseFloat(row.total_sqft) || 0, + type: (row.facility_type || "unknown").trim(), + status, + region: (row._shard || "").trim(), + }; + existing.push(dc); + + // Add to enrichments-compact.json + compact[String(newIndex)] = { + description: (row.description || "").trim(), + verified_status: status, + power_capacity_mw: parseFloat(row.power_capacity_mw) || 0, + total_sqft: parseFloat(row.total_sqft) || 0, + year_online: (row.year_online || "").trim(), + construction_update: (row.construction_update || "").trim(), + recent_news: (row.recent_news || "").trim(), + notable_tenants: (row.notable_tenants || "").trim(), + verified_name: (row.verified_name || "").trim(), + verified_operator: (row.verified_operator || "").trim(), + verified_owner: (row.verified_owner || "").trim(), + cooling_type: (row.cooling_type || "").trim(), + tier_level: (row.tier_level || "").trim(), + fiber_providers: (row.fiber_providers || "").trim(), + num_buildings: parseFloat(row.num_buildings) || 0, + campus_acres: parseFloat(row.campus_acres) || 0, + utility_provider: (row.utility_provider || "").trim(), + tax_incentives: (row.tax_incentives || "").trim(), + natural_hazard_zone: (row.natural_hazard_zone || "").trim(), + }; + + added++; +} + +// Save +fs.writeFileSync(dcPath, JSON.stringify(existing)); +fs.writeFileSync(compactPath, JSON.stringify(compact, null, 0)); + +console.log(`\nAdded: ${added} new facilities`); +console.log(`Skipped: ${skipped} (existing, missing coords, or unknown status)`); +console.log(`Total now: ${existing.length} facilities, ${Object.keys(compact).length} enrichments`); +console.log(`\nSaved to ${dcPath} and ${compactPath}`); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/backfill-basis.ts b/typescript-recipes/parallel-datacenter-map/scripts/backfill-basis.ts new file mode 100644 index 0000000..2a5450e --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/backfill-basis.ts @@ -0,0 +1,126 @@ +/** + * Backfills the missing `basis` (citations + reasoning) on facility enrichment + * blob files that were imported with data but no basis. + * + * Each blob file (enrichments/{index}.json) already stores the `runId` of the + * Task API enrichment run that produced it. Those runs are still retrievable, + * so we re-fetch /result and write output.basis back onto the file — no new + * Task API runs, no fabricated data. + * + * Usage: npx tsx scripts/backfill-basis.ts [--dry] + */ + +import { list, put } from "@vercel/blob"; +import * as fs from "fs"; + +const BASE_URL = "https://api.parallel.ai"; + +function env(key: string): string { + const line = fs.readFileSync(".env.local", "utf8").split("\n").find((l) => l.startsWith(key + "=")); + return line ? line.slice(key.length + 1).replace(/^["']|["']$/g, "").trim() : ""; +} + +const API_KEY = process.env.PARALLEL_API_KEY || env("PARALLEL_API_KEY"); +const TOKEN = process.env.BLOB_READ_WRITE_TOKEN || env("BLOB_READ_WRITE_TOKEN"); +const DRY = process.argv.includes("--dry"); + +interface BlobEntry { + enrichment?: Record; + basis?: unknown[]; + runId?: string; + [k: string]: unknown; +} + +async function fetchResultBasis(runId: string): Promise { + try { + const statusRes = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}`, { headers: { "x-api-key": API_KEY } }); + if (!statusRes.ok) return null; + const status = await statusRes.json(); + if (status.status !== "completed") return null; + const res = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}/result`, { headers: { "x-api-key": API_KEY } }); + if (!res.ok) return null; + const data = await res.json(); + const basis = data.output?.basis; + return Array.isArray(basis) ? basis : null; + } catch { + return null; + } +} + +async function mapWithConcurrency(items: T[], limit: number, fn: (item: T, i: number) => Promise): Promise { + const results: R[] = new Array(items.length); + let next = 0; + async function worker() { + while (next < items.length) { + const i = next++; + results[i] = await fn(items[i], i); + } + } + await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker)); + return results; +} + +async function main() { + if (!API_KEY || !TOKEN) { console.error("Missing PARALLEL_API_KEY or BLOB_READ_WRITE_TOKEN"); process.exit(1); } + + // 1. List every enrichment blob and its downloadUrl + console.log("Listing enrichment blobs…"); + const files: { index: number; pathname: string; downloadUrl: string }[] = []; + let cursor: string | undefined; + do { + const r = await list({ prefix: "enrichments/", token: TOKEN, cursor, limit: 1000 }); + for (const b of r.blobs) { + const m = b.pathname.match(/enrichments\/(\d+)\.json$/); + if (m) files.push({ index: Number(m[1]), pathname: b.pathname, downloadUrl: b.downloadUrl }); + } + cursor = r.cursor; + } while (cursor); + files.sort((a, b) => a.index - b.index); + console.log(`Found ${files.length} enrichment blobs.`); + + // 2. Find files with empty basis but a runId + console.log("Scanning for empty-basis files…"); + const scan = await mapWithConcurrency(files, 24, async (f) => { + try { + const res = await fetch(f.downloadUrl, { headers: { Authorization: `Bearer ${TOKEN}` } }); + if (!res.ok) return null; + const entry: BlobEntry = await res.json(); + const hasBasis = Array.isArray(entry.basis) && entry.basis.length > 0; + return { ...f, entry, hasBasis, runId: entry.runId }; + } catch { + return null; + } + }); + + const targets = scan.filter((s): s is NonNullable => !!s && !s.hasBasis && !!s.runId); + const noRun = scan.filter((s) => s && !s.hasBasis && !s.runId).length; + console.log(`Empty basis: ${scan.filter((s) => s && !s.hasBasis).length} (with runId: ${targets.length}, without: ${noRun})`); + + if (DRY) { + console.log("Dry run — sample targets:", targets.slice(0, 5).map((t) => ({ index: t.index, runId: t.runId }))); + return; + } + + // 3. Recover basis from each runId and re-upload + let fixed = 0, failed = 0, empty = 0; + await mapWithConcurrency(targets, 12, async (t) => { + const basis = await fetchResultBasis(t.runId!); + if (!basis) { failed++; return; } + if (basis.length === 0) { empty++; return; } + const updated = { ...t.entry, basis, basisBackfilledAt: new Date().toISOString() }; + try { + await put(t.pathname, JSON.stringify(updated), { + access: "private", allowOverwrite: true, contentType: "application/json", token: TOKEN, + }); + fixed++; + if (fixed % 50 === 0) console.log(` …${fixed} fixed`); + } catch (e) { + failed++; + console.error(` put failed idx ${t.index}:`, (e as Error).message); + } + }); + + console.log(`\nDone. Fixed: ${fixed}, run had empty basis: ${empty}, failed: ${failed}`); +} + +main().catch((e) => { console.error(e); process.exit(1); }); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/build_datacenters_iterative.py b/typescript-recipes/parallel-datacenter-map/scripts/build_datacenters_iterative.py new file mode 100644 index 0000000..7e133c4 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/build_datacenters_iterative.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 +""" +Build a US datacenter list with Parallel ultra2x — iterative / paginated. + +THE IDEA (why this works) +───────────────────────── +Exhaustively enumerating US datacenters is a decomposition problem. The market +is a long tail of ~1,800 colocation, enterprise, telecom, and edge operators with +no public registry, and a broad, unscoped query surfaces the most prominent +facilities first. Reaching the full tail takes two techniques: + + 1. SHARD by geography. Scope every query to ONE state so enumeration + (reading directories) is the natural move instead of dumping a global + top-of-mind list. One dense metro alone (Ashburn) goes 13 → ~90 this way. + + 2. PAGINATE via interactions. After the first pass for a state, keep asking + "find MORE net-new" while passing `previous_interaction_id` — the model + carries its OWN context of what it already returned in that thread, so we + never paste a list of known facilities into the prompt. Loop until a page + stops adding new results ("loop until dry"). + +Everything is resumable: results checkpoint after each shard, and every run's +`run_id` / `interaction_id` / `previous_interaction_id` is logged so work that +completed server-side is always recoverable (the runs execute on Parallel's +servers regardless of this process staying alive). + +USAGE +───── + export PARALLEL_API_KEY=... + python build_datacenters_iterative.py # all states, until dry + python build_datacenters_iterative.py --states "Texas,Ohio" + python build_datacenters_iterative.py --max-pages 3 --min-new 5 --workers 8 + +OUTPUT +────── + datacenters.json deduped list (each record + _shard + _trun provenance) + datacenters.runs.jsonl run manifest: {run_id, interaction_id, previous_interaction_id, state, page} +Re-run any time to go deeper; states that have gone dry are skipped. +""" + +import argparse +import json +import os +import re +import sys +import threading +from concurrent.futures import ThreadPoolExecutor, as_completed + +from parallel import Parallel + +# ── Shards: state is the universal unit (covers all US geography) ────────────── +STATES = [ + "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", + "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", + "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", + "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", + "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", + "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", + "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", + "Wisconsin", "Wyoming", "District of Columbia", +] + +# ── Output schema: everything needed to map & attribute a facility ───────────── +ITEM = { + "type": "object", + "properties": { + "name": {"type": "string", "description": "Facility name."}, + "operator_company": {"type": "string", "description": "Company that operates the facility."}, + "owner_company": {"type": "string", "description": "Owner if different; else same as operator."}, + "address": {"type": "string", "description": "Full street address if known."}, + "city": {"type": "string"}, + "state": {"type": "string", "description": "US state, 2-letter abbreviation."}, + "zip_code": {"type": "string"}, + "latitude": {"type": "number", "description": "Decimal degrees; null if unknown."}, + "longitude": {"type": "number", "description": "Decimal degrees; null if unknown."}, + "year_online": {"type": "string", "description": "Year online (YYYY) or 'unknown'."}, + "power_capacity_mw": {"type": "number", "description": "Critical IT power MW; null if unknown."}, + "total_sqft": {"type": "number", "description": "Total sqft; null if unknown."}, + "facility_type": {"type": "string", "description": "colocation, hyperscale, enterprise, edge, telecom, wholesale, crypto."}, + "status": {"type": "string", "description": "operational, under-construction, planned, unknown."}, + "source_url": {"type": "string", "description": "URL supporting existence/location."}, + }, + "required": ["name", "operator_company", "city", "state"], + "additionalProperties": False, +} +OUTPUT_SCHEMA = { + "type": "json", + "json_schema": { + "type": "object", + "properties": {"datacenters": {"type": "array", "items": ITEM}}, + "required": ["datacenters"], + "additionalProperties": False, + }, +} + + +def first_prompt(state): + """Page 1 for a state: exhaustive, directory-anchored, long-tail-aware.""" + return ( + f"Enumerate EVERY physical data center facility located in the U.S. state of {state}. " + f"Be exhaustive across the whole state — all cities and towns, including secondary and " + f"smaller markets, not just the largest hub.\n\n" + f"Go FAR beyond the well-known hyperscaler campuses (AWS, Microsoft, Google, Meta). Most " + f"facilities are COLOCATION, wholesale, enterprise, telecom/network, and edge, run by a " + f"long tail of operators (Equinix, Digital Realty, CoreSite, Cyxtera, Iron Mountain, QTS, " + f"Sabey, Stack, Vantage, Aligned, Flexential, DataBank, Cologix, EdgeConneX, H5, and many " + f"smaller regional providers). Consult facility directories (datacentermap.com, " + f"cloudscene.com) and operator site lists to enumerate them.\n\n" + f"For each facility return name, operator, owner, full street address, city, state, zip, " + f"latitude/longitude (the specific building), year online, power MW, sqft, facility type, " + f"and status — with a source_url. PRECISION REQUIRED: each must be a real, individually " + f"verifiable, physically distinct building; never fabricate; use null/'unknown' for " + f"anything you cannot verify." + ) + + +def next_prompt(state): + """Pages 2..N: the model already has its prior results via the interaction chain.""" + return ( + f"Continue. Return MORE real data center facilities in the U.S. state of {state} that you " + f"have NOT already returned earlier in this conversation — net-new only, no repeats, no " + f"fabrication. Push into cities, towns, and operators you have not yet covered (colocation, " + f"enterprise, telecom, wholesale, edge, crypto). Keep the same fields and precision rules; " + f"include a real source_url." + ) + + +# ── Dedupe: address is the most reliable key; the model fills 0.0 for unknown geo ── +def norm(s): + return re.sub(r"[^a-z0-9]+", "", (s or "").lower()) + + +def dedupe_key(dc): + addr = norm(dc.get("address")) + if addr: + return f"addr:{addr}|{norm(dc.get('city'))}|{norm(dc.get('state'))}" + lat, lng = dc.get("latitude"), dc.get("longitude") + if isinstance(lat, (int, float)) and isinstance(lng, (int, float)) and (lat, lng) != (0, 0): + return f"geo:{round(lat, 3)},{round(lng, 3)}" + return f"name:{norm(dc.get('operator_company'))}|{norm(dc.get('city'))}|{norm(dc.get('state'))}|{norm(dc.get('name'))}" + + +_lock = threading.Lock() + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--states", default=None, help="Comma-separated states; default = all 51.") + ap.add_argument("--processor", default="ultra2x", help="ultra2x | ultra2x-fast | ultra4x ...") + ap.add_argument("--max-pages", type=int, default=6, help="Max pagination pages per state.") + ap.add_argument("--min-new", type=int, default=3, help="Stop a state when a page adds fewer than this.") + ap.add_argument("--workers", type=int, default=8, help="States processed concurrently.") + ap.add_argument("--timeout", type=int, default=3600) + ap.add_argument("--out", default="datacenters.json") + args = ap.parse_args() + if not os.environ.get("PARALLEL_API_KEY"): + sys.exit("Set PARALLEL_API_KEY") + + client = Parallel(api_key=os.environ["PARALLEL_API_KEY"]) + manifest = args.out.rsplit(".", 1)[0] + ".runs.jsonl" + targets = [s.strip() for s in args.states.split(",")] if args.states else STATES + + # Resume: load prior results, skip states already done in this file. + all_dc, done = [], set() + if os.path.exists(args.out): + all_dc = json.load(open(args.out)).get("datacenters", []) + done = {dc.get("_shard") for dc in all_dc} + print(f"[resume] loaded {len(all_dc)} facilities; {len(done)} states already done.", file=sys.stderr) + seen = {dedupe_key(dc) for dc in all_dc} + + def log_run(run_id, iid, prev, state, page): + with _lock: + with open(manifest, "a") as f: + f.write(json.dumps({"run_id": run_id, "interaction_id": iid, + "previous_interaction_id": prev, "state": state, "page": page}) + "\n") + + def checkpoint(): + with _lock: + json.dump({"count": len(all_dc), "datacenters": all_dc}, open(args.out, "w"), indent=2) + + def one_call(state, prev_iid, page): + kwargs = {"input": first_prompt(state) if page == 1 else next_prompt(state), + "processor": args.processor, "task_spec": {"output_schema": OUTPUT_SCHEMA}} + if prev_iid: + kwargs["previous_interaction_id"] = prev_iid + run = client.task_run.create(**kwargs) + log_run(run.run_id, run.interaction_id, prev_iid, state, page) # persist BEFORE blocking + res = client.task_run.result(run.run_id, api_timeout=args.timeout) + content = res.output.content + if isinstance(content, str): + content = json.loads(content) + items = (content or {}).get("datacenters", []) if isinstance(content, dict) else [] + return items, run.run_id, run.interaction_id + + def process_state(state): + """Page 1, then paginate via interaction chaining until a page goes dry.""" + prev_iid, total_new = None, 0 + for page in range(1, args.max_pages + 1): + try: + items, run_id, iid = one_call(state, prev_iid, page) + except Exception as e: + print(f" [{state} p{page}] error: {e}", file=sys.stderr) + break + prev_iid = iid # extend the chain + new = 0 + with _lock: + for dc in items: + k = dedupe_key(dc) + if k in seen: + continue + seen.add(k) + dc["_shard"], dc["_trun"] = state, run_id + all_dc.append(dc) + new += 1 + total_new += new + print(f" [{state} p{page}] +{new} net-new (state total this run: {total_new})", file=sys.stderr) + checkpoint() + if new < args.min_new: # loop-until-dry + break + return state, total_new + + todo = [s for s in targets if s not in done] + print(f"processing {len(todo)} states ({args.workers}-wide, {args.processor})", file=sys.stderr) + with ThreadPoolExecutor(max_workers=args.workers) as ex: + for fut in as_completed([ex.submit(process_state, s) for s in todo]): + try: + s, n = fut.result() + print(f"[done] {s}: +{n} (grand total {len(all_dc)})", file=sys.stderr) + except Exception as e: + print(f"[error] {e}", file=sys.stderr) + + checkpoint() + print(f"\nDONE. {len(all_dc)} unique facilities -> {args.out}", file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/typescript-recipes/parallel-datacenter-map/scripts/check-events.ts b/typescript-recipes/parallel-datacenter-map/scripts/check-events.ts new file mode 100644 index 0000000..3df5a55 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/check-events.ts @@ -0,0 +1,52 @@ +/** + * Check for events from all active monitors. + * Usage: npx tsx scripts/check-events.ts + */ + +import * as fs from "fs"; + +const API_KEY = process.env.PARALLEL_API_KEY; +const BASE_URL = "https://api.parallel.ai"; + +async function main() { + const monitorsPath = "./src/data/monitors.json"; + if (!fs.existsSync(monitorsPath)) { + console.error("No monitors.json found. Run setup-monitors.ts first."); + process.exit(1); + } + + const monitors = JSON.parse(fs.readFileSync(monitorsPath, "utf-8")); + + for (const [defId, info] of Object.entries(monitors) as [string, { monitorId: string; name: string }][]) { + console.log(`\n--- ${info.name} (${info.monitorId}) ---`); + + const res = await fetch( + `${BASE_URL}/v1/monitors/${info.monitorId}/events`, + { headers: { "x-api-key": API_KEY } } + ); + + if (!res.ok) { + console.error(` Error: ${res.status} ${await res.text()}`); + continue; + } + + const data = await res.json(); + const events = data.events || []; + + if (events.length === 0) { + console.log(" No events yet."); + } else { + for (const evt of events) { + console.log(` [${evt.type}] ${evt.event_id}`); + if (evt.output?.content) { + const content = typeof evt.output.content === "string" + ? evt.output.content.slice(0, 200) + : JSON.stringify(evt.output.content).slice(0, 200); + console.log(` ${content}...`); + } + } + } + } +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/classify-ai.ts b/typescript-recipes/parallel-datacenter-map/scripts/classify-ai.ts new file mode 100644 index 0000000..0907f86 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/classify-ai.ts @@ -0,0 +1,207 @@ +#!/usr/bin/env npx tsx +/** + * AI datacenter classification: which facilities are AI datacenters, and what + * are their environmental/community impact classifications (water, grid, + * community) — à la brockovichdatacenter.com, scoped to AI facilities. + * + * Candidates: facilities with AI/GPU/hyperscale signals in existing enrichment, + * ≥100 MW power, or AI-heavy operators/owners (~700 of 2,811). + * + * Usage: + * PARALLEL_API_KEY=xxx npx tsx scripts/classify-ai.ts kickoff # start task group + * PARALLEL_API_KEY=xxx npx tsx scripts/classify-ai.ts collect # poll + save results + * + * Both steps are idempotent and resumable. Run IDs are saved at kickoff to + * src/data/ai-classification-runs.json; results land in + * public/data/ai-classifications.json keyed by facility index. + */ + +import * as fs from "fs"; + +const API_KEY = process.env.PARALLEL_API_KEY; +if (!API_KEY) { console.error("Set PARALLEL_API_KEY env var."); process.exit(1); } + +const BASE_URL = "https://api.parallel.ai"; +const RUNS_PATH = "./src/data/ai-classification-runs.json"; +const OUT_PATH = "./public/data/ai-classifications.json"; +const PROCESSOR = "ultra2x"; + +function sleep(ms: number) { return new Promise(r => setTimeout(r, ms)); } + +const AI_OPERATORS = /microsoft|azure|google|meta|amazon|aws|oracle|openai|xai|x\.ai|coreweave|crusoe|lambda|nvidia|anthropic|tesla|applied digital|core scientific|cipher|terawulf|vantage|switch|aligned|stack infra|qts|compass|cyrusone|novva|edged|prime data|colovore/i; +const AI_SIGNALS = /\b(AI|artificial intelligence|GPU|H100|GB200|hyperscale|machine learning)\b/i; + +type Dc = Record; + +function loadCandidates(): { index: number; dc: Dc; enrichment: Record }[] { + const dcs = JSON.parse(fs.readFileSync("./public/data/datacenters.json", "utf-8")) as Dc[]; + const enr = JSON.parse(fs.readFileSync("./public/data/enrichments-compact.json", "utf-8")) as Record>; + + const candidates: { index: number; dc: Dc; enrichment: Record }[] = []; + dcs.forEach((dc, i) => { + const e = enr[String(i)] || {}; + const text = [dc.name, dc.operator, dc.owner, e.notable_tenants, e.description, e.recent_news].join(" "); + const power = Math.max((dc.powerMw as number) || 0, (e.power_capacity_mw as number) || 0); + if (AI_SIGNALS.test(text) || power >= 100 || AI_OPERATORS.test(`${dc.operator} ${dc.owner}`)) { + candidates.push({ index: i, dc, enrichment: e }); + } + }); + return candidates; +} + +function buildInput(dc: Dc, e: Record): string { + const facts = [ + `Facility: ${dc.name}`, + `Operator: ${dc.operator}`, + dc.owner && dc.owner !== dc.operator ? `Owner: ${dc.owner}` : "", + `Location: ${dc.address}, ${dc.city}, ${dc.state}`, + (dc.powerMw as number) > 0 ? `Power: ${dc.powerMw} MW` : "", + e.notable_tenants ? `Known tenants: ${e.notable_tenants}` : "", + e.cooling_type ? `Cooling: ${e.cooling_type}` : "", + e.utility_provider ? `Utility: ${e.utility_provider}` : "", + e.description ? `Background: ${e.description}` : "", + ].filter(Boolean).join("\n"); + + return `Classify this U.S. data center facility for an infrastructure-investor audience: + +${facts} + +1. Determine whether this is an AI data center: does it host AI training clusters (GPU superclusters), AI inference/cloud AI workloads, or is it traditional colocation/enterprise? Look for GPU deployments, AI tenant announcements, liquid cooling retrofits, and power density signals. +2. Assess its local-impact profile with specific evidence: + - WATER: cooling water consumption, water source stress, aquifer/drought concerns, discharge issues. + - GRID: strain on the local grid, ratepayer cost impact, new generation/transmission required, curtailment risk. + - COMMUNITY: organized opposition, lawsuits, zoning fights, noise/air-quality complaints (e.g., diesel or gas turbine generators), moratorium campaigns. +Base every classification on verifiable reporting. If there is no evidence for an impact, say so rather than speculating.`; +} + +const SCHEMA = { + type: "json" as const, + json_schema: { + type: "object" as const, + properties: { + ai_class: { + type: "string" as const, + enum: ["ai-training", "ai-inference", "ai-mixed", "cloud-hyperscale", "not-ai"], + description: "AI workload classification. 'ai-training' = GPU training clusters; 'ai-inference' = inference/cloud AI serving; 'ai-mixed' = both or AI plus other workloads; 'cloud-hyperscale' = hyperscale cloud without confirmed AI focus; 'not-ai' = traditional colo/enterprise.", + }, + ai_evidence: { type: "string" as const, description: "1-2 sentence evidence for the AI classification (GPU deployments, tenants, announcements). Empty if not-ai." }, + water_impact: { type: "string" as const, enum: ["high", "moderate", "low", "unknown"], description: "Water impact: consumption scale, source stress, discharge concerns." }, + water_note: { type: "string" as const, description: "1 sentence on water: gallons/day if reported, source, drought/aquifer concerns. Empty if nothing found." }, + grid_impact: { type: "string" as const, enum: ["high", "moderate", "low", "unknown"], description: "Grid impact: load relative to local grid, new generation/transmission needed, ratepayer effects." }, + grid_note: { type: "string" as const, description: "1 sentence on grid: MW load, utility upgrades, rate cases. Empty if nothing found." }, + community_pushback: { type: "string" as const, enum: ["active-opposition", "some-concern", "none-found"], description: "Community response: organized opposition/litigation, scattered concern, or none found." }, + community_note: { type: "string" as const, description: "1 sentence on community response: who opposes, over what, current status. Empty if none." }, + }, + required: ["ai_class", "ai_evidence", "water_impact", "water_note", "grid_impact", "grid_note", "community_pushback", "community_note"], + additionalProperties: false, + }, +}; + +// ─── Kickoff ───────────────────────────────────────────────────────── + +async function kickoff() { + if (fs.existsSync(RUNS_PATH)) { + const existing = JSON.parse(fs.readFileSync(RUNS_PATH, "utf-8")); + console.log(`Already kicked off ${existing.runs?.length || 0} runs (${existing.startedAt}). Delete ${RUNS_PATH} to restart.`); + return; + } + + const candidates = loadCandidates(); + console.log(`Classifying ${candidates.length} AI-candidate facilities with ${PROCESSOR}...`); + + const runData: { groups: unknown[]; runs: { runId: string; groupId: string; facilityIndex: number; facilityName: string }[]; startedAt: string; processor: string; totalCandidates: number } = { + groups: [], runs: [], startedAt: new Date().toISOString(), processor: PROCESSOR, totalCandidates: candidates.length, + }; + + const grpRes = await fetch(`${BASE_URL}/v1/tasks/groups`, { + method: "POST", headers: { "x-api-key": API_KEY!, "Content-Type": "application/json" }, + body: JSON.stringify({ metadata: { type: "ai-classification", size: String(candidates.length) } }), + }); + if (!grpRes.ok) { console.error(`Group create failed: ${grpRes.status} ${await grpRes.text()}`); process.exit(1); } + const grp = await grpRes.json(); + runData.groups.push({ groupId: grp.taskgroup_id, size: candidates.length }); + console.log(`Task group: ${grp.taskgroup_id}`); + + for (let j = 0; j < candidates.length; j += 500) { + const sub = candidates.slice(j, j + 500); + const inputs = sub.map((c) => ({ + input: buildInput(c.dc, c.enrichment), + task_spec: { output_schema: SCHEMA }, + processor: PROCESSOR, + metadata: { facility_index: String(c.index), facility_name: String(c.dc.name).slice(0, 100), type: "ai-classification" }, + })); + + const res = await fetch(`${BASE_URL}/v1/tasks/groups/${grp.taskgroup_id}/runs`, { + method: "POST", headers: { "x-api-key": API_KEY!, "Content-Type": "application/json" }, + body: JSON.stringify({ inputs }), + }); + if (!res.ok) { console.error(` Submit failed at ${j}: ${res.status} ${await res.text()}`); break; } + const data = await res.json(); + const runIds: string[] = data.run_ids || []; + + runIds.forEach((runId, k) => { + runData.runs.push({ runId, groupId: grp.taskgroup_id, facilityIndex: sub[k].index, facilityName: String(sub[k].dc.name) }); + }); + // Save immediately after each sub-batch so run IDs are never lost + fs.writeFileSync(RUNS_PATH, JSON.stringify(runData, null, 2)); + console.log(` Submitted ${j + 1}-${j + sub.length}: ${runIds.length} run IDs`); + } + + console.log(`Kicked off ${runData.runs.length} classification tasks. Run 'collect' to gather results.`); +} + +// ─── Collect ───────────────────────────────────────────────────────── + +async function collect() { + if (!fs.existsSync(RUNS_PATH)) { console.error("No runs file. Run kickoff first."); process.exit(1); } + const runData = JSON.parse(fs.readFileSync(RUNS_PATH, "utf-8")); + + let results: Record = {}; + if (fs.existsSync(OUT_PATH)) results = JSON.parse(fs.readFileSync(OUT_PATH, "utf-8")); + + let collected = 0, pending = 0, failed = 0; + + for (let i = 0; i < runData.runs.length; i += 20) { + const batch = runData.runs.slice(i, i + 20); + const settled = await Promise.all(batch.map(async (run: { runId: string; facilityIndex: number; facilityName: string }) => { + if (results[String(run.facilityIndex)]) return null; + + const statusRes = await fetch(`${BASE_URL}/v1/tasks/runs/${run.runId}`, { headers: { "x-api-key": API_KEY! } }); + if (!statusRes.ok) { pending++; return null; } + const statusData = await statusRes.json(); + if (statusData.status === "failed") { failed++; return null; } + if (statusData.status !== "completed") { pending++; return null; } + + const resultRes = await fetch(`${BASE_URL}/v1/tasks/runs/${run.runId}/result`, { headers: { "x-api-key": API_KEY! } }); + if (!resultRes.ok) return null; + return { run, result: await resultRes.json() }; + })); + + for (const r of settled) { + if (!r) continue; + const content = r.result?.output?.content; + if (!content || typeof content !== "object") continue; + const basis = (r.result?.output?.basis || []) as { citations?: { title?: string; url?: string }[] }[]; + const citations = basis + .flatMap((b) => (b.citations || []).map((c) => ({ title: c.title || "", url: c.url || "" }))) + .filter((c) => c.url) + .slice(0, 5); + results[String(r.run.facilityIndex)] = { ...content, citations, runId: r.run.runId, classifiedAt: new Date().toISOString() }; + collected++; + } + + fs.writeFileSync(OUT_PATH, JSON.stringify(results, null, 0)); + process.stdout.write(`\r Collected: ${Object.keys(results).length}/${runData.runs.length} (${collected} new, ${pending} pending, ${failed} failed)`); + await sleep(100); + } + + console.log(`\nDone. ${Object.keys(results).length}/${runData.runs.length} classifications in ${OUT_PATH}`); + if (pending > 0) console.log(`${pending} still pending — re-run 'collect' later.`); +} + +// ─── Main ──────────────────────────────────────────────────────────── + +const mode = process.argv[2]; +if (mode === "kickoff") kickoff().catch(console.error); +else if (mode === "collect") collect().catch(console.error); +else { console.error("Usage: npx tsx scripts/classify-ai.ts "); process.exit(1); } diff --git a/typescript-recipes/parallel-datacenter-map/scripts/collect-enrichments-v2.ts b/typescript-recipes/parallel-datacenter-map/scripts/collect-enrichments-v2.ts new file mode 100644 index 0000000..c23cced --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/collect-enrichments-v2.ts @@ -0,0 +1,150 @@ +/** + * Collects v2 enrichment results and merges with v1. + * Saves combined enrichments to public/data/enrichments.json. + * + * Usage: npx tsx scripts/collect-enrichments-v2.ts + */ + +import * as fs from "fs"; + +const API_KEY = + process.env.PARALLEL_API_KEY; +const BASE_URL = "https://api.parallel.ai"; + +async function checkGroupStatus(groupId: string) { + const res = await fetch(`${BASE_URL}/v1/tasks/groups/${groupId}`, { + headers: { "x-api-key": API_KEY }, + }); + if (!res.ok) return null; + return res.json(); +} + +async function fetchResult(runId: string) { + const statusRes = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}`, { + headers: { "x-api-key": API_KEY }, + }); + if (!statusRes.ok) return null; + const statusData = await statusRes.json(); + if (statusData.status !== "completed") return null; + + const resultRes = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}/result`, { + headers: { "x-api-key": API_KEY }, + }); + if (!resultRes.ok) return null; + return resultRes.json(); +} + +function sleep(ms: number) { + return new Promise((r) => setTimeout(r, ms)); +} + +async function main() { + const runsPath = "./src/data/enrichment-v2-runs.json"; + if (!fs.existsSync(runsPath)) { + console.error("No enrichment-v2-runs.json. Run run-enrichment-v2.ts first."); + process.exit(1); + } + + const runData = JSON.parse(fs.readFileSync(runsPath, "utf-8")); + console.log(`Collecting v2 results for ${runData.runs.length} runs...\n`); + + for (const group of runData.groups) { + const status = await checkGroupStatus(group.groupId); + if (status) { + console.log(`Group ${group.groupId}: ${JSON.stringify(status.status?.task_run_status_counts)}`); + } + } + console.log(); + + // Load existing v1 enrichments + const enrichPath = "./public/data/enrichments.json"; + const enrichments = JSON.parse(fs.readFileSync(enrichPath, "utf-8")); + console.log(`Existing v1 enrichments: ${Object.keys(enrichments).length}\n`); + + // Track v2 collection + let collected = 0; + let pending = 0; + const CONCURRENCY = 20; + + for (let i = 0; i < runData.runs.length; i += CONCURRENCY) { + const batch = runData.runs.slice(i, i + CONCURRENCY); + + const results = await Promise.all( + batch.map(async (run: { runId: string; facilityIndex: number; facilityName: string }) => { + // Skip if v2 already merged + const existing = enrichments[String(run.facilityIndex)]; + if (existing?.enrichment?.verified_operator) return null; + + const result = await fetchResult(run.runId); + if (!result) { + pending++; + return null; + } + return { run, result }; + }) + ); + + for (const r of results) { + if (!r) continue; + const v2Content = r.result?.output?.content; + if (!v2Content) continue; + + const key = String(r.run.facilityIndex); + const existing = enrichments[key]; + + if (existing) { + // Merge v2 fields into existing v1 enrichment + existing.enrichment = { + ...existing.enrichment, + ...v2Content, + }; + // Merge v2 basis into existing basis + const v2Basis = r.result?.output?.basis || []; + if (Array.isArray(v2Basis)) { + existing.basis = [...(existing.basis || []), ...v2Basis]; + } + existing.v2RunId = r.run.runId; + existing.v2CollectedAt = new Date().toISOString(); + } else { + enrichments[key] = { + runId: r.run.runId, + facilityName: r.run.facilityName, + facilityIndex: r.run.facilityIndex, + enrichment: v2Content, + basis: r.result?.output?.basis || [], + collectedAt: new Date().toISOString(), + }; + } + collected++; + } + + if ((i + CONCURRENCY) % 100 === 0 || i + CONCURRENCY >= runData.runs.length) { + fs.writeFileSync(enrichPath, JSON.stringify(enrichments, null, 2)); + process.stdout.write( + `\r Collected: ${collected} new v2, ${pending} pending` + ); + } + + await sleep(100); + } + + fs.writeFileSync(enrichPath, JSON.stringify(enrichments, null, 2)); + console.log(`\n\nDone. ${collected} v2 enrichments merged.`); + console.log(`${pending} still pending.`); + + // Show sample + const sample = enrichments["0"]; + if (sample?.enrichment) { + const e = sample.enrichment; + console.log(`\nSample (facility 0):`); + console.log(` verified_operator: ${e.verified_operator || "?"}`); + console.log(` verified_owner: ${e.verified_owner || "?"}`); + console.log(` cooling_type: ${e.cooling_type || "?"}`); + console.log(` utility_provider: ${e.utility_provider || "?"}`); + console.log(` campus_acres: ${e.campus_acres || "?"}`); + console.log(` expansion_capacity_mw: ${e.expansion_capacity_mw || "?"}`); + console.log(` community_opposition: ${e.community_opposition || "?"}`); + } +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/collect-enrichments.ts b/typescript-recipes/parallel-datacenter-map/scripts/collect-enrichments.ts new file mode 100644 index 0000000..245eb77 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/collect-enrichments.ts @@ -0,0 +1,159 @@ +/** + * Collects enrichment results from completed Task API runs. + * Reads run IDs from src/data/enrichment-runs.json, fetches results, + * saves to public/data/enrichments.json. + * + * Can be run multiple times — only fetches completed runs, skips others. + * + * Usage: npx tsx scripts/collect-enrichments.ts + */ + +import * as fs from "fs"; + +const API_KEY = + process.env.PARALLEL_API_KEY; +const BASE_URL = "https://api.parallel.ai"; + +interface EnrichmentRun { + runId: string; + groupId: string; + facilityIndex: number; + facilityName: string; +} + +interface EnrichmentData { + groups: { groupId: string; batchIndex: number; size: number }[]; + runs: EnrichmentRun[]; + startedAt: string; + processor: string; + totalFacilities: number; +} + +async function checkGroupStatus(groupId: string) { + const res = await fetch(`${BASE_URL}/v1/tasks/groups/${groupId}`, { + headers: { "x-api-key": API_KEY }, + }); + if (!res.ok) return null; + return res.json(); +} + +async function fetchResult(runId: string) { + // Check status first + const statusRes = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}`, { + headers: { "x-api-key": API_KEY }, + }); + if (!statusRes.ok) return null; + const statusData = await statusRes.json(); + if (statusData.status !== "completed") return null; + + // Fetch full result + const resultRes = await fetch( + `${BASE_URL}/v1/tasks/runs/${runId}/result`, + { headers: { "x-api-key": API_KEY } } + ); + if (!resultRes.ok) return null; + return resultRes.json(); +} + +function sleep(ms: number) { + return new Promise((r) => setTimeout(r, ms)); +} + +async function main() { + const runsPath = "./src/data/enrichment-runs.json"; + if (!fs.existsSync(runsPath)) { + console.error("No enrichment-runs.json found. Run run-enrichment.ts first."); + process.exit(1); + } + + const data: EnrichmentData = JSON.parse(fs.readFileSync(runsPath, "utf-8")); + console.log(`Collecting results for ${data.runs.length} enrichment runs...\n`); + + // Check group status first + for (const group of data.groups) { + const status = await checkGroupStatus(group.groupId); + if (status) { + console.log(`Group ${group.groupId}: ${JSON.stringify(status.status?.task_run_status_counts)}`); + } + } + console.log(); + + // Load existing enrichments (for incremental collection) + const enrichPath = "./public/data/enrichments.json"; + let enrichments: Record = {}; + if (fs.existsSync(enrichPath)) { + enrichments = JSON.parse(fs.readFileSync(enrichPath, "utf-8")); + } + const existingCount = Object.keys(enrichments).length; + console.log(`Existing enrichments: ${existingCount}\n`); + + // Fetch results in parallel batches + const CONCURRENCY = 20; + let completed = 0; + let failed = 0; + let pending = 0; + + for (let i = 0; i < data.runs.length; i += CONCURRENCY) { + const batch = data.runs.slice(i, i + CONCURRENCY); + + const results = await Promise.all( + batch.map(async (run) => { + // Skip if already collected + if (enrichments[String(run.facilityIndex)]) return null; + + const result = await fetchResult(run.runId); + if (!result) { + pending++; + return null; + } + + return { run, result }; + }) + ); + + for (const r of results) { + if (!r) continue; + + const content = r.result?.output?.content; + if (content) { + enrichments[String(r.run.facilityIndex)] = { + runId: r.run.runId, + facilityName: r.run.facilityName, + facilityIndex: r.run.facilityIndex, + enrichment: content, + basis: r.result?.output?.basis, + collectedAt: new Date().toISOString(), + }; + completed++; + } else { + failed++; + } + } + + // Save incrementally every 100 results + if ((i + CONCURRENCY) % 100 === 0 || i + CONCURRENCY >= data.runs.length) { + fs.writeFileSync(enrichPath, JSON.stringify(enrichments, null, 2)); + const total = Object.keys(enrichments).length; + process.stdout.write( + `\r Collected: ${total}/${data.runs.length} (${completed} new, ${pending} pending, ${failed} failed)` + ); + } + + // Small delay to avoid rate limits + await sleep(100); + } + + const totalCollected = Object.keys(enrichments).length; + console.log( + `\n\nDone. ${totalCollected}/${data.runs.length} enrichments collected.` + ); + console.log(`Saved to ${enrichPath}`); + + if (totalCollected < data.runs.length) { + console.log( + `\n${data.runs.length - totalCollected} runs still pending. Run this script again later.` + ); + } +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/convert-csv.ts b/typescript-recipes/parallel-datacenter-map/scripts/convert-csv.ts new file mode 100644 index 0000000..7b30936 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/convert-csv.ts @@ -0,0 +1,34 @@ +import * as fs from "fs"; +import Papa from "papaparse"; + +const csvPath = "/Users/khushishelat/Downloads/datacenters_clean.csv"; +const outPath = "./public/data/datacenters.json"; + +const raw = fs.readFileSync(csvPath, "utf-8"); +const { data } = Papa.parse(raw, { header: true, skipEmptyLines: true }); + +const cleaned = (data as Record[]).map((row) => ({ + name: row.name?.trim() || "", + operator: row.operator_company?.trim() || "", + owner: row.owner_company?.trim() || "", + address: row.address?.trim() || "", + city: row.city?.trim() || "", + state: row.state?.trim() || "", + zip: row.zip_code?.trim() || "", + lat: parseFloat(row.latitude) || 0, + lng: parseFloat(row.longitude) || 0, + yearOnline: row.year_online?.trim() || "unknown", + powerMw: Math.min(parseFloat(row.power_capacity_mw) || 0, 5000), // clamp absurd values + sqft: parseFloat(row.total_sqft) || 0, + type: row.facility_type?.trim() || "unknown", + status: row.status?.trim() || "unknown", + region: row._shard?.trim() || "", +})).filter((r) => r.lat !== 0 && r.lng !== 0); // drop rows with no coords + +fs.writeFileSync(outPath, JSON.stringify(cleaned, null, 0)); +console.log(`Wrote ${cleaned.length} datacenters to ${outPath}`); + +// Stats +const statusCounts: Record = {}; +cleaned.forEach((r) => { statusCounts[r.status] = (statusCounts[r.status] || 0) + 1; }); +console.log("Status counts:", statusCounts); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/create-snapshots.ts b/typescript-recipes/parallel-datacenter-map/scripts/create-snapshots.ts new file mode 100644 index 0000000..dd6a27e --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/create-snapshots.ts @@ -0,0 +1,144 @@ +/** + * Creates snapshot monitors for all enrichment runs. + * Each monitor watches one facility's enrichment for changes daily (1d). + * Uses v2 run IDs (most complete enrichment). + * + * Usage: npx tsx scripts/create-snapshots.ts + */ + +import * as fs from "fs"; + +const API_KEY = + process.env.PARALLEL_API_KEY; +const BASE_URL = "https://api.parallel.ai"; + +// Deployed webhook URL — update after deployment +const WEBHOOK_URL = process.env.WEBHOOK_URL || ""; +if (!WEBHOOK_URL) console.warn("Warning: WEBHOOK_URL not set. Snapshots won't push events to the app."); + +interface RunEntry { + runId: string; + groupId: string; + facilityIndex: number; + facilityName: string; +} + +function sleep(ms: number) { + return new Promise((r) => setTimeout(r, ms)); +} + +async function createSnapshotMonitor( + taskRunId: string, + facilityName: string, + facilityIndex: number +): Promise { + const res = await fetch(`${BASE_URL}/v1/monitors`, { + method: "POST", + headers: { + "x-api-key": API_KEY, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + type: "snapshot", + frequency: "1d", + processor: "base", + settings: { task_run_id: taskRunId }, + webhook: { + url: WEBHOOK_URL, + event_types: ["monitor.event.detected"], + }, + metadata: { + facility_name: facilityName.slice(0, 100), + facility_index: String(facilityIndex), + type: "datacenter-snapshot", + }, + }), + }); + + if (!res.ok) { + const err = await res.text(); + console.error(` ✗ [${facilityIndex}] ${facilityName}: ${res.status} ${err.slice(0, 150)}`); + return null; + } + + const data = await res.json(); + return data.monitor_id; +} + +async function main() { + // Use v2 run IDs (most complete enrichment) + const runsPath = "./src/data/enrichment-v2-runs.json"; + if (!fs.existsSync(runsPath)) { + console.error("No enrichment-v2-runs.json found."); + process.exit(1); + } + + const runData = JSON.parse(fs.readFileSync(runsPath, "utf-8")); + const runs: RunEntry[] = runData.runs; + + console.log(`Creating snapshot monitors for ${runs.length} facilities...`); + console.log(`Webhook: ${WEBHOOK_URL}`); + console.log(`Rate limit: ~300/min, pacing at ~200/min\n`); + + // Load existing snapshots to resume + const snapshotPath = "./src/data/snapshot-monitors.json"; + let snapshots: Record = {}; + if (fs.existsSync(snapshotPath)) { + snapshots = JSON.parse(fs.readFileSync(snapshotPath, "utf-8")); + } + + let created = 0; + let skipped = 0; + let failed = 0; + + for (let i = 0; i < runs.length; i++) { + const run = runs[i]; + const key = String(run.facilityIndex); + + // Skip if already has a snapshot + if (snapshots[key]) { + skipped++; + continue; + } + + const monitorId = await createSnapshotMonitor( + run.runId, + run.facilityName, + run.facilityIndex + ); + + if (monitorId) { + snapshots[key] = { + monitorId, + runId: run.runId, + facilityName: run.facilityName, + }; + created++; + } else { + failed++; + } + + // Save every 50 + if ((created + failed) % 50 === 0 && (created + failed) > 0) { + fs.writeFileSync(snapshotPath, JSON.stringify(snapshots, null, 2)); + process.stdout.write( + `\r Progress: ${i + 1}/${runs.length} | Created: ${created} | Skipped: ${skipped} | Failed: ${failed}` + ); + } + + // Rate limit: ~200/min = 1 every 300ms + await sleep(300); + } + + // Final save + fs.writeFileSync(snapshotPath, JSON.stringify(snapshots, null, 2)); + + console.log(`\n\n=== DONE ===`); + console.log(`Created: ${created}`); + console.log(`Skipped: ${skipped}`); + console.log(`Failed: ${failed}`); + console.log(`Total snapshots: ${Object.keys(snapshots).length}`); + console.log(`Saved to ${snapshotPath}`); +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/finish-issue.ts b/typescript-recipes/parallel-datacenter-map/scripts/finish-issue.ts new file mode 100644 index 0000000..ce35162 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/finish-issue.ts @@ -0,0 +1,103 @@ +#!/usr/bin/env npx tsx +/** + * Resume a Datacenter Signal issue whose Task API research run is already + * in-flight (or done): poll the existing run, then run the Claude writer and + * store to Vercel Blob. Avoids re-kicking research that's already running. + * + * Usage: + * ... npx tsx scripts/finish-issue.ts "" + */ + +import * as fs from "fs"; +import { put, list } from "@vercel/blob"; +import { writeNewsletter, wrapEmailTemplate } from "../src/lib/newsletter-writer"; +import monitorsData from "../src/data/monitors.json"; + +const API_KEY = process.env.PARALLEL_API_KEY || ""; +const ANTHROPIC_KEY = process.env.ANTHROPIC_API_KEY || ""; +const BLOB_TOKEN = process.env.BLOB_READ_WRITE_TOKEN || ""; +const BASE_URL = "https://api.parallel.ai"; + +function weekOf(n: number): string { + const ms = new Date("2024-01-01").getTime() + n * 7 * 24 * 60 * 60 * 1000; + return new Date(ms).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }); +} + +async function fetchMonitorEvents() { + const monitors = monitorsData as Record; + const all: { headline: string; monitorName: string; severity: string }[] = []; + const full = new Map(); + for (const [, info] of Object.entries(monitors)) { + try { + const res = await fetch(`${BASE_URL}/v1/monitors/${info.monitorId}/events`, { headers: { "x-api-key": API_KEY }, cache: "no-store" }); + if (!res.ok) continue; + const data = await res.json(); + for (const evt of data.events || []) { + const c = evt.output?.content; + if (!c || typeof c !== "object") continue; + const e = { headline: c.headline || "", monitorName: info.name, severity: c.severity || "informational" }; + all.push(e); + if (!full.has(info.name)) full.set(info.name, []); + full.get(info.name)!.push(e); + } + } catch {} + } + return { all, regions: full }; +} + +async function main() { + const issueNumber = parseInt(process.argv[2]); + const runId = process.argv[3]; + const focus = process.argv[4] || ""; + if (!issueNumber || !runId) { console.error("Pass [focus]"); process.exit(1); } + + const existing = await list({ prefix: `newsletters/issue-${issueNumber}`, token: BLOB_TOKEN }); + if (existing.blobs.length) { + const r = await fetch(existing.blobs[0].downloadUrl, { headers: { Authorization: `Bearer ${BLOB_TOKEN}` } }); + if (r.ok && (await r.json()).content) { console.log(`[${issueNumber}] already done`); fs.writeFileSync(`/tmp/issue-${issueNumber}.done`, "ok"); return; } + } + + console.log(`[${issueNumber}] Polling existing run ${runId}...`); + let research = "", interactionId = runId; + const start = Date.now(); + while (Date.now() - start < 20 * 60 * 1000) { + await new Promise((r) => setTimeout(r, 6000)); + const s = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}`, { headers: { "x-api-key": API_KEY } }); + if (!s.ok) continue; + const sd = await s.json(); + if (sd.status === "completed") { + interactionId = sd.interaction_id || runId; + const rr = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}/result`, { headers: { "x-api-key": API_KEY } }); + const raw = (await rr.json()).output?.content; + research = typeof raw === "string" ? raw : JSON.stringify(raw) || ""; + break; + } + if (sd.status === "failed" || sd.status === "cancelled") { console.error(`[${issueNumber}] run ${sd.status}`); process.exit(1); } + } + if (!research) { console.error(`[${issueNumber}] research timed out`); process.exit(1); } + console.log(`[${issueNumber}] research done (${research.length} chars). Writing...`); + + const { all, regions } = await fetchMonitorEvents(); + const bodyHtml = await writeNewsletter({ + research, interactionId, issueNumber, + eventsTotal: all.length, + criticalCount: all.filter((e) => e.severity === "critical").length, + marketsActive: regions.size, + regionSummaries: Array.from(regions.entries()).map(([name, evts]) => `${name} (${evts.length} events): ${evts[0]?.headline || ""}`).join("\n"), + parallelApiKey: API_KEY, anthropicApiKey: ANTHROPIC_KEY, + }); + + const issueData = { + issueNumber, content: bodyHtml, emailHtml: wrapEmailTemplate(bodyHtml, issueNumber), + focus, weekOf: weekOf(issueNumber), researchRunId: runId, interactionId, + stats: { events: all.length, critical: all.filter((e) => e.severity === "critical").length, markets: regions.size }, + generatedAt: new Date().toISOString(), status: "completed", + }; + await put(`newsletters/issue-${issueNumber}.json`, JSON.stringify(issueData), { + access: "private", allowOverwrite: true, contentType: "application/json", token: BLOB_TOKEN, + }); + console.log(`[${issueNumber}] ✓ stored (${bodyHtml.length} chars)`); + fs.writeFileSync(`/tmp/issue-${issueNumber}.done`, "ok"); +} + +main().catch((e) => { console.error(e); process.exit(1); }); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/generate-issue.ts b/typescript-recipes/parallel-datacenter-map/scripts/generate-issue.ts new file mode 100644 index 0000000..831a7b3 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/generate-issue.ts @@ -0,0 +1,179 @@ +#!/usr/bin/env npx tsx +/** + * Generate a single Datacenter Signal issue for a given issue number and store + * it to Vercel Blob (same shape the app's /api/newsletter pipeline writes). + * + * Real Task API deep research + Claude writer — nothing fabricated. Used to + * seed the newsletter archive with a few back-issues so the reader has issues + * to click through. Each issue takes an editorial "focus" so back-issues read + * distinctly even though they draw from the same live monitor pool. + * + * Usage: + * PARALLEL_API_KEY=.. ANTHROPIC_API_KEY=.. BLOB_READ_WRITE_TOKEN=.. \ + * npx tsx scripts/generate-issue.ts "" + */ + +import * as fs from "fs"; +import { put, list } from "@vercel/blob"; +import { writeNewsletter, wrapEmailTemplate } from "../src/lib/newsletter-writer"; +import monitorsData from "../src/data/monitors.json"; + +const API_KEY = process.env.PARALLEL_API_KEY || ""; +const ANTHROPIC_KEY = process.env.ANTHROPIC_API_KEY || ""; +const BLOB_TOKEN = process.env.BLOB_READ_WRITE_TOKEN || ""; +const BASE_URL = "https://api.parallel.ai"; + +if (!API_KEY || !ANTHROPIC_KEY || !BLOB_TOKEN) { + console.error("Need PARALLEL_API_KEY, ANTHROPIC_API_KEY, BLOB_READ_WRITE_TOKEN."); + process.exit(1); +} + +function weekOf(issueNumber: number): string { + const ms = new Date("2024-01-01").getTime() + issueNumber * 7 * 24 * 60 * 60 * 1000; + return new Date(ms).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }); +} + +async function fetchMonitorEvents() { + const monitors = monitorsData as Record; + const allEvents: { headline: string; summary: string; category: string; severity: string; eventDate: string; affectedEntities: string; monitorName: string; citations: { title: string; url: string }[] }[] = []; + for (const [, info] of Object.entries(monitors)) { + try { + const res = await fetch(`${BASE_URL}/v1/monitors/${info.monitorId}/events`, { headers: { "x-api-key": API_KEY }, cache: "no-store" }); + if (!res.ok) continue; + const data = await res.json(); + for (const evt of data.events || []) { + const content = evt.output?.content; + if (!content || typeof content !== "object") continue; + const basis = evt.output?.basis || []; + const citations = basis.flatMap((b: { citations?: { title?: string; url?: string }[] }) => + (b.citations || []).map((c) => ({ title: c.title || "", url: c.url || "" }))).slice(0, 3); + allEvents.push({ + headline: content.headline || "", summary: content.summary || "", + category: content.category || "", severity: content.severity || "informational", + eventDate: evt.event_date || "", affectedEntities: content.affected_entities || "", + monitorName: info.name, citations, + }); + } + } catch {} + } + return allEvents; +} + +function buildPrompt(events: Awaited>, issueNumber: number, focus: string) { + const critical = events.filter((e) => e.severity === "critical").slice(0, 6); + const regions = new Map(); + for (const e of events) { + if (!regions.has(e.monitorName)) regions.set(e.monitorName, []); + regions.get(e.monitorName)!.push(e); + } + let criticalSection = ""; + for (const evt of critical) { + criticalSection += `\n### ${evt.headline}\nRegion: ${evt.monitorName} | Category: ${evt.category} | Date: ${evt.eventDate}\n${evt.summary}\n`; + if (evt.affectedEntities) criticalSection += `Affects: ${evt.affectedEntities}\n`; + if (evt.citations.length) criticalSection += `Sources: ${evt.citations.map((c) => `${c.title} (${c.url})`).join("; ")}\n`; + } + let regionalSection = ""; + for (const [name, evts] of Array.from(regions.entries()).slice(0, 12)) { + regionalSection += `- **${name}** (${evts.length} events): ${evts[0].headline}\n`; + } + + return `Write "Datacenter Signal — Issue ${issueNumber}" (Week of ${weekOf(issueNumber)}), a weekly infrastructure intelligence brief for datacenter investors. + +EDITORIAL FOCUS FOR THIS ISSUE: ${focus} +Lead the issue with the developments most relevant to that focus. Do not omit other critical items, but frame the "week in one read" and lead story around the focus. + +CRITICAL EVENTS THIS WEEK (deep-research each one): +${criticalSection || "No critical events this week."} + +ALL EVENTS SUMMARY: +- Total events detected: ${events.length} +- Critical: ${critical.length} +- Markets with activity: ${regions.size} + +REGIONAL ACTIVITY: +${regionalSection || "No regional activity."} + +INSTRUCTIONS: +1. Open with "The Week in One Read" — 2-3 sentence executive summary anchored on the editorial focus +2. "Critical Developments" — thorough analysis of each critical event with background, stakeholders, implications, and what to watch +3. "Regional Roundup" — one line per active region +4. "By the Numbers" — key stats + +Tone: analytical, concise, data-anchored, like a Financial Times briefing. No hype, no speculation. Weave inline source links into prose using publication names. No emoji. No numbered references like [1].`; +} + +async function main() { + const issueNumber = parseInt(process.argv[2]); + const focus = process.argv[3] || "The most consequential developments of the week"; + if (!issueNumber) { console.error("Pass an issue number."); process.exit(1); } + + // Skip if already fully generated + const { blobs } = await list({ prefix: `newsletters/issue-${issueNumber}`, token: BLOB_TOKEN }); + if (blobs.length) { + const res = await fetch(blobs[0].downloadUrl, { headers: { Authorization: `Bearer ${BLOB_TOKEN}` } }); + if (res.ok && (await res.json()).content) { console.log(`Issue ${issueNumber} already generated. Skipping.`); return; } + } + + console.log(`[${issueNumber}] Fetching monitor events...`); + const events = await fetchMonitorEvents(); + console.log(`[${issueNumber}] ${events.length} events. Kicking off Task API research (ultra-fast)...`); + + const taskRes = await fetch(`${BASE_URL}/v1/tasks/runs`, { + method: "POST", headers: { "x-api-key": API_KEY, "Content-Type": "application/json" }, + body: JSON.stringify({ + input: buildPrompt(events, issueNumber, focus), + task_spec: { output_schema: { type: "text", description: "Comprehensive factual research with specific data points, dates, numbers, and source URLs for each critical event." } }, + processor: "ultra-fast", + }), + }); + if (!taskRes.ok) { console.error(`[${issueNumber}] Task API failed: ${await taskRes.text()}`); process.exit(1); } + const { run_id } = await taskRes.json(); + console.log(`[${issueNumber}] Research run: ${run_id}`); + + // Poll research + let research = "", interactionId = run_id; + const start = Date.now(); + while (Date.now() - start < 8 * 60 * 1000) { + await new Promise((r) => setTimeout(r, 5000)); + const s = await fetch(`${BASE_URL}/v1/tasks/runs/${run_id}`, { headers: { "x-api-key": API_KEY } }); + if (!s.ok) continue; + const sd = await s.json(); + if (sd.status === "completed") { + interactionId = sd.interaction_id || run_id; + const rr = await fetch(`${BASE_URL}/v1/tasks/runs/${run_id}/result`, { headers: { "x-api-key": API_KEY } }); + const raw = (await rr.json()).output?.content; + research = typeof raw === "string" ? raw : JSON.stringify(raw) || ""; + break; + } + if (sd.status === "failed") { console.error(`[${issueNumber}] Research failed`); process.exit(1); } + } + if (!research) { console.error(`[${issueNumber}] Research timed out`); process.exit(1); } + console.log(`[${issueNumber}] Research done (${research.length} chars). Writing with Claude...`); + + const regions = new Map(); + for (const e of events) { if (!regions.has(e.monitorName)) regions.set(e.monitorName, []); regions.get(e.monitorName)!.push(e); } + + const bodyHtml = await writeNewsletter({ + research, interactionId, issueNumber, + eventsTotal: events.length, + criticalCount: events.filter((e) => e.severity === "critical").length, + marketsActive: regions.size, + regionSummaries: Array.from(regions.entries()).map(([name, evts]) => `${name} (${evts.length} events): ${evts[0]?.headline || ""}`).join("\n"), + parallelApiKey: API_KEY, anthropicApiKey: ANTHROPIC_KEY, + }); + + const emailHtml = wrapEmailTemplate(bodyHtml, issueNumber); + const issueData = { + issueNumber, content: bodyHtml, emailHtml, focus, weekOf: weekOf(issueNumber), + researchRunId: run_id, interactionId, + stats: { events: events.length, critical: events.filter((e) => e.severity === "critical").length, markets: regions.size }, + generatedAt: new Date().toISOString(), status: "completed", + }; + await put(`newsletters/issue-${issueNumber}.json`, JSON.stringify(issueData), { + access: "private", allowOverwrite: true, contentType: "application/json", token: BLOB_TOKEN, + }); + console.log(`[${issueNumber}] ✓ Stored to blob (${bodyHtml.length} chars body).`); + fs.writeFileSync(`/tmp/issue-${issueNumber}.done`, "ok"); +} + +main().catch((e) => { console.error(e); process.exit(1); }); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/monitor-configs.ts b/typescript-recipes/parallel-datacenter-map/scripts/monitor-configs.ts new file mode 100644 index 0000000..8726826 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/monitor-configs.ts @@ -0,0 +1,509 @@ +export interface MonitorDef { + id: string; + name: string; + class: "region" | "facility" | "discovery"; + query: string; + frequency: string; + processor: string; + region?: string; + facilityCode?: string; + states?: string[]; // which US states this monitor covers +} + +/** + * Structured output schema for all monitors. + * Every detected event comes back with a classified category. + */ +export const MONITOR_OUTPUT_SCHEMA = { + type: "json" as const, + json_schema: { + type: "object" as const, + properties: { + category: { + type: "string" as const, + description: "The primary category of this development", + enum: [ + "POWER_GRID", + "ZONING_POLICY", + "COMMUNITY", + "WATER", + "LAND_SUPPLY", + "TENANT_DEMAND", + "CAPITAL_OWNERSHIP", + "CONSTRUCTION", + ], + }, + headline: { + type: "string" as const, + description: "One-line headline for the event (under 120 characters)", + }, + summary: { + type: "string" as const, + description: + "2-3 sentence summary including specific entities, dates, numbers, and what changed", + }, + severity: { + type: "string" as const, + description: "Impact level for datacenter infrastructure investors", + enum: ["critical", "notable", "informational"], + }, + affected_entities: { + type: "string" as const, + description: + "Specific companies, facilities, or projects affected (e.g., 'QTS Manassas, Dominion Energy')", + }, + }, + required: [ + "category", + "headline", + "summary", + "severity", + "affected_entities", + ], + additionalProperties: false, + }, +}; + +/** + * Category labels for the UI + */ +export const CATEGORY_LABELS: Record = { + POWER_GRID: "Power & Grid", + ZONING_POLICY: "Zoning & Policy", + COMMUNITY: "Community", + WATER: "Water & Cooling", + LAND_SUPPLY: "Land & Supply", + TENANT_DEMAND: "Tenant & Demand", + CAPITAL_OWNERSHIP: "Capital & Ownership", + CONSTRUCTION: "Construction", +}; + +// Comprehensive query template covering all signal types +function regionQuery(region: string, specifics: string): string { + return `Data center developments in ${region}: ${specifics}. Track: utility interconnection and power capacity filings, rezoning and special-use permit applications and decisions, moratoria or development freezes, community opposition and litigation, water-use restrictions or drought actions, large land assemblies and site transactions, hyperscaler expansion announcements, operator M&A or ownership changes, and construction milestones.`; +} + +function facilityQuery(facility: string, specifics: string): string { + return `${facility}: ${specifics}. Track any material development including power interconnection filings, zoning or permit actions, construction milestones, ownership or tenant changes, community opposition, and water or environmental restrictions.`; +} + +export const MONITOR_DEFS: MonitorDef[] = [ + // ============================================= + // CLASS 1: Region monitors (23) + // ============================================= + + // --- Original 8 regions --- + { + id: "region-nova", + name: "Northern Virginia", + class: "region", + query: regionQuery( + "Loudoun and Prince William County, Virginia", + "Dominion Energy interconnection and large-load filings, SCC transmission approvals, county zoning and special-exception votes" + ), + frequency: "1h", + processor: "base", + region: "Northern Virginia", + states: ["VA"], + }, + { + id: "region-atlanta", + name: "Atlanta / Georgia", + class: "region", + query: regionQuery( + "Georgia (metro Atlanta, Fayette, Coweta, DeKalb counties)", + "Georgia Power interconnection actions, county rezoning approvals and denials, development moratoria" + ), + frequency: "1h", + processor: "base", + region: "Atlanta, GA", + states: ["GA"], + }, + { + id: "region-ohio", + name: "Central Ohio", + class: "region", + query: regionQuery( + "central Ohio (New Albany, Columbus, Licking County, Etna Township)", + "AEP Ohio power agreements and tariff disputes, township zoning bans, statewide moratorium legislation" + ), + frequency: "1h", + processor: "base", + region: "Central Ohio", + states: ["OH"], + }, + { + id: "region-phoenix", + name: "Phoenix / Arizona", + class: "region", + query: regionQuery( + "metro Phoenix and Maricopa County, Arizona", + "APS and SRP power capacity, groundwater restrictions, municipal water-use caps for data centers, Pinal County developments" + ), + frequency: "1h", + processor: "base", + region: "Phoenix, AZ", + states: ["AZ"], + }, + { + id: "region-utah", + name: "Utah", + class: "region", + query: regionQuery( + "Utah (Eagle Mountain, Salt Lake City corridor, West Jordan)", + "Rocky Mountain Power load commitments, municipal water and power approvals, West Valley and Iron County permits" + ), + frequency: "1h", + processor: "base", + region: "Utah", + states: ["UT"], + }, + { + id: "region-texas", + name: "Texas", + class: "region", + query: regionQuery( + "Texas", + "ERCOT large-load interconnection rules and Batch Zero process, grid-reliability legislation, PUCT actions, municipal approvals in Dallas, San Antonio, and Red Oak" + ), + frequency: "1h", + processor: "base", + region: "Texas", + states: ["TX"], + }, + { + id: "region-pnw", + name: "Pacific Northwest", + class: "region", + query: regionQuery( + "Washington and Oregon (Seattle, Hillsboro, Quincy, The Dalles)", + "Seattle municipal moratoria, BPA and PSE power constraints, Bonneville Power Administration capacity, Oregon permitting" + ), + frequency: "1h", + processor: "base", + region: "Pacific Northwest", + states: ["WA", "OR"], + }, + { + id: "region-florida", + name: "Florida", + class: "region", + query: regionQuery( + "Florida", + "county moratoria and rezoning freezes (Citrus, Palm Coast, Flagler, Lake), FPL power agreements, hurricane resilience requirements" + ), + frequency: "1h", + processor: "base", + region: "Florida", + states: ["FL"], + }, + + // --- 15 new regions for 90% coverage --- + { + id: "region-norcal", + name: "Northern California", + class: "region", + query: regionQuery( + "Northern California (Silicon Valley, Santa Clara, Sacramento, Stockton)", + "PG&E power capacity and interconnection, CPUC filings, Santa Clara city approvals, Bay Area environmental review" + ), + frequency: "1h", + processor: "base", + region: "Northern California", + states: ["CA"], + }, + { + id: "region-socal", + name: "Southern California", + class: "region", + query: regionQuery( + "Southern California (Los Angeles, Inland Empire, San Diego)", + "SCE and LADWP power capacity, SCAQMD air quality permits, water restrictions, Riverside and San Bernardino county approvals" + ), + frequency: "1h", + processor: "base", + region: "Southern California", + states: ["CA"], + }, + { + id: "region-chicago", + name: "Chicago / Illinois", + class: "region", + query: regionQuery( + "Illinois (Chicago, Elk Grove Village, Aurora, Joliet)", + "ComEd power capacity and interconnection, Cook and DuPage county approvals, Illinois tax incentive programs" + ), + frequency: "1h", + processor: "base", + region: "Chicago, IL", + states: ["IL"], + }, + { + id: "region-nymetro", + name: "New York Metro", + class: "region", + query: regionQuery( + "New Jersey and New York", + "PSE&G and ConEd interconnection capacity, NJ Board of Public Utilities filings, NYC and Newark zoning, New York State moratorium proposals" + ), + frequency: "1h", + processor: "base", + region: "New York Metro", + states: ["NJ", "NY"], + }, + { + id: "region-newengland", + name: "New England", + class: "region", + query: regionQuery( + "New England (Massachusetts, Connecticut, New Hampshire)", + "Eversource and National Grid power capacity, Boston-area and Hartford zoning, Maine renewable-powered DC proposals" + ), + frequency: "1h", + processor: "base", + region: "New England", + states: ["MA", "CT", "NH", "ME", "RI", "VT"], + }, + { + id: "region-minnesota", + name: "Minnesota", + class: "region", + query: regionQuery( + "Minnesota (Minneapolis, Shakopee, Chaska)", + "Xcel Energy power capacity, Shakopee and Scott County approvals, Minnesota legislative actions on data centers" + ), + frequency: "1h", + processor: "base", + region: "Minnesota", + states: ["MN"], + }, + { + id: "region-michigan", + name: "Michigan", + class: "region", + query: regionQuery( + "Michigan (Detroit, Grand Rapids, West Michigan)", + "DTE Energy and Consumers Energy power capacity, county economic incentives, Michigan Strategic Fund approvals" + ), + frequency: "1h", + processor: "base", + region: "Michigan", + states: ["MI"], + }, + { + id: "region-kentucky", + name: "Kentucky", + class: "region", + query: regionQuery( + "Kentucky (Louisville, Lexington, Bowling Green)", + "LG&E and KU power agreements, Kentucky economic development incentives, TVA-connected sites" + ), + frequency: "1h", + processor: "base", + region: "Kentucky", + states: ["KY"], + }, + { + id: "region-nevada", + name: "Las Vegas / Nevada", + class: "region", + query: regionQuery( + "Nevada (Las Vegas, Reno, Henderson)", + "NV Energy power capacity, Southern Nevada Water Authority restrictions, Clark County approvals, Switch and other operator expansions" + ), + frequency: "1h", + processor: "base", + region: "Nevada", + states: ["NV"], + }, + { + id: "region-dcmetro", + name: "DC Metro / Maryland", + class: "region", + query: regionQuery( + "Maryland and Washington DC metro (Prince George's County, Frederick, Loudoun adjacent)", + "BGE and Pepco power capacity, PJM interconnection for MD sites, county zoning, Frederick County data center ordinances" + ), + frequency: "1h", + processor: "base", + region: "DC Metro", + states: ["MD", "DC", "DE"], + }, + { + id: "region-tennessee", + name: "Tennessee", + class: "region", + query: regionQuery( + "Tennessee (Nashville, Clarksville, Chattanooga)", + "TVA power agreements and industrial rates, Clarksville campus developments, state economic incentives" + ), + frequency: "1h", + processor: "base", + region: "Tennessee", + states: ["TN"], + }, + { + id: "region-midwest", + name: "Kansas City / Midwest", + class: "region", + query: regionQuery( + "the central Midwest (Missouri, Kansas, Nebraska, Iowa)", + "Evergy and MidAmerican Energy power capacity, Kansas City metro approvals, Iowa and Nebraska economic incentives" + ), + frequency: "1h", + processor: "base", + region: "Central Midwest", + states: ["MO", "KS", "NE", "IA"], + }, + { + id: "region-carolinas", + name: "Carolinas", + class: "region", + query: regionQuery( + "North and South Carolina", + "Duke Energy power capacity and interconnection, Charlotte and Raleigh-Durham area approvals, Stokes County and rural county rezoning controversies" + ), + frequency: "1h", + processor: "base", + region: "Carolinas", + states: ["NC", "SC"], + }, + { + id: "region-colorado", + name: "Colorado", + class: "region", + query: regionQuery( + "Colorado (Denver, Aurora, Colorado Springs)", + "Xcel Energy power capacity, Aurora and Douglas County approvals, Colorado water court filings" + ), + frequency: "1h", + processor: "base", + region: "Colorado", + states: ["CO"], + }, + { + id: "region-pennsylvania", + name: "Pennsylvania", + class: "region", + query: regionQuery( + "Pennsylvania (Philadelphia, Lehigh Valley, Pittsburgh)", + "PECO and PPL Electric power capacity, Lehigh Valley zoning, Pennsylvania economic incentive programs" + ), + frequency: "1h", + processor: "base", + region: "Pennsylvania", + states: ["PA"], + }, + + // ============================================= + // CLASS 2: Facility monitors (6) + // ============================================= + { + id: "facility-qts-cedar-rapids", + name: "QTS Cedar Rapids", + class: "facility", + query: facilityQuery( + "QTS Data Centers Cedar Rapids, Iowa campus", + "Alliant Energy and ITC Midwest power agreements, Linn County approvals, construction progress" + ), + frequency: "1h", + processor: "base", + facilityCode: "QTS-CR", + region: "Iowa", + states: ["IA"], + }, + { + id: "facility-qts-new-albany", + name: "QTS New Albany", + class: "facility", + query: facilityQuery( + "QTS Data Centers New Albany, Ohio campus expansion", + "AEP Ohio power agreements, New Albany and Licking County zoning, construction milestones" + ), + frequency: "1h", + processor: "base", + facilityCode: "QTS-NA", + region: "Central Ohio", + states: ["OH"], + }, + { + id: "facility-qts-eagle-mountain", + name: "QTS Eagle Mountain", + class: "facility", + query: facilityQuery( + "QTS Data Centers Eagle Mountain, Utah campus", + "Rocky Mountain Power commitments, Eagle Mountain City water rights and municipal actions" + ), + frequency: "1h", + processor: "base", + facilityCode: "QTS-EM", + region: "Utah", + states: ["UT"], + }, + { + id: "facility-qts-manassas", + name: "QTS Manassas", + class: "facility", + query: facilityQuery( + "QTS Data Centers Manassas, Virginia expansion", + "Prince William County zoning votes, Dominion Energy interconnection filings, community opposition" + ), + frequency: "1h", + processor: "base", + facilityCode: "QTS-MAN", + region: "Northern Virginia", + states: ["VA"], + }, + { + id: "facility-qts-fayetteville", + name: "QTS Fayetteville", + class: "facility", + query: facilityQuery( + "QTS Data Centers Fayetteville and Atlanta, Georgia campuses", + "Fayette County rezoning, Georgia Power interconnection, local government actions" + ), + frequency: "1h", + processor: "base", + facilityCode: "QTS-FAY", + region: "Atlanta, GA", + states: ["GA"], + }, + { + id: "facility-qts-aurora", + name: "QTS Aurora-Denver", + class: "facility", + query: facilityQuery( + "QTS Data Centers Aurora, Colorado campus expansion", + "Xcel Energy power agreements, Aurora city approvals, construction milestones" + ), + frequency: "1h", + processor: "base", + facilityCode: "QTS-AUR", + region: "Colorado", + states: ["CO"], + }, + + // ============================================= + // CLASS 3: Discovery monitors (2) + // ============================================= + { + id: "discovery-hyperscale", + name: "New Hyperscale Sites", + class: "discovery", + query: + "Newly disclosed or rumored hyperscale data center projects in the U.S.: large land assemblies (500+ acres), new substation load studies, county rezoning filings consistent with 200MW+ campuses, and reports of hyperscaler site selection activity where no operator has confirmed. Include brownfield or failed-industrial sites with grid access being repurposed for data centers.", + frequency: "1h", + processor: "base", + region: "National", + }, + { + id: "discovery-power-markets", + name: "Power-First Emerging Markets", + class: "discovery", + query: + "U.S. regions newly attracting data center investment due to available power: utility announcements of large-load data center customers, new generation (gas, nuclear, SMR) tied to data center campuses, and secondary markets (Louisiana, Mississippi, Indiana, Wyoming, Alabama, Idaho, Wisconsin) seeing their first large-scale data center proposals or groundbreakings.", + frequency: "1h", + processor: "base", + region: "National", + }, +]; diff --git a/typescript-recipes/parallel-datacenter-map/scripts/regenerate-brief.ts b/typescript-recipes/parallel-datacenter-map/scripts/regenerate-brief.ts new file mode 100644 index 0000000..716714d --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/regenerate-brief.ts @@ -0,0 +1,146 @@ +#!/usr/bin/env npx tsx +/** + * Regenerate the current week's Datacenter Signal issue with DENSE citations. + * + * Builds a large citation pool from (a) every monitor event's basis citations + * and (b) the deep-research run's own basis, then hands it to the enhanced + * writer which is instructed to hyperlink aggressively. All real Task API data. + * + * Usage: PARALLEL_API_KEY=.. ANTHROPIC_API_KEY=.. BLOB_READ_WRITE_TOKEN=.. \ + * npx tsx scripts/regenerate-brief.ts + */ +import * as fs from "fs"; +import { put } from "@vercel/blob"; +import { writeNewsletter, wrapEmailTemplate } from "../src/lib/newsletter-writer"; +import monitorsData from "../src/data/monitors.json"; + +const API_KEY = process.env.PARALLEL_API_KEY || ""; +const ANTHROPIC_KEY = process.env.ANTHROPIC_API_KEY || ""; +const BLOB_TOKEN = process.env.BLOB_READ_WRITE_TOKEN || ""; +const BASE_URL = "https://api.parallel.ai"; + +function getIssueNumber() { + return Math.floor((Date.now() - new Date("2024-01-01").getTime()) / (7 * 24 * 60 * 60 * 1000)); +} +function weekOf(n: number): string { + const ms = new Date("2024-01-01").getTime() + n * 7 * 24 * 60 * 60 * 1000; + return new Date(ms).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }); +} + +interface Evt { headline: string; summary: string; category: string; severity: string; eventDate: string; affectedEntities: string; monitorName: string; citations: { title: string; url: string }[]; } + +async function fetchMonitorEvents() { + const monitors = monitorsData as Record; + const all: Evt[] = []; + const pool: { title: string; url: string }[] = []; + for (const [, info] of Object.entries(monitors)) { + try { + const res = await fetch(`${BASE_URL}/v1/monitors/${info.monitorId}/events`, { headers: { "x-api-key": API_KEY }, cache: "no-store" }); + if (!res.ok) continue; + const data = await res.json(); + for (const evt of data.events || []) { + const c = evt.output?.content; + if (!c || typeof c !== "object") continue; + const basis = evt.output?.basis || []; + const cites = basis.flatMap((b: { citations?: { title?: string; url?: string }[] }) => + (b.citations || []).map((x) => ({ title: x.title || "", url: x.url || "" }))).filter((x: { url: string }) => x.url); + pool.push(...cites); + all.push({ headline: c.headline || "", summary: c.summary || "", category: c.category || "", severity: c.severity || "informational", eventDate: evt.event_date || "", affectedEntities: c.affected_entities || "", monitorName: info.name, citations: cites.slice(0, 3) }); + } + } catch {} + } + return { all, pool }; +} + +function buildPrompt(events: Evt[], issueNumber: number) { + const critical = events.filter((e) => e.severity === "critical").slice(0, 6); + const regions = new Map(); + for (const e of events) { if (!regions.has(e.monitorName)) regions.set(e.monitorName, []); regions.get(e.monitorName)!.push(e); } + let cs = ""; + for (const e of critical) { + cs += `\n### ${e.headline}\nRegion: ${e.monitorName} | Category: ${e.category} | Date: ${e.eventDate}\n${e.summary}\n`; + if (e.affectedEntities) cs += `Affects: ${e.affectedEntities}\n`; + if (e.citations.length) cs += `Sources: ${e.citations.map((c) => `${c.title} (${c.url})`).join("; ")}\n`; + } + const rs = Array.from(regions.entries()).slice(0, 12).map(([n, e]) => `- **${n}** (${e.length} events): ${e[0].headline}`).join("\n"); + return `Write "Datacenter Signal — Issue ${issueNumber}" (Week of ${weekOf(issueNumber)}), a weekly infrastructure intelligence brief for datacenter investors. + +CRITICAL EVENTS THIS WEEK (deep-research each one, and surface as many primary sources with URLs as possible): +${cs || "No critical events this week."} + +ALL EVENTS SUMMARY: ${events.length} total, ${critical.length} critical, ${regions.size} markets. + +REGIONAL ACTIVITY: +${rs} + +Return comprehensive factual research with specific data points, dates, dollar figures, and — critically — the source URL for every claim. Include as many distinct primary sources as possible.`; +} + +async function main() { + const issueNumber = getIssueNumber(); + console.log(`Regenerating issue ${issueNumber} (Week of ${weekOf(issueNumber)}) with dense citations...`); + + console.log("Fetching monitor events + citation pool..."); + const { all: events, pool: eventPool } = await fetchMonitorEvents(); + console.log(`${events.length} events, ${eventPool.length} raw event citations`); + + console.log("Kicking off Task API deep research (ultra-fast)..."); + const taskRes = await fetch(`${BASE_URL}/v1/tasks/runs`, { + method: "POST", headers: { "x-api-key": API_KEY, "Content-Type": "application/json" }, + body: JSON.stringify({ input: buildPrompt(events, issueNumber), task_spec: { output_schema: { type: "text", description: "Comprehensive factual research with specific data points, dates, numbers, and a source URL for every claim." } }, processor: "ultra-fast" }), + }); + if (!taskRes.ok) { console.error("Task API failed:", await taskRes.text()); process.exit(1); } + const { run_id } = await taskRes.json(); + console.log("Research run:", run_id); + + let research = "", interactionId = run_id; + const researchPool: { title: string; url: string }[] = []; + const start = Date.now(); + while (Date.now() - start < 20 * 60 * 1000) { + await new Promise((r) => setTimeout(r, 6000)); + const s = await fetch(`${BASE_URL}/v1/tasks/runs/${run_id}`, { headers: { "x-api-key": API_KEY } }); + if (!s.ok) continue; + const sd = await s.json(); + if (sd.status === "completed") { + interactionId = sd.interaction_id || run_id; + const rr = await (await fetch(`${BASE_URL}/v1/tasks/runs/${run_id}/result`, { headers: { "x-api-key": API_KEY } })).json(); + const raw = rr.output?.content; + research = typeof raw === "string" ? raw : JSON.stringify(raw) || ""; + for (const b of rr.output?.basis || []) for (const c of b.citations || []) if (c.url) researchPool.push({ title: c.title || "", url: c.url }); + break; + } + if (sd.status === "failed" || sd.status === "cancelled") { console.error("research", sd.status); process.exit(1); } + } + if (!research) { console.error("research timed out"); process.exit(1); } + console.log(`research done (${research.length} chars, ${researchPool.length} research citations)`); + + const regions = new Map(); + for (const e of events) { if (!regions.has(e.monitorName)) regions.set(e.monitorName, []); regions.get(e.monitorName)!.push(e); } + + // Combined, deduped citation pool: research basis first (most relevant), then event citations + const pool = Array.from(new Map([...researchPool, ...eventPool].filter((c) => c.url).map((c) => [c.url, c])).values()); + console.log(`combined citation pool: ${pool.length} distinct sources`); + + console.log("Writing with enhanced writer (dense citations)..."); + const bodyHtml = await writeNewsletter({ + research, interactionId, issueNumber, + eventsTotal: events.length, criticalCount: events.filter((e) => e.severity === "critical").length, + marketsActive: regions.size, + regionSummaries: Array.from(regions.entries()).map(([n, e]) => `${n} (${e.length} events): ${e[0]?.headline || ""}`).join("\n"), + parallelApiKey: API_KEY, anthropicApiKey: ANTHROPIC_KEY, citationPool: pool, + }); + + const linkCount = (bodyHtml.match(/ e.severity === "critical").length, markets: regions.size, sources: pool.length, links: linkCount }, + generatedAt: new Date().toISOString(), status: "completed", + }; + await put(`newsletters/issue-${issueNumber}.json`, JSON.stringify(issueData), { access: "private", allowOverwrite: true, contentType: "application/json", token: BLOB_TOKEN }); + console.log(`✓ stored issue ${issueNumber} (${linkCount} links, ${pool.length} sources available)`); + fs.writeFileSync("/tmp/regen-brief.done", "ok"); +} +main().catch((e) => { console.error(e); process.exit(1); }); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/run-backfill.ts b/typescript-recipes/parallel-datacenter-map/scripts/run-backfill.ts new file mode 100644 index 0000000..a00b635 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/run-backfill.ts @@ -0,0 +1,226 @@ +/** + * Runs Task API deep research for each of the 16 monitor topics. + * This backfills the event feed with recent past events. + * + * Usage: npx tsx scripts/run-backfill.ts + * + * Uses "pro" processor for deep research (2-10 min per query). + * Results are saved to src/data/backfill-events.json + */ + +import * as fs from "fs"; +import { MONITOR_DEFS } from "./monitor-configs"; + +const API_KEY = process.env.PARALLEL_API_KEY; +const BASE_URL = "https://api.parallel.ai"; + +const OUTPUT_SCHEMA = { + type: "json" as const, + json_schema: { + type: "object" as const, + properties: { + events: { + type: "array" as const, + items: { + type: "object" as const, + properties: { + headline: { + type: "string" as const, + description: "Short headline summarizing the event (under 100 chars)", + }, + description: { + type: "string" as const, + description: + "2-3 sentence description of what happened, including specific numbers, dates, and entities involved", + }, + date: { + type: "string" as const, + description: "Approximate date of the event (YYYY-MM-DD or YYYY-MM)", + }, + category: { + type: "string" as const, + description: "Event category", + enum: [ + "POWER & GRID", + "OWNERSHIP", + "NEW SITE", + "PERMITS", + "EXPANSION", + "COMMUNITY", + "WATER", + "POLICY", + ], + }, + affected_facilities: { + type: "string" as const, + description: + "Names or codes of specific data center facilities affected, if identifiable", + }, + source_name: { + type: "string" as const, + description: "Name of the primary source (e.g., 'Virginia SCC Filing', 'County Board Minutes')", + }, + source_url: { + type: "string" as const, + description: "URL of the primary source, or empty string if not available", + }, + }, + required: [ + "headline", + "description", + "date", + "category", + "affected_facilities", + "source_name", + "source_url", + ], + additionalProperties: false, + }, + }, + summary: { + type: "string" as const, + description: + "Brief overall summary of the current landscape for this region/facility (2-3 sentences)", + }, + }, + required: ["events", "summary"], + additionalProperties: false, + }, +}; + +async function createTaskRun(query: string, name: string) { + const body = { + input: `Find the most significant recent developments (last 3 months) related to: ${query}\n\nFocus on concrete events with dates, specific entities, and verifiable details. Include regulatory filings, zoning decisions, utility actions, community opposition, construction milestones, and ownership changes. Return up to 8 of the most material events.`, + task_spec: { + output_schema: OUTPUT_SCHEMA, + }, + processor: "pro", + metadata: { demo_backfill: true, monitor_name: name }, + }; + + const res = await fetch(`${BASE_URL}/v1/tasks/runs`, { + method: "POST", + headers: { + "x-api-key": API_KEY, + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + const err = await res.text(); + throw new Error(`Failed to create task for ${name}: ${res.status} ${err}`); + } + + return res.json(); +} + +async function pollForResult( + runId: string, + name: string, + maxWaitMs = 600000 // 10 minutes +): Promise | null> { + const start = Date.now(); + let attempt = 0; + + while (Date.now() - start < maxWaitMs) { + attempt++; + const res = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}`, { + headers: { "x-api-key": API_KEY }, + }); + + if (!res.ok) { + console.error(` Poll error for ${name}: ${res.status}`); + await sleep(5000); + continue; + } + + const data = await res.json(); + + if (data.status === "completed") { + // Fetch full result with output from /result endpoint + const resultRes = await fetch(`${BASE_URL}/v1/tasks/runs/${runId}/result`, { + headers: { "x-api-key": API_KEY }, + }); + if (resultRes.ok) { + const resultData = await resultRes.json(); + return { ...data, output: resultData.output }; + } + return data; + } + if (data.status === "failed") { + console.error(` Task failed for ${name}:`, data.error); + return null; + } + + // Still running — wait with increasing delay + const delay = Math.min(5000 + attempt * 2000, 15000); + process.stdout.write(` [${name}] status=${data.status}, waiting ${delay / 1000}s...\r`); + await sleep(delay); + } + + console.error(` Timeout waiting for ${name}`); + return null; +} + +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +async function main() { + const concurrency = 4; // run 4 at a time to avoid rate limits + const allResults: Record[] = []; + + console.log(`Starting backfill for ${MONITOR_DEFS.length} topics (${concurrency} concurrent)...\n`); + + // Submit all tasks first + const submissions: { def: (typeof MONITOR_DEFS)[number]; runId: string }[] = []; + + for (const def of MONITOR_DEFS) { + try { + const result = await createTaskRun(def.query, def.name); + submissions.push({ def, runId: result.run_id }); + console.log(` Submitted: ${def.name} → ${result.run_id}`); + } catch (e) { + console.error(` Failed to submit ${def.name}:`, (e as Error).message); + } + // Small delay between submissions + await sleep(500); + } + + console.log(`\nWaiting for ${submissions.length} tasks to complete...\n`); + + // Poll in batches + for (let i = 0; i < submissions.length; i += concurrency) { + const batch = submissions.slice(i, i + concurrency); + const batchResults = await Promise.all( + batch.map(async ({ def, runId }) => { + const result = await pollForResult(runId, def.name); + if (result) { + console.log(`\n✓ ${def.name} completed`); + return { + monitorDefId: def.id, + monitorName: def.name, + monitorClass: def.class, + region: def.region, + facilityCode: def.facilityCode, + runId, + ...result, + }; + } + console.log(`\n✗ ${def.name} failed or timed out`); + return null; + }) + ); + + allResults.push( + ...batchResults.filter((r): r is Record => r !== null) + ); + } + + const outPath = "./src/data/backfill-results.json"; + fs.writeFileSync(outPath, JSON.stringify(allResults, null, 2)); + console.log(`\nSaved ${allResults.length} backfill results to ${outPath}`); +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/run-enrichment-v2.ts b/typescript-recipes/parallel-datacenter-map/scripts/run-enrichment-v2.ts new file mode 100644 index 0000000..8c77d1c --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/run-enrichment-v2.ts @@ -0,0 +1,306 @@ +/** + * Second enrichment pass — expands the dataset with 15+ additional fields. + * Confirms operator/owner/name and adds technical, financial, land, and risk data. + * Uses ultra2x processor via Task Groups. + * + * Usage: npx tsx scripts/run-enrichment-v2.ts + */ + +import * as fs from "fs"; + +const API_KEY = + process.env.PARALLEL_API_KEY; +const BASE_URL = "https://api.parallel.ai"; + +const ENRICHMENT_V2_SCHEMA = { + type: "json" as const, + json_schema: { + type: "object" as const, + properties: { + // Identity verification + verified_name: { + type: "string" as const, + description: + "The correct, current facility name. Correct any errors in the provided name.", + }, + verified_operator: { + type: "string" as const, + description: + "The company that currently operates this facility. May differ from owner.", + }, + verified_owner: { + type: "string" as const, + description: + "The company or entity that owns the real estate asset (e.g., Digital Realty Trust, Blackstone/QTS, Brookfield). This is often a REIT, PE fund, or JV — not the operator. Use empty string if not determinable.", + }, + + // Technical specs + cooling_type: { + type: "string" as const, + description: + "Primary cooling technology: air-cooled, evaporative, chilled water, liquid cooling, hybrid, or unknown.", + }, + tier_level: { + type: "string" as const, + description: + "Uptime Institute Tier certification level (Tier I, Tier II, Tier III, Tier IV) or equivalent design standard. Empty string if not certified or not determinable.", + }, + backup_power_mw: { + type: "number" as const, + description: + "Backup/generator power capacity in MW. Use 0 if not determinable.", + }, + fiber_providers: { + type: "string" as const, + description: + "Major fiber/network providers connected to this facility, or 'carrier-neutral' if applicable. Empty string if not determinable.", + }, + pue: { + type: "number" as const, + description: + "Power Usage Effectiveness ratio if publicly reported (e.g., 1.2). Use 0 if not determinable.", + }, + + // Land & expansion + campus_acres: { + type: "number" as const, + description: + "Total campus or land area in acres. Use 0 if not determinable.", + }, + expansion_capacity_mw: { + type: "number" as const, + description: + "Planned or permitted expansion capacity in MW beyond current capacity. Use 0 if none or not determinable.", + }, + num_buildings: { + type: "number" as const, + description: + "Number of data center buildings or phases on this campus. Use 0 if not determinable.", + }, + + // Financial signals + estimated_investment_usd: { + type: "number" as const, + description: + "Estimated total project investment in USD if publicly reported (e.g., 500000000 for $500M). Use 0 if not determinable.", + }, + utility_provider: { + type: "string" as const, + description: + "Primary electric utility serving this facility (e.g., Dominion Energy, PG&E, ComEd). Empty string if not determinable.", + }, + tax_incentives: { + type: "string" as const, + description: + "Any active state or local tax incentives, abatements, or enterprise zone benefits. Empty string if none or not determinable.", + }, + + // Risk + water_source: { + type: "string" as const, + description: + "Primary water source for cooling: municipal, groundwater/well, recycled/reclaimed, air-cooled (no water), or unknown.", + }, + natural_hazard_zone: { + type: "string" as const, + description: + "Notable natural hazard exposure: FEMA flood zone designation, seismic zone, hurricane zone, or 'low risk' if none identified. Empty string if not determinable.", + }, + community_opposition: { + type: "string" as const, + description: + "Any organized community opposition, litigation, or political controversy affecting this facility. Empty string if none found.", + }, + }, + required: [ + "verified_name", + "verified_operator", + "verified_owner", + "cooling_type", + "tier_level", + "backup_power_mw", + "fiber_providers", + "pue", + "campus_acres", + "expansion_capacity_mw", + "num_buildings", + "estimated_investment_usd", + "utility_provider", + "tax_incentives", + "water_source", + "natural_hazard_zone", + "community_opposition", + ], + additionalProperties: false, + }, +}; + +interface Datacenter { + name: string; + operator: string; + owner: string; + address: string; + city: string; + state: string; + type: string; + status: string; + powerMw: number; + sqft: number; +} + +function buildInput(dc: Datacenter): string { + const parts = [ + `Facility: ${dc.name}`, + `Operator: ${dc.operator}`, + dc.owner !== dc.operator ? `Owner: ${dc.owner}` : "", + `Location: ${dc.address}, ${dc.city}, ${dc.state}`, + `Type: ${dc.type}`, + `Status: ${dc.status}`, + dc.powerMw > 0 ? `Power: ${dc.powerMw} MW` : "", + dc.sqft > 0 ? `Size: ${dc.sqft} sq ft` : "", + ] + .filter(Boolean) + .join("\n"); + + return `Research this U.S. data center facility thoroughly and provide detailed technical, financial, and risk information:\n\n${parts}\n\nVerify the facility name, operator, and owner (owner may differ from operator — look for the REIT, PE fund, or real estate entity that owns the asset). Find technical specs (cooling, tier, backup power, fiber, PUE), land and expansion details, financial signals (investment cost, utility provider, tax incentives), and risk factors (water source, natural hazards, community opposition).`; +} + +async function createTaskGroup( + metadata: Record +): Promise { + const res = await fetch(`${BASE_URL}/v1/tasks/groups`, { + method: "POST", + headers: { + "x-api-key": API_KEY, + "Content-Type": "application/json", + }, + body: JSON.stringify({ metadata }), + }); + if (!res.ok) + throw new Error( + `Failed to create task group: ${res.status} ${await res.text()}` + ); + const data = await res.json(); + return data.taskgroup_id; +} + +async function submitBatch( + groupId: string, + runs: { input: string; task_spec: unknown; processor: string; metadata: Record }[] +): Promise { + const res = await fetch(`${BASE_URL}/v1/tasks/groups/${groupId}/runs`, { + method: "POST", + headers: { + "x-api-key": API_KEY, + "Content-Type": "application/json", + }, + body: JSON.stringify({ inputs: runs }), + }); + if (!res.ok) + throw new Error( + `Failed to submit batch: ${res.status} ${await res.text()}` + ); + const data = await res.json(); + return data.run_ids || []; +} + +async function main() { + const dcs: Datacenter[] = JSON.parse( + fs.readFileSync("./public/data/datacenters.json", "utf-8") + ); + console.log(`Enrichment v2: ${dcs.length} datacenters with ultra2x\n`); + + const BATCH_SIZE = 1000; + const batches: Datacenter[][] = []; + for (let i = 0; i < dcs.length; i += BATCH_SIZE) { + batches.push(dcs.slice(i, i + BATCH_SIZE)); + } + + const enrichmentData: { + groups: { groupId: string; batchIndex: number; size: number }[]; + runs: { runId: string; groupId: string; facilityIndex: number; facilityName: string }[]; + startedAt: string; + processor: string; + version: string; + totalFacilities: number; + } = { + groups: [], + runs: [], + startedAt: new Date().toISOString(), + processor: "ultra2x", + version: "v2", + totalFacilities: dcs.length, + }; + + for (let batchIdx = 0; batchIdx < batches.length; batchIdx++) { + const batch = batches[batchIdx]; + const globalOffset = batchIdx * BATCH_SIZE; + + console.log( + `Creating task group ${batchIdx + 1}/${batches.length} (${batch.length} facilities)...` + ); + const groupId = await createTaskGroup({ + batch: String(batchIdx), + type: "datacenter-enrichment-v2", + size: String(batch.length), + }); + console.log(` Group ID: ${groupId}`); + enrichmentData.groups.push({ groupId, batchIndex: batchIdx, size: batch.length }); + + const SUB_BATCH = 500; + for (let j = 0; j < batch.length; j += SUB_BATCH) { + const sub = batch.slice(j, j + SUB_BATCH); + console.log(` Submitting runs ${j + 1}-${j + sub.length}...`); + + const specs = sub.map((dc, k) => ({ + input: buildInput(dc), + task_spec: { output_schema: ENRICHMENT_V2_SCHEMA }, + processor: "ultra2x", + metadata: { + facility_index: String(globalOffset + j + k), + facility_name: dc.name.slice(0, 100), + version: "v2", + }, + })); + + const runIds = await submitBatch(groupId, specs); + for (let k = 0; k < runIds.length; k++) { + enrichmentData.runs.push({ + runId: runIds[k], + groupId, + facilityIndex: globalOffset + j + k, + facilityName: batch[j + k].name, + }); + } + console.log(` Got ${runIds.length} run IDs`); + } + + // Save immediately after each group + fs.writeFileSync( + "./src/data/enrichment-v2-runs.json", + JSON.stringify(enrichmentData, null, 2) + ); + console.log(` Saved ${enrichmentData.runs.length} run IDs\n`); + } + + console.log(`\n=== KICKOFF COMPLETE ===`); + console.log(`Groups: ${enrichmentData.groups.length}`); + console.log(`Runs: ${enrichmentData.runs.length}`); + console.log(`Processor: ultra2x`); + console.log(`Schema: v2 (17 new fields)`); + console.log(`All run IDs saved to src/data/enrichment-v2-runs.json`); + + // Poll status + console.log(`\nPolling group status...`); + for (const group of enrichmentData.groups) { + const res = await fetch(`${BASE_URL}/v1/tasks/groups/${group.groupId}`, { + headers: { "x-api-key": API_KEY }, + }); + if (res.ok) { + const data = await res.json(); + console.log(` Group ${group.groupId}: ${JSON.stringify(data.status?.task_run_status_counts)}`); + } + } +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/run-enrichment.ts b/typescript-recipes/parallel-datacenter-map/scripts/run-enrichment.ts new file mode 100644 index 0000000..b29602d --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/run-enrichment.ts @@ -0,0 +1,274 @@ +/** + * Enriches all 1,939 datacenters via Task API using Task Groups. + * Uses ultra2x processor for maximum depth. + * Saves run IDs IMMEDIATELY at kickoff (not after completion). + * + * Usage: npx tsx scripts/run-enrichment.ts + */ + +import * as fs from "fs"; + +const API_KEY = + process.env.PARALLEL_API_KEY; +const BASE_URL = "https://api.parallel.ai"; + +const ENRICHMENT_SCHEMA = { + type: "json" as const, + json_schema: { + type: "object" as const, + properties: { + description: { + type: "string" as const, + description: + "1-2 sentence summary of the facility: what it is, who operates it, and what is notable about it", + }, + verified_status: { + type: "string" as const, + description: + "Current operational status based on latest available information", + enum: ["operational", "under-construction", "planned", "decommissioned"], + }, + power_capacity_mw: { + type: "number" as const, + description: + "Total power capacity in megawatts. Use 0 if not determinable.", + }, + total_sqft: { + type: "number" as const, + description: + "Total facility footprint in square feet. Use 0 if not determinable.", + }, + year_online: { + type: "string" as const, + description: + "Year the facility came online or is expected to come online. Use 'unknown' if not determinable.", + }, + construction_update: { + type: "string" as const, + description: + "Latest construction or development milestone with date, if facility is under construction or planned. Empty string if operational and no active expansion.", + }, + recent_news: { + type: "string" as const, + description: + "Most notable recent development about this facility (last 6 months): expansion, new tenant, opposition, regulatory action. Empty string if no recent news found.", + }, + notable_tenants: { + type: "string" as const, + description: + "Known anchor tenants or major customers. Empty string if not publicly known.", + }, + }, + required: [ + "description", + "verified_status", + "power_capacity_mw", + "total_sqft", + "year_online", + "construction_update", + "recent_news", + "notable_tenants", + ], + additionalProperties: false, + }, +}; + +interface Datacenter { + name: string; + operator: string; + owner: string; + address: string; + city: string; + state: string; + type: string; + status: string; + powerMw: number; + sqft: number; +} + +function buildInput(dc: Datacenter): string { + const parts = [ + `Facility: ${dc.name}`, + `Operator: ${dc.operator}`, + dc.owner !== dc.operator ? `Owner: ${dc.owner}` : "", + `Location: ${dc.address}, ${dc.city}, ${dc.state}`, + `Type: ${dc.type}`, + `Current listed status: ${dc.status}`, + dc.powerMw > 0 ? `Listed power: ${dc.powerMw} MW` : "", + dc.sqft > 0 ? `Listed size: ${dc.sqft} sq ft` : "", + ] + .filter(Boolean) + .join("\n"); + + return `Research this U.S. data center facility and provide verified, current information:\n\n${parts}\n\nVerify or correct all fields. Find the actual power capacity, square footage, and year online if not listed. Check for recent news, construction updates, and notable tenants.`; +} + +async function createTaskGroup( + metadata: Record +): Promise { + const res = await fetch(`${BASE_URL}/v1/tasks/groups`, { + method: "POST", + headers: { + "x-api-key": API_KEY, + "Content-Type": "application/json", + }, + body: JSON.stringify({ metadata }), + }); + if (!res.ok) { + throw new Error(`Failed to create task group: ${res.status} ${await res.text()}`); + } + const data = await res.json(); + return data.taskgroup_id; +} + +interface RunSpec { + input: string; + task_spec: { output_schema: typeof ENRICHMENT_SCHEMA }; + processor: string; + metadata: Record; +} + +async function submitBatchRuns( + groupId: string, + runs: RunSpec[] +): Promise { + const res = await fetch(`${BASE_URL}/v1/tasks/groups/${groupId}/runs`, { + method: "POST", + headers: { + "x-api-key": API_KEY, + "Content-Type": "application/json", + }, + body: JSON.stringify({ inputs: runs }), + }); + if (!res.ok) { + throw new Error( + `Failed to submit batch: ${res.status} ${await res.text()}` + ); + } + const data = await res.json(); + return data.run_ids || []; +} + +async function main() { + // Load datacenters + const dcs: Datacenter[] = JSON.parse( + fs.readFileSync("./public/data/datacenters.json", "utf-8") + ); + console.log(`Enriching ${dcs.length} datacenters with ultra2x...\n`); + + // Split into groups of 1000 + const BATCH_SIZE = 1000; + const batches: Datacenter[][] = []; + for (let i = 0; i < dcs.length; i += BATCH_SIZE) { + batches.push(dcs.slice(i, i + BATCH_SIZE)); + } + console.log(`Split into ${batches.length} task groups\n`); + + // Track everything for immediate save + const enrichmentData: { + groups: { groupId: string; batchIndex: number; size: number }[]; + runs: { + runId: string; + groupId: string; + facilityIndex: number; + facilityName: string; + }[]; + startedAt: string; + processor: string; + totalFacilities: number; + } = { + groups: [], + runs: [], + startedAt: new Date().toISOString(), + processor: "ultra2x", + totalFacilities: dcs.length, + }; + + for (let batchIdx = 0; batchIdx < batches.length; batchIdx++) { + const batch = batches[batchIdx]; + const globalOffset = batchIdx * BATCH_SIZE; + + // Create task group + console.log( + `Creating task group ${batchIdx + 1}/${batches.length} (${batch.length} facilities)...` + ); + const groupId = await createTaskGroup({ + batch: String(batchIdx), + type: "datacenter-enrichment", + size: String(batch.length), + }); + console.log(` Group ID: ${groupId}`); + + enrichmentData.groups.push({ + groupId, + batchIndex: batchIdx, + size: batch.length, + }); + + // Build run specs + const runSpecs: RunSpec[] = batch.map((dc, i) => ({ + input: buildInput(dc), + task_spec: { output_schema: ENRICHMENT_SCHEMA }, + processor: "ultra2x", + metadata: { + facility_index: String(globalOffset + i), + facility_name: dc.name.slice(0, 100), + }, + })); + + // Submit in sub-batches of 500 to be safe + const SUB_BATCH = 500; + for (let j = 0; j < runSpecs.length; j += SUB_BATCH) { + const subBatch = runSpecs.slice(j, j + SUB_BATCH); + console.log( + ` Submitting runs ${j + 1}-${j + subBatch.length} of ${runSpecs.length}...` + ); + + const runIds = await submitBatchRuns(groupId, subBatch); + + for (let k = 0; k < runIds.length; k++) { + enrichmentData.runs.push({ + runId: runIds[k], + groupId, + facilityIndex: globalOffset + j + k, + facilityName: batch[j + k].name, + }); + } + + console.log(` Got ${runIds.length} run IDs`); + } + + // SAVE IMMEDIATELY after each group + fs.writeFileSync( + "./src/data/enrichment-runs.json", + JSON.stringify(enrichmentData, null, 2) + ); + console.log( + ` Saved ${enrichmentData.runs.length} run IDs to src/data/enrichment-runs.json\n` + ); + } + + console.log(`\n=== KICKOFF COMPLETE ===`); + console.log(`Groups: ${enrichmentData.groups.length}`); + console.log(`Runs: ${enrichmentData.runs.length}`); + console.log(`Processor: ultra2x`); + console.log(`All run IDs saved to src/data/enrichment-runs.json`); + console.log(`\nRun 'npx tsx scripts/collect-enrichments.ts' to collect results once complete.`); + + // Poll for group status + console.log(`\nPolling group status...`); + for (const group of enrichmentData.groups) { + const res = await fetch( + `${BASE_URL}/v1/tasks/groups/${group.groupId}`, + { headers: { "x-api-key": API_KEY } } + ); + if (res.ok) { + const data = await res.json(); + console.log( + ` Group ${group.groupId}: ${JSON.stringify(data.status)}` + ); + } + } +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/run-pipeline.ts b/typescript-recipes/parallel-datacenter-map/scripts/run-pipeline.ts new file mode 100644 index 0000000..6dfe564 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/run-pipeline.ts @@ -0,0 +1,485 @@ +#!/usr/bin/env npx tsx +/** + * End-to-end pipeline: CSV → enriched dataset with monitors + snapshots. + * + * Takes a raw datacenter CSV and produces: + * 1. Clean JSON dataset (public/data/datacenters.json) + * 2. 31 event-stream monitors watching U.S. markets + * 3. V1 enrichment (8 fields: description, status, power, size, year, news, tenants, construction) + * 4. V2 enrichment (17 fields: owner, cooling, tier, fiber, PUE, acres, buildings, utility, tax, hazard...) + * 5. Compact enrichment index for the app (public/data/enrichments-compact.json) + * 6. Per-facility enrichment files in Vercel Blob (for basis panel) + * 7. Snapshot monitors (daily re-verification, 1d) + * + * Usage: + * PARALLEL_API_KEY=xxx npx tsx scripts/run-pipeline.ts /path/to/datacenters.csv + * + * Optional env vars: + * BLOB_READ_WRITE_TOKEN — for uploading to Vercel Blob (step 6) + * WEBHOOK_URL — for snapshot monitor webhooks (step 7) + * + * Each step is idempotent — re-running skips already-completed work. + * Progress is saved after each batch so the script can be interrupted and resumed. + */ + +import * as fs from "fs"; +import Papa from "papaparse"; +import { MONITOR_DEFS, MONITOR_OUTPUT_SCHEMA } from "./monitor-configs"; + +const API_KEY = process.env.PARALLEL_API_KEY; +if (!API_KEY) { console.error("Set PARALLEL_API_KEY env var."); process.exit(1); } + +const BASE_URL = "https://api.parallel.ai"; +const BLOB_TOKEN = process.env.BLOB_READ_WRITE_TOKEN || ""; +const WEBHOOK_URL = process.env.WEBHOOK_URL || ""; + +function sleep(ms: number) { return new Promise(r => setTimeout(r, ms)); } + +// ─── STEP 1: CSV → JSON ───────────────────────────────────────────── + +function step1_convertCsv(csvPath: string) { + console.log("\n═══ STEP 1: Convert CSV to JSON ═══"); + const outPath = "./public/data/datacenters.json"; + + if (fs.existsSync(outPath)) { + const existing = JSON.parse(fs.readFileSync(outPath, "utf-8")); + console.log(` Already exists: ${existing.length} facilities. Skipping.`); + return existing.length; + } + + const raw = fs.readFileSync(csvPath, "utf-8"); + const { data } = Papa.parse(raw, { header: true, skipEmptyLines: true }); + + const cleaned = (data as Record[]).map((row) => ({ + name: row.name?.trim() || "", + operator: row.operator_company?.trim() || "", + owner: row.owner_company?.trim() || "", + address: row.address?.trim() || "", + city: row.city?.trim() || "", + state: row.state?.trim() || "", + zip: row.zip_code?.trim() || "", + lat: parseFloat(row.latitude) || 0, + lng: parseFloat(row.longitude) || 0, + yearOnline: row.year_online?.trim() || "unknown", + powerMw: Math.min(parseFloat(row.power_capacity_mw) || 0, 5000), + sqft: parseFloat(row.total_sqft) || 0, + type: row.facility_type?.trim() || "unknown", + status: row.status?.trim() || "unknown", + region: row._shard?.trim() || "", + })).filter((r) => r.lat !== 0 && r.lng !== 0); + + fs.mkdirSync("./public/data", { recursive: true }); + fs.writeFileSync(outPath, JSON.stringify(cleaned)); + console.log(` Wrote ${cleaned.length} facilities to ${outPath}`); + return cleaned.length; +} + +// ─── STEP 2: Create monitors ───────────────────────────────────────── + +async function step2_setupMonitors() { + console.log("\n═══ STEP 2: Create event-stream monitors ═══"); + const outPath = "./src/data/monitors.json"; + + if (fs.existsSync(outPath)) { + const existing = JSON.parse(fs.readFileSync(outPath, "utf-8")); + const count = Object.keys(existing).length; + if (count >= MONITOR_DEFS.length) { + console.log(` Already have ${count} monitors. Skipping.`); + return count; + } + } + + const results: Record = {}; + + for (const def of MONITOR_DEFS) { + const metadata: Record = { demo_id: def.id, name: def.name, class: def.class }; + if (def.region) metadata.region = def.region; + if (def.facilityCode) metadata.facilityCode = def.facilityCode; + if (def.states) metadata.states = def.states.join(","); + + const res = await fetch(`${BASE_URL}/v1/monitors`, { + method: "POST", + headers: { "x-api-key": API_KEY!, "Content-Type": "application/json" }, + body: JSON.stringify({ + type: "event_stream", frequency: def.frequency, + settings: { query: def.query, processor: def.processor, output_schema: MONITOR_OUTPUT_SCHEMA }, + metadata, + }), + }); + + if (res.ok) { + const data = await res.json(); + results[def.id] = { monitorId: data.monitor_id, name: def.name, class: def.class, query: def.query, frequency: def.frequency, region: def.region, facilityCode: def.facilityCode, states: def.states }; + console.log(` ✓ ${def.id}`); + } else { + console.error(` ✗ ${def.id}: ${res.status}`); + } + } + + fs.mkdirSync("./src/data", { recursive: true }); + fs.writeFileSync(outPath, JSON.stringify(results, null, 2)); + console.log(` Created ${Object.keys(results).length} monitors`); + return Object.keys(results).length; +} + +// ─── STEP 3+4: Run enrichment (v1 or v2) ──────────────────────────── + +async function step_runEnrichment(version: "v1" | "v2") { + const isV2 = version === "v2"; + console.log(`\n═══ STEP ${isV2 ? "4" : "3"}: Run ${version} enrichment (ultra2x) ═══`); + + const runsPath = isV2 ? "./src/data/enrichment-v2-runs.json" : "./src/data/enrichment-runs.json"; + + if (fs.existsSync(runsPath)) { + const existing = JSON.parse(fs.readFileSync(runsPath, "utf-8")); + console.log(` Already kicked off ${existing.runs?.length || 0} runs. Skipping.`); + return; + } + + const dcs = JSON.parse(fs.readFileSync("./public/data/datacenters.json", "utf-8")); + const schema = isV2 ? getV2Schema() : getV1Schema(); + + const BATCH_SIZE = 1000; + const enrichmentData: { groups: unknown[]; runs: { runId: string; groupId: string; facilityIndex: number; facilityName: string }[]; startedAt: string; processor: string; version: string; totalFacilities: number } = { + groups: [], runs: [], startedAt: new Date().toISOString(), processor: "ultra2x", version, totalFacilities: dcs.length, + }; + + for (let batchIdx = 0; batchIdx * BATCH_SIZE < dcs.length; batchIdx++) { + const batch = dcs.slice(batchIdx * BATCH_SIZE, (batchIdx + 1) * BATCH_SIZE); + const offset = batchIdx * BATCH_SIZE; + + // Create task group + const grpRes = await fetch(`${BASE_URL}/v1/tasks/groups`, { + method: "POST", headers: { "x-api-key": API_KEY!, "Content-Type": "application/json" }, + body: JSON.stringify({ metadata: { batch: String(batchIdx), type: `enrichment-${version}`, size: String(batch.length) } }), + }); + const grp = await grpRes.json(); + enrichmentData.groups.push({ groupId: grp.taskgroup_id, batchIndex: batchIdx, size: batch.length }); + console.log(` Group ${batchIdx + 1}: ${grp.taskgroup_id}`); + + // Submit in sub-batches of 500 + for (let j = 0; j < batch.length; j += 500) { + const sub = batch.slice(j, j + 500); + const inputs = sub.map((dc: Record, k: number) => ({ + input: buildEnrichmentInput(dc, isV2), + task_spec: { output_schema: schema }, + processor: "ultra2x", + metadata: { facility_index: String(offset + j + k), facility_name: (dc.name as string).slice(0, 100), version }, + })); + + const res = await fetch(`${BASE_URL}/v1/tasks/groups/${grp.taskgroup_id}/runs`, { + method: "POST", headers: { "x-api-key": API_KEY!, "Content-Type": "application/json" }, + body: JSON.stringify({ inputs }), + }); + const data = await res.json(); + const runIds = data.run_ids || []; + + for (let k = 0; k < runIds.length; k++) { + enrichmentData.runs.push({ runId: runIds[k], groupId: grp.taskgroup_id, facilityIndex: offset + j + k, facilityName: batch[j + k].name }); + } + console.log(` Submitted ${j + 1}-${j + sub.length}: ${runIds.length} run IDs`); + } + + // Save immediately after each group + fs.writeFileSync(runsPath, JSON.stringify(enrichmentData, null, 2)); + } + + console.log(` Kicked off ${enrichmentData.runs.length} ${version} enrichment tasks`); +} + +// ─── STEP 5+6: Collect results ─────────────────────────────────────── + +async function step_collectResults(version: "v1" | "v2") { + const isV2 = version === "v2"; + console.log(`\n═══ STEP ${isV2 ? "6" : "5"}: Collect ${version} enrichment results ═══`); + + const runsPath = isV2 ? "./src/data/enrichment-v2-runs.json" : "./src/data/enrichment-runs.json"; + if (!fs.existsSync(runsPath)) { console.log(" No runs file found. Skipping."); return; } + + const runData = JSON.parse(fs.readFileSync(runsPath, "utf-8")); + const enrichPath = "./public/data/enrichments.json"; + let enrichments: Record = {}; + if (fs.existsSync(enrichPath)) enrichments = JSON.parse(fs.readFileSync(enrichPath, "utf-8")); + + let collected = 0, pending = 0; + + for (let i = 0; i < runData.runs.length; i += 20) { + const batch = runData.runs.slice(i, i + 20); + const results = await Promise.all(batch.map(async (run: { runId: string; facilityIndex: number; facilityName: string }) => { + const key = String(run.facilityIndex); + // Skip if already collected (for v1) or already has v2 (for v2) + if (!isV2 && enrichments[key]) return null; + if (isV2 && (enrichments[key] as Record)?.v2RunId) return null; + + const statusRes = await fetch(`${BASE_URL}/v1/tasks/runs/${run.runId}`, { headers: { "x-api-key": API_KEY! } }); + if (!statusRes.ok) { pending++; return null; } + const statusData = await statusRes.json(); + if (statusData.status !== "completed") { pending++; return null; } + + const resultRes = await fetch(`${BASE_URL}/v1/tasks/runs/${run.runId}/result`, { headers: { "x-api-key": API_KEY! } }); + if (!resultRes.ok) return null; + return { run, result: await resultRes.json() }; + })); + + for (const r of results) { + if (!r) continue; + const key = String(r.run.facilityIndex); + const content = r.result?.output?.content; + if (!content) continue; + + if (isV2 && enrichments[key]) { + // Merge v2 into existing v1 + const existing = enrichments[key] as Record; + existing.enrichment = { ...(existing.enrichment as object), ...content }; + existing.basis = [...((existing.basis as unknown[]) || []), ...((r.result?.output?.basis || []) as unknown[])]; + existing.v2RunId = r.run.runId; + existing.v2CollectedAt = new Date().toISOString(); + } else { + enrichments[key] = { + runId: r.run.runId, facilityName: r.run.facilityName, facilityIndex: r.run.facilityIndex, + enrichment: content, basis: r.result?.output?.basis || [], collectedAt: new Date().toISOString(), + }; + } + collected++; + } + + if ((i + 20) % 100 === 0 || i + 20 >= runData.runs.length) { + fs.writeFileSync(enrichPath, JSON.stringify(enrichments, null, 2)); + process.stdout.write(`\r Collected: ${collected} new, ${pending} pending, ${Object.keys(enrichments).length} total`); + } + await sleep(100); + } + + console.log(`\n Done: ${collected} new ${version} enrichments collected`); + if (pending > 0) console.log(` ${pending} still pending — re-run this script later`); +} + +// ─── STEP 7: Build compact index ───────────────────────────────────── + +function step7_buildCompactIndex() { + console.log("\n═══ STEP 7: Build compact enrichment index ═══"); + const enrichPath = "./public/data/enrichments.json"; + if (!fs.existsSync(enrichPath)) { console.log(" No enrichments.json found. Skipping."); return; } + + const data = JSON.parse(fs.readFileSync(enrichPath, "utf-8")); + const compact: Record = {}; + + for (const [key, entry] of Object.entries(data)) { + const e = (entry as Record).enrichment as Record; + if (!e) continue; + compact[key] = { + description: e.description || "", verified_status: e.verified_status || "", + power_capacity_mw: e.power_capacity_mw || 0, total_sqft: e.total_sqft || 0, + year_online: e.year_online || "", construction_update: e.construction_update || "", + recent_news: e.recent_news || "", notable_tenants: e.notable_tenants || "", + verified_name: e.verified_name || "", verified_operator: e.verified_operator || "", + verified_owner: e.verified_owner || "", cooling_type: e.cooling_type || "", + tier_level: e.tier_level || "", fiber_providers: e.fiber_providers || "", + num_buildings: e.num_buildings || 0, campus_acres: e.campus_acres || 0, + utility_provider: e.utility_provider || "", tax_incentives: e.tax_incentives || "", + natural_hazard_zone: e.natural_hazard_zone || "", + }; + } + + const outPath = "./public/data/enrichments-compact.json"; + fs.writeFileSync(outPath, JSON.stringify(compact, null, 0)); + const sizeMb = (fs.statSync(outPath).size / 1024 / 1024).toFixed(1); + console.log(` Wrote compact index: ${Object.keys(compact).length} facilities (${sizeMb} MB)`); +} + +// ─── STEP 8: Upload per-facility to Vercel Blob ───────────────────── + +async function step8_uploadToBlob() { + console.log("\n═══ STEP 8: Upload per-facility enrichments to Vercel Blob ═══"); + if (!BLOB_TOKEN) { console.log(" BLOB_READ_WRITE_TOKEN not set. Skipping."); return; } + + const { put } = await import("@vercel/blob"); + const data = JSON.parse(fs.readFileSync("./public/data/enrichments.json", "utf-8")); + const keys = Object.keys(data); + let uploaded = 0; + + for (let i = 0; i < keys.length; i += 20) { + const batch = keys.slice(i, i + 20); + await Promise.all(batch.map(async (key) => { + await put(`enrichments/${key}.json`, JSON.stringify(data[key]), { + access: "private", allowOverwrite: true, contentType: "application/json", token: BLOB_TOKEN, + }); + uploaded++; + })); + process.stdout.write(`\r ${uploaded} / ${keys.length}`); + } + console.log(`\n Uploaded ${uploaded} per-facility files`); +} + +// ─── STEP 9: Create snapshot monitors ──────────────────────────────── + +async function step9_createSnapshots() { + console.log("\n═══ STEP 9: Create snapshot monitors ═══"); + const runsPath = "./src/data/enrichment-v2-runs.json"; + if (!fs.existsSync(runsPath)) { console.log(" No v2 runs file. Skipping."); return; } + + const snapshotPath = "./src/data/snapshot-monitors.json"; + let snapshots: Record = {}; + if (fs.existsSync(snapshotPath)) snapshots = JSON.parse(fs.readFileSync(snapshotPath, "utf-8")); + + const runData = JSON.parse(fs.readFileSync(runsPath, "utf-8")); + let created = 0, skipped = 0; + + for (const run of runData.runs) { + if (snapshots[String(run.facilityIndex)]) { skipped++; continue; } + + const res = await fetch(`${BASE_URL}/v1/monitors`, { + method: "POST", headers: { "x-api-key": API_KEY!, "Content-Type": "application/json" }, + body: JSON.stringify({ + type: "snapshot", frequency: "1d", processor: "base", + settings: { task_run_id: run.runId }, + ...(WEBHOOK_URL ? { webhook: { url: WEBHOOK_URL, event_types: ["monitor.event.detected"] } } : {}), + metadata: { facility_name: run.facilityName.slice(0, 100), facility_index: String(run.facilityIndex), type: "datacenter-snapshot" }, + }), + }); + + if (res.ok) { + const data = await res.json(); + snapshots[String(run.facilityIndex)] = { monitorId: data.monitor_id, runId: run.runId, facilityName: run.facilityName }; + created++; + } + + if ((created + skipped) % 50 === 0) { + fs.writeFileSync(snapshotPath, JSON.stringify(snapshots, null, 2)); + process.stdout.write(`\r Created: ${created}, Skipped: ${skipped}`); + } + await sleep(300); // Rate limit: ~200/min + } + + fs.writeFileSync(snapshotPath, JSON.stringify(snapshots, null, 2)); + console.log(`\n Created ${created} snapshot monitors (${skipped} skipped)`); +} + +// ─── Helpers ───────────────────────────────────────────────────────── + +function buildEnrichmentInput(dc: Record, isV2: boolean): string { + const parts = [ + `Facility: ${dc.name}`, `Operator: ${dc.operator}`, + dc.owner !== dc.operator ? `Owner: ${dc.owner}` : "", + `Location: ${dc.address}, ${dc.city}, ${dc.state}`, + `Type: ${dc.type}`, `Status: ${dc.status}`, + (dc.powerMw as number) > 0 ? `Power: ${dc.powerMw} MW` : "", + (dc.sqft as number) > 0 ? `Size: ${dc.sqft} sq ft` : "", + ].filter(Boolean).join("\n"); + + if (isV2) { + return `Research this U.S. data center facility thoroughly and provide detailed technical, financial, and risk information:\n\n${parts}\n\nVerify the facility name, operator, and owner. Find technical specs (cooling, tier, backup power, fiber, PUE), land and expansion details, financial signals (investment cost, utility provider, tax incentives), and risk factors (water source, natural hazards, community opposition).`; + } + return `Research this U.S. data center facility and provide verified, current information:\n\n${parts}\n\nVerify or correct all fields. Find the actual power capacity, square footage, and year online if not listed. Check for recent news, construction updates, and notable tenants.`; +} + +function getV1Schema() { + return { + type: "json" as const, json_schema: { + type: "object" as const, + properties: { + description: { type: "string" as const, description: "1-2 sentence summary of the facility" }, + verified_status: { type: "string" as const, enum: ["operational", "under-construction", "planned", "decommissioned"] }, + power_capacity_mw: { type: "number" as const, description: "Total power in MW. 0 if unknown." }, + total_sqft: { type: "number" as const, description: "Total footprint in sq ft. 0 if unknown." }, + year_online: { type: "string" as const, description: "Year online or expected. 'unknown' if indeterminate." }, + construction_update: { type: "string" as const, description: "Latest construction milestone. Empty if operational." }, + recent_news: { type: "string" as const, description: "Most notable recent development (last 6 months). Empty if none." }, + notable_tenants: { type: "string" as const, description: "Known anchor tenants. Empty if unknown." }, + }, + required: ["description", "verified_status", "power_capacity_mw", "total_sqft", "year_online", "construction_update", "recent_news", "notable_tenants"], + additionalProperties: false, + }, + }; +} + +function getV2Schema() { + return { + type: "json" as const, json_schema: { + type: "object" as const, + properties: { + verified_name: { type: "string" as const, description: "Correct, current facility name." }, + verified_operator: { type: "string" as const, description: "Current operating company." }, + verified_owner: { type: "string" as const, description: "Real estate owner (REIT, PE fund). Empty if unknown." }, + cooling_type: { type: "string" as const, description: "Primary cooling: air-cooled, evaporative, chilled water, liquid, hybrid, unknown." }, + tier_level: { type: "string" as const, description: "Uptime Institute tier. Empty if not certified." }, + backup_power_mw: { type: "number" as const, description: "Generator capacity in MW. 0 if unknown." }, + fiber_providers: { type: "string" as const, description: "Major fiber providers or 'carrier-neutral'. Empty if unknown." }, + pue: { type: "number" as const, description: "Power Usage Effectiveness. 0 if unreported." }, + campus_acres: { type: "number" as const, description: "Total campus area in acres. 0 if unknown." }, + expansion_capacity_mw: { type: "number" as const, description: "Planned expansion MW. 0 if none." }, + num_buildings: { type: "number" as const, description: "Number of DC buildings/phases. 0 if unknown." }, + estimated_investment_usd: { type: "number" as const, description: "Total project investment in USD. 0 if unknown." }, + utility_provider: { type: "string" as const, description: "Primary electric utility. Empty if unknown." }, + tax_incentives: { type: "string" as const, description: "Active tax incentives. Empty if none." }, + water_source: { type: "string" as const, description: "Primary water source: municipal, groundwater, recycled, air-cooled, unknown." }, + natural_hazard_zone: { type: "string" as const, description: "FEMA flood zone, seismic, hurricane, or 'low risk'. Empty if unknown." }, + community_opposition: { type: "string" as const, description: "Opposition or litigation. Empty if none." }, + }, + required: ["verified_name", "verified_operator", "verified_owner", "cooling_type", "tier_level", "backup_power_mw", "fiber_providers", "pue", "campus_acres", "expansion_capacity_mw", "num_buildings", "estimated_investment_usd", "utility_provider", "tax_incentives", "water_source", "natural_hazard_zone", "community_opposition"], + additionalProperties: false, + }, + }; +} + +// ─── Main ──────────────────────────────────────────────────────────── + +async function main() { + const csvPath = process.argv[2]; + if (!csvPath) { + console.error("Usage: PARALLEL_API_KEY=xxx npx tsx scripts/run-pipeline.ts /path/to/datacenters.csv"); + console.error("\nOptional env vars:"); + console.error(" BLOB_READ_WRITE_TOKEN — upload to Vercel Blob"); + console.error(" WEBHOOK_URL — snapshot monitor webhooks"); + process.exit(1); + } + + if (!fs.existsSync(csvPath)) { console.error(`CSV not found: ${csvPath}`); process.exit(1); } + + console.log("╔═══════════════════════════════════════════════╗"); + console.log("║ Datacenter Monitor — E2E Pipeline ║"); + console.log("╚═══════════════════════════════════════════════╝"); + console.log(` CSV: ${csvPath}`); + console.log(` API Key: ${API_KEY!.slice(0, 8)}...`); + console.log(` Blob: ${BLOB_TOKEN ? "configured" : "not set (skip upload)"}`); + console.log(` Webhook: ${WEBHOOK_URL || "not set (skip snapshot webhooks)"}`); + + const startTime = Date.now(); + + // Step 1: CSV → JSON + const facilityCount = step1_convertCsv(csvPath); + + // Step 2: Create monitors (parallel with enrichment) + await step2_setupMonitors(); + + // Step 3: Kick off v1 enrichment + await step_runEnrichment("v1"); + + // Step 4: Kick off v2 enrichment (can run in parallel with v1) + await step_runEnrichment("v2"); + + // Step 5: Collect v1 results (poll until done or pending) + await step_collectResults("v1"); + + // Step 6: Collect v2 results and merge + await step_collectResults("v2"); + + // Step 7: Build compact index for the app + step7_buildCompactIndex(); + + // Step 8: Upload per-facility to Vercel Blob + if (BLOB_TOKEN) await step8_uploadToBlob(); + + // Step 9: Create snapshot monitors + await step9_createSnapshots(); + + const elapsed = Math.round((Date.now() - startTime) / 1000); + console.log(`\n╔═══════════════════════════════════════════════╗`); + console.log(`║ Pipeline complete in ${elapsed}s `); + console.log(`║ ${facilityCount} facilities enriched `); + console.log(`║ ${MONITOR_DEFS.length} event-stream monitors created `); + console.log(`║ Run 'npm run dev' to see the app `); + console.log(`╚═══════════════════════════════════════════════╝`); +} + +main().catch(console.error); diff --git a/typescript-recipes/parallel-datacenter-map/scripts/seed-issue.ts b/typescript-recipes/parallel-datacenter-map/scripts/seed-issue.ts new file mode 100644 index 0000000..3175da9 --- /dev/null +++ b/typescript-recipes/parallel-datacenter-map/scripts/seed-issue.ts @@ -0,0 +1,153 @@ +#!/usr/bin/env npx tsx +/** + * Seed a back-issue of Datacenter Signal directly from real monitor events. + * + * The events themselves come from the Parallel Task API monitors (real + * headlines, summaries, categories, and source citations). Claude composes + * them into a themed newsletter body in ONE call — no dependency on the + * (currently slow) deep-research runs or the multi-turn lookup loop that was + * truncating output. Nothing is fabricated: every fact traces to a monitor + * event and its cited source. + * + * Usage: + * ... npx tsx scripts/seed-issue.ts "" + */ + +import * as fs from "fs"; +import Anthropic from "@anthropic-ai/sdk"; +import { put, list } from "@vercel/blob"; +import { wrapEmailTemplate } from "../src/lib/newsletter-writer"; +import monitorsData from "../src/data/monitors.json"; + +const API_KEY = process.env.PARALLEL_API_KEY || ""; +const ANTHROPIC_KEY = process.env.ANTHROPIC_API_KEY || ""; +const BLOB_TOKEN = process.env.BLOB_READ_WRITE_TOKEN || ""; +const BASE_URL = "https://api.parallel.ai"; + +function weekOf(n: number): string { + const ms = new Date("2024-01-01").getTime() + n * 7 * 24 * 60 * 60 * 1000; + return new Date(ms).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }); +} + +interface Evt { + headline: string; summary: string; category: string; severity: string; + eventDate: string; affectedEntities: string; monitorName: string; + citations: { title: string; url: string }[]; +} + +async function fetchMonitorEvents(): Promise { + const monitors = monitorsData as Record; + const all: Evt[] = []; + for (const [, info] of Object.entries(monitors)) { + try { + const res = await fetch(`${BASE_URL}/v1/monitors/${info.monitorId}/events`, { headers: { "x-api-key": API_KEY }, cache: "no-store" }); + if (!res.ok) continue; + const data = await res.json(); + for (const evt of data.events || []) { + const c = evt.output?.content; + if (!c || typeof c !== "object") continue; + const basis = evt.output?.basis || []; + const citations = basis.flatMap((b: { citations?: { title?: string; url?: string }[] }) => + (b.citations || []).map((x) => ({ title: x.title || "", url: x.url || "" }))).filter((x: {url: string}) => x.url).slice(0, 3); + all.push({ + headline: c.headline || "", summary: c.summary || "", category: c.category || "", + severity: c.severity || "informational", eventDate: evt.event_date || "", + affectedEntities: c.affected_entities || "", monitorName: info.name, citations, + }); + } + } catch {} + } + return all; +} + +const SYSTEM = `You are the editor of "Datacenter Signal," a weekly intelligence brief for datacenter infrastructure investors. Transform the supplied monitor events into a polished HTML newsletter body. + +VOICE: Analytical, concise, data-anchored — like a Financial Times or Stratechery briefing. No hype, no speculation, no emoji. + +STRUCTURE: +1. An issue line:

Issue N — Week of DATE

+2. "The Week in One Read" — 2-3 sentence executive summary anchored on the editorial focus +3. "Critical Developments" — 3-4 of the most important events (lead with ones matching the focus). For each: a category tag, a bold headline, and 2 paragraphs of analysis (what happened, stakeholders, implications, what to watch). Weave the provided source links inline using the publication name as anchor text. +4. "Regional Roundup" — one line per active region +5. "By the Numbers" — 6-10 key data points + +Use ONLY the supplied events as facts. Do not invent numbers, deals, or quotes beyond what the events state. If an event lacks a citation, state the fact without a link. + +HTML (inline styles only): +- H2:

+- Body:

+- Links: +- Bold: +- Lists: