From 99375bb534edb6554bc37fc97be5faf77869b15f Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Mon, 17 Aug 2026 21:30:19 -0400 Subject: [PATCH 1/4] Load Perspective from bundle, not CDN; pin all packages at 5.2.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pivot stopped rendering with: LinkError: WebAssembly.instantiate(): Import #8 "env" "psp_opfs_load": function import requires a callable Nobody changed anything. The 4.x CDN bundle resolves its server WASM with new URL("../../../server/dist/wasm/perspective-server.wasm", import.meta.url) which from .../client@4.4.0/dist/cdn/ resolves to .../npm/@perspective-dev/server/dist/wasm/perspective-server.wasm -- with no version. jsdelivr serves @latest, so when @perspective-dev/server@5.2.0 was published on 2026-08-10 every page load began linking a 5.2.0 WASM against a 4.4.0 client. 4.4.1 and 4.5.2 carry the identical unversioned pattern, so no 4.x pin is safe over CDN. Beyond the outage, an unversioned URL means users execute whatever that package publishes next, unreviewed. Switch to the /inline entrypoints, which embed the WASM in the Vite build: no runtime fetch, and the version is fixed by package-lock.json (verified: zero `new URL(...perspective-server...)` in perspective.inline.js). - pin client/viewer/viewer-datagrid/server exact at 5.2.0. The explicit `server` pin matters: client declares it as "" (an empty range), which npm also resolves to latest -- the same break, at install time instead. - drop the viewer-d3fc import. pf_app never selects a chart plugin, and d3fc has no 5.x; loading 4.4.1 against a 5.x viewer only emits `get_static_config is not a function` per plugin. - themes move from a CDN to @perspective-dev/viewer/themes. Verified end-to-end with every non-localhost request aborted: no external requests are attempted, both custom elements register, the Arrow stream ingests, and the pivot renders (TOTAL 17,235.97 = -7,573.97 + 30,907.47 - 6,097.53). apache-arrow 21.1.0 ingests cleanly against the 5.2.0 WASM. Bundle grows 263 KB -> 11.6 MB (5.4 MB gzipped); that is the embedded WASM. PERSPECTIVE.md also records findings from the same investigation: - §3a: expression columns are row-level, evaluated before aggregation, so a ratio like "revenue"/"qty" summed per row is wrong under any pivot (not just split_by). Fix is a weighted-mean aggregate, whose weight column must be a NESTED array: ['weighted mean', ['qty']]. Works in 4.4.0 and survives incremental table.update(). - §2: withdraws the recommendation of the 4.5.1-core + 4.4.1-d3fc pair. It does not deliver charts, so the trilemma is really a dilemma: inline bundling XOR charts. dataflow is on that pair and needs the same migration. - §5: cleanLayout() does not sanitize `aggregates`; guard it before adopting the weighted-mean pattern or a dropped column aborts the whole restore. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SBt3EtKaP9D2mmWJ6Q4bov --- PERSPECTIVE.md | 175 ++++++++- ui/index.html | 1 - ui/package-lock.json | 742 +++++++++++++++++++++++++++++++++++++- ui/package.json | 4 + ui/src/views/Forecast.jsx | 24 +- 5 files changed, 906 insertions(+), 40 deletions(-) diff --git a/PERSPECTIVE.md b/PERSPECTIVE.md index 7d19abe..da40019 100644 --- a/PERSPECTIVE.md +++ b/PERSPECTIVE.md @@ -47,8 +47,27 @@ import '@perspective-dev/viewer/themes' - **Do not load from a CDN at runtime.** It's convenient for a prototype (smaller build, one-line version bumps) but in production it means: app breaks if the CDN is unreachable, version isn't captured in `package-lock.json`, slower cold start, and you - pull executable WASM from a third party on every load. (pf_app currently does this in - `ui/src/views/Forecast.jsx` — migrating off it is the main open item.) + pull executable WASM from a third party on every load. + + > **This is not hypothetical — it took pf_app down on 2026-08-10.** The 4.x CDN bundle + > resolves its server WASM with + > `new URL("../../../server/dist/wasm/perspective-server.wasm", import.meta.url)`, + > which from `.../client@4.4.0/dist/cdn/` resolves to + > `.../npm/@perspective-dev/server/dist/wasm/perspective-server.wasm` — **no version**. + > jsdelivr serves `@latest`. The moment `@perspective-dev/server@5.2.0` published, every + > pf_app page load linked a 5.2.0 WASM against a 4.4.0 client and threw + > `LinkError: Import #8 "env" "psp_opfs_load": function import requires a callable`. + > Nobody changed anything. 4.4.1 and 4.5.2 have the identical unversioned pattern. + > + > The security framing matters as much as the outage: an unversioned URL means your + > users execute whatever that package publishes next, automatically, unreviewed. + > + > 5.2.0 fixes it by carrying the client's version across + > (`/client@X/dist/cdn/… → /server@X/dist/wasm/…`), but the durable fix is `/inline`: + > the WASM is embedded in the bundle and there is no runtime fetch to hijack + > (verified: zero `new URL(...perspective-server...)` in `perspective.inline.js`). + + pf_app migrated off CDN to npm `/inline` at 5.2.0 on 2026-08-17. - The themes CSS is imported in JS (`@perspective-dev/viewer/themes`), **not** via a `` in `index.html` — so it's bundled and versioned too. @@ -60,7 +79,9 @@ The version choice is constrained by two hard facts about the `@perspective-dev` **(verified against installed metadata, 2026-06)**: - **`viewer-d3fc` caps at 4.4.1** — npm publishes no 4.5.x. The d3fc charts (Bar / Line / - Treemap / Heatmap / etc.) live only in this package. + Treemap / Heatmap / etc.) live only in this package. **Still true as of 2026-08**, even + though `client`/`viewer`/`viewer-datagrid` now publish through **5.2.0** — so the + trilemma below has widened, not closed: taking 5.x costs the d3fc charts outright. - **The `/inline` and `/themes` entrypoints are 4.5.x-only** — `@perspective-dev/client/inline`, `@perspective-dev/viewer/inline`, and `@perspective-dev/viewer/themes` do **not** exist in 4.4.1's `exports` map. Bundling inline WASM requires 4.5.x. @@ -71,21 +92,47 @@ So you can have at most **two** of these three: |---|---| | Inline WASM bundling (`/inline`, `/themes`) | **4.5.x** viewer/client | | One coherent single-version suite | **4.4.1** everything (d3fc ceiling) | -| d3fc chart plugins | **4.4.1** viewer-d3fc | +| d3fc chart plugins | **4.4.1** viewer-d3fc — *and a 4.4.1 viewer to match* (see correction) | There is **no** version where all three hold. Pick by what the app needs: -- **Inline-bundled + charts** (dataflow's case) → `^4.5.1` viewer/client/datagrid **+ - `^4.4.1` viewer-d3fc`. This is a deliberate, necessary mixed-version pair, *not* an - accident — it's the only combo that keeps both. Accept it; pin the lockfile and gate - bumps on the smoke test (§7). Do **not** "fix" it by pinning everything to 4.4.1 — the - build breaks (`"./inline" is not exported`). +> ### ⚠️ CORRECTION (2026-08): the mixed pair does NOT deliver charts +> +> This section previously recommended `^4.5.1` viewer/client/datagrid + `^4.4.1` +> viewer-d3fc as "the only combo that keeps both." **That recommendation was wrong.** +> +> - **Confirmed by the app owner:** in the deployed dataflow install (`/opt/dataflow`, +> running exactly that pair), *every chart type other than Datagrid fails.* +> - **Mechanism, reproduced in isolation:** loading 4.4.1 `viewer-d3fc` against a 4.5.1 +> `viewer` throws `get_static_config is not a function` — once per chart plugin. The +> 4.5.x viewer calls a registration method the 4.4.1 plugins don't implement. The same +> load against a coherent 4.4.1 viewer produces no such error. +> +> So the "Inline-bundled + charts" row below is **not achievable**. The trilemma is +> really a **dilemma**: inline WASM bundling **XOR** d3fc charts — pick one. +> +> Consequence: dataflow currently has the worst of both worlds. It carries the +> mixed-version complexity *specifically* to keep charts, and does not have charts. +> Both directions are strictly better than standing still: down to a coherent **4.4.1** +> suite (if charts matter) or up to **5.x** (if they don't, and you want the newer +> engine — §3a, `split_rollup_mode`, `edit_mode` persistence). +> +> **Still unverified:** whether a coherent 4.4.1 suite actually *renders* charts in a +> real bundled build. It is the documented-and-untested assumption this whole policy +> rests on — establish it before betting a version choice on it. + +- ~~**Inline-bundled + charts** (dataflow's case) → `^4.5.1` viewer/client/datagrid **+ + `^4.4.1` viewer-d3fc`.~~ **Withdrawn — see correction above.** This pair yields a + working Datagrid and no charts. If you are on it today, you are choosing inline + bundling, not charts; be explicit about which one you actually want. - **Coherent single suite, no inline** (e.g. CDN or `.`-entry loading) → pin all four to - **4.4.1 exact**. Charts work; you give up `/inline` bundling. + **4.4.1 exact**. Charts are *believed* to work here (unverified — see above); you give + up `/inline` bundling. Whatever you pick, **commit the lockfile** so the resolved set can't drift on -`npm install`. Re-evaluate the whole policy only when `viewer-d3fc` ships a 4.5.x (then a -fully-coherent inline-capable 4.5.x suite becomes possible). +`npm install`. Re-evaluate the whole policy only when `viewer-d3fc` ships a 4.5.x or +later (then a fully-coherent inline-capable suite becomes possible — and only then does +"both" come back on the table). --- @@ -122,6 +169,74 @@ to client-side heuristics — acceptable only at small scale. --- +## 3a. Expression columns and aggregation order (ratio correctness) + +**Expression columns are row-level.** Perspective evaluates every expression against +each *raw row* first, then feeds the result into the column's aggregate. It has no +post-aggregate expression stage. So a ratio written the obvious way: + +```js +expressions: { price: '"revenue" / "qty"' } // default aggregate: sum +``` + +...computes `revenue/qty` per row and then **sums the per-row ratios** — the classic +sum-then-divide error. Verified on 4.4.0/4.4.1/4.5.2/5.2.0 (all identical): for a group +whose true `sum(revenue)/sum(qty)` is `16.15`, the pivot shows `42`. + +This is **not** a `split_by` bug. It is equally wrong with only `group_by` — column +grouping just makes it visible by putting several wrong numbers side by side. No +scalar aggregate fixes it: `avg`/`mean` give the average *of ratios* (`14`), and +`high`/`low`/`median`/`dominant` are all wrong for the same reason. + +### The fix: a weighted-mean aggregate + +Weight the ratio by its own denominator. `sum(price_i × qty_i) / sum(qty_i)` is +algebraically `sum(revenue)/sum(qty)` — the correct answer at *every* level of both axes: + +```js +expressions: { price: '"revenue" / "qty"' }, +aggregates: { price: ['weighted mean', ['qty']] } // note the NESTED array +``` + +**The nested array matters.** The type is +`Aggregate = string | [string, Array]` (`ts-rs/Aggregate.d.ts`), so the weight +column goes in *its own array*. The flat form `['weighted mean', 'qty']` is rejected +with the unhelpful `data did not match any variant of untagged enum Aggregate` — which +reads like "no such aggregate" and is easy to misread as the feature being absent. + +Available since **4.4.0** — no version bump needed, and because the aggregate is +evaluated inside the engine, incremental `table.update()` stays correct (verified: a +`table.update()` on a live view re-derives the weighted mean from the merged rows +without a reload). + +### Rules of thumb + +- Column is a **sum of a measure** (incl. `if(...)` column-subtotal expressions, §below) + → leave the default `sum`. Those are unaffected by any of this. +- Column is a **ratio, rate, price, or per-unit figure** → it *must* carry a + `['weighted mean', ['']]` aggregate, or it is wrong under any pivot. +- Mixing both in one view is fine and was verified. + +### Type inference can silently break expressions + +`if("Year" == '2026', "Amount", 0)` returns 0 for every row if `Year` was **inferred** +as `integer` — which happens to numeric-looking strings when the table is created from +inferred JSON. With an explicit `string` schema the same expression is correct. Neither +literal form (`'2026'` or `2026`) works against a mis-inferred column, and there is no +error. Give period/year columns an explicit `string` type at table creation. + +### Not fixed by any of this: column-axis expand/collapse + +`view.expand()` / `view.collapse()` / `set_depth()` take a **row index** and act on the +row axis only; there is no column-axis equivalent in 4.4.0 **or** 5.2.0, contrary to the +docs' claim that both axes support it. Confirmed directly against the API. 5.2.0 adds +`split_rollup_mode: 'rollup'`, which *emits* subtotal and grand-total column groups +statically (no interactivity) — the nearest thing to Excel-style column subtotals, and +it would retire the `if(...)`-expression workaround. It costs the d3fc charts, though +(§2: `viewer-d3fc` still caps at 4.4.1). + +--- + ## 4. Theming - One toggle drives both app CSS and the viewer: @@ -142,6 +257,16 @@ to client-side heuristics — acceptable only at small scale. exist in the current dataset (plus any `expressions`). dataflow's `cleanLayout()` is the reference implementation; a stale layout referencing a dropped column otherwise throws on restore. +- **`aggregates` needs the same guard, and doesn't currently have it** (verified 2026-08, + pf_app). Both existing `cleanLayout()` implementations filter + `columns`/`group_by`/`split_by`/`sort`/`filter` but leave `aggregates` untouched. That + is harmless *today* only because `viewer.save()` emits `aggregates: {}` until someone + sets one explicitly. The moment a layout adopts the weighted-mean pattern (§3a), a + dropped column aborts the entire restore — both `table.view()` and `viewer.restore()` + throw `Could not get dtype for column 'X' as it does not exist in the schema`. An + aggregate entry references a *target* column and, in the multi-arg form, a *weight* + column; both need validating, and the entry should be dropped rather than the layout. + Add this guard as part of adopting §3a, not after. --- @@ -168,6 +293,13 @@ Run this whenever bumping **any** Perspective package or `apache-arrow`: (`npm view @perspective-dev/viewer-d3fc versions`). If not, **don't bump** the others. 2. Pin all four packages + `apache-arrow` to exact, matching versions; `npm install`; commit the lockfile. + - **Pin `@perspective-dev/server` explicitly too.** `@perspective-dev/client` declares + it as `"@perspective-dev/server": ""` — an *empty* range, which npm resolves to + `latest`. A fresh `npm i @perspective-dev/client@4.4.0` today pulls **server 5.2.0** + and the WASM fails to link: + `Import #8 "env" "psp_opfs_load": function import requires a callable`. + Five packages, not four. This is invisible while pf_app loads from the CDN, and + will bite on the "move off CDN" open item below. 3. `vite build` — no unresolved imports. 4. **Arrow apps:** load a real dataset and confirm `worker.table(buffer)` ingests without a WASM dictionary error; verify a numeric column is `Float64`/`Int`, not a @@ -183,17 +315,22 @@ Run this whenever bumping **any** Perspective package or `apache-arrow`: | | pf_app | dataflow | Target | |---|---|---|---| -| Loader | CDN (runtime) | npm `/inline` | **npm `/inline`** | -| Version | 4.4.0 (CDN URLs) | 4.5.1 viewer/client + 4.4.1 d3fc | depends on loader (§2) | +| Loader | **npm `/inline`** (was CDN until 2026-08-17) | npm `/inline` | **npm `/inline`** | +| Version | **5.2.0 exact, all four** (incl. `server`) | 4.5.1 viewer/client + 4.4.1 d3fc | **5.2.0 exact** | +| Charts | none — d3fc import dropped (unused) | d3fc imported but **broken** (§2 correction) | decide per app | | Data | Arrow IPC (single batch) | JSON (≤100k) | per workload (§3) | -| `apache-arrow` | `^21.1.0` (client built vs 17) | n/a | pin exact, match WASM | +| `apache-arrow` | `^21.1.0` — **verified OK against 5.2.0 WASM** | n/a | pin exact; verify by test | | Deploy | none | systemd + nginx + `deploy.sh` | **systemd + nginx + `deploy.sh`** | **dataflow's 4.5.1/4.4.1 pair is correct** — it's the only combo giving both inline bundling and d3fc charts (§2). Leave it; just keep the lockfile committed. **Open items:** -- pf_app → move off CDN. Note this forces the §2 choice: going npm-`/inline` means - 4.5.x viewer/client + 4.4.1 d3fc (same pair as dataflow); or stay coherent at 4.4.x and - load via the `.` entry instead of `/inline`. Either way, pin + commit the lockfile, and - add deploy automation (systemd + nginx + `deploy.sh`). +- ~~pf_app → move off CDN.~~ **Done 2026-08-17** — npm `/inline`, all four packages + pinned exact at 5.2.0, lockfile committed. Verified end-to-end with every external host + blocked: viewer + datagrid register, the real Arrow stream ingests, the pivot renders. +- **dataflow → same migration.** It is on the withdrawn 4.5.1/4.4.1 pair (§2 correction): + its d3fc charts do not work, so it is paying mixed-version complexity for nothing. + Either drop d3fc and go to 5.2.0, or go coherent 4.4.1 — but verify charts actually + render before choosing the latter, because nobody has confirmed they do. +- pf_app still has no deploy automation (systemd + nginx + `deploy.sh`). diff --git a/ui/index.html b/ui/index.html index 79bf1b9..6f5da67 100644 --- a/ui/index.html +++ b/ui/index.html @@ -5,7 +5,6 @@ Pivot Forecast -
diff --git a/ui/package-lock.json b/ui/package-lock.json index 7709e1f..a3a7acf 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8,6 +8,10 @@ "name": "ui", "version": "0.0.0", "dependencies": { + "@perspective-dev/client": "5.2.0", + "@perspective-dev/server": "5.2.0", + "@perspective-dev/viewer": "5.2.0", + "@perspective-dev/viewer-datagrid": "5.2.0", "react": "^19.2.5", "react-dom": "^19.2.5" }, @@ -266,9 +270,9 @@ } }, "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==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", "dev": true, "license": "MIT", "optional": true, @@ -549,6 +553,46 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@perspective-dev/client": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@perspective-dev/client/-/client-5.2.0.tgz", + "integrity": "sha512-zkJmJFwdw0wMREoJt8gUJyCsflzi7s7Yc8ZtUCOLE9XB6fdyxJmDB99cxO3Q+hno/57kLsz8VNoz8XSm6PZNrg==", + "license": "Apache-2.0", + "dependencies": { + "@perspective-dev/server": "", + "pro_self_extracting_wasm": "0.0.9", + "stoppable": "=1.1.0", + "ws": "^8.17.0" + } + }, + "node_modules/@perspective-dev/server": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@perspective-dev/server/-/server-5.2.0.tgz", + "integrity": "sha512-WRBiokT2/BYM8Ipe7Dg1/2UYNb01Vsox79KBfFVI800VmwdId0GdqI95zufN5ZoFffeBfri1sr3S3AShBRFXKA==", + "license": "Apache-2.0" + }, + "node_modules/@perspective-dev/viewer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@perspective-dev/viewer/-/viewer-5.2.0.tgz", + "integrity": "sha512-IIyqdPduofzzZ/QWrteq29IadJQR8IapTRz7U6XbrtBBm7eyiFsIBKQV0wFfcqWg4TRnhuvCAUvBRieuE0R8Eg==", + "license": "Apache-2.0", + "dependencies": { + "@perspective-dev/client": "", + "pro_self_extracting_wasm": "0.0.9", + "regular-layout": "=0.6.1" + } + }, + "node_modules/@perspective-dev/viewer-datagrid": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@perspective-dev/viewer-datagrid/-/viewer-datagrid-5.2.0.tgz", + "integrity": "sha512-v/SR/35YfyKfivO21nglJFiyG1iE5G8vMwIwWI6fQuwjW764pmNrm/zcrNWNY70x5XHkPRM94aY6LjkLsLkO2g==", + "license": "Apache-2.0", + "dependencies": { + "@perspective-dev/client": "", + "@perspective-dev/viewer": "", + "regular-table": "=0.8.6" + } + }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", @@ -772,6 +816,40 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-wasm32-wasi/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/@rolldown/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/@rolldown/binding-wasm32-wasi/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/@rolldown/binding-win32-arm64-msvc": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", @@ -1205,6 +1283,27 @@ "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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -1228,6 +1327,24 @@ "node": ">=6.0.0" } }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bn.js": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz", + "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", @@ -1276,6 +1393,44 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-pipe": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/buffer-pipe/-/buffer-pipe-0.0.3.tgz", + "integrity": "sha512-GlxfuD/NrKvCNs0Ut+7b1IHjylfdegMBxQIlZHj7bObKVQBxB5S84gtm2yu1mQ8/sSggceWBDPY0cPXgvX2MuA==", + "license": "MPL-2.0", + "dependencies": { + "safe-buffer": "^5.1.2" + } + }, + "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==", + "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==", + "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/caniuse-lite": { "version": "1.0.30001790", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", @@ -1297,6 +1452,40 @@ ], "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==", + "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/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==", + "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==", + "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", @@ -1304,6 +1493,15 @@ "dev": true, "license": "MIT" }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1330,7 +1528,6 @@ "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" @@ -1361,6 +1558,20 @@ "node": ">=8" } }, + "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==", + "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.344", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz", @@ -1382,6 +1593,36 @@ "node": ">=10.13.0" } }, + "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==", + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1588,6 +1829,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1678,6 +1925,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1693,6 +1960,15 @@ "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==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1703,6 +1979,43 @@ "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==", + "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==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1729,6 +2042,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "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", @@ -1736,6 +2061,48 @@ "dev": true, "license": "ISC" }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -1753,6 +2120,71 @@ "hermes-estree": "0.25.1" } }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", + "license": "MIT", + "dependencies": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.6", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1809,7 +2241,6 @@ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -1878,6 +2309,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/leb128": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/leb128/-/leb128-0.0.5.tgz", + "integrity": "sha512-elbNtfmu3GndZbesVF6+iQAfVjOXW9bM/aax9WwMlABZW+oK9sbAZEXoewaPHmL34sxa8kVwWsru8cNE/yn2gg==", + "license": "MPL-2.0", + "dependencies": { + "bn.js": "^5.0.0", + "buffer-pipe": "0.0.3" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2189,6 +2630,27 @@ "@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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", @@ -2205,11 +2667,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "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": { @@ -2245,6 +2715,27 @@ "dev": true, "license": "MIT" }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2336,6 +2827,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/portfinder": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", + "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", + "license": "MIT", + "dependencies": { + "async": "^3.2.6", + "debug": "^4.3.6" + }, + "engines": { + "node": ">= 10.12" + } + }, "node_modules/postcss": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", @@ -2375,6 +2879,20 @@ "node": ">= 0.8.0" } }, + "node_modules/pro_self_extracting_wasm": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/pro_self_extracting_wasm/-/pro_self_extracting_wasm-0.0.9.tgz", + "integrity": "sha512-95/dZfLmlGc/6Xp7gqvRBgXF8M+osw/Xtalz1U/Va8MpSC1TiR7rM4lEvAs1p/q4v/EZk6bow3tKEclbMGsSFQ==", + "license": "Apache-2.0", + "dependencies": { + "http-server": "^14.1.1", + "leb128": "^0.0.5", + "zx": "^8.6.1" + }, + "bin": { + "pro_self_extracting_wasm": "main.mjs" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2385,6 +2903,22 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/react": { "version": "19.2.5", "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", @@ -2407,6 +2941,27 @@ "react": "^19.2.5" } }, + "node_modules/regular-layout": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/regular-layout/-/regular-layout-0.6.1.tgz", + "integrity": "sha512-vGDEFACgFbS/d5kLWJ6AMWY/3DYaZoF1P8+y4KIDnPUFqUQgV5bV8avX7836izmexfmz6ik8JZ4V0Xo4FhaZGQ==", + "license": "Apache-2.0" + }, + "node_modules/regular-table": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/regular-table/-/regular-table-0.8.6.tgz", + "integrity": "sha512-jzJzu9WLtqwMgbf5ak/VdNm/YLHUDnDSCHD5SOksnHrHLuDN6l5i2stYfe7BjsHbQV1Gx9369Ma40nTBCgOFvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, "node_modules/rolldown": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", @@ -2448,12 +3003,30 @@ "dev": true, "license": "MIT" }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "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/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", + "license": "MIT" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -2487,6 +3060,78 @@ "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==", + "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==", + "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==", + "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==", + "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/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2497,6 +3142,28 @@ "node": ">=0.10.0" } }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "license": "MIT", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tailwindcss": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz", @@ -2556,6 +3223,17 @@ "node": ">= 0.8.0" } }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -2597,6 +3275,12 @@ "punycode": "^2.1.0" } }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "license": "MIT" + }, "node_modules/vite": { "version": "8.0.10", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", @@ -2676,6 +3360,19 @@ } } }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2702,6 +3399,27 @@ "node": ">=0.10.0" } }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -2745,6 +3463,18 @@ "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } + }, + "node_modules/zx": { + "version": "8.8.5", + "resolved": "https://registry.npmjs.org/zx/-/zx-8.8.5.tgz", + "integrity": "sha512-SNgDF5L0gfN7FwVOdEFguY3orU5AkfFZm9B5YSHog/UDHv+lvmd82ZAsOenOkQixigwH2+yyH198AwNdKhj+RA==", + "license": "Apache-2.0", + "bin": { + "zx": "build/cli.js" + }, + "engines": { + "node": ">= 12.17.0" + } } } } diff --git a/ui/package.json b/ui/package.json index 7ebf77d..8d88e21 100644 --- a/ui/package.json +++ b/ui/package.json @@ -10,6 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "@perspective-dev/client": "5.2.0", + "@perspective-dev/server": "5.2.0", + "@perspective-dev/viewer": "5.2.0", + "@perspective-dev/viewer-datagrid": "5.2.0", "react": "^19.2.5", "react-dom": "^19.2.5" }, diff --git a/ui/src/views/Forecast.jsx b/ui/src/views/Forecast.jsx index b83e459..8000588 100644 --- a/ui/src/views/Forecast.jsx +++ b/ui/src/views/Forecast.jsx @@ -1,21 +1,18 @@ import { useState, useEffect, useRef } from 'react' import useTheme from '../theme.jsx' +// Perspective is bundled, not fetched at runtime. The /inline entrypoints embed the +// WASM in the build, so the version is fixed by package-lock.json. Do NOT go back to +// CDN