From 6cae7f9982c8a1a8d02793b58c1469b0e67f0d7b Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 25 Mar 2026 00:46:53 -0700 Subject: [PATCH 1/7] Add streaming response optimization spec for non-Next.js paths --- .../2026-03-25-streaming-response-design.md | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-25-streaming-response-design.md diff --git a/docs/superpowers/specs/2026-03-25-streaming-response-design.md b/docs/superpowers/specs/2026-03-25-streaming-response-design.md new file mode 100644 index 00000000..7011dea6 --- /dev/null +++ b/docs/superpowers/specs/2026-03-25-streaming-response-design.md @@ -0,0 +1,194 @@ +# Streaming Response Optimization (Next.js Disabled) + +## Problem + +When Next.js is disabled, the publisher proxy buffers the entire response body +in memory before sending any bytes to the client. This creates two costs: + +1. **Latency** — The client receives zero bytes until the full response is + decompressed, rewritten, and recompressed. For a 222KB HTML page, this adds + hundreds of milliseconds to time-to-last-byte. +2. **Memory** — Peak memory holds ~4x the response size simultaneously + (compressed input + decompressed + processed output + recompressed output). + With WASM's ~16MB heap, this limits the size of pages we can proxy. + +## Scope + +**In scope**: All content types flowing through the publisher proxy path — HTML, +text/JSON, and binary pass-through. Only when Next.js is disabled (no +post-processor requiring the full document). + +**Out of scope**: Concurrent origin+auction fetch, Next.js-enabled paths (these +require full-document post-processing by design), non-publisher routes (static +JS, auction, discovery). + +## Streaming Gate + +Before committing to `stream_to_client()`, check: + +1. Backend status is success (2xx). +2. `html_post_processors()` is empty — no registered post-processors. + +If either check fails, fall back to the current buffered path. This keeps the +optimization transparent: same behavior for all existing configurations, +streaming only activates when safe. + +## Architecture + +Two implementation steps, each independently valuable and testable. + +### Step 1: Make the pipeline chunk-emitting + +Three changes to existing processors: + +#### A) `HtmlRewriterAdapter` — incremental streaming + +The current implementation accumulates the entire HTML document and processes it +on `is_last`. This is unnecessary — `lol_html::HtmlRewriter` supports +incremental `write()` calls and emits output via its `OutputSink` callback after +each chunk. + +Fix: create the rewriter eagerly in the constructor, use +`Rc>>` to share the output buffer between the sink and +`process_chunk()`, drain the buffer on every call instead of only on `is_last`. + +#### B) `process_gzip_to_gzip` — chunk-based decompression + +Currently calls `read_to_end()` to decompress the entire body into memory. The +deflate and brotli paths already use the chunk-based +`process_through_compression()`. + +Fix: use the same `process_through_compression` pattern for gzip. + +#### C) `process_through_compression` finalization + +Currently uses `drop(encoder)` which silently swallows errors from the gzip +trailer CRC32 checksum. + +Fix: call `encoder.finish()` explicitly and propagate errors. + +### Step 2: Stream response to client + +Change the publisher proxy path to use Fastly's `StreamingBody` API: + +1. Fetch from origin, receive response headers. +2. Validate status — if backend error, return buffered error response via + `send_to_client()`. +3. Check streaming gate — if `html_post_processors()` is non-empty, fall back + to buffered path. +4. Finalize all response headers (cookies, synthetic ID, geo, version). +5. Call `response.stream_to_client()` — headers sent to client immediately. +6. Pipe origin body through the streaming pipeline, writing chunks directly to + `StreamingBody`. +7. Call `finish()` on success; on error, log and drop (client sees truncated + response). + +For binary/non-text content: use `StreamingBody::append(body)` for zero-copy +pass-through, bypassing the pipeline entirely. + +#### Entry point change + +Migrate `main.rs` from `#[fastly::main]` to raw `main()` with `fastly::init()` ++ `Request::from_client()`. This is required because `stream_to_client()` / +`send_to_client()` are incompatible with `#[fastly::main]`'s return-based model. + +Non-streaming routes (static, auction, discovery) use `send_to_client()` as +before. + +## Data Flow + +### Streaming path (HTML, text/JSON with processing) + +``` +Origin body (gzip) + → Read 8KB chunk from GzDecoder + → StreamProcessor::process_chunk(chunk, is_last) + → HtmlRewriterAdapter: lol_html.write(chunk) → sink emits rewritten bytes + → OR StreamingReplacer: URL replacement with overlap buffer + → GzEncoder::write(processed_chunk) → compressed bytes + → StreamingBody::write(compressed) → chunk sent to client + → repeat until EOF + → StreamingBody::finish() +``` + +Memory at steady state: ~8KB input chunk buffer + lol_html internal parser state ++ gzip encoder window + overlap buffer for replacer. Roughly constant regardless +of document size, versus the current ~4x document size. + +### Pass-through path (binary, images, fonts, etc.) + +``` +Origin body + → StreamingBody::append(body) → zero-copy transfer +``` + +No decompression, no processing, no buffering. + +### Buffered fallback path (error responses or post-processors present) + +``` +Origin returns 4xx/5xx OR html_post_processors() is non-empty + → Current buffered path unchanged + → send_to_client() with proper status and full body +``` + +## Error Handling + +**Backend returns error status**: Detected before calling `stream_to_client()`. +Return the backend response as-is via `send_to_client()`. Client sees the +correct error status code. No change from current behavior. + +**Processing fails mid-stream**: `lol_html` parse error, decompression +corruption, I/O error. Headers (200 OK) are already sent. Log the error +server-side, drop the `StreamingBody`. Client sees a truncated response and the +connection closes. Standard reverse proxy behavior. + +**Compression finalization fails**: The gzip trailer CRC32 write fails. With the +fix, `encoder.finish()` is called explicitly and errors propagate. Same +mid-stream handling — log and truncate. + +No retry logic. No fallback to buffered after streaming has started — once +headers are sent, we are committed. + +## Files Changed + +| File | Change | Risk | +|------|--------|------| +| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally; fix `process_gzip_to_gzip` to use chunk-based processing; fix `process_through_compression` to call `finish()` explicitly | Medium | +| `crates/trusted-server-core/src/publisher.rs` | Split `handle_publisher_request` into streaming vs buffered paths based on `html_post_processors().is_empty()` | Medium | +| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to raw `main()` with `fastly::init()` + `Request::from_client()`; route results to `send_to_client()` or let streaming path handle its own output | Medium | + +**Not changed**: `html_processor.rs` (builds lol_html `Settings` passed to +`HtmlRewriterAdapter`, works as-is), integration registration, JS build +pipeline, tsjs module serving, auction handler, cookie/synthetic ID logic. + +## Testing Strategy + +### Unit tests (streaming_processor.rs) + +- `HtmlRewriterAdapter` emits output on every `process_chunk()` call, not just + `is_last`. +- `process_gzip_to_gzip` produces correct output without `read_to_end`. +- `encoder.finish()` errors propagate (not swallowed by `drop`). +- Multi-chunk HTML produces identical output to single-chunk processing. + +### Integration tests (publisher.rs) + +- Streaming gate: when `html_post_processors()` is non-empty, response is + buffered. +- Streaming gate: when `html_post_processors()` is empty, response streams. +- Backend error (4xx/5xx) returns buffered error response with correct status. +- Binary content passes through without processing. + +### End-to-end validation (Viceroy) + +- `cargo test --workspace` — all existing tests pass. +- Manual verification via `fastly compute serve` against a real origin. +- Compare response bodies before/after to confirm byte-identical output for + HTML, text, and binary. + +### Measurement (post-deploy) + +- Compare TTFB and time-to-last-byte on staging before and after. +- Monitor WASM heap usage via Fastly dashboard. +- Verify no regressions on static endpoints or auction. From 930a584e102692a55f1c0de9bcd84588f7d8955c Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 25 Mar 2026 00:50:17 -0700 Subject: [PATCH 2/7] Address spec review: Content-Length, streaming gate, finalization order, rollback --- .../2026-03-25-streaming-response-design.md | 58 ++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/docs/superpowers/specs/2026-03-25-streaming-response-design.md b/docs/superpowers/specs/2026-03-25-streaming-response-design.md index 7011dea6..f745f3dd 100644 --- a/docs/superpowers/specs/2026-03-25-streaming-response-design.md +++ b/docs/superpowers/specs/2026-03-25-streaming-response-design.md @@ -15,8 +15,8 @@ in memory before sending any bytes to the client. This creates two costs: ## Scope **In scope**: All content types flowing through the publisher proxy path — HTML, -text/JSON, and binary pass-through. Only when Next.js is disabled (no -post-processor requiring the full document). +text/JSON, RSC Flight (`text/x-component`), and binary pass-through. Only when +Next.js is disabled (no post-processor requiring the full document). **Out of scope**: Concurrent origin+auction fetch, Next.js-enabled paths (these require full-document post-processing by design), non-publisher routes (static @@ -27,11 +27,14 @@ JS, auction, discovery). Before committing to `stream_to_client()`, check: 1. Backend status is success (2xx). -2. `html_post_processors()` is empty — no registered post-processors. +2. For HTML content: `html_post_processors()` is empty — no registered + post-processors. Non-HTML content types (text/JSON, RSC Flight, binary) can + always stream regardless of post-processor registration, since + post-processors only apply to HTML. -If either check fails, fall back to the current buffered path. This keeps the -optimization transparent: same behavior for all existing configurations, -streaming only activates when safe. +If either check fails for the given content type, fall back to the current +buffered path. This keeps the optimization transparent: same behavior for all +existing configurations, streaming only activates when safe. ## Architecture @@ -51,6 +54,12 @@ each chunk. Fix: create the rewriter eagerly in the constructor, use `Rc>>` to share the output buffer between the sink and `process_chunk()`, drain the buffer on every call instead of only on `is_last`. +The output buffer is drained *after* each `rewriter.write()` returns, so the +`RefCell` borrow in the sink closure never overlaps with the drain borrow. + +Note: this makes `HtmlRewriterAdapter` single-use — `reset()` becomes a no-op +since the `Settings` are consumed by the rewriter constructor. This matches +actual usage (one adapter per request). #### B) `process_gzip_to_gzip` — chunk-based decompression @@ -60,12 +69,16 @@ deflate and brotli paths already use the chunk-based Fix: use the same `process_through_compression` pattern for gzip. -#### C) `process_through_compression` finalization +#### C) `process_through_compression` finalization — prerequisite for B -Currently uses `drop(encoder)` which silently swallows errors from the gzip -trailer CRC32 checksum. +`process_through_compression` currently uses `drop(encoder)` which silently +swallows errors. For gzip specifically, the trailer contains a CRC32 checksum — +if `finish()` fails, corrupted responses are served silently. Today this affects +deflate and brotli (which already use `process_through_compression`); after Step +1B moves gzip to this path, it will affect gzip too. -Fix: call `encoder.finish()` explicitly and propagate errors. +Fix: call `encoder.finish()` explicitly and propagate errors. This must land +before or with Step 1B. ### Step 2: Stream response to client @@ -77,10 +90,13 @@ Change the publisher proxy path to use Fastly's `StreamingBody` API: 3. Check streaming gate — if `html_post_processors()` is non-empty, fall back to buffered path. 4. Finalize all response headers (cookies, synthetic ID, geo, version). -5. Call `response.stream_to_client()` — headers sent to client immediately. -6. Pipe origin body through the streaming pipeline, writing chunks directly to +5. Remove `Content-Length` header — the final size is unknown after processing. + Fastly's `StreamingBody` sends the response using chunked transfer encoding + automatically. +6. Call `response.stream_to_client()` — headers sent to client immediately. +7. Pipe origin body through the streaming pipeline, writing chunks directly to `StreamingBody`. -7. Call `finish()` on success; on error, log and drop (client sees truncated +8. Call `finish()` on success; on error, log and drop (client sees truncated response). For binary/non-text content: use `StreamingBody::append(body)` for zero-copy @@ -154,7 +170,7 @@ headers are sent, we are committed. | File | Change | Risk | |------|--------|------| -| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally; fix `process_gzip_to_gzip` to use chunk-based processing; fix `process_through_compression` to call `finish()` explicitly | Medium | +| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); fix `process_gzip_to_gzip` to use chunk-based processing; fix `process_through_compression` to call `finish()` explicitly | High | | `crates/trusted-server-core/src/publisher.rs` | Split `handle_publisher_request` into streaming vs buffered paths based on `html_post_processors().is_empty()` | Medium | | `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to raw `main()` with `fastly::init()` + `Request::from_client()`; route results to `send_to_client()` or let streaming path handle its own output | Medium | @@ -162,6 +178,20 @@ headers are sent, we are committed. `HtmlRewriterAdapter`, works as-is), integration registration, JS build pipeline, tsjs module serving, auction handler, cookie/synthetic ID logic. +Note: `HtmlWithPostProcessing` wraps `HtmlRewriterAdapter` and applies +post-processors on `is_last`. In the streaming path the post-processor list is +empty (that's the gate condition), so the wrapper is a no-op passthrough. It +remains in place — no need to bypass it. + +## Rollback Strategy + +The `#[fastly::main]` to raw `main()` migration is a structural change. If +streaming causes issues in production, the fastest rollback is reverting the +`main.rs` change — the buffered path still exists and the pipeline improvements +(Step 1) are safe to keep regardless. No feature flag needed; a git revert of +the Step 2 commit restores buffered behavior while retaining Step 1 memory +improvements. + ## Testing Strategy ### Unit tests (streaming_processor.rs) From a2b71bf53be89be5167eaa4a605767c50b3afb67 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 25 Mar 2026 01:13:06 -0700 Subject: [PATCH 3/7] Address deep review: header timing, error phases, process_response_streaming refactor --- .../2026-03-25-streaming-response-design.md | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/docs/superpowers/specs/2026-03-25-streaming-response-design.md b/docs/superpowers/specs/2026-03-25-streaming-response-design.md index f745f3dd..dd31097d 100644 --- a/docs/superpowers/specs/2026-03-25-streaming-response-design.md +++ b/docs/superpowers/specs/2026-03-25-streaming-response-design.md @@ -54,7 +54,7 @@ each chunk. Fix: create the rewriter eagerly in the constructor, use `Rc>>` to share the output buffer between the sink and `process_chunk()`, drain the buffer on every call instead of only on `is_last`. -The output buffer is drained *after* each `rewriter.write()` returns, so the +The output buffer is drained _after_ each `rewriter.write()` returns, so the `RefCell` borrow in the sink closure never overlaps with the drain borrow. Note: this makes `HtmlRewriterAdapter` single-use — `reset()` becomes a no-op @@ -90,6 +90,10 @@ Change the publisher proxy path to use Fastly's `StreamingBody` API: 3. Check streaming gate — if `html_post_processors()` is non-empty, fall back to buffered path. 4. Finalize all response headers (cookies, synthetic ID, geo, version). + Today, synthetic ID/cookie headers are set _after_ body processing in + `handle_publisher_request`. Since they are body-independent (computed from + request cookies and consent context), they must be reordered to run _before_ + `stream_to_client()` so headers are complete before streaming begins. 5. Remove `Content-Length` header — the final size is unknown after processing. Fastly's `StreamingBody` sends the response using chunked transfer encoding automatically. @@ -99,13 +103,16 @@ Change the publisher proxy path to use Fastly's `StreamingBody` API: 8. Call `finish()` on success; on error, log and drop (client sees truncated response). -For binary/non-text content: use `StreamingBody::append(body)` for zero-copy -pass-through, bypassing the pipeline entirely. +For binary/non-text content: call `response.take_body()` then +`StreamingBody::append(body)` for zero-copy pass-through, bypassing the pipeline +entirely. Today binary responses skip `take_body()` and return the response +as-is — the streaming path needs to explicitly take the body to hand it to +`append()`. #### Entry point change Migrate `main.rs` from `#[fastly::main]` to raw `main()` with `fastly::init()` -+ `Request::from_client()`. This is required because `stream_to_client()` / +\+ `Request::from_client()`. This is required because `stream_to_client()` / `send_to_client()` are incompatible with `#[fastly::main]`'s return-based model. Non-streaming routes (static, auction, discovery) use `send_to_client()` as @@ -128,7 +135,7 @@ Origin body (gzip) ``` Memory at steady state: ~8KB input chunk buffer + lol_html internal parser state -+ gzip encoder window + overlap buffer for replacer. Roughly constant regardless +\+ gzip encoder window + overlap buffer for replacer. Roughly constant regardless of document size, versus the current ~4x document size. ### Pass-through path (binary, images, fonts, etc.) @@ -154,10 +161,15 @@ Origin returns 4xx/5xx OR html_post_processors() is non-empty Return the backend response as-is via `send_to_client()`. Client sees the correct error status code. No change from current behavior. +**Processor creation fails**: `create_html_stream_processor()` or pipeline +construction errors happen _before_ `stream_to_client()` is called. Since +headers have not been sent yet, return a proper error response via +`send_to_client()`. Same as current behavior. + **Processing fails mid-stream**: `lol_html` parse error, decompression -corruption, I/O error. Headers (200 OK) are already sent. Log the error -server-side, drop the `StreamingBody`. Client sees a truncated response and the -connection closes. Standard reverse proxy behavior. +corruption, I/O error during chunk processing. Headers (200 OK) are already +sent. Log the error server-side, drop the `StreamingBody`. Client sees a +truncated response and the connection closes. Standard reverse proxy behavior. **Compression finalization fails**: The gzip trailer CRC32 write fails. With the fix, `encoder.finish()` is called explicitly and errors propagate. Same @@ -168,11 +180,11 @@ headers are sent, we are committed. ## Files Changed -| File | Change | Risk | -|------|--------|------| -| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); fix `process_gzip_to_gzip` to use chunk-based processing; fix `process_through_compression` to call `finish()` explicitly | High | -| `crates/trusted-server-core/src/publisher.rs` | Split `handle_publisher_request` into streaming vs buffered paths based on `html_post_processors().is_empty()` | Medium | -| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to raw `main()` with `fastly::init()` + `Request::from_client()`; route results to `send_to_client()` or let streaming path handle its own output | Medium | +| File | Change | Risk | +| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | +| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); fix `process_gzip_to_gzip` to use chunk-based processing; fix `process_through_compression` to call `finish()` explicitly | High | +| `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | +| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to raw `main()` with `fastly::init()` + `Request::from_client()`; route results to `send_to_client()` or let streaming path handle its own output | Medium | **Not changed**: `html_processor.rs` (builds lol_html `Settings` passed to `HtmlRewriterAdapter`, works as-is), integration registration, JS build From b363e562ac105b114ad5562f04245507393d80e8 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Wed, 25 Mar 2026 07:59:42 -0700 Subject: [PATCH 4/7] Address deep review: remove fastly::init, fix API assumptions, add missing paths --- .../2026-03-25-streaming-response-design.md | 100 +++++++++++++----- 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/docs/superpowers/specs/2026-03-25-streaming-response-design.md b/docs/superpowers/specs/2026-03-25-streaming-response-design.md index dd31097d..80c49ed8 100644 --- a/docs/superpowers/specs/2026-03-25-streaming-response-design.md +++ b/docs/superpowers/specs/2026-03-25-streaming-response-design.md @@ -61,21 +61,32 @@ Note: this makes `HtmlRewriterAdapter` single-use — `reset()` becomes a no-op since the `Settings` are consumed by the rewriter constructor. This matches actual usage (one adapter per request). -#### B) `process_gzip_to_gzip` — chunk-based decompression +#### B) Chunk-based decompression for all compression paths -Currently calls `read_to_end()` to decompress the entire body into memory. The -deflate and brotli paths already use the chunk-based +`process_gzip_to_gzip` calls `read_to_end()` to decompress the entire body into +memory. The deflate and brotli keep-compression paths already use chunk-based `process_through_compression()`. Fix: use the same `process_through_compression` pattern for gzip. +Additionally, `decompress_and_process()` (used by `process_gzip_to_none`, +`process_deflate_to_none`, `process_brotli_to_none`) also calls +`read_to_end()`. These strip-compression paths must be converted to chunk-based +processing too — read decompressed chunks, process each, write uncompressed +output directly. + +Reference: `process_uncompressed` already implements the correct chunk-based +pattern (read loop → `process_chunk()` per chunk → `write_all()` → flush). The +compressed paths should follow the same structure. + #### C) `process_through_compression` finalization — prerequisite for B `process_through_compression` currently uses `drop(encoder)` which silently -swallows errors. For gzip specifically, the trailer contains a CRC32 checksum — -if `finish()` fails, corrupted responses are served silently. Today this affects -deflate and brotli (which already use `process_through_compression`); after Step -1B moves gzip to this path, it will affect gzip too. +swallows errors. Today this affects deflate and brotli (which already use this +path). The current `process_gzip_to_gzip` calls `encoder.finish()` explicitly — +but Step 1B moves gzip to `process_through_compression`, which would **regress** +gzip from working `finish()` to broken `drop()`. This fix prevents that +regression and also fixes the pre-existing issue for deflate/brotli. Fix: call `encoder.finish()` explicitly and propagate errors. This must land before or with Step 1B. @@ -89,11 +100,14 @@ Change the publisher proxy path to use Fastly's `StreamingBody` API: `send_to_client()`. 3. Check streaming gate — if `html_post_processors()` is non-empty, fall back to buffered path. -4. Finalize all response headers (cookies, synthetic ID, geo, version). - Today, synthetic ID/cookie headers are set _after_ body processing in - `handle_publisher_request`. Since they are body-independent (computed from - request cookies and consent context), they must be reordered to run _before_ - `stream_to_client()` so headers are complete before streaming begins. +4. Finalize all response headers. This requires reordering two things: + - **Synthetic ID/cookie headers**: today set _after_ body processing in + `handle_publisher_request`. Since they are body-independent (computed from + request cookies and consent context), move them _before_ streaming. + - **`finalize_response()`** (main.rs): today called _after_ `route_request` + returns, adding geo, version, staging, and operator headers. In the + streaming path, this must run _before_ `stream_to_client()` since the + publisher handler sends the response directly instead of returning it. 5. Remove `Content-Length` header — the final size is unknown after processing. Fastly's `StreamingBody` sends the response using chunked transfer encoding automatically. @@ -103,17 +117,36 @@ Change the publisher proxy path to use Fastly's `StreamingBody` API: 8. Call `finish()` on success; on error, log and drop (client sees truncated response). -For binary/non-text content: call `response.take_body()` then -`StreamingBody::append(body)` for zero-copy pass-through, bypassing the pipeline -entirely. Today binary responses skip `take_body()` and return the response -as-is — the streaming path needs to explicitly take the body to hand it to -`append()`. +For binary/non-text content: call `response.take_body()` then stream via +`io::copy(&mut body, &mut streaming_body)`. The `Body` type implements `Read` +and `StreamingBody` implements `Write`, so this streams the backend body to the +client without buffering the full content. Today binary responses skip +`take_body()` and return the response as-is — the streaming path needs to +explicitly take the body to pipe it through. #### Entry point change -Migrate `main.rs` from `#[fastly::main]` to raw `main()` with `fastly::init()` -\+ `Request::from_client()`. This is required because `stream_to_client()` / -`send_to_client()` are incompatible with `#[fastly::main]`'s return-based model. +Migrate `main.rs` from `#[fastly::main]` to an undecorated `main()` with +`Request::from_client()`. No separate initialization call is needed — +`#[fastly::main]` is just syntactic sugar for `Request::from_client()` + +`Response::send_to_client()`. The migration is required because +`stream_to_client()` / `send_to_client()` are incompatible with +`#[fastly::main]`'s return-based model. + +```rust +fn main() { + let req = Request::from_client(); + match handle(req) { + Ok(()) => {} + Err(e) => to_error_response(&e).send_to_client(), + } +} +``` + +Note: the return type changes from `Result` to `()` (or +`Result<(), Error>`). Errors that currently propagate to `main`'s `Result` must +now be caught explicitly and sent via `send_to_client()` with +`to_error_response()`. Non-streaming routes (static, auction, discovery) use `send_to_client()` as before. @@ -134,18 +167,19 @@ Origin body (gzip) → StreamingBody::finish() ``` -Memory at steady state: ~8KB input chunk buffer + lol_html internal parser state -\+ gzip encoder window + overlap buffer for replacer. Roughly constant regardless +Memory at steady state: ~8KB input chunk buffer, lol_html internal parser state, +gzip encoder window, and overlap buffer for replacer. Roughly constant regardless of document size, versus the current ~4x document size. ### Pass-through path (binary, images, fonts, etc.) ``` -Origin body - → StreamingBody::append(body) → zero-copy transfer +Origin body (via take_body()) + → io::copy(&mut body, &mut streaming_body) → streamed transfer + → StreamingBody::finish() ``` -No decompression, no processing, no buffering. +No decompression, no processing. Body streams through as read. ### Buffered fallback path (error responses or post-processors present) @@ -168,8 +202,10 @@ headers have not been sent yet, return a proper error response via **Processing fails mid-stream**: `lol_html` parse error, decompression corruption, I/O error during chunk processing. Headers (200 OK) are already -sent. Log the error server-side, drop the `StreamingBody`. Client sees a -truncated response and the connection closes. Standard reverse proxy behavior. +sent. Log the error server-side, drop the `StreamingBody`. Per the Fastly SDK, +`StreamingBody` automatically aborts the response if dropped without calling +`finish()` — the client sees a connection reset / truncated response. This is +standard reverse proxy behavior. **Compression finalization fails**: The gzip trailer CRC32 write fails. With the fix, `encoder.finish()` is called explicitly and errors propagate. Same @@ -182,9 +218,9 @@ headers are sent, we are committed. | File | Change | Risk | | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); fix `process_gzip_to_gzip` to use chunk-based processing; fix `process_through_compression` to call `finish()` explicitly | High | +| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); convert all compression paths to chunk-based processing (`process_gzip_to_gzip` and `decompress_and_process`); fix `process_through_compression` to call `finish()` explicitly | High | | `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | -| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to raw `main()` with `fastly::init()` + `Request::from_client()`; route results to `send_to_client()` or let streaming path handle its own output | Medium | +| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to undecorated `main()` with `Request::from_client()`; explicit error handling via `to_error_response().send_to_client()`; call `finalize_response()` before streaming | Medium | **Not changed**: `html_processor.rs` (builds lol_html `Settings` passed to `HtmlRewriterAdapter`, works as-is), integration registration, JS build @@ -195,6 +231,12 @@ post-processors on `is_last`. In the streaming path the post-processor list is empty (that's the gate condition), so the wrapper is a no-op passthrough. It remains in place — no need to bypass it. +Clarification: `script_rewriters` (used by Next.js and GTM) are distinct from +`html_post_processors`. Script rewriters run inside `lol_html` element handlers +during streaming — they do not require buffering and are unaffected by this +change. The streaming gate checks only `html_post_processors().is_empty()`, not +script rewriters. Currently only Next.js registers a post-processor. + ## Rollback Strategy The `#[fastly::main]` to raw `main()` migration is a structural change. If From ccd948718f43fb975db54d36d46590fcebeef540 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:40:55 -0700 Subject: [PATCH 5/7] Cleanup package files and update streaming response design spec --- docs/package-lock.json | 1296 +++++++---------- docs/package.json | 6 +- .../2026-03-25-streaming-response-design.md | 10 +- 3 files changed, 562 insertions(+), 750 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 78dc9fb8..e31c9db5 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9,27 +9,27 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "@eslint/js": "^9.17.0", + "@eslint/js": "^10", "@types/node": "^24.10", - "eslint": "^9.17.0", + "eslint": "^10", "mermaid": "^11.12.3", "prettier": "^3.4.2", - "typescript-eslint": "^8.55.0", + "typescript-eslint": "8.57", "vitepress": "^1.5.0", "vitepress-plugin-mermaid": "^2.0.17" } }, "node_modules/@algolia/abtesting": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.13.0.tgz", - "integrity": "sha512-Zrqam12iorp3FjiKMXSTpedGYznZ3hTEOAr2oCxI8tbF8bS1kQHClyDYNq/eV0ewMNLyFkgZVWjaS+8spsOYiQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.16.0.tgz", + "integrity": "sha512-alHFZ68/i9qLC/muEB07VQ9r7cB8AvCcGX6dVQi2PNHhc/ZQRmmFAv8KK1ay4UiseGSFr7f0nXBKsZ/jRg7e4g==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" @@ -85,41 +85,41 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.47.0.tgz", - "integrity": "sha512-aOpsdlgS9xTEvz47+nXmw8m0NtUiQbvGWNuSEb7fA46iPL5FxOmOUZkh8PREBJpZ0/H8fclSc7BMJCVr+Dn72w==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.50.0.tgz", + "integrity": "sha512-mfgUdLQNxOAvCZUGzPQxjahEWEPuQkKlV0ZtGmePOa9ZxIQZlk31vRBNbM6ScU8jTH41SCYE77G/lCifDr1SVw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.47.0.tgz", - "integrity": "sha512-EcF4w7IvIk1sowrO7Pdy4Ako7x/S8+nuCgdk6En+u5jsaNQM4rTT09zjBPA+WQphXkA2mLrsMwge96rf6i7Mow==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.50.0.tgz", + "integrity": "sha512-5mjokeKYyPaP3Q8IYJEnutI+O4dW/Ixxx5IgsSxT04pCfGqPXxTOH311hTQxyNpcGGEOGrMv8n8Z+UMTPamioQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.47.0.tgz", - "integrity": "sha512-Wzg5Me2FqgRDj0lFuPWFK05UOWccSMsIBL2YqmTmaOzxVlLZ+oUqvKbsUSOE5ud8Fo1JU7JyiLmEXBtgDKzTwg==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.50.0.tgz", + "integrity": "sha512-emtOvR6dl3rX3sBJXXbofMNHU1qMQqQSWu319RMrNL5BWoBqyiq7y0Zn6cjJm7aGHV/Qbf+KCCYeWNKEMPI3BQ==", "dev": true, "license": "MIT", "engines": { @@ -127,151 +127,152 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.47.0.tgz", - "integrity": "sha512-Ci+cn/FDIsDxSKMRBEiyKrqybblbk8xugo6ujDN1GSTv9RIZxwxqZYuHfdLnLEwLlX7GB8pqVyqrUSlRnR+sJA==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.50.0.tgz", + "integrity": "sha512-IerGH2/hcj/6bwkpQg/HHRqmlGN1XwygQWythAk0gZFBrghs9danJaYuSS3ShzLSVoIVth4jY5GDPX9Lbw5cgg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.47.0.tgz", - "integrity": "sha512-gsLnHPZmWcX0T3IigkDL2imCNtsQ7dR5xfnwiFsb+uTHCuYQt+IwSNjsd8tok6HLGLzZrliSaXtB5mfGBtYZvQ==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.50.0.tgz", + "integrity": "sha512-3idPJeXn5L0MmgP9jk9JJqblrQ/SguN93dNK9z9gfgyupBhHnJMOEjrRYcVgTIfvG13Y04wO+Q0FxE2Ut8PVbA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.47.0.tgz", - "integrity": "sha512-PDOw0s8WSlR2fWFjPQldEpmm/gAoUgLigvC3k/jCSi/DzigdGX6RdC0Gh1RR1P8Cbk5KOWYDuL3TNzdYwkfDyA==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.50.0.tgz", + "integrity": "sha512-q7qRoWrQK1a8m5EFQEmPlo7+pg9mVQ8X5jsChtChERre0uS2pdYEDixBBl0ydBSGkdGbLUDufcACIhH/077E4g==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.47.0.tgz", - "integrity": "sha512-b5hlU69CuhnS2Rqgsz7uSW0t4VqrLMLTPbUpEl0QVz56rsSwr1Sugyogrjb493sWDA+XU1FU5m9eB8uH7MoI0g==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.50.0.tgz", + "integrity": "sha512-Jc360x4yqb3eEg4OY4KEIdGePBxZogivKI+OGIU8aLXgAYPTECvzeOBc90312yHA1hr3AeRlAFl0rIc8lQaIrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.47.0.tgz", - "integrity": "sha512-WvwwXp5+LqIGISK3zHRApLT1xkuEk320/EGeD7uYy+K8WwDd5OjXnhjuXRhYr1685KnkvWkq1rQ/ihCJjOfHpQ==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.50.0.tgz", + "integrity": "sha512-OS3/Viao+NPpyBbEY3tf6hLewppG+UclD+9i0ju56mq2DrdMJFCkEky6Sk9S5VPcbLzxzg3BqBX6u9Q35w19aQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.47.0.tgz", - "integrity": "sha512-j2EUFKAlzM0TE4GRfkDE3IDfkVeJdcbBANWzK16Tb3RHz87WuDfQ9oeEW6XiRE1/bEkq2xf4MvZesvSeQrZRDA==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.50.0.tgz", + "integrity": "sha512-/znwgSiGufpbJVIoDmeQaHtTq+OMdDawFRbMSJVv+12n79hW+qdQXS8/Uu3BD3yn0BzgVFJEvrsHrCsInZKdhw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.47.0.tgz", - "integrity": "sha512-+kTSE4aQ1ARj2feXyN+DMq0CIDHJwZw1kpxIunedkmpWUg8k3TzFwWsMCzJVkF2nu1UcFbl7xsIURz3Q3XwOXA==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.50.0.tgz", + "integrity": "sha512-dHjUfu4jfjdQiKDpCpAnM7LP5yfG0oNShtfpF5rMCel6/4HIoqJ4DC4h5GKDzgrvJYtgAhblo0AYBmOM00T+lQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/client-common": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.47.0.tgz", - "integrity": "sha512-Ja+zPoeSA2SDowPwCNRbm5Q2mzDvVV8oqxCQ4m6SNmbKmPlCfe30zPfrt9ho3kBHnsg37pGucwOedRIOIklCHw==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.50.0.tgz", + "integrity": "sha512-bffIbUljAWnh/Ctu5uScORajuUavqmZ0ACYd1fQQeSSYA9NNN83ynO26pSc2dZRXpSK0fkc1//qSSFXMKGu+aw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0" + "@algolia/client-common": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.47.0.tgz", - "integrity": "sha512-N6nOvLbaR4Ge+oVm7T4W/ea1PqcSbsHR4O58FJ31XtZjFPtOyxmnhgCmGCzP9hsJI6+x0yxJjkW5BMK/XI8OvA==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.50.0.tgz", + "integrity": "sha512-y0EwNvPGvkM+yTAqqO6Gpt9wVGm3CLDtpLvNEiB3VGvN3WzfkjZGtLUsG/ru2kVJIIU7QcV0puuYgEpBeFxcJg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0" + "@algolia/client-common": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.47.0.tgz", - "integrity": "sha512-z1oyLq5/UVkohVXNDEY70mJbT/sv/t6HYtCvCwNrOri6pxBJDomP9R83KOlwcat+xqBQEdJHjbrPh36f1avmZA==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.50.0.tgz", + "integrity": "sha512-xpwefe4fCOWnZgXCbkGpqQY6jgBSCf2hmgnySbyzZIccrv3SoashHKGPE4x6vVG+gdHrGciMTAcDo9HOZwH22Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.47.0" + "@algolia/client-common": "5.50.0" }, "engines": { "node": ">= 14.0.0" @@ -312,13 +313,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -328,9 +329,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { @@ -349,46 +350,46 @@ "license": "MIT" }, "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", - "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", + "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@chevrotain/gast": "11.1.1", - "@chevrotain/types": "11.1.1", + "@chevrotain/gast": "11.1.2", + "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/gast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", - "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", + "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@chevrotain/types": "11.1.1", + "@chevrotain/types": "11.1.2", "lodash-es": "4.17.23" } }, "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", - "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", + "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", "dev": true, "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", - "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "dev": true, "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", - "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", + "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", "dev": true, "license": "Apache-2.0" }, @@ -877,105 +878,89 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", + "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^3.0.3", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^10.2.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "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==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.3.tgz", + "integrity": "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "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==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", + "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", "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.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "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.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "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==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", + "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "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==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", + "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0", + "@eslint/core": "^1.1.1", "levn": "^0.4.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@humanfs/core": { @@ -1031,9 +1016,9 @@ } }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.68", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.68.tgz", - "integrity": "sha512-bQPl1zuZlX6AnofreA1v7J+hoPncrFMppqGboe/SH54jZO37meiBUGBqNOxEpc0HKfZGxJaVVJwZd4gdMYu3hw==", + "version": "1.2.75", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.75.tgz", + "integrity": "sha512-KvcCUbvcBWb0sbqLIxHoY8z5/piXY08wcY9gfMhF+ph3AfzGMaSmZFkUY71HSXAljQngXkgs4bdKdekO0HQWvg==", "dev": true, "license": "CC0-1.0", "dependencies": { @@ -1092,9 +1077,9 @@ "optional": true }, "node_modules/@mermaid-js/parser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", - "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.1.tgz", + "integrity": "sha512-opmV19kN1JsK0T6HhhokHpcVkqKpF+x2pPDKKM2ThHtZAB5F4PROopk0amuVYK5qMrIA4erzpNm8gmPNJgMDxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1102,9 +1087,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", + "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==", "cpu": [ "arm" ], @@ -1116,9 +1101,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz", + "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==", "cpu": [ "arm64" ], @@ -1130,9 +1115,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz", + "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==", "cpu": [ "arm64" ], @@ -1144,9 +1129,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz", + "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==", "cpu": [ "x64" ], @@ -1158,9 +1143,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz", + "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==", "cpu": [ "arm64" ], @@ -1172,9 +1157,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz", + "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==", "cpu": [ "x64" ], @@ -1186,9 +1171,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz", + "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==", "cpu": [ "arm" ], @@ -1200,9 +1185,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz", + "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==", "cpu": [ "arm" ], @@ -1214,9 +1199,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz", + "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==", "cpu": [ "arm64" ], @@ -1228,9 +1213,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz", + "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==", "cpu": [ "arm64" ], @@ -1242,9 +1227,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz", + "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==", "cpu": [ "loong64" ], @@ -1256,9 +1241,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz", + "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==", "cpu": [ "loong64" ], @@ -1270,9 +1255,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz", + "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==", "cpu": [ "ppc64" ], @@ -1284,9 +1269,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz", + "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==", "cpu": [ "ppc64" ], @@ -1298,9 +1283,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz", + "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==", "cpu": [ "riscv64" ], @@ -1312,9 +1297,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz", + "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==", "cpu": [ "riscv64" ], @@ -1326,9 +1311,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz", + "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==", "cpu": [ "s390x" ], @@ -1340,9 +1325,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", + "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", "cpu": [ "x64" ], @@ -1354,9 +1339,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz", + "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==", "cpu": [ "x64" ], @@ -1368,9 +1353,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", + "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==", "cpu": [ "x64" ], @@ -1382,9 +1367,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz", + "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==", "cpu": [ "arm64" ], @@ -1396,9 +1381,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz", + "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==", "cpu": [ "arm64" ], @@ -1410,9 +1395,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz", + "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==", "cpu": [ "ia32" ], @@ -1424,9 +1409,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz", + "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==", "cpu": [ "x64" ], @@ -1438,9 +1423,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz", + "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==", "cpu": [ "x64" ], @@ -1822,6 +1807,13 @@ "@types/d3-selection": "*" } }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1889,11 +1881,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", - "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -1921,17 +1914,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.55.0.tgz", - "integrity": "sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", + "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.55.0", - "@typescript-eslint/type-utils": "8.55.0", - "@typescript-eslint/utils": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/type-utils": "8.57.2", + "@typescript-eslint/utils": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -1944,8 +1937,8 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.55.0", - "eslint": "^8.57.0 || ^9.0.0", + "@typescript-eslint/parser": "^8.57.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, @@ -1960,16 +1953,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.55.0.tgz", - "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", + "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", "debug": "^4.4.3" }, "engines": { @@ -1980,19 +1974,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.55.0.tgz", - "integrity": "sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", + "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.55.0", - "@typescript-eslint/types": "^8.55.0", + "@typescript-eslint/tsconfig-utils": "^8.57.2", + "@typescript-eslint/types": "^8.57.2", "debug": "^4.4.3" }, "engines": { @@ -2007,14 +2001,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.55.0.tgz", - "integrity": "sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", + "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0" + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2025,9 +2019,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.55.0.tgz", - "integrity": "sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", + "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", "dev": true, "license": "MIT", "engines": { @@ -2042,15 +2036,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.55.0.tgz", - "integrity": "sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", + "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0", - "@typescript-eslint/utils": "8.55.0", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/utils": "8.57.2", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -2062,14 +2056,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.55.0.tgz", - "integrity": "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", + "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", "dev": true, "license": "MIT", "engines": { @@ -2081,18 +2075,18 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.55.0.tgz", - "integrity": "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", + "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.55.0", - "@typescript-eslint/tsconfig-utils": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0", + "@typescript-eslint/project-service": "8.57.2", + "@typescript-eslint/tsconfig-utils": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" @@ -2108,43 +2102,17 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.55.0.tgz", - "integrity": "sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", + "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0" + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2154,19 +2122,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.55.0.tgz", - "integrity": "sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", + "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.55.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.57.2", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2183,6 +2151,17 @@ "dev": true, "license": "ISC" }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", @@ -2198,57 +2177,57 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz", - "integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.31.tgz", + "integrity": "sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.27", - "entities": "^7.0.0", + "@babel/parser": "^7.29.2", + "@vue/shared": "3.5.31", + "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz", - "integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.31.tgz", + "integrity": "sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-core": "3.5.31", + "@vue/shared": "3.5.31" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz", - "integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.31.tgz", + "integrity": "sha512-M8wpPgR9UJ8MiRGjppvx9uWJfLV7A/T+/rL8s/y3QG3u0c2/YZgff3d6SuimKRIhcYnWg5fTfDMlz2E6seUW8Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.27", - "@vue/compiler-dom": "3.5.27", - "@vue/compiler-ssr": "3.5.27", - "@vue/shared": "3.5.27", + "@babel/parser": "^7.29.2", + "@vue/compiler-core": "3.5.31", + "@vue/compiler-dom": "3.5.31", + "@vue/compiler-ssr": "3.5.31", + "@vue/shared": "3.5.31", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.6", + "postcss": "^8.5.8", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz", - "integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.31.tgz", + "integrity": "sha512-h0xIMxrt/LHOvJKMri+vdYT92BrK3HFLtDqq9Pr/lVVfE4IyKZKvWf0vJFW10Yr6nX02OR4MkJwI0c1HDa1hog==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-dom": "3.5.31", + "@vue/shared": "3.5.31" } }, "node_modules/@vue/devtools-api": { @@ -2288,57 +2267,57 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.27.tgz", - "integrity": "sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.31.tgz", + "integrity": "sha512-DtKXxk9E/KuVvt8VxWu+6Luc9I9ETNcqR1T1oW1gf02nXaZ1kuAx58oVu7uX9XxJR0iJCro6fqBLw9oSBELo5g==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.27" + "@vue/shared": "3.5.31" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.27.tgz", - "integrity": "sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.31.tgz", + "integrity": "sha512-AZPmIHXEAyhpkmN7aWlqjSfYynmkWlluDNPHMCZKFHH+lLtxP/30UJmoVhXmbDoP1Ng0jG0fyY2zCj1PnSSA6Q==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/reactivity": "3.5.31", + "@vue/shared": "3.5.31" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz", - "integrity": "sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.31.tgz", + "integrity": "sha512-xQJsNRmGPeDCJq/u813tyonNgWBFjzfVkBwDREdEWndBnGdHLHgkwNBQxLtg4zDrzKTEcnikUy1UUNecb3lJ6g==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.27", - "@vue/runtime-core": "3.5.27", - "@vue/shared": "3.5.27", + "@vue/reactivity": "3.5.31", + "@vue/runtime-core": "3.5.31", + "@vue/shared": "3.5.31", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.27.tgz", - "integrity": "sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.31.tgz", + "integrity": "sha512-GJuwRvMcdZX/CriUnyIIOGkx3rMV3H6sOu0JhdKbduaeCji6zb60iOGMY7tFoN24NfsUYoFBhshZtGxGpxO4iA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-ssr": "3.5.31", + "@vue/shared": "3.5.31" }, "peerDependencies": { - "vue": "3.5.27" + "vue": "3.5.31" } }, "node_modules/@vue/shared": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz", - "integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.31.tgz", + "integrity": "sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==", "dev": true, "license": "MIT" }, @@ -2449,11 +2428,12 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2472,9 +2452,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -2489,61 +2469,42 @@ } }, "node_modules/algoliasearch": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.47.0.tgz", - "integrity": "sha512-AGtz2U7zOV4DlsuYV84tLp2tBbA7RPtLA44jbVH4TTpDcc1dIWmULjHSsunlhscbzDydnjuFlNhflR3nV4VJaQ==", + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.50.0.tgz", + "integrity": "sha512-yE5I83Q2s8euVou8Y3feXK08wyZInJWLYXgWO6Xti9jBUEZAGUahyeQ7wSZWkifLWVnQVKEz5RAmBlXG5nqxog==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@algolia/abtesting": "1.13.0", - "@algolia/client-abtesting": "5.47.0", - "@algolia/client-analytics": "5.47.0", - "@algolia/client-common": "5.47.0", - "@algolia/client-insights": "5.47.0", - "@algolia/client-personalization": "5.47.0", - "@algolia/client-query-suggestions": "5.47.0", - "@algolia/client-search": "5.47.0", - "@algolia/ingestion": "1.47.0", - "@algolia/monitoring": "1.47.0", - "@algolia/recommend": "5.47.0", - "@algolia/requester-browser-xhr": "5.47.0", - "@algolia/requester-fetch": "5.47.0", - "@algolia/requester-node-http": "5.47.0" + "@algolia/abtesting": "1.16.0", + "@algolia/client-abtesting": "5.50.0", + "@algolia/client-analytics": "5.50.0", + "@algolia/client-common": "5.50.0", + "@algolia/client-insights": "5.50.0", + "@algolia/client-personalization": "5.50.0", + "@algolia/client-query-suggestions": "5.50.0", + "@algolia/client-search": "5.50.0", + "@algolia/ingestion": "1.50.0", + "@algolia/monitoring": "1.50.0", + "@algolia/recommend": "5.50.0", + "@algolia/requester-browser-xhr": "5.50.0", + "@algolia/requester-fetch": "5.50.0", + "@algolia/requester-node-http": "5.50.0" }, "engines": { "node": ">= 14.0.0" } }, - "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==", + "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", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "18 || 20 || >=22" } }, - "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/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/birpc": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", @@ -2555,24 +2516,16 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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", + "balanced-match": "^4.0.2" + }, "engines": { - "node": ">=6" + "node": "18 || 20 || >=22" } }, "node_modules/ccount": { @@ -2586,23 +2539,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "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/character-entities-html4": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", @@ -2626,17 +2562,18 @@ } }, "node_modules/chevrotain": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", - "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", + "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { - "@chevrotain/cst-dts-gen": "11.1.1", - "@chevrotain/gast": "11.1.1", - "@chevrotain/regexp-to-ast": "11.1.1", - "@chevrotain/types": "11.1.1", - "@chevrotain/utils": "11.1.1", + "@chevrotain/cst-dts-gen": "11.1.2", + "@chevrotain/gast": "11.1.2", + "@chevrotain/regexp-to-ast": "11.1.2", + "@chevrotain/types": "11.1.2", + "@chevrotain/utils": "11.1.2", "lodash-es": "4.17.23" } }, @@ -2653,26 +2590,6 @@ "chevrotain": "^11.0.0" } }, - "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/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -2694,13 +2611,6 @@ "node": ">= 10" } }, - "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/confbox": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", @@ -2762,6 +2672,7 @@ "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10" } @@ -3196,6 +3107,7 @@ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -3287,9 +3199,9 @@ } }, "node_modules/dagre-d3-es": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", - "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", "dev": true, "license": "MIT", "dependencies": { @@ -3298,9 +3210,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "version": "1.11.20", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", "dev": true, "license": "MIT" }, @@ -3330,9 +3242,9 @@ "license": "MIT" }, "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", "dev": true, "license": "ISC", "dependencies": { @@ -3364,9 +3276,9 @@ } }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", + "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", "dev": true, "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { @@ -3446,33 +3358,31 @@ } }, "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.1.0.tgz", + "integrity": "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.3", + "@eslint/config-helpers": "^0.5.3", + "@eslint/core": "^1.1.1", + "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", + "ajv": "^6.14.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", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -3482,8 +3392,7 @@ "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.2", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -3491,7 +3400,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" @@ -3506,48 +3415,50 @@ } }, "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==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "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==", + "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": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "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==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" + "eslint-visitor-keys": "^5.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3690,9 +3601,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -3702,6 +3613,7 @@ "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "tabbable": "^6.4.0" } @@ -3734,19 +3646,6 @@ "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/hachure-fill": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", @@ -3754,16 +3653,6 @@ "dev": true, "license": "MIT" }, - "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/hast-util-to-html": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", @@ -3843,23 +3732,6 @@ "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", @@ -3923,19 +3795,6 @@ "dev": true, "license": "ISC" }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3958,9 +3817,9 @@ "license": "MIT" }, "node_modules/katex": { - "version": "0.16.28", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.28.tgz", - "integrity": "sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==", + "version": "0.16.44", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.44.tgz", + "integrity": "sha512-EkxoDTk8ufHqHlf9QxGwcxeLkWRR3iOuYfRpfORgYfqc8s13bgb+YtRY59NK5ZpRaCwq1kqA6a5lpX8C/eLphQ==", "dev": true, "funding": [ "https://opencollective.com/katex", @@ -4062,13 +3921,6 @@ "dev": true, "license": "MIT" }, - "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/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -4122,28 +3974,30 @@ } }, "node_modules/mermaid": { - "version": "11.12.3", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", - "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.13.0.tgz", + "integrity": "sha512-fEnci+Immw6lKMFI8sqzjlATTyjLkRa6axrEgLV2yHTfv8r+h1wjFbV6xeRtd4rUV1cS4EpR9rwp3Rci7TRWDw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@braintree/sanitize-url": "^7.1.1", - "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^1.0.0", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.0.1", "@types/d3": "^7.4.3", - "cytoscape": "^3.29.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.13", - "dayjs": "^1.11.18", - "dompurify": "^3.2.5", - "katex": "^0.16.22", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "katex": "^0.16.25", "khroma": "^2.1.0", "lodash-es": "^4.17.23", - "marked": "^16.2.1", + "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", @@ -4245,16 +4099,19 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minisearch": { @@ -4272,16 +4129,16 @@ "license": "MIT" }, "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", "dev": true, "license": "MIT", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", - "ufo": "^1.6.1" + "ufo": "^1.6.3" } }, "node_modules/ms": { @@ -4394,19 +4251,6 @@ "dev": true, "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-data-parser": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", @@ -4456,11 +4300,12 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "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", + "peer": true, "engines": { "node": ">=12" }, @@ -4499,9 +4344,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -4528,9 +4373,9 @@ } }, "node_modules/preact": { - "version": "10.28.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", - "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", + "version": "10.29.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz", + "integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==", "dev": true, "license": "MIT", "funding": { @@ -4612,16 +4457,6 @@ "dev": true, "license": "MIT" }, - "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/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -4630,16 +4465,16 @@ "license": "MIT" }, "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "dev": true, "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", + "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4653,31 +4488,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@rollup/rollup-android-arm-eabi": "4.60.0", + "@rollup/rollup-android-arm64": "4.60.0", + "@rollup/rollup-darwin-arm64": "4.60.0", + "@rollup/rollup-darwin-x64": "4.60.0", + "@rollup/rollup-freebsd-arm64": "4.60.0", + "@rollup/rollup-freebsd-x64": "4.60.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.0", + "@rollup/rollup-linux-arm-musleabihf": "4.60.0", + "@rollup/rollup-linux-arm64-gnu": "4.60.0", + "@rollup/rollup-linux-arm64-musl": "4.60.0", + "@rollup/rollup-linux-loong64-gnu": "4.60.0", + "@rollup/rollup-linux-loong64-musl": "4.60.0", + "@rollup/rollup-linux-ppc64-gnu": "4.60.0", + "@rollup/rollup-linux-ppc64-musl": "4.60.0", + "@rollup/rollup-linux-riscv64-gnu": "4.60.0", + "@rollup/rollup-linux-riscv64-musl": "4.60.0", + "@rollup/rollup-linux-s390x-gnu": "4.60.0", + "@rollup/rollup-linux-x64-gnu": "4.60.0", + "@rollup/rollup-linux-x64-musl": "4.60.0", + "@rollup/rollup-openbsd-x64": "4.60.0", + "@rollup/rollup-openharmony-arm64": "4.60.0", + "@rollup/rollup-win32-arm64-msvc": "4.60.0", + "@rollup/rollup-win32-ia32-msvc": "4.60.0", + "@rollup/rollup-win32-x64-gnu": "4.60.0", + "@rollup/rollup-win32-x64-msvc": "4.60.0", "fsevents": "~2.3.2" } }, @@ -4815,19 +4650,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "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/stylis": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", @@ -4848,19 +4670,6 @@ "node": ">=16" } }, - "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/tabbable": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", @@ -4869,9 +4678,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", + "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", "dev": true, "license": "MIT", "engines": { @@ -4907,9 +4716,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "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": { @@ -4958,16 +4767,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.55.0.tgz", - "integrity": "sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz", + "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.55.0", - "@typescript-eslint/parser": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0", - "@typescript-eslint/utils": "8.55.0" + "@typescript-eslint/eslint-plugin": "8.57.2", + "@typescript-eslint/parser": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2", + "@typescript-eslint/utils": "8.57.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4977,7 +4786,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, @@ -5128,6 +4937,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -5188,6 +4998,7 @@ "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", @@ -5294,17 +5105,18 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.27", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", - "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", + "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@vue/compiler-dom": "3.5.27", - "@vue/compiler-sfc": "3.5.27", - "@vue/runtime-dom": "3.5.27", - "@vue/server-renderer": "3.5.27", - "@vue/shared": "3.5.27" + "@vue/compiler-dom": "3.5.31", + "@vue/compiler-sfc": "3.5.31", + "@vue/runtime-dom": "3.5.31", + "@vue/server-renderer": "3.5.31", + "@vue/shared": "3.5.31" }, "peerDependencies": { "typescript": "*" diff --git a/docs/package.json b/docs/package.json index a49562e9..f74991a4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -15,12 +15,12 @@ "lint:fix": "eslint . --fix" }, "devDependencies": { + "@eslint/js": "^10", "@types/node": "^24.10", - "eslint": "^9.17.0", - "@eslint/js": "^9.17.0", + "eslint": "^10", "mermaid": "^11.12.3", - "typescript-eslint": "^8.55.0", "prettier": "^3.4.2", + "typescript-eslint": "8.57", "vitepress": "^1.5.0", "vitepress-plugin-mermaid": "^2.0.17" } diff --git a/docs/superpowers/specs/2026-03-25-streaming-response-design.md b/docs/superpowers/specs/2026-03-25-streaming-response-design.md index 80c49ed8..27650636 100644 --- a/docs/superpowers/specs/2026-03-25-streaming-response-design.md +++ b/docs/superpowers/specs/2026-03-25-streaming-response-design.md @@ -216,11 +216,11 @@ headers are sent, we are committed. ## Files Changed -| File | Change | Risk | -| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); convert all compression paths to chunk-based processing (`process_gzip_to_gzip` and `decompress_and_process`); fix `process_through_compression` to call `finish()` explicitly | High | -| `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | -| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to undecorated `main()` with `Request::from_client()`; explicit error handling via `to_error_response().send_to_client()`; call `finalize_response()` before streaming | Medium | +| File | Change | Risk | +| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | +| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); convert all compression paths to chunk-based processing (`process_gzip_to_gzip` and `decompress_and_process`); fix `process_through_compression` to call `finish()` explicitly | High | +| `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | +| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to undecorated `main()` with `Request::from_client()`; explicit error handling via `to_error_response().send_to_client()`; call `finalize_response()` before streaming | Medium | **Not changed**: `html_processor.rs` (builds lol_html `Settings` passed to `HtmlRewriterAdapter`, works as-is), integration registration, JS build From a754ab1888694bd54a38b5b325c123fe299fe96d Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:45:19 -0700 Subject: [PATCH 6/7] Revert streaming response design spec formatting changes --- .../specs/2026-03-25-streaming-response-design.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/superpowers/specs/2026-03-25-streaming-response-design.md b/docs/superpowers/specs/2026-03-25-streaming-response-design.md index 27650636..80c49ed8 100644 --- a/docs/superpowers/specs/2026-03-25-streaming-response-design.md +++ b/docs/superpowers/specs/2026-03-25-streaming-response-design.md @@ -216,11 +216,11 @@ headers are sent, we are committed. ## Files Changed -| File | Change | Risk | -| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); convert all compression paths to chunk-based processing (`process_gzip_to_gzip` and `decompress_and_process`); fix `process_through_compression` to call `finish()` explicitly | High | -| `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | -| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to undecorated `main()` with `Request::from_client()`; explicit error handling via `to_error_response().send_to_client()`; call `finalize_response()` before streaming | Medium | +| File | Change | Risk | +| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | +| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); convert all compression paths to chunk-based processing (`process_gzip_to_gzip` and `decompress_and_process`); fix `process_through_compression` to call `finish()` explicitly | High | +| `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | +| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to undecorated `main()` with `Request::from_client()`; explicit error handling via `to_error_response().send_to_client()`; call `finalize_response()` before streaming | Medium | **Not changed**: `html_processor.rs` (builds lol_html `Settings` passed to `HtmlRewriterAdapter`, works as-is), integration registration, JS build From db765a67c674c3d9832270555d425cfbd6e52d53 Mon Sep 17 00:00:00 2001 From: Aram Grigoryan <132480+aram356@users.noreply.github.com> Date: Fri, 27 Mar 2026 16:22:16 -0700 Subject: [PATCH 7/7] Fix dead links in spec docs after crate rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update stale crate paths (crates/common/ → crates/trusted-server-core/, crates/fastly/ → crates/trusted-server-adapter-fastly/) and convert source code file references from markdown links to backtick references since vitepress cannot resolve paths outside the docs directory. --- ...3-11-production-readiness-report-design.md | 180 +++++++++--------- .../2026-03-19-edgezero-migration-design.md | 6 +- .../2026-03-24-ssc-technical-spec-design.md | 28 +-- .../2026-03-25-streaming-response-design.md | 10 +- 4 files changed, 112 insertions(+), 112 deletions(-) diff --git a/docs/superpowers/specs/2026-03-11-production-readiness-report-design.md b/docs/superpowers/specs/2026-03-11-production-readiness-report-design.md index d49fa647..5203e5ff 100644 --- a/docs/superpowers/specs/2026-03-11-production-readiness-report-design.md +++ b/docs/superpowers/specs/2026-03-11-production-readiness-report-design.md @@ -36,12 +36,12 @@ find, and key rotation writes to the wrong store. **Refs:** -- [signing.rs:20](crates/common/src/request_signing/signing.rs#L20) -- `FastlyConfigStore::new("jwks_store")` hardcoded -- [signing.rs:122](crates/common/src/request_signing/signing.rs#L122) -- `FastlyConfigStore::new("jwks_store")` hardcoded -- [signing.rs:130](crates/common/src/request_signing/signing.rs#L130) -- `FastlySecretStore::new("signing_keys")` hardcoded -- [jwks.rs:63](crates/common/src/request_signing/jwks.rs#L63) -- `FastlyConfigStore::new("jwks_store")` hardcoded -- [rotation.rs:44](crates/common/src/request_signing/rotation.rs#L44) -- `FastlyConfigStore::new("jwks_store")` hardcoded, ignores `config_store_id` constructor arg -- [endpoints.rs:151](crates/common/src/request_signing/endpoints.rs#L151) -- reads `config_store_id`/`secret_store_id` from settings +- `signing.rs:20` -- `FastlyConfigStore::new("jwks_store")` hardcoded +- `signing.rs:122` -- `FastlyConfigStore::new("jwks_store")` hardcoded +- `signing.rs:130` -- `FastlySecretStore::new("signing_keys")` hardcoded +- `jwks.rs:63` -- `FastlyConfigStore::new("jwks_store")` hardcoded +- `rotation.rs:44` -- `FastlyConfigStore::new("jwks_store")` hardcoded, ignores `config_store_id` constructor arg +- `endpoints.rs:151` -- reads `config_store_id`/`secret_store_id` from settings **Recommendation:** Single source of truth -- either always read store IDs from `Settings` and thread them through, or document + assert the hardcoded names @@ -59,10 +59,10 @@ match config. **Refs:** -- [main.rs:97-98](crates/fastly/src/main.rs#L97-L98) -- admin route matching -- [auth.rs:10](crates/common/src/auth.rs#L10) -- `enforce_basic_auth` checks `handlers` list -- [settings.rs:381](crates/common/src/settings.rs#L381) -- `handlers` parsing -- [trusted-server.toml:1](trusted-server.toml#L1) -- default handler only covers `^/secure` +- `main.rs:97-98` -- admin route matching +- `auth.rs:10` -- `enforce_basic_auth` checks `handlers` list +- `settings.rs:381` -- `handlers` parsing +- `trusted-server.toml:1` -- default handler only covers `^/secure` **Recommendation:** Either hard-require auth for `/admin/*` paths regardless of handler config, or validate at startup that an admin handler exists. @@ -79,10 +79,10 @@ publisher's page context, cookies, and localStorage. **Refs:** -- [request.ts:77-102](crates/js/lib/src/core/request.ts#L77-L102) -- `iframe.srcdoc = buildCreativeDocument(creativeHtml)` -- [render.ts:104-111](crates/js/lib/src/core/render.ts#L104-L111) -- sandbox with `allow-scripts` + `allow-same-origin` -- [render.ts:133-137](crates/js/lib/src/core/render.ts#L133-L137) -- `buildCreativeDocument` does raw string replace -- [auction.ts:141-172](crates/js/lib/src/core/auction.ts#L141-L172) -- `parseAuctionResponse` passes `adm` straight through +- `request.ts:77-102` -- `iframe.srcdoc = buildCreativeDocument(creativeHtml)` +- `render.ts:104-111` -- sandbox with `allow-scripts` + `allow-same-origin` +- `render.ts:133-137` -- `buildCreativeDocument` does raw string replace +- `auction.ts:141-172` -- `parseAuctionResponse` passes `adm` straight through **Recommendation:** Either (a) remove `allow-same-origin` if creatives don't need it, (b) serve creatives from a separate origin, or (c) sanitize `adm` with @@ -104,9 +104,9 @@ original prototype methods, so SPA contexts and test runs accumulate wrappers. **Refs:** -- [shared/script_guard.ts:155-191](crates/js/lib/src/shared/script_guard.ts#L155-L191) -- shared factory patches -- [gpt/script_guard.ts:432-450](crates/js/lib/src/integrations/gpt/script_guard.ts#L432-L450) -- independent GPT patch -- [shared/script_guard.ts:197-199](crates/js/lib/src/shared/script_guard.ts#L197-L199) -- `reset()` doesn't restore originals +- `shared/script_guard.ts:155-191` -- shared factory patches +- `gpt/script_guard.ts:432-450` -- independent GPT patch +- `shared/script_guard.ts:197-199` -- `reset()` doesn't restore originals **Recommendation:** Use a centralized dispatcher -- single prototype patch, register per-integration handlers. Implement proper `reset()` that restores @@ -123,10 +123,10 @@ TOML edit), the service crashes on first matching request. **Refs:** -- [settings.rs:255](crates/common/src/settings.rs#L255) -- `Regex::new(&self.path).expect(...)` -- [script_rewriter.rs:125](crates/common/src/integrations/nextjs/script_rewriter.rs#L125) -- `Regex::new(&pattern).expect(...)` -- [script_rewriter.rs:141](crates/common/src/integrations/nextjs/script_rewriter.rs#L141) -- `Regex::new(&pattern).expect(...)` -- [shared.rs:83](crates/common/src/integrations/nextjs/shared.rs#L83) -- `Regex::new(...).expect(...)` +- `settings.rs:255` -- `Regex::new(&self.path).expect(...)` +- `script_rewriter.rs:125` -- `Regex::new(&pattern).expect(...)` +- `script_rewriter.rs:141` -- `Regex::new(&pattern).expect(...)` +- `shared.rs:83` -- `Regex::new(...).expect(...)` **Recommendation:** Return `Result` from these constructors; catch at startup with a descriptive error message. @@ -145,13 +145,13 @@ globally set to debug level. **Refs:** -- [main.rs:42](crates/fastly/src/main.rs#L42) -- `log::info!("Settings {settings:?}")` -- [main.rs:177](crates/fastly/src/main.rs#L177) -- logger level set to debug -- [synthetic.rs:99](crates/common/src/synthetic.rs#L99) -- logs HMAC input (IP, UA) -- [synthetic.rs:112](crates/common/src/synthetic.rs#L112) -- logs synthetic ID details -- [prebid.rs:832](crates/common/src/integrations/prebid.rs#L832) -- logs full bid response -- [aps.rs:444](crates/common/src/integrations/aps.rs#L444) -- logs APS response -- [adserver_mock.rs:284](crates/common/src/integrations/adserver_mock.rs#L284) -- logs mock response +- `main.rs:42` -- `log::info!("Settings {settings:?}")` +- `main.rs:177` -- logger level set to debug +- `synthetic.rs:99` -- logs HMAC input (IP, UA) +- `synthetic.rs:112` -- logs synthetic ID details +- `prebid.rs:832` -- logs full bid response +- `aps.rs:444` -- logs APS response +- `adserver_mock.rs:284` -- logs mock response **Recommendation:** Implement a `Redacted` wrapper for secret fields that prints `[REDACTED]` in `Debug`/`Display`. Set production log level to `INFO` or @@ -168,10 +168,10 @@ requests when the auction timeout is reached. **Refs:** -- [endpoints.rs:51](crates/common/src/auction/endpoints.rs#L51) -- `timeout_ms: settings.auction.timeout_ms` -- [provider.rs:54](crates/common/src/auction/provider.rs#L54) -- `fn timeout_ms(&self) -> u32` -- [orchestrator.rs:287](crates/common/src/auction/orchestrator.rs#L287) -- `while !remaining.is_empty() { select(remaining) }` -- [backend.rs:118-119](crates/common/src/backend.rs#L118-L119) -- hardcoded 15s first_byte_timeout +- `endpoints.rs:51` -- `timeout_ms: settings.auction.timeout_ms` +- `provider.rs:54` -- `fn timeout_ms(&self) -> u32` +- `orchestrator.rs:287` -- `while !remaining.is_empty() { select(remaining) }` +- `backend.rs:118-119` -- hardcoded 15s first_byte_timeout **Recommendation:** Implement a deadline-based loop that drops remaining pending requests when `timeout_ms` elapses, returning partial results. @@ -187,10 +187,10 @@ the single check. A deployment using defaults has predictable encryption keys. **Refs:** -- [trusted-server.toml:10](trusted-server.toml#L10) -- `proxy_secret = "change-me-proxy-secret"` -- [trusted-server.toml:15](trusted-server.toml#L15) -- `secret_key = "trusted-server"` -- [settings.rs:197](crates/common/src/settings.rs#L197) -- `Settings::validate()` -- no proxy_secret check -- [settings_data.rs:37](crates/common/src/settings_data.rs#L37) -- only checks `== "secret-key"` +- `trusted-server.toml:10` -- `proxy_secret = "change-me-proxy-secret"` +- `trusted-server.toml:15` -- `secret_key = "trusted-server"` +- `settings.rs:197` -- `Settings::validate()` -- no proxy_secret check +- `settings_data.rs:37` -- only checks `== "secret-key"` **Recommendation:** Reject all known placeholder values for both secrets. Consider minimum entropy requirements. @@ -207,7 +207,7 @@ through the first-party proxy. **Refs:** -- [gpt/script_guard.ts:206-230](crates/js/lib/src/integrations/gpt/script_guard.ts#L206-L230) -- `rewriteHtmlString` regex +- `gpt/script_guard.ts:206-230` -- `rewriteHtmlString` regex **Recommendation:** Use DOM-based parsing (`DOMParser`) instead of regex, or fail-closed (block unmatched URLs rather than passing through). @@ -222,11 +222,11 @@ converts it to `None`, making the integration appear "not configured" rather tha **Refs:** -- [prebid.rs:211-212](crates/common/src/integrations/prebid.rs#L211-L212) -- `.ok().flatten()?` -- [nextjs/mod.rs:97-99](crates/common/src/integrations/nextjs/mod.rs#L97-L99) -- `.ok().flatten()?` -- [adserver_mock.rs:373](crates/common/src/integrations/adserver_mock.rs#L373) -- `BackendConfig::from_url(...).ok()` -- [aps.rs:521](crates/common/src/integrations/aps.rs#L521) -- `BackendConfig::from_url(...).ok()` -- [prebid.rs:950](crates/common/src/integrations/prebid.rs#L950) -- `BackendConfig::from_url(...).ok()` +- `prebid.rs:211-212` -- `.ok().flatten()?` +- `nextjs/mod.rs:97-99` -- `.ok().flatten()?` +- `adserver_mock.rs:373` -- `BackendConfig::from_url(...).ok()` +- `aps.rs:521` -- `BackendConfig::from_url(...).ok()` +- `prebid.rs:950` -- `BackendConfig::from_url(...).ok()` **Recommendation:** Log a warning with the error before converting to `None`, or fail the integration registration with a clear message. @@ -244,7 +244,7 @@ with `evil.com`. **Refs:** -- [http_util.rs:55-75](crates/common/src/http_util.rs#L55-L75) -- `extract_request_host` trusts forwarded headers +- `http_util.rs:55-75` -- `extract_request_host` trusts forwarded headers **Recommendation:** Strip or validate forwarded headers at the Fastly VCL layer, or validate against a configured allowlist. @@ -258,9 +258,9 @@ standard `==` comparison, enabling timing side-channel attacks. **Refs:** -- [proxy.rs:1054-1058](crates/common/src/proxy.rs#L1054-L1058) -- `expected != sig` -- [http_util.rs:289-291](crates/common/src/http_util.rs#L289-L291) -- `sign_clear_url(...) == token` -- [auth.rs:17-18](crates/common/src/auth.rs#L17-L18) -- `password == handler.password` +- `proxy.rs:1054-1058` -- `expected != sig` +- `http_util.rs:289-291` -- `sign_clear_url(...) == token` +- `auth.rs:17-18` -- `password == handler.password` **Recommendation:** Use `subtle::ConstantTimeEq` (already in dependency tree via crypto crates). @@ -275,7 +275,7 @@ Any XSS on the publisher's page can exfiltrate this tracking identifier via **Refs:** -- [cookies.rs:67-72](crates/common/src/cookies.rs#L67-L72) -- `create_synthetic_cookie` format string +- `cookies.rs:67-72` -- `create_synthetic_cookie` format string **Recommendation:** Add `HttpOnly` if client-side JS doesn't need to read this cookie directly (it already gets the value via the `x-synthetic-id` header). @@ -291,9 +291,9 @@ third-party APIs. **Refs:** -- [synthetic.rs:129-153](crates/common/src/synthetic.rs#L129-L153) -- `get_synthetic_id` accepts any string -- [publisher.rs:336](crates/common/src/publisher.rs#L336) -- set as response header -- [proxy.rs:442](crates/common/src/proxy.rs#L442) -- forwarded as query parameter +- `synthetic.rs:129-153` -- `get_synthetic_id` accepts any string +- `publisher.rs:336` -- set as response header +- `proxy.rs:442` -- forwarded as query parameter **Recommendation:** Validate against the expected format (64 hex + dot + 6 alphanumeric) in production code, not just tests. @@ -308,7 +308,7 @@ cookie attributes (e.g., `evil; Domain=.attacker.com`). **Refs:** -- [cookies.rs:67-72](crates/common/src/cookies.rs#L67-L72) -- `format!("...={}; Domain=...", synthetic_id, ...)` +- `cookies.rs:67-72` -- `format!("...={}; Domain=...", synthetic_id, ...)` **Recommendation:** Validate/sanitize the value before interpolation, or use a cookie builder library. @@ -324,8 +324,8 @@ URL redirects. **Refs:** -- [proxy.rs:600-621](crates/common/src/proxy.rs#L600-L621) -- `handle_first_party_proxy` -- [proxy.rs:463-582](crates/common/src/proxy.rs#L463-L582) -- `proxy_with_redirects` follows redirects +- `proxy.rs:600-621` -- `handle_first_party_proxy` +- `proxy.rs:463-582` -- `proxy_with_redirects` follows redirects **Recommendation:** Validate redirect targets against an allowlist or block private IP ranges. @@ -340,9 +340,9 @@ The gzip+HTML path reads the entire decompressed body into memory, then the **Refs:** -- [streaming_processor.rs:196](crates/common/src/streaming_processor.rs#L196) -- `decoder.read_to_end(&mut decompressed)` -- [streaming_processor.rs:398](crates/common/src/streaming_processor.rs#L398) -- `HtmlRewriterAdapter::accumulated_input` -- [publisher.rs:129](crates/common/src/publisher.rs#L129) -- `process_response_streaming` collects into `Vec` +- `streaming_processor.rs:196` -- `decoder.read_to_end(&mut decompressed)` +- `streaming_processor.rs:398` -- `HtmlRewriterAdapter::accumulated_input` +- `publisher.rs:129` -- `process_response_streaming` collects into `Vec` **Recommendation:** Feed chunks incrementally to `lol_html::HtmlRewriter` instead of accumulating. Use the streaming `process_through_compression` path @@ -358,10 +358,10 @@ are repeated for every incoming request. **Refs:** -- [main.rs:35](crates/fastly/src/main.rs#L35) -- `get_settings()` per request -- [main.rs:45](crates/fastly/src/main.rs#L45) -- `build_orchestrator()` per request -- [main.rs:47](crates/fastly/src/main.rs#L47) -- `IntegrationRegistry::new()` per request -- [settings_data.rs:28-32](crates/common/src/settings_data.rs#L28-L32) -- TOML parsing + validation +- `main.rs:35` -- `get_settings()` per request +- `main.rs:45` -- `build_orchestrator()` per request +- `main.rs:47` -- `IntegrationRegistry::new()` per request +- `settings_data.rs:28-32` -- TOML parsing + validation **Recommendation:** Cache parsed settings and registry in `OnceLock` or equivalent per-instance state (Fastly Compute instances can reuse across @@ -378,9 +378,9 @@ host/scheme values. **Refs:** -- [prebid.rs:904](crates/common/src/integrations/prebid.rs#L904) -- reads `request_host` from response JSON -- [prebid.rs:911](crates/common/src/integrations/prebid.rs#L911) -- reads `request_scheme` from response JSON -- [prebid.rs:922](crates/common/src/integrations/prebid.rs#L922) -- passes them to `transform_prebid_response` +- `prebid.rs:904` -- reads `request_host` from response JSON +- `prebid.rs:911` -- reads `request_scheme` from response JSON +- `prebid.rs:922` -- passes them to `transform_prebid_response` **Recommendation:** Use the local request's host/scheme from `RequestInfo` instead of the bidder's response body. @@ -396,8 +396,8 @@ should be computed once. **Refs:** -- [bundle.rs:50-55](crates/js/src/bundle.rs#L50-L55) -- `concatenated_hash` allocates full bundle -- [tsjs.rs:7](crates/common/src/tsjs.rs#L7) -- called on every HTML response +- `bundle.rs:50-55` -- `concatenated_hash` allocates full bundle +- `tsjs.rs:7` -- called on every HTML response **Recommendation:** Hash modules incrementally without concatenation, and cache the result in a `OnceLock`. @@ -412,7 +412,7 @@ dozens to hundreds of these. **Refs:** -- [html_processor.rs:128-177](crates/common/src/html_processor.rs#L128-L177) -- 5 methods each allocating a String +- `html_processor.rs:128-177` -- 5 methods each allocating a String **Recommendation:** Pre-compute these strings once and store as fields in `UrlPatterns`. @@ -426,8 +426,8 @@ Bid width/height from external bidder responses are cast from `u64` to `u32` via **Refs:** -- [prebid.rs:751-755](crates/common/src/integrations/prebid.rs#L751-L755) -- `as u32` truncation -- [adserver_mock.rs:235-236](crates/common/src/integrations/adserver_mock.rs#L235-L236) -- `as u32` truncation +- `prebid.rs:751-755` -- `as u32` truncation +- `adserver_mock.rs:235-236` -- `as u32` truncation **Recommendation:** Use `u32::try_from()` or `.min(u32::MAX as u64) as u32`. @@ -441,9 +441,9 @@ on each bundle re-evaluation, creating memory leaks and callback overhead. **Refs:** -- [creative/click.ts:355-359](crates/js/lib/src/integrations/creative/click.ts#L355-L359) -- [creative/dynamic_src_guard.ts:160-165](crates/js/lib/src/integrations/creative/dynamic_src_guard.ts#L160-L165) -- [gpt/script_guard.ts:499-504](crates/js/lib/src/integrations/gpt/script_guard.ts#L499-L504) +- `creative/click.ts:355-359` +- `creative/dynamic_src_guard.ts:160-165` +- `gpt/script_guard.ts:499-504` **Recommendation:** Expose `disconnect()` APIs. Consider a shared observer with multiple handlers. Only install when needed. @@ -458,8 +458,8 @@ closes, and the shim is silently skipped. **Refs:** -- [lockr/index.ts:82-101](crates/js/lib/src/integrations/lockr/index.ts#L82-L101) -- [permutive/index.ts:81-100](crates/js/lib/src/integrations/permutive/index.ts#L81-L100) +- `lockr/index.ts:82-101` +- `permutive/index.ts:81-100` **Recommendation:** Increase timeout, use exponential backoff, or add event-based detection (MutationObserver on script insertion). @@ -474,7 +474,7 @@ semantics will find an empty bid state. **Refs:** -- [core/request.ts:15-60](crates/js/lib/src/core/request.ts#L15-L60) -- callback at line 55 +- `core/request.ts:15-60` -- callback at line 55 **Recommendation:** Fire callback inside `.then()` after rendering, or document the difference from Prebid's contract. @@ -489,7 +489,7 @@ All JSON API responses chain `.with_content_type(APPLICATION_JSON)` then **Refs:** -- [endpoints.rs:49-51](crates/common/src/request_signing/endpoints.rs#L49-L51) -- repeated across 6 endpoints +- `endpoints.rs:49-51` -- repeated across 6 endpoints **Recommendation:** Use `.with_body()` instead of `.with_body_text_plain()`. @@ -499,84 +499,84 @@ All JSON API responses chain `.with_content_type(APPLICATION_JSON)` then ### L-1: Lockr regex compiled per request -**Ref:** [lockr.rs:123-126](crates/common/src/integrations/lockr.rs#L123-L126) +**Ref:** `lockr.rs:123-126` Should use `Lazy` like other integrations (datadome, nextjs). ### L-2: `serve_static_with_etag` rehashes body already hashed for URL -**Ref:** [http_util.rs:182-186](crates/common/src/http_util.rs#L182-L186) +**Ref:** `http_util.rs:182-186` The SHA-256 hash is computed twice for the same static content. ### L-3: Handlebars engine created per request in synthetic ID generation -**Ref:** [synthetic.rs:84](crates/common/src/synthetic.rs#L84) +**Ref:** `synthetic.rs:84` Template engine should be initialized once. ### L-4: ETag comparison doesn't handle multi-value `If-None-Match` -**Ref:** [http_util.rs:188-192](crates/common/src/http_util.rs#L188-L192) +**Ref:** `http_util.rs:188-192` Per RFC 7232, `If-None-Match` can contain comma-separated ETags. ### L-5: `image/*` is not a valid Content-Type -**Ref:** [proxy.rs:247-248](crates/common/src/proxy.rs#L247-L248) +**Ref:** `proxy.rs:247-248` Wildcard MIME types are only valid in Accept headers. Use `application/octet-stream`. ### L-6: Proxy errors return 502 for client-caused failures -**Ref:** [error.rs:107](crates/common/src/error.rs#L107) +**Ref:** `error.rs:107` "Missing tsurl", "invalid tstoken", "expired tsexp" should be 400/403. ### L-7: Body re-sent on 301/302 redirects -**Ref:** [proxy.rs:503-506](crates/common/src/proxy.rs#L503-L506) +**Ref:** `proxy.rs:503-506` Per HTTP spec, only 307/308 should preserve body. ### L-8: `rewrite_attribute` allocates String even when no rewriters match -**Ref:** [registry.rs:696](crates/common/src/integrations/registry.rs#L696) +**Ref:** `registry.rs:696` Use `Cow` to avoid allocation on the common no-match path. ### L-9: `StreamingReplacer` clones overlap buffer + N+1 String allocs per chunk -**Ref:** [streaming_replacer.rs:63](crates/common/src/streaming_replacer.rs#L63) +**Ref:** `streaming_replacer.rs:63` Clone on empty buffer and chained `String::replace()` per replacement pattern. ### L-10: `Compression::from_content_encoding` allocates String for case comparison -**Ref:** [streaming_processor.rs:46-53](crates/common/src/streaming_processor.rs#L46-L53) +**Ref:** `streaming_processor.rs:46-53` Use `eq_ignore_ascii_case` instead of `.to_lowercase()`. ### L-11: `all_module_ids()` allocates Vec on every call -**Ref:** [bundle.rs:17-19](crates/js/src/bundle.rs#L17-L19) +**Ref:** `bundle.rs:17-19` Return from a `OnceLock` or return an iterator. ### L-12: No `X-Content-Type-Options: nosniff` on server-generated responses -**Refs:** [http_util.rs:204](crates/common/src/http_util.rs#L204), [error.rs:18](crates/fastly/src/error.rs#L18) +**Refs:** `http_util.rs:204`, `error.rs:18` ### L-13: Error responses expose internal error context to clients -**Ref:** [error.rs:17-18](crates/fastly/src/error.rs#L17-L18) +**Ref:** `error.rs:17-18` `user_message()` includes configuration/proxy error strings. ### L-14: Static JS bundles cached for only 300 seconds despite cache-busting hash -**Ref:** [http_util.rs:207-208](crates/common/src/http_util.rs#L207-L208) +**Ref:** `http_util.rs:207-208` With `?v={hash}` query strings, `max-age` could be much longer (1 year). @@ -587,7 +587,7 @@ With `?v={hash}` query strings, `max-age` could be much longer (1 year). 1. Assumes `handlers` are the only auth gate for admin endpoints (C-2). 2. If Fastly reuses instances, repeated logger init via `.apply()` could become a runtime foot-gun; worth validating in the runtime model - ([main.rs:197](crates/fastly/src/main.rs#L197)). + (`main.rs:197`). 3. The creative HTML injection (C-3) severity depends on whether upstream bidder responses are already considered trusted. In an open RTB context they are not. 4. Per-request settings parsing (M-8) may be inherent to Fastly Compute's diff --git a/docs/superpowers/specs/2026-03-19-edgezero-migration-design.md b/docs/superpowers/specs/2026-03-19-edgezero-migration-design.md index b78a2c09..894c423e 100644 --- a/docs/superpowers/specs/2026-03-19-edgezero-migration-design.md +++ b/docs/superpowers/specs/2026-03-19-edgezero-migration-design.md @@ -113,7 +113,7 @@ files in `crates/trusted-server-core` and `crates/trusted-server-adapter-fastly` > **Note:** Paths below use post-rename crate names (`crates/trusted-server-core/`, > `crates/trusted-server-adapter-fastly/`). Before PR 1 lands, these correspond to -> `crates/common/` and `crates/fastly/` respectively. +> `crates/trusted-server-core/` and `crates/trusted-server-adapter-fastly/` respectively. | Module | Fastly Imports | | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | @@ -498,8 +498,8 @@ graph TD #### PR 1 — Rename crates and add EdgeZero workspace dependencies **Blocked by:** Nothing -**Files:** `Cargo.toml` (workspace), `crates/common/` → `crates/trusted-server-core/`, -`crates/fastly/` → `crates/trusted-server-adapter-fastly/`, all internal path references +**Files:** `Cargo.toml` (workspace), `crates/trusted-server-core/` → `crates/trusted-server-core/`, +`crates/trusted-server-adapter-fastly/` → `crates/trusted-server-adapter-fastly/`, all internal path references Changes: diff --git a/docs/superpowers/specs/2026-03-24-ssc-technical-spec-design.md b/docs/superpowers/specs/2026-03-24-ssc-technical-spec-design.md index 94028a03..90fd9a7f 100644 --- a/docs/superpowers/specs/2026-03-24-ssc-technical-spec-design.md +++ b/docs/superpowers/specs/2026-03-24-ssc-technical-spec-design.md @@ -106,10 +106,10 @@ EC state flows through an `EcContext` struct created once per request and passed ## 3. Module Structure -New files in `crates/common/src/`: +New files in `crates/trusted-server-core/src/`: ``` -crates/common/src/ +crates/trusted-server-core/src/ ec/ mod.rs — EcContext, pub re-exports identity.rs — EC generation (HMAC-SHA256, IP normalization) @@ -126,13 +126,13 @@ crates/common/src/ Existing files modified: -| File | Change | -| -------------------------------- | ----------------------------------------------------- | -| `crates/common/src/settings.rs` | Add `EdgeCookie` settings struct | -| `crates/common/src/constants.rs` | Add EC header/cookie name constants | -| `crates/common/src/error.rs` | Add `EdgeCookie` error variant | -| `crates/common/src/auction/` | Inject EC into `user.id`, `user.eids`, `user.consent` | -| `crates/fastly/src/main.rs` | Register new routes, run EC middleware | +| File | Change | +| -------------------------------------------------- | ----------------------------------------------------- | +| `crates/trusted-server-core/src/settings.rs` | Add `EdgeCookie` settings struct | +| `crates/trusted-server-core/src/constants.rs` | Add EC header/cookie name constants | +| `crates/trusted-server-core/src/error.rs` | Add `EdgeCookie` error variant | +| `crates/trusted-server-core/src/auction/` | Inject EC into `user.id`, `user.eids`, `user.consent` | +| `crates/trusted-server-adapter-fastly/src/main.rs` | Register new routes, run EC middleware | --- @@ -1143,7 +1143,7 @@ Browser `fetch()` with `credentials: "include"` sends an `OPTIONS` preflight. Th ### 12.1 Changes to existing auction path -The auction handler (`crates/common/src/auction/`) is modified to inject EC identity into outbound OpenRTB requests. This is **not** a builder tweak — it requires explicit schema additions across multiple files. SyntheticID is fully removed from the auction path — no fallback, no `X-Synthetic-*` headers, no `get_or_generate_synthetic_id()`. +The auction handler (`crates/trusted-server-core/src/auction/`) is modified to inject EC identity into outbound OpenRTB requests. This is **not** a builder tweak — it requires explicit schema additions across multiple files. SyntheticID is fully removed from the auction path — no fallback, no `X-Synthetic-*` headers, no `get_or_generate_synthetic_id()`. | Concern | Behavior | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------- | @@ -1388,7 +1388,7 @@ The response confirms the registration succeeded and echoes key fields. `api_key ### 14.1 New `EdgeCookie` settings struct -Added to `crates/common/src/settings.rs`: +Added to `crates/trusted-server-core/src/settings.rs`: ```rust #[derive(Debug, Clone, Deserialize, Serialize, Validate)] @@ -1475,7 +1475,7 @@ Engineering must confirm `fastly::erl::RateCounter` availability in the target b ## 15. Constants and Header Names -New constants in `crates/common/src/constants.rs`: +New constants in `crates/trusted-server-core/src/constants.rs`: ```rust // EC cookie name @@ -1510,7 +1510,7 @@ The following EC headers must be added to `INTERNAL_HEADERS` in `constants.rs` t ## 16. Error Handling -New error variants in `crates/common/src/error.rs`: +New error variants in `crates/trusted-server-core/src/error.rs`: ```rust pub enum TrustedServerError { @@ -1541,7 +1541,7 @@ pub enum TrustedServerError { ## 17. Request Routing -New routes added to `route_request()` in `crates/fastly/src/main.rs`: +New routes added to `route_request()` in `crates/trusted-server-adapter-fastly/src/main.rs`: ```rust // EC sync pixel — no auth required (partner validation is internal) diff --git a/docs/superpowers/specs/2026-03-25-streaming-response-design.md b/docs/superpowers/specs/2026-03-25-streaming-response-design.md index 80c49ed8..27650636 100644 --- a/docs/superpowers/specs/2026-03-25-streaming-response-design.md +++ b/docs/superpowers/specs/2026-03-25-streaming-response-design.md @@ -216,11 +216,11 @@ headers are sent, we are committed. ## Files Changed -| File | Change | Risk | -| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); convert all compression paths to chunk-based processing (`process_gzip_to_gzip` and `decompress_and_process`); fix `process_through_compression` to call `finish()` explicitly | High | -| `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | -| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to undecorated `main()` with `Request::from_client()`; explicit error handling via `to_error_response().send_to_client()`; call `finalize_response()` before streaming | Medium | +| File | Change | Risk | +| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | +| `crates/trusted-server-core/src/streaming_processor.rs` | Rewrite `HtmlRewriterAdapter` to stream incrementally (becomes single-use); convert all compression paths to chunk-based processing (`process_gzip_to_gzip` and `decompress_and_process`); fix `process_through_compression` to call `finish()` explicitly | High | +| `crates/trusted-server-core/src/publisher.rs` | Refactor `process_response_streaming` to accept `W: Write` instead of hardcoding `Vec`; split `handle_publisher_request` into streaming vs buffered paths; reorder synthetic ID/cookie logic before streaming | Medium | +| `crates/trusted-server-adapter-fastly/src/main.rs` | Migrate from `#[fastly::main]` to undecorated `main()` with `Request::from_client()`; explicit error handling via `to_error_response().send_to_client()`; call `finalize_response()` before streaming | Medium | **Not changed**: `html_processor.rs` (builds lol_html `Settings` passed to `HtmlRewriterAdapter`, works as-is), integration registration, JS build