From de7bca66b5f00e8b92e0db8cc366538ed8d64a44 Mon Sep 17 00:00:00 2001 From: Filip Pilar Date: Mon, 7 Sep 2026 21:25:11 +0400 Subject: [PATCH 1/3] fix(linq): modernize adapter contracts and toolchain --- .agents/skills/integrating-linq/SKILL.md | 58 +- .../integrating-linq/reference/webhooks.md | 26 +- .github/workflows/ci.yml | 6 +- README.md | 17 +- package.json | 11 +- packages/adapter-linq/.gitignore | 1 + packages/adapter-linq/FEATURE_PARITY.md | 43 +- packages/adapter-linq/MODERNIZATION.md | 117 ++ packages/adapter-linq/README.md | 35 +- packages/adapter-linq/package.json | 28 +- packages/adapter-linq/src/adapter.ts | 1 + .../src/linq-event-types.generated.ts | 1 + packages/adapter-linq/src/mention-range.ts | 21 + packages/adapter-linq/src/message-compiler.ts | 21 +- packages/adapter-linq/src/message-parser.ts | 40 +- packages/adapter-linq/src/verification.ts | 14 +- packages/adapter-linq/src/webhook.ts | 14 +- .../adapter-linq/test/event-dispatch.test.ts | 102 +- .../contact-card-received-2026-02-03.json | 16 + packages/adapter-linq/test/mentions.test.ts | 145 +- .../adapter-linq/test/message-api.test.ts | 9 +- .../test/message-compiler.test.ts | 88 +- .../adapter-linq/test/message-options.test.ts | 21 +- packages/adapter-linq/test/public-api.test.ts | 5 + .../test/verified-webhook.test.ts | 95 +- packages/adapter-linq/test/webhook-fixture.ts | 36 + packages/adapter-linq/tsconfig.json | 3 +- packages/adapter-linq/tsconfig.test.json | 3 +- pnpm-lock.yaml | 1635 ++++++++++++----- pnpm-workspace.yaml | 49 + 30 files changed, 1966 insertions(+), 695 deletions(-) create mode 100644 packages/adapter-linq/.gitignore create mode 100644 packages/adapter-linq/MODERNIZATION.md create mode 100644 packages/adapter-linq/src/mention-range.ts create mode 100644 packages/adapter-linq/test/fixtures/contact-card-received-2026-02-03.json create mode 100644 packages/adapter-linq/test/webhook-fixture.ts diff --git a/.agents/skills/integrating-linq/SKILL.md b/.agents/skills/integrating-linq/SKILL.md index b0d985a..7f91043 100644 --- a/.agents/skills/integrating-linq/SKILL.md +++ b/.agents/skills/integrating-linq/SKILL.md @@ -6,7 +6,7 @@ description: Integrates the Linq Partner API for webhook intake, subscription se # Integrating Linq Use this workflow when changing Linq integration or `packages/adapter-linq`. Provider facts below -were reverified on **2026-08-22**; recheck current sources before relying on versioned schemas, +were reverified on **2026-09-07**; recheck current sources before relying on versioned schemas, operations, event names, limits, or delivery behavior. ## Evidence precedence @@ -25,13 +25,14 @@ installed SDK exposes it, and a generated SDK union may lag current provider eve Start at: -- `https://docs.linqapp.com/llms.txt` — current documentation index; -- `https://docs.linqapp.com/guides/webhooks/` — verification, versioning, and delivery guarantees; -- `https://docs.linqapp.com/guides/webhooks/events/` — envelope and event examples; -- `https://docs.linqapp.com/guides/webhooks/subscriptions/` — subscription lifecycle; -- `https://docs.linqapp.com/guides/integrations/chat-sdk/` — Linq's published Chat SDK integration; -- `https://docs.linqapp.com/guides/messaging/` — message behavior; -- `https://docs.linqapp.com/getting-started/sdks/` — official client behavior; and +- `https://docs.linqapp.com/llms.txt` — channel index; follow the iMessage + `https://docs.linqapp.com/channel/imessage/llms.txt` for current page paths; +- `https://docs.linqapp.com/channel/imessage/guides/webhooks/` — verification, versioning, and delivery guarantees; +- `https://docs.linqapp.com/channel/imessage/guides/webhooks/events/` — envelope and event examples; +- `https://docs.linqapp.com/channel/imessage/guides/webhooks/subscriptions/` — subscription lifecycle; +- `https://docs.linqapp.com/channel/imessage/guides/integrations/chat-sdk/` — Linq's published Chat SDK integration; +- `https://docs.linqapp.com/channel/imessage/guides/messaging/` — message behavior; +- `https://docs.linqapp.com/channel/imessage/getting-started/sdks/` — official client behavior; and - `https://cdn.linqapp.com/openapi/linq-api-v3.yaml` — canonical endpoints, schemas, and event enum. Use the index to discover current page paths rather than guessing old documentation URLs. @@ -78,13 +79,16 @@ The signed content is: {webhook-id}.{webhook-timestamp}.{raw_body} ``` -The current adapter verifies this scheme directly with `standardwebhooks@1.0.0`. Standard secrets +The current adapter verifies this scheme directly with `standardwebhooks@1.1.1`. Standard secrets use the `whsec_` format, and signatures use `v1,{base64}` values. Linq's current Chat SDK integration page still describes the older `{timestamp}.{body}` HMAC shape, while the primary webhook guide -specifies Standard Webhooks over `{webhook-id}.{webhook-timestamp}.{body}`. The documentation also -describes SDK `webhooks.unwrap()`, but installed `@linqapp/sdk@0.44.3` does not expose that method or -wrapper event types at runtime or in declarations. Treat these as provider documentation/SDK -discrepancies and follow the primary webhook guide plus the installed runtime. +specifies Standard Webhooks over `{webhook-id}.{webhook-timestamp}.{body}`. Installed `@linqapp/sdk@0.62.0` now exposes +`webhooks.unwrap()` and generated event types. Its existence does not replace the adapter-owned +verification/error contract. Keep direct Standard Webhooks verification, explicit trusted +forwarding, and lossless future-event handling. Version 1.1.1 rejects empty decoded secrets and +returns undefined for authenticated empty bodies; the adapter explicitly parses after +authentication to preserve `invalid_json`. Refuse lossy UTF-8 round trips before using the +reference verifier so signatures cannot authenticate substituted bytes. The repository adapter accepts Standard Webhooks only. Deprecated `X-Webhook-*` signature handling is not part of its public contract. Partial Standard header sets fail, and verified requests @@ -108,11 +112,20 @@ identifies the sender, `chat` contains canonical chat facts including `id`, `is_ `owner_handle`, and message fields such as `id`, `parts`, `sent_at`, `delivered_at`, and `read_at` live directly on `data`. -Installed `@linqapp/sdk@0.44.3` exposes the subscription event-name enum and useful lower-level resource -types, but no exhaustive webhook envelope union or unwrap runtime. The adapter therefore owns a -stable envelope, a checked-in OpenAPI-derived event-name inventory, curated normalized -message/reaction observations, and a lossless raw form for unknown/future events. The drift check -intentionally does not inventory provider-wide operations. +Installed `@linqapp/sdk@0.62.0` supplies useful message/resource and webhook types. The adapter +retains a stable envelope, the canonical OpenAPI-derived 46-event inventory, curated observations, +and a lossless raw form for unknown/future events. The drift check intentionally does not +inventory provider-wide operations. + +Inbound group owner mentions use authenticated `mentions[]`: `is_me: true`, exact owner handle, +and valid half-open UTF-16 ranges, without splitting surrogate pairs. Multiple mentions and +formatting are allowed inbound. Only an absent `mentions` field permits the deprecated singular +first-mention fallback; null, empty, or malformed modern values never fall back. Outbound text +parts still use singular `mention` / `mention_range` and the existing send-side exclusions. + +`contact_card.received` is a named/raw line-level observation only. Preserve unknown +reaction/sticker values and per-event `zero_retention` in raw facts; do not invent contact, +retention, download, or persistence workflows. The installed SDK also includes the `app_clip` message part for a standalone Linq checkout URL. It is iMessage-only and does not downgrade to SMS or RCS. Keep outbound use on the typed native client; @@ -120,3 +133,12 @@ the adapter normalizes an inbound App Clip URL as ordinary text/link while retai part for title, description, and image metadata. Read `reference/webhooks.md` for the repository-specific ingress and setup checklist. + +## Adapter maintenance baseline + +Use Chat/shared `4.40.0`, Linq SDK `0.62.0`, and `standardwebhooks@1.1.1`. The tested Chat peer +floor is `4.40.0`. Run `pnpm check:adapter` with pnpm `12.3.4` and Node.js 22.12 or 24. +TypeScript `7.0.2` builds declarations and maps natively; only introduce a TypeScript 6 +compatibility alias if a verified compiler-API consumer needs it. Keep installs explicit and +frozen after lockfile preparation, and review lifecycle permissions narrowly. Example/demo +maintenance is separate from adapter work and must not be inferred from the paths above. diff --git a/.agents/skills/integrating-linq/reference/webhooks.md b/.agents/skills/integrating-linq/reference/webhooks.md index beb61ac..35c1585 100644 --- a/.agents/skills/integrating-linq/reference/webhooks.md +++ b/.agents/skills/integrating-linq/reference/webhooks.md @@ -1,8 +1,8 @@ # Linq webhook checklist -Provider facts here were reverified on **2026-08-22**. Start with the current +Provider facts here were reverified on **2026-09-07**. Start with the current [`docs.linqapp.com` index](https://docs.linqapp.com/llms.txt), -[webhook guide](https://docs.linqapp.com/guides/webhooks/), and +[webhook guide](https://docs.linqapp.com/channel/imessage/guides/webhooks/), and [canonical OpenAPI](https://cdn.linqapp.com/openapi/linq-api-v3.yaml). Then inspect the resolved `@linqapp/sdk` types and current repository tests. Record disagreements; do not resolve them from this summary alone. @@ -17,10 +17,12 @@ Always preserve the raw request body until authentication succeeds. - Verify `{webhook-id}.{webhook-timestamp}.{raw_body}` using the subscription secret. - Standard secrets use `whsec_` plus base64 key material; signatures contain `v1,{base64}` values. - Reject timestamps outside five minutes and compare signatures in constant time. -- Use the direct `standardwebhooks` reference implementation. The current SDK's `Webhooks` class is - empty even though provider documentation still describes `webhooks.unwrap()`. +- Use `standardwebhooks@1.1.1` directly. SDK `0.62.0` now has `webhooks.unwrap()`, but the + adapter preserves its exact-byte, trusted-forwarding, and error contract independently. +- Reject empty decoded secrets. Parse JSON explicitly after authentication, including an empty + body, and reject lossy UTF-8 decoding before signature verification. -Linq's current [Chat SDK integration page](https://docs.linqapp.com/guides/integrations/chat-sdk/) +Linq's current [Chat SDK integration page](https://docs.linqapp.com/channel/imessage/guides/integrations/chat-sdk/) also describes an older `{timestamp}.{body}` HMAC shape. The primary webhook guide and Standard Webhooks headers are authoritative for this adapter: `{webhook-id}.{webhook-timestamp}.{raw_body}`. Do not copy the integration page's older signature @@ -71,8 +73,9 @@ behavior, or provider delivery reliability. Historical real-delivery observation The checked-in inventory records only the canonical event-name enum supporting the public typed event contract. Run `pnpm openapi:check` to detect that schema drift. Installed -`@linqapp/sdk@0.44.3` has no unwrap union; do not use generated SDK webhook wrappers as a -closed-world boundary. +`@linqapp/sdk@0.62.0` includes unwrap and event types; generated wrappers are still not a +closed-world boundary. All 46 canonical names, including raw-only `contact_card.received`, are +checked against OpenAPI. ## Repository setup and storage @@ -101,3 +104,12 @@ The `2026-02-03` envelope includes `api_version`, `webhook_version`, `event_type Before changing parsing, compare the official event guide/OpenAPI, installed SDK declarations, `packages/adapter-linq/src/webhook.ts`, and current fixtures. Preserve provider facts that cannot be normalized faithfully in the verified raw envelope. + +## Mention and raw-fact boundaries + +Inbound `mentions[]` is authoritative whenever present. Owner detection requires an exact owner +handle, `is_me: true`, and a valid UTF-16 range. Owner position and inbound formatting do not +exclude a mention. Only omitted modern fields use the deprecated singular fallback. Outbound +mentions stay singular. Contact-card events identify a line rather than a chat and receive only +named/raw dispatch. Unknown sticker/reaction details and `zero_retention` remain lossless; +applications own any contact, retention, or download workflow. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bec67f..1c0d533 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [20, 24] + node-version: ["22.12.0", "24"] steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 @@ -24,5 +24,5 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: pnpm - - run: pnpm install --frozen-lockfile - - run: pnpm check + - run: pnpm --filter @forma/linq-chat-sdk-adapter... install --frozen-lockfile + - run: pnpm check:adapter diff --git a/README.md b/README.md index bfb0bd3..c257241 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,19 @@ identity. ## Development ```bash -pnpm install -pnpm check +pnpm --filter @forma/linq-chat-sdk-adapter... install --frozen-lockfile +pnpm check:adapter ``` -`pnpm check` runs the canonical webhook event-name drift check, lint, formatting, tests, -TypeScript contracts, and workspace builds. CI runs the same check on Node.js 20 and 24. +`pnpm check:adapter` runs the canonical webhook event-name drift check, adapter lint, formatting, +tests, TypeScript contracts, and build. CI runs this adapter-only check on Node.js 22.12 and 24. +The example application is maintained separately and is outside this validation target. -The adapter currently uses `@linqapp/sdk@0.44.3` for provider operations, Chat SDK `4.38.1`, and -`standardwebhooks` for inbound authentication. Its verified webhook envelope remains adapter-owned -because the installed Linq SDK does not provide the required verification/event contract. +The adapter pins Linq SDK `0.62.0`, Chat/shared `4.40.0`, and `standardwebhooks@1.1.1`. +Development uses pnpm `12.3.4`, TypeScript `7.0.2`, and Vitest `5.0.0` with Vite `8.2.2`. +The SDK now exposes `webhooks.unwrap()`; the adapter retains its verified boundary for exact bytes, +explicit trusted forwarding, stable errors, and lossless future events. See the adapter +[modernization notes](packages/adapter-linq/MODERNIZATION.md) for migration and local release checks. ## Maintenance diff --git a/package.json b/package.json index 070baf8..5a9b791 100644 --- a/package.json +++ b/package.json @@ -11,15 +11,16 @@ "format": "turbo format", "format:check": "turbo format:check", "openapi:check": "pnpm --filter @forma/linq-chat-sdk-adapter openapi:check", - "check": "pnpm openapi:check && pnpm lint && pnpm format:check && pnpm test && pnpm typecheck && pnpm build" + "check": "pnpm openapi:check && pnpm lint && pnpm format:check && pnpm test && pnpm typecheck && pnpm build", + "check:adapter": "pnpm --filter @forma/linq-chat-sdk-adapter openapi:check && turbo lint format:check test typecheck build --filter=@forma/linq-chat-sdk-adapter --cache-dir=.turbo/cache --cache=local:rw" }, "devDependencies": { - "turbo": "^2.5.0", - "typescript": "^5.8.3", + "turbo": "2.10.12", + "typescript": "7.0.2", "yaml": "^2.9.0" }, "engines": { - "node": ">=20" + "node": "^22.12.0 || ^24.0.0" }, - "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319" + "packageManager": "pnpm@12.3.4" } diff --git a/packages/adapter-linq/.gitignore b/packages/adapter-linq/.gitignore new file mode 100644 index 0000000..404abb2 --- /dev/null +++ b/packages/adapter-linq/.gitignore @@ -0,0 +1 @@ +coverage/ diff --git a/packages/adapter-linq/FEATURE_PARITY.md b/packages/adapter-linq/FEATURE_PARITY.md index 82ac3f6..0be3360 100644 --- a/packages/adapter-linq/FEATURE_PARITY.md +++ b/packages/adapter-linq/FEATURE_PARITY.md @@ -13,18 +13,18 @@ Evidence labels: ## Standard Chat SDK surface -| Capability | Status | Evidence and boundary | -| --------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- | -| Existing-chat post/reply | Complete | `Contract-verified`; validated provider identity, idempotency, cards/files/attachments, shared errors | -| Edit message | Complete | `Contract-verified`; current provider operation is text-only | -| Thread/history/message retrieval | Complete | `Contract-verified`; untruthful rows omitted, full-precision stable chronology, cursors, bounded malformed-page traversal | -| Whole-message reactions | Complete | `Contract-verified`; ordinary Chat SDK API | -| Typing and mark-read | Complete | `Contract-verified`; direct/group start typing, standard chat-wide read plus released `markRead()` alias | -| Inbound message/reaction dispatch | Complete | `Contract-verified`; owner-targeted native group mentions route through `onNewMention()`; malformed facts stay lossless | -| Static cards and buffered streams | Complete | `Contract-verified`; compiled text/media rather than native interactive cards or native streaming | -| Inbound/outbound media | Complete | `Contract-verified`; bounded upload fetches, literal-target/redirect checks, stable inbound identity, conservative cleanup | -| Proactive `openDM()` | Complete | `Contract-verified`; pending bootstrap, first-post creation, canonical returned identity, explicit immutable-thread boundary | -| Lazy/static credentials | Complete | `Contract-verified`; per-operation lazy resolution and rotation; truthful sync/async native-client access | +| Capability | Status | Evidence and boundary | +| --------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Existing-chat post/reply | Complete | `Contract-verified`; validated provider identity, idempotency, cards/files/attachments, shared errors | +| Edit message | Complete | `Contract-verified`; current provider operation is text-only | +| Thread/history/message retrieval | Complete | `Contract-verified`; untruthful rows omitted, full-precision stable chronology, cursors, bounded malformed-page traversal | +| Whole-message reactions | Complete | `Contract-verified`; ordinary Chat SDK API | +| Typing and mark-read | Complete | `Contract-verified`; direct/group start typing, standard chat-wide read plus released `markRead()` alias | +| Inbound message/reaction dispatch | Complete | `Contract-verified`; authenticated multi-mention arrays route owner mentions through `onNewMention()`; formatting allowed; absent-only legacy fallback | +| Static cards and buffered streams | Complete | `Contract-verified`; compiled text/media rather than native interactive cards or native streaming | +| Inbound/outbound media | Complete | `Contract-verified`; bounded upload fetches, literal-target/redirect checks, stable inbound identity, conservative cleanup | +| Proactive `openDM()` | Complete | `Contract-verified`; pending bootstrap, first-post creation, canonical returned identity, explicit immutable-thread boundary | +| Lazy/static credentials | Complete | `Contract-verified`; per-operation lazy resolution and rotation; truthful sync/async native-client access | ## Linq-specific surface @@ -42,18 +42,19 @@ Evidence labels: ## Verified webhook boundary -| Capability | Status | Evidence and boundary | -| -------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------- | -| Direct/trusted webhook authentication | Complete | `Contract-verified`, `Provider-observed`; exact raw body, explicit authority, no fallback/double verification | -| Typed/lossless event observation | Complete | `Contract-verified`; curated projections, named canonical raw events, generic malformed/unknown/future facts | -| Lifecycle/edit/reconciliation/location facts | Complete | `Contract-verified`; observations only, no ordering/terminal/correlation claims | -| Poll event facts | Complete | `Documented`, `Contract-verified`; all nine current families typed/lossless, malformed curated data generic-only | -| Atomic dedupe/callback isolation/`waitUntil` | Complete | `Contract-verified`; per-event listener snapshots and rejected callbacks do not delay acknowledgement | -| Missing current chat kind | Complete | `Contract-verified`; reuse a known fact or retain raw observation without lookup/guess/standard dispatch | -| OpenAPI event-name drift | Complete | `Contract-verified`; only the canonical enum backing `onLinqEvent()` is inventoried | +| Capability | Status | Evidence and boundary | +| -------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Direct/trusted webhook authentication | Complete | `Contract-verified`, `Provider-observed`; exact raw body, explicit authority, no fallback/double verification | +| Typed/lossless event observation | Complete | `Contract-verified`; curated projections, 46 named canonical events including raw-only `contact_card.received`, generic malformed/unknown/future facts | +| Lifecycle/edit/reconciliation/location facts | Complete | `Contract-verified`; observations only, no ordering/terminal/correlation claims | +| Poll event facts | Complete | `Documented`, `Contract-verified`; all nine current families typed/lossless, malformed curated data generic-only | +| Atomic dedupe/callback isolation/`waitUntil` | Complete | `Contract-verified`; per-event listener snapshots and rejected callbacks do not delay acknowledgement | +| Missing current chat kind | Complete | `Contract-verified`; reuse a known fact or retain raw observation without lookup/guess/standard dispatch | +| OpenAPI event-name drift | Complete | `Contract-verified`; only the canonical enum backing `onLinqEvent()` is inventoried | ## Cross-cutting boundaries +- Unknown reaction/sticker data and per-event `zero_retention` stay lossless; no inferred retention or contact workflow. - Emit only `linq:{chatId}`; persisted `:dm/group` IDs are decode-only compatibility. - Voice memos and `text/vcard` parts use standard secure downloadable media. The schema does not distinguish native voice memos reliably; transcription and contact handling are application-owned. diff --git a/packages/adapter-linq/MODERNIZATION.md b/packages/adapter-linq/MODERNIZATION.md new file mode 100644 index 0000000..cdda28e --- /dev/null +++ b/packages/adapter-linq/MODERNIZATION.md @@ -0,0 +1,117 @@ +# Adapter modernization: 0.1.0-forma.8 + +This adapter-only change starts from `main` at +`7f5285207b4a737680a1d9cad1968e9deaf35e86` (`0.1.0-forma.7`). +Example applications, Nitro, databases, provider configuration, and deployments are separate work. + +## Pinned baseline + +| Component | Version | +| --------------------------------- | --------------- | +| Chat and shared adapter utilities | 4.40.0 | +| Linq SDK | 0.62.0 | +| Standard Webhooks | 1.1.1 | +| pnpm | 12.3.4 | +| TypeScript native compiler | 7.0.2 | +| Vitest and V8 coverage | 5.0.0 | +| Vite | 8.2.2 | +| Turbo | 2.10.12 | +| oxlint / oxfmt | 1.82.0 / 0.67.0 | +| Node types | 22.20.1 | + +The supported runtime lines are Node 22.12+ and 24. The tested Chat minimum is 4.40.0; +older versions are outside the peer range. Runtime dependencies are exact pins. + +The TypeScript build and test configs explicitly include Node types. The build retains ESM, +declarations, declaration maps, and JavaScript source maps. Package sources are included so map +references resolve in a clean consumer. The adapter tooling has no required legacy TypeScript +compiler-API consumer, so no TypeScript 6 alias is installed. `ChatWithThreads` remains necessary: +Chat 4.40.0 implements `thread()` but still omits it from `ChatInstance`. + +pnpm 12 uses a multi-document lockfile that also records the package manager. The example app's +importer retains its existing dependency specifications and resolved versions. The adapter/tooling +install graph needs no dependency lifecycle scripts (`allowBuilds: {}`). New scripts remain +unreviewed and fail under pnpm's strict default. Release-age exceptions name only the requested +oxlint/oxfmt versions and their platform bindings; further exceptions require review. +`verifyDepsBeforeRun: error` prevents validation commands from installing dependencies implicitly. + +## Contract changes + +- Authenticated inbound `mentions[]` takes precedence over deprecated first-mention fields. An + owner entry requires `is_me: true`, exact owner-handle equality, and a bounded non-empty UTF-16 + range with intact surrogate pairs. Multiple mentions and formatting are allowed inbound. Only + omission of the modern field permits the deprecated singular fallback. Outbound remains singular. +- `contact_card.received` is one of the 46 canonical named events and receives raw-only dispatch. + It belongs to a line, does not establish a chat, and adds no contact/media workflow. Unknown + sticker/reaction and `zero_retention` facts remain lossless raw data. +- Standard Webhooks still performs signature verification. Version 1.1.1 rejects empty decoded + secrets and returns undefined for an authenticated empty body. Explicit post-authentication JSON + parsing preserves `invalid_json` for that body. Lossy UTF-8 input cannot authenticate through + replacement characters. Trusted forwarding remains an explicit, exclusive authority. +- Tests call the production `compileLinqMessage()` path; the two internal test-only wrappers and + permissive option parsing are removed. No public compiler export was removed. +- Chat 4.40.0 callback storage includes action/conversation scope and uses a seven-day TTL. The + actual Chat integration assertion follows that runtime while continuing to verify Linq metadata + preservation. This does not add interactive-card support to Linq. + +## Evidence + +Provider contracts were checked on 2026-09-07 against the +[Linq channel index](https://docs.linqapp.com/llms.txt), its +[iMessage index](https://docs.linqapp.com/channel/imessage/llms.txt), and +[canonical OpenAPI](https://cdn.linqapp.com/openapi/linq-api-v3.yaml). +Relevant provider pages are [mentions](https://docs.linqapp.com/channel/imessage/guides/messaging/mentions/), +[webhooks](https://docs.linqapp.com/channel/imessage/guides/webhooks/), and +[zero-day retention](https://docs.linqapp.com/channel/imessage/guides/platform/zero-day-retention/). +The contact-card schema and example are `ContactCardReceivedEvent` and +`contact_card.received.v2026-02-03` in OpenAPI. + +Versions and runtime behavior were checked against the exact npm registry tarballs for +[Chat 4.40.0](https://registry.npmjs.org/chat/4.40.0), +[Linq SDK 0.62.0](https://registry.npmjs.org/@linqapp/sdk/0.62.0), +[Standard Webhooks 1.1.1](https://registry.npmjs.org/standardwebhooks/1.1.1), and +[TypeScript 7.0.2](https://registry.npmjs.org/typescript/7.0.2), including their shipped declarations, +runtime, and relevant bundled Chat docs. The Linq SDK now exposes `webhooks.unwrap()`; this does +not supersede the adapter's verification boundary. Linq's Chat integration page still describes +an older signature shape; the primary webhook guide and pinned Standard Webhooks implementation +are authoritative. pnpm policy behavior follows its [build settings](https://pnpm.io/settings/build). + +## Local validation and candidate handoff + +Run under both Node 22.12 and 24: + +```bash +pnpm --filter @forma/linq-chat-sdk-adapter... install --frozen-lockfile +pnpm check:adapter +pnpm --filter @forma/linq-chat-sdk-adapter exec vitest run --coverage --coverage.include "src/**/*.ts" +``` + +Before handoff, commit the validated source, build from that revision, and pack once to a unique +local candidate directory. Record the exact package version, full source revision, absolute +archive path, and SHA256 in an adjacent verification manifest. Inspect exports, declarations, +map targets, and package contents. Install those exact bytes with Chat 4.40.0 in a clean consumer +and validate types and actual Chat webhook/post behavior on both runtime lines. The consumer +must use the packed package, not a workspace link. Keep tests for authentication, hostile input, +identity, mentions, callbacks/dedupe, errors, groups/polls, history, media, and native-client access. + +Send the manifest and archive identity to the coordinating Locky task. Locky integrates those +exact bytes locally before any release; a changed archive requires fresh verification and a new +handoff. Provider/device/live behavior is not claimed by local checks. + +## Publication preparation only + +Publication requires separate owner approval after consumer feedback. The intended repository is +`formacity/linq-chat-sdk`, using an owner-controlled GitHub release asset rather than npm or an +upstream Linq release. For an owner-created release named `adapter-v0.1.0-forma.8`, the later upload +command is: + +```bash +gh release upload adapter-v0.1.0-forma.8 "$VERIFIED_ABSOLUTE_TARBALL_PATH" \ + --repo formacity/linq-chat-sdk +``` + +This uploads the approved bytes to that existing release. It does not create the release, push or +merge code, publish npm packages, or deploy anything. Do not add `--clobber`: existing assets must +remain immutable. Recheck SHA256 against the handed-off manifest immediately before any approved +upload. The release must describe the candidate's exact source revision and verification; its +Git tag is chosen separately by the owner. No publication command is run during local preparation. diff --git a/packages/adapter-linq/README.md b/packages/adapter-linq/README.md index 6bc02e2..d1b83ee 100644 --- a/packages/adapter-linq/README.md +++ b/packages/adapter-linq/README.md @@ -3,6 +3,10 @@ A private Forma-maintained Linq adapter for [Chat SDK](https://www.npmjs.com/package/chat). Linq's published package remains `@linqapp/chat-sdk-adapter`. +Requires Node.js 22.12+ on the 22 line or Node.js 24, and Chat SDK `^4.40.0` +(tested at `4.40.0`). Runtime dependencies are pinned to Linq SDK `0.62.0`, +Chat/shared `4.40.0`, and `standardwebhooks@1.1.1`. + ## Setup ```ts @@ -14,7 +18,8 @@ const linq = createLinqAdapter({ signingSecret: process.env.LINQ_SIGNING_SECRET!, }); -const chat = new Chat({ adapters: { linq } }); +// Supply your application's configured Chat SDK StateAdapter. +const chat = new Chat({ userName: "linq-bot", adapters: { linq }, state }); export const POST = chat.webhooks.linq; ``` @@ -35,7 +40,10 @@ Lazy credentials resolve once per logical adapter operation. Static API keys exp `adapter.client`; every configuration supports `await adapter.getClient()`. Construction enforces a usable credential and webhook authority even though the released, source-compatible config type has optional fields. Static direct secrets are validated exactly by `standardwebhooks`; lazy -secrets are validated per request and values are never trimmed. +secrets are validated per request and values are never trimmed. Empty decoded secrets are invalid. +Authenticated empty bodies return `invalid_json`; unauthenticated bodies never reach JSON parsing. +Direct verification rejects lossy UTF-8 decoding so replacement characters cannot authenticate +different request bytes. ## Standard Chat SDK behavior @@ -111,11 +119,21 @@ await groupThread.post( ); ``` -Mentions cannot share their text part with manual decorations or a rich link. Derived formatting +Outbound mentions remain singular `mention` / `mention_range` per text part and cannot share +their text part with manual decorations or a rich link. Derived formatting may degrade to plain text to preserve the mention. RCS/SMS intent is accepted, but recipient presentation remains provider/device-owned. RCS/SMS cannot combine with iMessage-only effects, animations, or manual decorations. +Inbound group mentions use the authenticated `mentions[]` entries, including an owner mentioned +second or multiple times. An entry must have `is_me: true`, the exact `chat.owner_handle.handle`, +and a non-empty, bounded UTF-16 range that does not split a surrogate pair. Inbound formatting +is allowed alongside mentions. Only payloads that omit `mentions` use the deprecated first-target +`mention` / optional `mention_range` fallback; present null, empty, or malformed modern fields +never fall back. The existing `mentionTarget` / `mentionRange` observations describe only those +deprecated first-target fields; complete modern mentions remain available in the immutable raw +part and received event data. Display text alone never establishes mention identity. + ## Conversation-scoped Linq extensions `adapter.conversation(threadOrId)` accepts a canonical ID or a Chat SDK `Thread`: @@ -187,6 +205,11 @@ listener snapshots, fast acknowledgement, and Chat SDK `waitUntil` integration s pipeline. All nine current poll event families use this pipeline; there is no separate poll registry or polling workflow. +`contact_card.received` is a named/raw event for a card shared with a line; it does not imply a +chat, a downloadable Chat attachment, or a contact workflow. Unknown reaction/sticker values and +`zero_retention` remain lossless raw facts. Retention is per event: the adapter does not infer +missing content, refetch it, persist it, or change acknowledgement based on this flag. + This seam is not a durable queue. Hosts own HTTP limits and request lifecycle; applications own persistence and long-running work. @@ -218,10 +241,12 @@ the repository [scope](../../scope.md) for the ownership boundary. ## Development -The peer floor is Chat SDK `4.38`; the adapter-level `reply()` and `markAsRead()` hooks are absent -from released `4.28.1` declarations/runtime. +The tested peer floor is Chat SDK `4.40.0`. Use pnpm `12.3.4` and Node.js 22.12 or 24. +TypeScript `7.0.2` emits ESM, declarations, and both map types; packaged sources make the maps +resolvable. The adapter test/build path does not need a legacy TypeScript compiler-API alias. ```bash +pnpm --filter @forma/linq-chat-sdk-adapter... install --frozen-lockfile pnpm --filter @forma/linq-chat-sdk-adapter test pnpm --filter @forma/linq-chat-sdk-adapter typecheck pnpm --filter @forma/linq-chat-sdk-adapter lint diff --git a/packages/adapter-linq/package.json b/packages/adapter-linq/package.json index 9ed5b43..55a44ba 100644 --- a/packages/adapter-linq/package.json +++ b/packages/adapter-linq/package.json @@ -1,6 +1,6 @@ { "name": "@forma/linq-chat-sdk-adapter", - "version": "0.1.0-forma.7", + "version": "0.1.0-forma.8", "private": true, "description": "Forma-maintained Linq adapter for Chat SDK", "keywords": [ @@ -24,7 +24,8 @@ "directory": "packages/adapter-linq" }, "files": [ - "dist" + "dist", + "src" ], "type": "module", "main": "./dist/index.js", @@ -47,22 +48,23 @@ "openapi:check": "node scripts/check-openapi-inventory.mjs" }, "dependencies": { - "@chat-adapter/shared": "^4.38.1", - "@linqapp/sdk": "^0.44.3", - "standardwebhooks": "^1.0.0" + "@chat-adapter/shared": "4.40.0", + "@linqapp/sdk": "0.62.0", + "standardwebhooks": "1.1.1" }, "devDependencies": { - "@types/node": "^25.6.0", - "@vitest/coverage-v8": "^4.1.6", - "chat": "^4.38.1", - "oxfmt": "^0.50.0", - "oxlint": "^1.65.0", - "vitest": "^4.1.6" + "@types/node": "22.20.1", + "@vitest/coverage-v8": "5.0.0", + "chat": "4.40.0", + "oxfmt": "0.67.0", + "oxlint": "1.82.0", + "vite": "8.2.2", + "vitest": "5.0.0" }, "peerDependencies": { - "chat": "^4.38.0" + "chat": "^4.40.0" }, "engines": { - "node": ">=20" + "node": "^22.12.0 || ^24.0.0" } } diff --git a/packages/adapter-linq/src/adapter.ts b/packages/adapter-linq/src/adapter.ts index 06305df..d342698 100644 --- a/packages/adapter-linq/src/adapter.ts +++ b/packages/adapter-linq/src/adapter.ts @@ -213,6 +213,7 @@ export interface LinqConversation { readonly location: LinqLocationConversation; } +// Chat 4.40.0 exposes thread() on Chat but still omits it from ChatInstance. type ChatWithThreads = ChatInstance & { thread(threadId: string): Thread }; const MAX_CONSECUTIVE_FILTERED_HISTORY_PAGES = 10; diff --git a/packages/adapter-linq/src/linq-event-types.generated.ts b/packages/adapter-linq/src/linq-event-types.generated.ts index 4a3da4e..7cd026c 100644 --- a/packages/adapter-linq/src/linq-event-types.generated.ts +++ b/packages/adapter-linq/src/linq-event-types.generated.ts @@ -30,6 +30,7 @@ export const LINQ_KNOWN_EVENT_TYPES = [ "chat.typing_indicator.started", "chat.typing_indicator.stopped", "phone_number.status_updated", + "contact_card.received", "call.initiated", "call.ringing", "call.answered", diff --git a/packages/adapter-linq/src/mention-range.ts b/packages/adapter-linq/src/mention-range.ts new file mode 100644 index 0000000..848cca7 --- /dev/null +++ b/packages/adapter-linq/src/mention-range.ts @@ -0,0 +1,21 @@ +/** Provider ranges are half-open UTF-16 code-unit offsets into the untrimmed text. */ +export function validMentionRange(range: unknown, text: unknown): range is [number, number] { + return ( + typeof text === "string" && + Array.isArray(range) && + range.length === 2 && + Number.isInteger(range[0]) && + Number.isInteger(range[1]) && + range[0] >= 0 && + range[0] < range[1] && + range[1] <= text.length && + isBoundary(text, range[0]) && + isBoundary(text, range[1]) + ); +} + +function isBoundary(text: string, offset: number): boolean { + const before = text.charCodeAt(offset - 1); + const after = text.charCodeAt(offset); + return !(before >= 0xd800 && before <= 0xdbff && after >= 0xdc00 && after <= 0xdfff); +} diff --git a/packages/adapter-linq/src/message-compiler.ts b/packages/adapter-linq/src/message-compiler.ts index 81e201e..beb67e0 100644 --- a/packages/adapter-linq/src/message-compiler.ts +++ b/packages/adapter-linq/src/message-compiler.ts @@ -85,18 +85,10 @@ type LinqOptionsRecord = Record | undefined; type TextFragment = CompiledLinqMessageText; -/** Compile the primary Linq text part and all inline decorations before any I/O. */ -export function compileLinqMessageText(message: AdapterPostableMessage): CompiledLinqMessageText { - return compileLinqMessageTextWithOptions( - trimFragment(compilePostable(message)), - readLinqOptions(message, false), - ); -} - /** Compile all adapter-owned text and request metadata through one validated options snapshot. */ export function compileLinqMessage(message: AdapterPostableMessage): CompiledLinqMessage { const rendered = trimFragment(compilePostable(message)); - const linq = readLinqOptions(message, true); + const linq = readLinqOptions(message); const content = compileLinqMessageTextWithOptions(rendered, linq); const options = compileLinqSendOptionsFromOptions(linq); validateCompiledLinqMention(content, options); @@ -155,10 +147,6 @@ export function resolveCompiledLinqMention( } /** Validate and compile Linq's message-level service/effect request fields before any I/O. */ -export function compileLinqSendOptions(message: AdapterPostableMessage): CompiledLinqSendOptions { - return compileLinqSendOptionsFromOptions(readLinqOptions(message, true)); -} - function compileLinqSendOptionsFromOptions(linq: LinqOptionsRecord): CompiledLinqSendOptions { if (!linq) return {}; @@ -691,11 +679,10 @@ function renderLabeledUrl(label: string | undefined, url: string): string { return label && label !== url ? `${label}: ${url}` : url; } -function readLinqOptions(message: AdapterPostableMessage, strict: boolean): LinqOptionsRecord { +function readLinqOptions(message: AdapterPostableMessage): LinqOptionsRecord { if (typeof message === "string" || !isRecord(message) || message.linq === undefined) { return undefined; } - if (isRecord(message.linq)) return message.linq; - if (strict) throw validationError("Linq message options must be an object."); - return undefined; + if (isRecord(message.linq) && !Array.isArray(message.linq)) return message.linq; + throw validationError("Linq message options must be an object."); } diff --git a/packages/adapter-linq/src/message-parser.ts b/packages/adapter-linq/src/message-parser.ts index 4883cba..d693b84 100644 --- a/packages/adapter-linq/src/message-parser.ts +++ b/packages/adapter-linq/src/message-parser.ts @@ -2,6 +2,7 @@ import { LinqAPIV3 } from "@linqapp/sdk"; import { Message, NotImplementedError, paragraph, root, text as textNode } from "chat"; import type { Attachment, FormattedContent, LinkPreview } from "chat"; +import { validMentionRange } from "./mention-range.js"; import { isRecord, isUsableLinqChatId, isUsableLinqId } from "./guards.js"; import { createLinqAttachmentFetcher } from "./inbound-media.js"; import { parseLinqTimestamp, selectLinqMessageTimestamp } from "./timestamps.js"; @@ -97,6 +98,7 @@ export function isLinqOwnerMention(raw: LinqMessageReceivedWebhookData): boolean raw.chat.is_group !== true || !isRecord(raw.chat.owner_handle) || typeof raw.chat.owner_handle.handle !== "string" || + raw.chat.owner_handle.handle.length === 0 || !Array.isArray(raw.parts) ) { return false; @@ -104,29 +106,29 @@ export function isLinqOwnerMention(raw: LinqMessageReceivedWebhookData): boolean const ownerHandle = raw.chat.owner_handle.handle; return raw.parts.some((part) => { - const decorations = isRecord(part) ? part.text_decorations : undefined; - if ( - !isRecord(part) || - part.type !== "text" || - typeof part.value !== "string" || - part.value.length === 0 || - part.mention !== ownerHandle || - (decorations !== undefined && decorations !== null && !Array.isArray(decorations)) || - (Array.isArray(decorations) && decorations.length > 0) - ) { + if (!isRecord(part) || part.type !== "text" || typeof part.value !== "string" || !part.value) { return false; } - const range = part.mention_range; - if (range === undefined || range === null) return true; + // A present modern field is authoritative, even null, empty, or malformed. + // Never resurrect the deprecated first mention when modern facts disagree. + if (part.mentions !== undefined) { + return ( + Array.isArray(part.mentions) && + part.mentions.some( + (mention) => + isRecord(mention) && + mention.is_me === true && + mention.handle === ownerHandle && + validMentionRange(mention.range, part.value), + ) + ); + } + + // Compatibility with older authenticated payloads that omit mentions entirely. return ( - Array.isArray(range) && - range.length === 2 && - Number.isInteger(range[0]) && - Number.isInteger(range[1]) && - (range[0] as number) >= 0 && - (range[0] as number) < (range[1] as number) && - (range[1] as number) <= part.value.length + part.mention === ownerHandle && + (part.mention_range == null || validMentionRange(part.mention_range, part.value)) ); }); } diff --git a/packages/adapter-linq/src/verification.ts b/packages/adapter-linq/src/verification.ts index efe886b..344c10c 100644 --- a/packages/adapter-linq/src/verification.ts +++ b/packages/adapter-linq/src/verification.ts @@ -97,7 +97,7 @@ async function verifyStandardWebhook( } const rawBytes = new Uint8Array(await request.arrayBuffer()); - const rawBody = new TextDecoder().decode(rawBytes); + const rawBody = Buffer.from(rawBytes).toString("utf8"); const timestamp = request.headers.get(STANDARD_TIMESTAMP_HEADER)?.trim() || ""; if (!isFreshTimestamp(timestamp)) { @@ -106,10 +106,14 @@ async function verifyStandardWebhook( try { const verifier = new Webhook(signingSecret); - const event: unknown = verifier.verify( - Buffer.from(rawBytes), - Object.fromEntries(request.headers), - ); + // standardwebhooks signs Buffer payloads through UTF-8 strings. Refuse a lossy + // round trip so a signature can never authenticate substituted raw bytes. + if (!Buffer.from(rawBody, "utf8").equals(rawBytes)) return invalidSignature(); + verifier.verify(Buffer.from(rawBytes), Object.fromEntries(request.headers), { + jsonParse: false, + }); + // Parse only after authentication, including an empty body (invalid JSON). + const event: unknown = JSON.parse(rawBody); return { ok: true, diff --git a/packages/adapter-linq/src/webhook.ts b/packages/adapter-linq/src/webhook.ts index 8c9df27..6dd353f 100644 --- a/packages/adapter-linq/src/webhook.ts +++ b/packages/adapter-linq/src/webhook.ts @@ -1,3 +1,4 @@ +import { validMentionRange } from "./mention-range.js"; import type { LinqAPIV3 } from "@linqapp/sdk"; import { immutableJsonSnapshot, isRecord, isUsableLinqChatId, isUsableLinqId } from "./guards.js"; @@ -847,18 +848,7 @@ function validMentionObservationRange( value: unknown, text: unknown, ): readonly [number, number] | null { - if ( - typeof text !== "string" || - !Array.isArray(value) || - value.length !== 2 || - !Number.isInteger(value[0]) || - !Number.isInteger(value[1]) || - (value[0] as number) < 0 || - (value[0] as number) >= (value[1] as number) || - (value[1] as number) > text.length - ) { - return null; - } + if (!validMentionRange(value, text)) return null; return Object.freeze([value[0] as number, value[1] as number]); } diff --git a/packages/adapter-linq/test/event-dispatch.test.ts b/packages/adapter-linq/test/event-dispatch.test.ts index b7e2864..d04d90b 100644 --- a/packages/adapter-linq/test/event-dispatch.test.ts +++ b/packages/adapter-linq/test/event-dispatch.test.ts @@ -1,14 +1,12 @@ -import { createHmac } from "node:crypto"; - import type { ChatInstance, Logger, StateAdapter } from "chat"; import { describe, expect, it, vi } from "vitest"; import { createLinqAdapter, type LinqAdapter } from "../src/index.js"; +import contactCardFixture from "./fixtures/contact-card-received-2026-02-03.json"; import fixture from "./fixtures/message-received-2026-02-03.json"; import unknownFixture from "./fixtures/unknown-event-2026-02-03.json"; -const SIGNING_KEY = "test_linq_webhook_secret"; -const SIGNING_SECRET = `whsec_${Buffer.from(SIGNING_KEY).toString("base64")}`; +import { createStandardRequest, SIGNING_SECRET } from "./webhook-fixture.js"; const EVENT_DEDUPE_TTL_MS = 60 * 60 * 1000; describe("verified generic Linq event dispatch", () => { @@ -18,6 +16,7 @@ describe("verified generic Linq event dispatch", () => { "participant.added", "chat.typing_indicator.started", "phone_number.status_updated", + "contact_card.received", "call.answered", ] as const)( "delivers valid canonical raw-only %s events to named and generic handlers", @@ -51,6 +50,81 @@ describe("verified generic Linq event dispatch", () => { }, ); + it("preserves a line-level contact card without inventing a chat or media workflow", async () => { + const context = await createContext(); + const named = vi.fn(); + const tasks: Promise[] = []; + const fetch = vi.spyOn(globalThis, "fetch").mockRejectedValue(new Error("Unexpected I/O")); + context.adapter.onLinqEvent("contact_card.received", named); + try { + const verification = await context.adapter.verifyWebhook( + createStandardRequest(contactCardFixture), + ); + expect(verification).toMatchObject({ + ok: true, + webhook: { kind: "unhandled", rawEvent: contactCardFixture }, + }); + const response = await context.adapter.handleWebhook( + createStandardRequest(contactCardFixture), + { + waitUntil: (task) => tasks.push(task), + }, + ); + await Promise.all(tasks); + expect(response.status).toBe(200); + expect(named).toHaveBeenCalledOnce(); + const event = named.mock.calls[0]?.[0]; + expect(event).toMatchObject({ type: "contact_card.received", data: contactCardFixture.data }); + expect(event.data.chat).toBeUndefined(); + expect(Object.isFrozen(event.data)).toBe(true); + expect(context.processMessage).not.toHaveBeenCalled(); + expect(context.processReaction).not.toHaveBeenCalled(); + expect(fetch).not.toHaveBeenCalled(); + } finally { + fetch.mockRestore(); + } + }); + + it.each([true, false])( + "retains zero_retention=%s and unknown part facts without recovery I/O", + async (zeroRetention) => { + const context = await createContext(); + const named = vi.fn(); + const tasks: Promise[] = []; + const payload = structuredClone(fixture); + Object.assign(payload.data, { zero_retention: zeroRetention }); + payload.data.parts = [ + { + type: "text", + value: "Original text", + reactions: [{ type: "future-sticker-reaction", sticker: { future: [1, "opaque"] } }], + } as never, + ]; + const fetch = vi.spyOn(globalThis, "fetch").mockRejectedValue(new Error("Unexpected I/O")); + context.adapter.onLinqEvent("message.received", named); + try { + const response = await context.adapter.handleWebhook(createStandardRequest(payload), { + waitUntil: (task) => tasks.push(task), + }); + await Promise.all(tasks); + expect(response.status).toBe(200); + expect(named).toHaveBeenCalledWith( + expect.objectContaining({ data: payload.data, rawEvent: payload }), + ); + expect( + Object.isFrozen( + named.mock.calls[0]?.[0].rawEvent.data.parts[0].reactions[0].sticker.future, + ), + ).toBe(true); + const factory = context.processMessage.mock.calls[0]?.[2] as () => Promise; + expect(await factory()).toMatchObject({ text: "Original text" }); + expect(fetch).not.toHaveBeenCalled(); + } finally { + fetch.mockRestore(); + } + }, + ); + it("isolates and dedupes raw-only named callbacks while preserving listener removal", async () => { const context = await createContext(); const failure = new Error("raw-only callback failed"); @@ -567,26 +641,6 @@ function reactionPayload(): Record { }; } -function createStandardRequest(payload: unknown, overrides: Record = {}): Request { - const body = JSON.stringify(payload); - const timestamp = overrides["webhook-timestamp"] ?? Math.floor(Date.now() / 1000).toString(); - const webhookId = overrides["webhook-id"] ?? "webhook-test-id"; - const signature = `v1,${createHmac("sha256", SIGNING_KEY) - .update(`${webhookId}.${timestamp}.${body}`) - .digest("base64")}`; - - return new Request("https://example.com/webhooks/linq", { - method: "POST", - headers: { - "content-type": "application/json", - "webhook-id": webhookId, - "webhook-signature": signature, - "webhook-timestamp": timestamp, - }, - body, - }); -} - function createDeferred(): { promise: Promise; resolve: () => void } { let resolve!: () => void; const promise = new Promise((complete) => { diff --git a/packages/adapter-linq/test/fixtures/contact-card-received-2026-02-03.json b/packages/adapter-linq/test/fixtures/contact-card-received-2026-02-03.json new file mode 100644 index 0000000..cb17998 --- /dev/null +++ b/packages/adapter-linq/test/fixtures/contact-card-received-2026-02-03.json @@ -0,0 +1,16 @@ +{ + "api_version": "v3", + "webhook_version": "2026-02-03", + "event_type": "contact_card.received", + "event_id": "contact-card-fixture-1", + "created_at": "2026-09-07T12:00:00.000Z", + "trace_id": "contact-card-trace", + "partner_id": "test-partner", + "data": { + "sender_handle": "+14155559876", + "owner_handle": "+12025551234", + "first_name": "Jane", + "last_name": "Appleseed", + "media_url": "https://cdn.linqapp.com/attachments/example/contact.png?Expires=1787604312" + } +} diff --git a/packages/adapter-linq/test/mentions.test.ts b/packages/adapter-linq/test/mentions.test.ts index 7ff2480..b3c735c 100644 --- a/packages/adapter-linq/test/mentions.test.ts +++ b/packages/adapter-linq/test/mentions.test.ts @@ -1,5 +1,3 @@ -import { createHmac } from "node:crypto"; - import { AdapterError, AdapterRateLimitError, @@ -21,8 +19,7 @@ const MESSAGE_ID = "22222222-2222-2222-2222-222222222222"; const PARTICIPANT_ID = "33333333-3333-3333-3333-333333333333"; const OWNER_HANDLE = "owner@example.com"; const TARGET_HANDLE = "+15550002000"; -const SIGNING_KEY = "test_linq_webhook_secret"; -const SIGNING_SECRET = `whsec_${Buffer.from(SIGNING_KEY).toString("base64")}`; +import { createStandardRequest, SIGNING_SECRET } from "./webhook-fixture.js"; const { adapterRandomUUID } = vi.hoisted(() => ({ adapterRandomUUID: vi.fn() })); @@ -503,11 +500,6 @@ describe("native Linq mentions", () => { (value: ReturnType) => { (value.data.parts[0] as unknown as { mention_range: number[] }).mention_range = [8, 3]; }, - (value: ReturnType) => { - (value.data.parts[0] as unknown as { text_decorations: unknown }).text_decorations = { - malformed: true, - }; - }, (value: ReturnType) => { value.data.chat.is_group = false; }, @@ -532,6 +524,99 @@ describe("native Linq mentions", () => { } }); + it.each([ + ["null", null], + ["empty", []], + ["malformed", {}], + ["wrong identity", [{ handle: TARGET_HANDLE, is_me: true, range: [3, 8] }]], + ["not this line", [{ handle: OWNER_HANDLE, is_me: false, range: [3, 8] }]], + ["missing flag", [{ handle: OWNER_HANDLE, range: [3, 8] }]], + ["missing range", [{ handle: OWNER_HANDLE, is_me: true }]], + ...[ + [0, 99], + [2, 2], + [-1, 2], + [0, 1.5], + [0, 1], + [1, 2], + ].map( + (range) => [JSON.stringify(range), [{ handle: OWNER_HANDLE, is_me: true, range }]] as const, + ), + ] as const)( + "does not fall back from present invalid modern mentions: %s", + async (_name, mentions) => { + const payload = modernMentionPayload(); + Object.assign(payload.data.parts[0]!, { mention: OWNER_HANDLE, mentions }); + const adapter = createLinqAdapter({ apiKey: "test-key", signingSecret: SIGNING_SECRET }); + const processMessage = vi.fn(); + await adapter.initialize({ + getLogger: () => silentLogger(), + getState: () => ({ setIfNotExists: vi.fn().mockResolvedValue(true) }), + processMessage, + processReaction: vi.fn(), + } as unknown as ChatInstance); + await adapter.handleWebhook(createStandardRequest(payload)); + const factory = processMessage.mock.calls[0]?.[2] as () => Promise; + expect(await factory()).not.toMatchObject({ isMention: true }); + }, + ); + + it.each(["first", "last", "repeated"] as const)( + "accepts formatted modern owner mentions in %s position", + async (position) => { + const payload = modernMentionPayload(); + const part = payload.data.parts[0]! as unknown as { value: string; mentions: unknown[] }; + if (position === "first") { + part.value = "👋 owner Dana"; + part.mentions = [ + { handle: OWNER_HANDLE, is_me: true, range: [3, 8] }, + { handle: TARGET_HANDLE, is_me: false, range: [9, 13] }, + ]; + } + if (position === "repeated") { + part.value += " owner"; + part.mentions.push({ handle: OWNER_HANDLE, is_me: true, range: [14, 19] }); + } + const adapter = createLinqAdapter({ apiKey: "test-key", signingSecret: SIGNING_SECRET }); + const processMessage = vi.fn(); + await adapter.initialize({ + getLogger: () => silentLogger(), + getState: () => ({ setIfNotExists: vi.fn().mockResolvedValue(true) }), + processMessage, + processReaction: vi.fn(), + } as unknown as ChatInstance); + await adapter.handleWebhook(createStandardRequest(payload)); + const factory = processMessage.mock.calls[0]?.[2] as () => Promise; + expect(await factory()).toMatchObject({ isMention: true, text: part.value }); + const result = await adapter.verifyWebhook(createStandardRequest(payload)); + expect(result).toMatchObject({ ok: true, webhook: { rawEvent: payload } }); + if (!result.ok) throw new Error("Expected verification"); + expect(Object.isFrozen(result.webhook.rawEvent.data)).toBe(true); + }, + ); + + it.each([undefined, null])( + "retains the absent-modern-field fallback with omitted/null legacy range: %s", + async (range) => { + const payload = mentionPayload(OWNER_HANDLE); + Object.assign(payload.data.parts[0]!, { + mention_range: range, + text_decorations: [{ range: [3, 8], style: "bold" }], + }); + const adapter = createLinqAdapter({ apiKey: "test-key", signingSecret: SIGNING_SECRET }); + const processMessage = vi.fn(); + await adapter.initialize({ + getLogger: () => silentLogger(), + getState: () => ({ setIfNotExists: vi.fn().mockResolvedValue(true) }), + processMessage, + processReaction: vi.fn(), + } as unknown as ChatInstance); + await adapter.handleWebhook(createStandardRequest(payload)); + const factory = processMessage.mock.calls[0]?.[2] as () => Promise; + expect(await factory()).toMatchObject({ isMention: true }); + }, + ); + it("routes native owner mentions through Chat SDK onNewMention", async () => { const adapter = createLinqAdapter({ apiKey: "test-key", signingSecret: SIGNING_SECRET }); const state = { @@ -552,12 +637,9 @@ describe("native Linq mentions", () => { chat.onNewMention(mention); await chat.initialize(); - const response = await adapter.handleWebhook( - createStandardRequest(mentionPayload(OWNER_HANDLE)), - { - waitUntil: (task) => tasks.push(task), - }, - ); + const response = await adapter.handleWebhook(createStandardRequest(modernMentionPayload()), { + waitUntil: (task) => tasks.push(task), + }); await Promise.all(tasks); expect(response.status).toBe(200); @@ -633,23 +715,22 @@ function mentionPayload(ownerHandle: string) { return payload; } -function createStandardRequest(payload: unknown): Request { - const body = JSON.stringify(payload); - const timestamp = Math.floor(Date.now() / 1000).toString(); - const webhookId = crypto.randomUUID(); - const signature = `v1,${createHmac("sha256", SIGNING_KEY) - .update(`${webhookId}.${timestamp}.${body}`) - .digest("base64")}`; - return new Request("https://example.com/webhooks/linq", { - method: "POST", - headers: { - "content-type": "application/json", - "webhook-id": webhookId, - "webhook-signature": signature, - "webhook-timestamp": timestamp, - }, - body, - }); +function modernMentionPayload() { + const payload = mentionPayload(OWNER_HANDLE); + payload.data.parts = [ + { + type: "text", + value: "👋 Dana owner", + mention: TARGET_HANDLE, + mention_range: [3, 7], + mentions: [ + { handle: TARGET_HANDLE, is_me: false, range: [3, 7] }, + { handle: OWNER_HANDLE, is_me: true, range: [8, 13] }, + ], + text_decorations: [{ range: [8, 13], style: "bold" }], + } as never, + ]; + return payload; } function participantMentionWithFile(): AdapterPostableMessage { diff --git a/packages/adapter-linq/test/message-api.test.ts b/packages/adapter-linq/test/message-api.test.ts index e7e7451..b0895e5 100644 --- a/packages/adapter-linq/test/message-api.test.ts +++ b/packages/adapter-linq/test/message-api.test.ts @@ -230,8 +230,13 @@ describe("linqMessage Chat SDK transport", () => { expect(context.state.set).toHaveBeenCalledWith( expect.stringMatching(/^chat:callback:/), - { originalValue: "order-123", url: "https://example.com/callback" }, - 30 * 24 * 60 * 60 * 1000, + { + actionId: "approve", + originalValue: "order-123", + scope: { id: "linq:chat-123", type: "thread" }, + url: "https://example.com/callback", + }, + 7 * 24 * 60 * 60 * 1000, ); const transported = context.postMessage.mock.calls[0]?.[1]; expect(transported).toMatchObject({ linq: OPTIONS, type: "card" }); diff --git a/packages/adapter-linq/test/message-compiler.test.ts b/packages/adapter-linq/test/message-compiler.test.ts index baaa3a3..0ff0965 100644 --- a/packages/adapter-linq/test/message-compiler.test.ts +++ b/packages/adapter-linq/test/message-compiler.test.ts @@ -4,42 +4,58 @@ import type { AdapterPostableMessage } from "chat"; import { describe, expect, it, vi } from "vitest"; import { createLinqAdapter, linqMessage } from "../src/index.js"; -import { compileLinqMessageText } from "../src/message-compiler.js"; +import { compileLinqMessage } from "../src/message-compiler.js"; + +describe("compileLinqMessage", () => { + it("compiles content and options together and rejects invalid options on the production path", () => { + expect( + compileLinqMessage(linqMessage({ markdown: "**Ready**" }, { preferredService: "iMessage" })), + ).toEqual({ + content: { text: "Ready", decorations: [{ range: [0, 5], style: "bold" }] }, + options: { preferredService: "iMessage" }, + }); + for (const linq of [null, false, 1, "ignored before", []]) { + expect(() => compileLinqMessage({ raw: "hello", linq } as AdapterPostableMessage)).toThrow( + ValidationError, + ); + } + }); -describe("compileLinqMessageText", () => { it("renders raw, Markdown, AST, links, newlines, and static card text deterministically", () => { - expect(compileLinqMessageText(" raw text ")).toEqual({ + expect(compileLinqMessage(" raw text ").content).toEqual({ text: "raw text", decorations: [], }); - expect(compileLinqMessageText({ markdown: "" })).toEqual({ text: "", decorations: [] }); + expect(compileLinqMessage({ markdown: "" }).content).toEqual({ text: "", decorations: [] }); expect( - compileLinqMessageText({ + compileLinqMessage({ markdown: "[**bold link**](https://example.com)\n\nnext", - }), + }).content, ).toEqual({ text: "bold link\n\nnext", decorations: [{ range: [0, 9], style: "bold" }], }); expect( - compileLinqMessageText({ + compileLinqMessage({ ast: root([paragraph([strikethrough([text("gone")])]), paragraph([text("next")])]), - }), + }).content, ).toEqual({ text: "gone\n\nnext", decorations: [{ range: [0, 4], style: "strikethrough" }], }); - expect(compileLinqMessageText({ ast: root([paragraph([strong([text(" bold ")])])]) })).toEqual({ + expect( + compileLinqMessage({ ast: root([paragraph([strong([text(" bold ")])])]) }).content, + ).toEqual({ text: "bold", decorations: [{ range: [0, 4], style: "bold" }], }); expect( - compileLinqMessageText( + compileLinqMessage( Card({ title: "Status", children: [CardText("**Ready** and _waiting_")], }), - ), + ).content, ).toEqual({ text: "Status\nReady and waiting", decorations: [ @@ -51,14 +67,14 @@ describe("compileLinqMessageText", () => { it("uses UTF-16 code-unit offsets without normalizing emoji or combining characters", () => { expect( - compileLinqMessageText( + compileLinqMessage( linqMessage("😀e\u0301!", { decorations: [ { range: [0, 2], style: "bold" }, { range: [2, 4], style: "underline" }, ], }), - ), + ).content, ).toEqual({ text: "😀e\u0301!", decorations: [ @@ -73,7 +89,7 @@ describe("compileLinqMessageText", () => { decorations: [{ range: [3, 5], style: "underline" }], }); - expect(compileLinqMessageText(message)).toEqual({ + expect(compileLinqMessage(message).content).toEqual({ text: "hi 😀", decorations: [{ range: [3, 5], style: "underline" }], }); @@ -97,7 +113,7 @@ describe("compileLinqMessageText", () => { }, ); - expect(compileLinqMessageText(message)).toEqual({ + expect(compileLinqMessage(message).content).toEqual({ text: "A B C", decorations: [ { range: [0, 5], style: "bold" }, @@ -110,7 +126,7 @@ describe("compileLinqMessageText", () => { it("allows adjacent animations but rejects animation overlap with any decoration", () => { expect( - compileLinqMessageText( + compileLinqMessage( linqMessage("abcd", { decorations: [ { range: [0, 2], animation: "shake" }, @@ -118,29 +134,31 @@ describe("compileLinqMessageText", () => { { range: [2, 4], animation: "bloom" }, ], }), - ).decorations, + ).content.decorations, ).toEqual([ { range: [0, 2], animation: "shake" }, { range: [2, 4], animation: "bloom" }, ]); - expect(() => - compileLinqMessageText( - linqMessage( - { markdown: "**abcd**" }, - { decorations: [{ range: [1, 3], animation: "shake" }] }, - ), - ), + expect( + () => + compileLinqMessage( + linqMessage( + { markdown: "**abcd**" }, + { decorations: [{ range: [1, 3], animation: "shake" }] }, + ), + ).content, ).toThrow("animation ranges cannot overlap"); - expect(() => - compileLinqMessageText( - linqMessage("abcd", { - decorations: [ - { range: [0, 3], animation: "shake" }, - { range: [2, 4], animation: "bloom" }, - ], - }), - ), + expect( + () => + compileLinqMessage( + linqMessage("abcd", { + decorations: [ + { range: [0, 3], animation: "shake" }, + { range: [2, 4], animation: "bloom" }, + ], + }), + ).content, ).toThrow("animation ranges cannot overlap"); }); @@ -158,7 +176,7 @@ describe("compileLinqMessageText", () => { ["unknown animation", { range: [0, 1], animation: "spin" }], ])("rejects %s", (_name, decoration) => { const message = { raw: "abcd", linq: { decorations: [decoration] } } as AdapterPostableMessage; - expect(() => compileLinqMessageText(message)).toThrow(ValidationError); + expect(() => compileLinqMessage(message).content).toThrow(ValidationError); }); it("rejects decorations on empty text", () => { @@ -166,7 +184,7 @@ describe("compileLinqMessageText", () => { raw: "", linq: { decorations: [{ range: [0, 1], style: "bold" }] }, } as AdapterPostableMessage; - expect(() => compileLinqMessageText(message)).toThrow(ValidationError); + expect(() => compileLinqMessage(message).content).toThrow(ValidationError); }); }); diff --git a/packages/adapter-linq/test/message-options.test.ts b/packages/adapter-linq/test/message-options.test.ts index 4ef17de..fe6e1f6 100644 --- a/packages/adapter-linq/test/message-options.test.ts +++ b/packages/adapter-linq/test/message-options.test.ts @@ -4,7 +4,7 @@ import type { AdapterPostableMessage } from "chat"; import { describe, expect, it, vi } from "vitest"; import { createLinqAdapter, linqMessage } from "../src/index.js"; -import { compileLinqSendOptions } from "../src/message-compiler.js"; +import { compileLinqMessage } from "../src/message-compiler.js"; const SCREEN_EFFECTS = [ "confetti", @@ -21,25 +21,27 @@ const SCREEN_EFFECTS = [ ] as const; const BUBBLE_EFFECTS = ["slam", "loud", "gentle", "invisible"] as const; -describe("compileLinqSendOptions", () => { +describe("compileLinqMessage", () => { it.each([undefined, "iMessage", "RCS", "SMS"] as const)( "preserves the %s preferred-service selection", (preferredService) => { const message = linqMessage("hello", preferredService ? { preferredService } : {}); - expect(compileLinqSendOptions(message)).toEqual(preferredService ? { preferredService } : {}); + expect(compileLinqMessage(message).options).toEqual( + preferredService ? { preferredService } : {}, + ); }, ); it.each(SCREEN_EFFECTS)("accepts the %s screen effect", (name) => { expect( - compileLinqSendOptions(linqMessage("hello", { effect: { type: "screen", name } })), + compileLinqMessage(linqMessage("hello", { effect: { type: "screen", name } })).options, ).toEqual({ effect: { type: "screen", name } }); }); it.each(BUBBLE_EFFECTS)("accepts the %s bubble effect", (name) => { expect( - compileLinqSendOptions(linqMessage("hello", { effect: { type: "bubble", name } })), + compileLinqMessage(linqMessage("hello", { effect: { type: "bubble", name } })).options, ).toEqual({ effect: { type: "bubble", name } }); }); @@ -52,13 +54,12 @@ describe("compileLinqSendOptions", () => { ], } as const; - expect(compileLinqSendOptions(linqMessage("hello", enhancements))).toEqual({ + expect(compileLinqMessage(linqMessage("hello", enhancements)).options).toEqual({ effect: enhancements.effect, }); expect( - compileLinqSendOptions( - linqMessage("hello", { preferredService: "iMessage", ...enhancements }), - ), + compileLinqMessage(linqMessage("hello", { preferredService: "iMessage", ...enhancements })) + .options, ).toEqual({ preferredService: "iMessage", effect: enhancements.effect }); }); @@ -75,7 +76,7 @@ describe("compileLinqSendOptions", () => { ["screen name on bubble", { effect: { type: "bubble", name: "confetti" } }], ])("rejects hostile %s input", (_name, linq) => { const message = { raw: "hello", linq } as AdapterPostableMessage; - expect(() => compileLinqSendOptions(message)).toThrow(ValidationError); + expect(() => compileLinqMessage(message).options).toThrow(ValidationError); }); }); diff --git a/packages/adapter-linq/test/public-api.test.ts b/packages/adapter-linq/test/public-api.test.ts index 96b6f64..ad7de32 100644 --- a/packages/adapter-linq/test/public-api.test.ts +++ b/packages/adapter-linq/test/public-api.test.ts @@ -45,6 +45,7 @@ import type { LinqVoiceMemoResult, LinqVoiceMemoSource, LinqWebhookVerifier, + LinqWebhookRawValue, LinqVerifiedUnhandledWebhook, LinqVerifiedWebhook, LinqWebhookVerificationResult, @@ -175,6 +176,10 @@ function assertTypedEventRegistration(adapter: LinqAdapter): void { expectTypeOf(event.type).toEqualTypeOf<"chat.created">(); expectTypeOf(event.data).not.toBeAny(); }); + adapter.onLinqEvent("contact_card.received", (event) => { + expectTypeOf(event.type).toEqualTypeOf<"contact_card.received">(); + expectTypeOf(event.data).toEqualTypeOf(); + }); adapter.onLinqEvent("poll.received", (event) => { expectTypeOf(event.data).toEqualTypeOf(); expectTypeOf(event.data.poll.options[0]?.optionId).toEqualTypeOf(); diff --git a/packages/adapter-linq/test/verified-webhook.test.ts b/packages/adapter-linq/test/verified-webhook.test.ts index 8572e53..ff2c600 100644 --- a/packages/adapter-linq/test/verified-webhook.test.ts +++ b/packages/adapter-linq/test/verified-webhook.test.ts @@ -1,12 +1,10 @@ -import { createHmac } from "node:crypto"; import type { ChatInstance } from "chat"; import { describe, expect, it, vi } from "vitest"; import { createLinqAdapter } from "../src/index.js"; import fixture from "./fixtures/message-received-2026-02-03.json"; -const SIGNING_KEY = "test_linq_webhook_secret"; -const SIGNING_SECRET = `whsec_${Buffer.from(SIGNING_KEY).toString("base64")}`; +import { createSignedBody, createStandardRequest, SIGNING_SECRET } from "./webhook-fixture.js"; describe("LinqAdapter verified webhook ingress", () => { it("reads, verifies, and parses a Standard Webhook exactly once", async () => { @@ -197,6 +195,63 @@ describe("LinqAdapter verified webhook ingress", () => { ).toThrow("valid Standard Webhooks signing secret"); }); + it.each(["", "whsec_"])("rejects an empty decoded static secret: %s", (signingSecret) => { + expect(() => createLinqAdapter({ apiKey: "test-key", signingSecret })).toThrow(); + }); + + it("reports an empty decoded lazy secret as a configuration failure", async () => { + const credentials = vi.fn().mockResolvedValue({ apiKey: "test-key", signingSecret: "whsec_" }); + const adapter = createLinqAdapter({ credentials }); + await expect(adapter.verifyWebhook(createStandardRequest(fixture))).resolves.toMatchObject({ + ok: false, + error: { code: "invalid_signing_secret", status: 503 }, + }); + expect(credentials).toHaveBeenCalledOnce(); + }); + + it("keeps authentication before empty-body JSON validation", async () => { + await expect(createTestAdapter().verifyWebhook(createSignedBody(""))).resolves.toMatchObject({ + ok: false, + error: { code: "invalid_json", status: 400 }, + }); + await expect( + createTestAdapter().verifyWebhook(createSignedBody("", { signature: "v1,bad" })), + ).resolves.toMatchObject({ ok: false, error: { code: "invalid_signature", status: 401 } }); + }); + + it("does not authenticate bytes via lossy UTF-8 replacement", async () => { + const body = Buffer.concat([Buffer.from('{"bad":"'), Buffer.from([0xff]), Buffer.from('"}')]); + await expect( + createTestAdapter().verifyWebhook(createSignedBody(body, { "webhook-timestamp": "1" })), + ).resolves.toMatchObject({ ok: false, error: { code: "stale_timestamp", status: 401 } }); + // The signature for a replacement character must not authenticate a different byte sequence. + const replacement = createSignedBody(body.toString("utf8")); + const forged = new Request(replacement.url, { + method: "POST", + headers: replacement.headers, + body, + }); + await expect(createTestAdapter().verifyWebhook(forged)).resolves.toMatchObject({ + ok: false, + error: { code: "invalid_signature", status: 401 }, + }); + }); + + it("retains raw UTF-8 bytes, whitespace, and signed BOM JSON error semantics", async () => { + const body = ` ${JSON.stringify({ ...fixture, extra: "😀e\u0301" })}\n`; + const result = await createTestAdapter().verifyWebhook(createSignedBody(body)); + expect(result).toMatchObject({ + ok: true, + webhook: { + rawBody: body, + rawBodyBase64: Buffer.from(body).toString("base64"), + }, + }); + await expect( + createTestAdapter().verifyWebhook(createSignedBody(`\ufeff${JSON.stringify(fixture)}`)), + ).resolves.toMatchObject({ ok: false, error: { code: "invalid_json", status: 400 } }); + }); + it("acknowledges a malformed authenticated current payload without false dispatch", async () => { const response = await createTestAdapter().handleWebhook( createStandardRequest({ ...fixture, data: { ...fixture.data, parts: "bad" } }), @@ -781,37 +836,3 @@ type MutableFixture = Record & { function cloneFixture(): MutableFixture { return structuredClone(fixture) as unknown as MutableFixture; } - -function createStandardRequest( - payload: unknown, - overrides: Record & { signature?: string } = {}, -): Request { - return createSignedBody(JSON.stringify(payload), overrides); -} - -function createSignedBody( - body: string, - overrides: Record & { signature?: string } = {}, -): Request { - const timestamp = overrides["webhook-timestamp"] ?? Math.floor(Date.now() / 1000).toString(); - const webhookId = overrides["webhook-id"] ?? "webhook-test-id"; - const signature = - overrides.signature ?? - `v1,${createHmac("sha256", SIGNING_KEY) - .update(`${webhookId}.${timestamp}.${body}`) - .digest("base64")}`; - const headers = new Headers({ - "content-type": "application/json", - "webhook-id": webhookId, - "webhook-signature": signature, - "webhook-timestamp": timestamp, - }); - - for (const [name, value] of Object.entries(overrides)) { - if (name !== "signature") { - headers.set(name, value); - } - } - - return new Request("https://example.com/webhooks/linq", { method: "POST", headers, body }); -} diff --git a/packages/adapter-linq/test/webhook-fixture.ts b/packages/adapter-linq/test/webhook-fixture.ts new file mode 100644 index 0000000..eb5ec7d --- /dev/null +++ b/packages/adapter-linq/test/webhook-fixture.ts @@ -0,0 +1,36 @@ +import { createHmac } from "node:crypto"; + +export const SIGNING_KEY = "test_linq_webhook_secret"; +export const SIGNING_SECRET = `whsec_${Buffer.from(SIGNING_KEY).toString("base64")}`; + +type HeaderOverrides = Record & { signature?: string }; + +export function createStandardRequest(payload: unknown, overrides: HeaderOverrides = {}): Request { + return createSignedBody(JSON.stringify(payload), overrides); +} + +/** Sign the actual bytes, independently of the production verifier. */ +export function createSignedBody(body: string | Buffer, overrides: HeaderOverrides = {}): Request { + const timestamp = overrides["webhook-timestamp"] ?? Math.floor(Date.now() / 1000).toString(); + const webhookId = overrides["webhook-id"] ?? "webhook-test-id"; + const signature = + overrides.signature ?? + `v1,${createHmac("sha256", SIGNING_KEY) + .update(`${webhookId}.${timestamp}.`) + .update(body) + .digest("base64")}`; + const headers = new Headers({ + "content-type": "application/json", + "webhook-id": webhookId, + "webhook-signature": signature, + "webhook-timestamp": timestamp, + }); + for (const [name, value] of Object.entries(overrides)) { + if (name !== "signature") headers.set(name, value); + } + return new Request("https://example.com/webhooks/linq", { + method: "POST", + headers, + body: typeof body === "string" ? body : new Uint8Array(body), + }); +} diff --git a/packages/adapter-linq/tsconfig.json b/packages/adapter-linq/tsconfig.json index ef2cfe4..73e9d6c 100644 --- a/packages/adapter-linq/tsconfig.json +++ b/packages/adapter-linq/tsconfig.json @@ -6,7 +6,8 @@ "declaration": true, "declarationMap": true, "sourceMap": true, - "noEmit": false + "noEmit": false, + "types": ["node"] }, "include": ["src/**/*.ts"] } diff --git a/packages/adapter-linq/tsconfig.test.json b/packages/adapter-linq/tsconfig.test.json index 7baee43..61eabd8 100644 --- a/packages/adapter-linq/tsconfig.test.json +++ b/packages/adapter-linq/tsconfig.test.json @@ -1,7 +1,8 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { - "noEmit": true + "noEmit": true, + "types": ["node"] }, "include": ["src/**/*.ts", "test/**/*.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d276f8..bc9a708 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,3 +1,104 @@ +--- +lockfileVersion: '9.0' + +importers: + + .: + configDependencies: {} + packageManagerDependencies: + pnpm: + specifier: 12.3.4 + version: 12.3.4 + +packages: + + '@pnpm/exe.darwin-arm64@12.3.4': + resolution: {integrity: sha512-PAyUol8T1+/+ViOiXAt51ECA+QnfXCqz6foL4bW+LsoX0NcVd5XVEM2mRQu+LV4oc7uRz9zf9U0P+XFfuQeDAw==} + cpu: [arm64] + os: [darwin] + + '@pnpm/exe.darwin-x64@12.3.4': + resolution: {integrity: sha512-fxP9JCk0Cdye+ePuj+GJJLMUMTqHGWRdb1dtv4How876uQ2ehxvenpgiYAir/ceO9PsYUZkFTtyZdx+rRu5QOA==} + cpu: [x64] + os: [darwin] + + '@pnpm/exe.linux-arm64-musl@12.3.4': + resolution: {integrity: sha512-FBOt0/7ye6O6q4AllVV5QMviB6qE6fqkeczV/+MDWQsmo+QJrlfsh6X7CpH/tClVpBZEyIbjpUoT8bNhCYBxEg==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-arm64@12.3.4': + resolution: {integrity: sha512-t71AVA7LRqiKTyZ5xMYaZc2n5DfdpMbfokZuiIOXHBOM03ECnF0t4iYwaBDqJgVjlKYUOwaF/bRQajGNA4cJ4w==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-x64-musl@12.3.4': + resolution: {integrity: sha512-RPmk7Jb/aYaFvL2iyDN/AtMY+hUEsue732WmXpcuQ9tBpMnGyA5py7Z3+e+qmQaJ0zY/4ni9jJiyPBQHujmv6w==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-x64@12.3.4': + resolution: {integrity: sha512-2ZqOlSPkfwX1h5cR+FPiWf8+F+2hZT/3TvhUK5sigHqwaQCIiq8R7CGxhndKs63JtcLi2a1Qpo+wX/EoyfjyJQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.win32-arm64@12.3.4': + resolution: {integrity: sha512-ANyrHqyqco6SXBysUTRF74itDyyraea7IbFsKFdNXTjcFnfycTDx37EwuhdpPYFNSIh2JhUG4fByclsRfiHX7w==} + cpu: [arm64] + os: [win32] + + '@pnpm/exe.win32-x64@12.3.4': + resolution: {integrity: sha512-WH/KqBPY/hq2Tb7SgQltEZytimcjgKRaCRL/aM9CI0c67iKc5TVmHUhIiL3Ux9FB4bWn36i6XewUcScQI+zG8w==} + cpu: [x64] + os: [win32] + + pnpm@12.3.4: + resolution: {integrity: sha512-lhqkH7B32joEpEHZ+OFevAyW2o73ELLrZ7+e58sGEOq9SPH9hfUc/+c4RnhfoPh8VqOocqHYk/hEZ0G1zORUVw==} + engines: {node: '>=18.*'} + hasBin: true + +snapshots: + + '@pnpm/exe.darwin-arm64@12.3.4': + optional: true + + '@pnpm/exe.darwin-x64@12.3.4': + optional: true + + '@pnpm/exe.linux-arm64-musl@12.3.4': + optional: true + + '@pnpm/exe.linux-arm64@12.3.4': + optional: true + + '@pnpm/exe.linux-x64-musl@12.3.4': + optional: true + + '@pnpm/exe.linux-x64@12.3.4': + optional: true + + '@pnpm/exe.win32-arm64@12.3.4': + optional: true + + '@pnpm/exe.win32-x64@12.3.4': + optional: true + + pnpm@12.3.4: + optionalDependencies: + '@pnpm/exe.darwin-arm64': 12.3.4 + '@pnpm/exe.darwin-x64': 12.3.4 + '@pnpm/exe.linux-arm64': 12.3.4 + '@pnpm/exe.linux-arm64-musl': 12.3.4 + '@pnpm/exe.linux-x64': 12.3.4 + '@pnpm/exe.linux-x64-musl': 12.3.4 + '@pnpm/exe.win32-arm64': 12.3.4 + '@pnpm/exe.win32-x64': 12.3.4 + +--- lockfileVersion: '9.0' settings: @@ -9,11 +110,11 @@ importers: .: devDependencies: turbo: - specifier: ^2.5.0 - version: 2.9.6 + specifier: 2.10.12 + version: 2.10.12 typescript: - specifier: ^5.8.3 - version: 5.9.3 + specifier: 7.0.2 + version: 7.0.2 yaml: specifier: ^2.9.0 version: 2.9.0 @@ -61,33 +162,36 @@ importers: packages/adapter-linq: dependencies: '@chat-adapter/shared': - specifier: ^4.38.1 - version: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + specifier: 4.40.0 + version: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) '@linqapp/sdk': - specifier: ^0.44.3 - version: 0.44.3 + specifier: 0.62.0 + version: 0.62.0 standardwebhooks: - specifier: ^1.0.0 - version: 1.0.0 + specifier: 1.1.1 + version: 1.1.1 devDependencies: '@types/node': - specifier: ^25.6.0 - version: 25.6.0 + specifier: 22.20.1 + version: 22.20.1 '@vitest/coverage-v8': - specifier: ^4.1.6 - version: 4.1.6(vitest@4.1.6) + specifier: 5.0.0 + version: 5.0.0(vitest@5.0.0) chat: - specifier: ^4.38.1 - version: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + specifier: 4.40.0 + version: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) oxfmt: - specifier: ^0.50.0 - version: 0.50.0 + specifier: 0.67.0 + version: 0.67.0 oxlint: - specifier: ^1.65.0 - version: 1.65.0 + specifier: 1.82.0 + version: 1.82.0 + vite: + specifier: 8.2.2 + version: 8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0) vitest: - specifier: ^4.1.6 - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0)) + specifier: 5.0.0 + version: 5.0.0(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/coverage-v8@5.0.0)(vite@8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0)) packages: @@ -107,21 +211,21 @@ packages: resolution: {integrity: sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw==} engines: {node: '>=18'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@1.0.2': @@ -132,6 +236,10 @@ packages: resolution: {integrity: sha512-zJiMl43fiS3a2RjLFdCyTUTqcDY2xss1Acbzc9yfsw8YAkS0LZRdrNmp9/RjLhZB0+FzLarNAayvdKqF2GwnQg==} engines: {node: '>=20'} + '@chat-adapter/shared@4.40.0': + resolution: {integrity: sha512-uTDl9p+PVkGtAw9dgvRdkydifvYVp98R26vGHhU4V5HuS7DBTedTdb1COUOh6vfP0SrC+xSozp4O/IyfbXZSKw==} + engines: {node: '>=20'} + '@chat-adapter/state-pg@4.38.1': resolution: {integrity: sha512-kwr6gfwhp1DjJXlWuMbGq5f36MF0v9A19/gPXLUh/1n188MGoR4eYPFE+QS/VKWl9Pimxh564i+rZ5m41zE5kw==} engines: {node: '>=20'} @@ -166,6 +274,9 @@ packages: '@linqapp/sdk@0.44.3': resolution: {integrity: sha512-qEuHXHo3M8olxI072/R2hZ0fiO95zujO+91MQXN07Ot4hj2s/SRE+TY813UOjbROsNOGwJzeqXrB1+I32mjp7g==} + '@linqapp/sdk@0.62.0': + resolution: {integrity: sha512-emdwW30tmzGwDXZQ/2wwE91X/1baqhsFq1+CVnp2yvTNZ1ilId4g/28yW0+8k1QH9lbAIugLDqWxZbCHoyYI5g==} + '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: @@ -182,250 +293,259 @@ packages: '@oxc-project/types@0.130.0': resolution: {integrity: sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==} - '@oxfmt/binding-android-arm-eabi@0.50.0': - resolution: {integrity: sha512-ICXQVKrDvsWUtfx6EiVJxfWrajKTwTfRV8vz2XiMkxZeuCKJLgD4YAj6dE3BWvpqDlkVkie4VSTAtMUWO9LDXg==} + '@oxc-project/types@0.148.0': + resolution: {integrity: sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==} + + '@oxfmt/binding-android-arm-eabi@0.67.0': + resolution: {integrity: sha512-2olh3ioEmc4gRzQm7jxyB1b/PFBoFvTq8KdgYySeNpysDtA6DEg2Mvya4/I6flhL7G0eOrE8RD7JCNCIMhE16Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.50.0': - resolution: {integrity: sha512-quwjLQFkuW6OwLHeDeIXsTzOmipQFQbqsYN9HLk2B5I01IlAQZHP1UiLIg0O7pP+dUgPD2AD7SCYA3gs6NH5/g==} + '@oxfmt/binding-android-arm64@0.67.0': + resolution: {integrity: sha512-ulfw8EHN1MBq/MFFDXw2/M1VAFu5mRUcnuZ8Hqbv9viAnFzO9t1jKSAsDqKYYDGMlytF/uj6Z5z5n/tHupnKhw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.50.0': - resolution: {integrity: sha512-ikU5umElcMi78/TNI334wtjr5WZ5F4nWa1aIDseAKKGL0W3ygxeYKkrIJ0fggWa8MOon66BmG3xCqmX1m9YAOw==} + '@oxfmt/binding-darwin-arm64@0.67.0': + resolution: {integrity: sha512-MfONZx/O2o9M5v2jDFol556G9+A+P9xCuJ4DZ+qhE+RnaCdoscy6Eu5nq1dbuNxhwdJyZ6kLI7fnG9mwEeOeGg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.50.0': - resolution: {integrity: sha512-WT4MOYG4mv9IXrH0m60vHsJh+rRMPSOKTQmwDpwmgQ+DuW/i5dU4pqc0HDO5uclO5vjz5IFX5z/taW86LSVe/g==} + '@oxfmt/binding-darwin-x64@0.67.0': + resolution: {integrity: sha512-CYnIx5LvFVJnyJcCqwH2jxMKjFjqo5678MPjdmNFoSGMhlOvZ/xRZqvhDcolKrXc8fezW3AKh+C4wyoFuWOSSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.50.0': - resolution: {integrity: sha512-gH0rycVXqV4juWkvLs2uPMtTyppDc7qEUVzXAxnQ7FpcSZNXqKowUgtjH8q67ngj416r8+4NnAlyR/D35zwwhQ==} + '@oxfmt/binding-freebsd-x64@0.67.0': + resolution: {integrity: sha512-7/iF1orvIS9mxhKUqnmtMgm+OrSQ5acPwuvdQrm6ECgqbwPmC+Pw9cdke3sNfVN6pT2hbJ58+jP8BCThl5HXOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.50.0': - resolution: {integrity: sha512-wL/k+o0hiTeRvi/gPzeC1L/yTHTXIeHDKWU09s2zTBmv7ma59wTm+fADNSGYxhJQDxyavQbwTf1QpW3Zj924tQ==} + '@oxfmt/binding-linux-arm-gnueabihf@0.67.0': + resolution: {integrity: sha512-yy+OGys07IZOpOmYPZoObKyUQLkfxeQqeCypk+1jaZd8HGo77hzvU1Jg8X3+W75o+9lszOjBfg0nkGtlwYywXw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.50.0': - resolution: {integrity: sha512-Y59FKqoUM3Gf00E395b4ixfWyJGwO2GzaZawF5MZoVWcb3f6CkWUXyao0jyOvoIxDMzMybcVRuXyG7ih/Nxweg==} + '@oxfmt/binding-linux-arm-musleabihf@0.67.0': + resolution: {integrity: sha512-wPIeeigXgJpwNw3wydYRt3U9iN9Y/ejpOZuYL9IA7igxWs7LIQMOkhKxTumRvy6dIv0iXKk3RTw3Vmjg0i+2sg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.50.0': - resolution: {integrity: sha512-OvXbfTjMignXWyJXg/NOFsiy996vFe8wb9tkxJaUq8ylq0XrzJg3ttavC5Tcmm6F8/GUs2r3XFJWWu9q/27uYw==} + '@oxfmt/binding-linux-arm64-gnu@0.67.0': + resolution: {integrity: sha512-0+XNxcdbkTfxdcD4qW6Ci9n+mBNJ8xTBumnxKvKBmRFOdx0Wf8/KiHjCJayooXmYkqRpRVd98Q5egvzx5BLSgQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.50.0': - resolution: {integrity: sha512-rqmvHZm7vMa3NLYa0khwkhReCmp9tqKnF23TFZ7S5cYJLvIE4b0k8famWE7kO897/DXznJe675n5SohFBggbxA==} + '@oxfmt/binding-linux-arm64-musl@0.67.0': + resolution: {integrity: sha512-I75LKPJyNOYUzkqAiAMIE31+Ye7xtQXZdoty1IXn4B+bw5Zpmez5wfG19ejGpNnS/BzQ7LFS+7jxuTPb+vHiZw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.50.0': - resolution: {integrity: sha512-49bAdYbMSde42tzPDtuHnBWzOgmoS0PT9THCjvMnDVYMQYiHzPc2Mv5rkpBHVQOXM+PHfafJlxgK0anXSWBVvw==} + '@oxfmt/binding-linux-ppc64-gnu@0.67.0': + resolution: {integrity: sha512-c2M5iRpe1QMZSRE/UvZoPdXBWb5Ic/ycvOyNiKCqPwQ/OyOKIMiJs02ynlNnjb7ZZJnRXYLmGcohoINOcwDK3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.50.0': - resolution: {integrity: sha512-VFT25/6kckkIM62KeWB2bi+xCEmC/zC+DcMaIpEfaio8ulkGDLSiTz11TyK0eqgTl3x5OklYEGDWohvAgOr8Bw==} + '@oxfmt/binding-linux-riscv64-gnu@0.67.0': + resolution: {integrity: sha512-dQzzYlV24Udhfm5ECuSdgqRvFJU/CGHzcYYEO3dLM6W6+CHiBFrq9OjIllkdCcPhsoSQ8o223Dja84MOSzed9A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.50.0': - resolution: {integrity: sha512-BBJMuNy6jjkXjUUINF5UTQqb/nvjmtJad43Gp7bab0AAURAdthhJvduR7rHpWInpWYiaMzYsdrmURNcrmpxdZA==} + '@oxfmt/binding-linux-riscv64-musl@0.67.0': + resolution: {integrity: sha512-rFNq1CgX4qMJANOq42LkAs90JE80GpiaEohAV2qn/gT2hGjQTW1zBO5zQBxArI4926pM1OSzo3CN0tBszGBIaA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.50.0': - resolution: {integrity: sha512-Xd4y+yjAYHKmryXhyUUwbyRD01iKfcvI74iE01L6p4F8SwjhZQXDshK+T8PcrPZLiFqH263P5xqJk94amjkjzQ==} + '@oxfmt/binding-linux-s390x-gnu@0.67.0': + resolution: {integrity: sha512-Sky6rEdz2o5IGq01lPhS12yEvDdChVEcaYrcLHkveh4Fx0qPjljE/Iul6SX/bRMl6lNc8J7J/mDQdzgBdA++Pg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.50.0': - resolution: {integrity: sha512-Qp96rYJru7l++7mk4R+eh8qq9GFfFAMdmoN6VGoRHI8AA1XMnUIzH4u+zOcKZZwY+irHdsaBldDearwB4nOH7A==} + '@oxfmt/binding-linux-x64-gnu@0.67.0': + resolution: {integrity: sha512-vPXmlNORV8AZq2Ocxh07pxwMjfENUWCV/eZArnao0qC3NO/hDeTVkQvee7SJJUbIiF5PZbBa4kYmaXnu7Rk58w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.50.0': - resolution: {integrity: sha512-5XLGp+yd5w2Key5LMqJO+X3XVsJKgeeUKljy32+MBF/J/JZ5m8WHl6dI5eOQOr3ixopxPiXIyDAxn3slI3UXiQ==} + '@oxfmt/binding-linux-x64-musl@0.67.0': + resolution: {integrity: sha512-x/WAtFqYtVr3vZ9ni8nr4kn9whSitg8fOljq/pZzBpxopRdY1BMLZCZkrbIbaBcYkm46qGbqVea2FCWmtQ2P9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.50.0': - resolution: {integrity: sha512-QAxwzh7+GHugCD7WuERolVs8TKQwXNIAZXAHHTecbKVc9oWBkWzOiLauQuezXS57tVcof5zhi1IjZ8tOV0htTg==} + '@oxfmt/binding-openharmony-arm64@0.67.0': + resolution: {integrity: sha512-eRw9Neh4/aA6i+q/R3WU1gGQINhVM0J4fXIm6t27caOamkr/37uAkp1IdBx4zlJH97hmXR63z/q9n5c5dN7MzA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.50.0': - resolution: {integrity: sha512-3nKN/kqClm9iCFWTwtJ9UpR5SGyExp5l3nw6uIiBt+3XitQtszin+vjHrL7JHfDksZ7Svigdaow2zqz/IKCfqw==} + '@oxfmt/binding-win32-arm64-msvc@0.67.0': + resolution: {integrity: sha512-YIMvb+sGNYN2uc6+QK2HLPeEKM2vl7QZ5onQzpAJRb6pnf0DwUFP5R8tdS9R0l8hdUil2gu4Uxd0Yxrop0iT4w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.50.0': - resolution: {integrity: sha512-3r6XZ8+X6qlLbXaPW2NygfiAWSpKbkE36pAVzS83mY+cYY+pSMalJ+qnCgkr92tr+Iqv988XKQ1CpARTg9ITbQ==} + '@oxfmt/binding-win32-ia32-msvc@0.67.0': + resolution: {integrity: sha512-LzmU9MyACPzwNDIK0ItMedHPz735Ug7ELWguxo4/kuy6zWuDoeglOAEFCY8jLg0PzRpFO3hDyLFe2Gu2eFDeGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.50.0': - resolution: {integrity: sha512-BSE8D8KsvquMG9vU+Qt4qGuoOcZ36rxU5S6ZkHNguj+MlWkXWCBETnno3yJ9CfWvfCrbmieaN9LK6hdcdHNZ/w==} + '@oxfmt/binding-win32-x64-msvc@0.67.0': + resolution: {integrity: sha512-sbQOIDNLUEeVZcAJcSL5VURn7kfjvilPviody4Yl5n8lQCDtUm+C9oHTTwZS/m4d/Z6Vv3jNEiAofH932NPPCg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.65.0': - resolution: {integrity: sha512-jDVaGNURT5pEA9qcabh6WusIoBNybOMMDPCx+EFt+gxo6rVvoUf0+73Xy5x81+ZrxU+ewk5uRBYifjy5pgkcnA==} + '@oxlint/binding-android-arm-eabi@1.82.0': + resolution: {integrity: sha512-a3LB+C5Dsj5b/qtmG/mv5WrzuiXEpg1KF5nXWcEvaoN5TYAqkIvxPOwTPp3Jy/FoGpRo8zsTFhMElMXfeoOEzA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.65.0': - resolution: {integrity: sha512-v0z80IWNA7c9RhUydq9YprBxCVZrQ6Ixls2tdxUC1F/1FFqSfa7xTX+EJf0mj6+BKRg2zWXqWfcbJUnETlLlIw==} + '@oxlint/binding-android-arm64@1.82.0': + resolution: {integrity: sha512-OBlhRgNqFblGpGenno/aqOfJLOkQ2B8Ig3iDAalfn0H8hJGZKXPeexCRTDm6uwv6YUjSA9Xnwt1y/Bgj5ZH8uw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.65.0': - resolution: {integrity: sha512-pL/mG/5gMzBwp1gdc5+Cwi87F9j3XRnPxHGyVj5Zd+dCEV5YkKt0L70PB3EGmEEHxgn4H+jnMS3xLuXs6mZW/Q==} + '@oxlint/binding-darwin-arm64@1.82.0': + resolution: {integrity: sha512-dsopxqtY5ZdyT9uLHyGt1SyiLop6hi7hWI3PKpePodkRQOkLaCm+OE4fR9CAz9qdfjiFO8531tX/QDyP/psjFg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.65.0': - resolution: {integrity: sha512-jVTneaeuHtqTrKYnhrdH1buhnSorinvpy1sv43ayclfWx/e/DfdRWv+h1fopJcHQbYr5WMcZMmDvnfEBkPZ+1A==} + '@oxlint/binding-darwin-x64@1.82.0': + resolution: {integrity: sha512-94Lu0SgTClKColU66g1VDuigV3HkcbkJBnTtZjGYfE8UPugaWDgKrm2icjC6HJVUYler2OXaHP/X0TBy8+CowQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.65.0': - resolution: {integrity: sha512-8lJQ7B6RloYDUhwVdbSpwT2eKsCN5KP1Scn18ly1tytCuhXhbs0nkfKHT4jWWZBJqmynWuzd+78bF7wILrj6pw==} + '@oxlint/binding-freebsd-x64@1.82.0': + resolution: {integrity: sha512-hne/V06ewhh1i0w8+l7GDNROAGCGPmyFuOwiP7YTRu0JycyStJ4785dmF8xU5p0uUwt2emvIF9vc7Xjis+cJ0g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.65.0': - resolution: {integrity: sha512-EgmZY+DeWhLLEnNl70/49j3ltA8I6X9kxMfexupWi2Vwfp6RonGsBaHtGoedLolaU37ne7eDUgoxa3CFB95GZA==} + '@oxlint/binding-linux-arm-gnueabihf@1.82.0': + resolution: {integrity: sha512-aWY2xtbZf1LneW9Qsv/n2Sp8gOu74JrlQzEtj4coHX2SHFrCfhmAumaU+sI/A5nr+yoTRTSmI/pL2s6ADlNSkw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.65.0': - resolution: {integrity: sha512-OJMWmAYRVBCPPxnYr3j5sXRwHPh1bAuMlTStGco1Z8q3HkvSH4h+A10E9MiRNYmLhUuli5a2P5wmfj8cagiF5Q==} + '@oxlint/binding-linux-arm-musleabihf@1.82.0': + resolution: {integrity: sha512-Fe+TtXCXMh/5f7kWlZ2VAwsMumZWtraFlKVk1NJlL52/beGwfDE7ov+/8gVirHzWokzGu7X65hSPq0ucPDskWQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.65.0': - resolution: {integrity: sha512-D8uNi50LsYKgS0vGARZDRx05TBZeSxAVdLGddSEqQLSU7xsiqdImHPEw55xq8sKA5rCc/4au/5uS7FQALWdLCg==} + '@oxlint/binding-linux-arm64-gnu@1.82.0': + resolution: {integrity: sha512-6azCZ6OJudlvipNttXCCQcyeFfcJ/NvUZdSN1z8elo73kCHtyQC7WTiUcSjWYvJ1jaq9KDUyMAoAS/vNzhBomA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.65.0': - resolution: {integrity: sha512-IpbA8QGbwFehQhO+YaHwmoI81f93xvywpspf8HrdPCWOIeKwYfM1dhVhO4YKfZewTRRQEPY/JFjTOXTgkwhKrA==} + '@oxlint/binding-linux-arm64-musl@1.82.0': + resolution: {integrity: sha512-PLEaSD8IAIIlwW4dwOd9YaxuxeOpwiXL4J24rcnE4iNtyM5j9Q9/3+gti08oXpx0u2ygNjRDx9xjWWpQonuJEw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.65.0': - resolution: {integrity: sha512-ZSe8HgaZdgyHSv2+/pTG68z10+OarB18CkFKQOhRs3lmmP/p2vuigedK2e9d0ztoG2DU/duJzhxXBSjy/492HQ==} + '@oxlint/binding-linux-ppc64-gnu@1.82.0': + resolution: {integrity: sha512-D94em/BwknNTn4vqxjHh5wb2oL566eFhArabqKIr0cNZMHOJuiraFp1A8tXpH05bbE5tqwEfLXTI0MWEGtn3Dw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.65.0': - resolution: {integrity: sha512-DcTERf++v6HyPHukKAr0JFTRqB+YeDEvqzRgNDMaz7jITPf+tlJIwRxodlAqoXMYhNVEZhXdQM5RAAYH8/oPuw==} + '@oxlint/binding-linux-riscv64-gnu@1.82.0': + resolution: {integrity: sha512-MOprxBaoYU2D4VgxXCl3ghydThWtx7Um1lL51kGYNeQ5Al7WzsH7/tqGdNtbLrIWnjq3bsm13+nz/gRIxjrOXw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.65.0': - resolution: {integrity: sha512-xjhMwuFJwRh40NOBzol4gM5gqAa0xPCJU+GQLM6BydV8TbfkIA7JeyCFNhyfbE9Q/5EWcKYTx62R0cRcjP7DAA==} + '@oxlint/binding-linux-riscv64-musl@1.82.0': + resolution: {integrity: sha512-5h55QsfJ/luDXZzC20k6SNOY1Az+dCP9WvntKtcUWh2JhckAdwApY2ZusaBTwLENnReXU+A2fJtSrYvZJNKNPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.65.0': - resolution: {integrity: sha512-lrWSXb8JzboPWYBG6Kunt/eemvjo2oCFXktShsm3yMToY7HjzKLjxh7CljSvGnnZH9oohNFHOKc9xYpGKCPm6w==} + '@oxlint/binding-linux-s390x-gnu@1.82.0': + resolution: {integrity: sha512-IE8NJNLlHr0CaXyGJPGVn0eTkUyoj1I2UfA8x7I4PSOYKsQ/6btVC7Pywrj5onk0cMH25r6Z38SoN3AvE5Zuog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.65.0': - resolution: {integrity: sha512-A7xfghw250m4a1sPV+q44Mow2G5bhiC9FBvhAuIhJS6QovWnqzuL5AFQPEuwOB+PM4DhABkqxVa3Iwe3Y/nFlQ==} + '@oxlint/binding-linux-x64-gnu@1.82.0': + resolution: {integrity: sha512-XUUUxaBo9XKl+J1B9EmP1cTGQPddzeURvoGkfwh/94PGnbW+hBprDljneoI2M1jzC1bzrIV3ihc7iM9UXl8+tg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.65.0': - resolution: {integrity: sha512-reqOun1+pWO3fW6cv7bsa8hHG0TN3t/82qPdaoJo90FwugXiMjKhZMChmH5Z01cFNRHmxN4+543Fy8478cM/iA==} + '@oxlint/binding-linux-x64-musl@1.82.0': + resolution: {integrity: sha512-SWLSFulX9TDuH6yvbPYp4+VNn6jkkIvvI+KiujDM5rWBRHEfkesCC/pCneIIUr6ovkxZ5fRtpi2v5Cz5FrMJZg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.65.0': - resolution: {integrity: sha512-KQpqOb/juDBO0xyloDkVDhOVxDUgAfZ2OAAVq99TJScJDzT319xry1QzB9LQohV9QGnA7p6m/XATZkMXc84lwA==} + '@oxlint/binding-openharmony-arm64@1.82.0': + resolution: {integrity: sha512-BQy35f6ZUdNr9a6c7B7orxQTcLjByGT2z3WAgmRovpRwmPYAaJ+NTplmMzhdjdJ4qSchfMNZy/Ukg+qRg6zseQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.65.0': - resolution: {integrity: sha512-xfqcOc3nJFeAd1kDY4T9d3XeJIhr00twaaW0kOAzGPyUHkruXtNJv6zz1Ra9fRtSek5VpW2Yoj5AcwPIlT0ZiQ==} + '@oxlint/binding-win32-arm64-msvc@1.82.0': + resolution: {integrity: sha512-V4QhSTg5gctZue8RJjsGi7NpQPThr/p1/HfmiMC5kfe1KFEup9SQRVub4A6kijQjdHfxj7bLL1KO3QO7/5bwMQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.65.0': - resolution: {integrity: sha512-JV+pXm45p8sdgs3c7LOPAohW23optCNZETFOXUcjn6cS4PYZhEU/RI54Z5dHdMudab3nw7T48PZILthM+Q0COQ==} + '@oxlint/binding-win32-ia32-msvc@1.82.0': + resolution: {integrity: sha512-TUSCLaKB2yktpFAJ/r3HAUYsaV/3DT7JS4iNKyoh3a9YNwD0UG7Ezh4D8m23654vQcU6P/RQrCAjRPKe4peP/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.65.0': - resolution: {integrity: sha512-D7L/oBbskLss21bYrRbFuIs81AiSQV+wRzwck54dOkHIlq2qu1xjLz8u6jCqGH8Fltk8bB5DLBpVhE7v/fA8XQ==} + '@oxlint/binding-win32-x64-msvc@1.82.0': + resolution: {integrity: sha512-VTVoRIWJTb+wvUX8EYoPArfFH02whuR10goFXE/LHRRX33ajRrFgqbcONXZMiF4C5rnattfkm87HqYn8jb8hmQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/binding-android-arm-eabi@1.2.7': + resolution: {integrity: sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@rolldown/binding-android-arm64@1.0.0-rc.17': resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -438,6 +558,12 @@ packages: cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.2.7': + resolution: {integrity: sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -450,6 +576,12 @@ packages: cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.2.7': + resolution: {integrity: sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.17': resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -462,6 +594,12 @@ packages: cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.2.7': + resolution: {integrity: sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -474,6 +612,12 @@ packages: cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.2.7': + resolution: {integrity: sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -486,6 +630,12 @@ packages: cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.2.7': + resolution: {integrity: sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -500,6 +650,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.2.7': + resolution: {integrity: sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -514,6 +671,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.2.7': + resolution: {integrity: sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -528,6 +692,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.2.7': + resolution: {integrity: sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -542,6 +713,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.2.7': + resolution: {integrity: sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -556,6 +734,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.2.7': + resolution: {integrity: sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -570,6 +755,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.2.7': + resolution: {integrity: sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -582,6 +774,12 @@ packages: cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.2.7': + resolution: {integrity: sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -604,6 +802,12 @@ packages: cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.2.7': + resolution: {integrity: sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -616,6 +820,12 @@ packages: cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.2.7': + resolution: {integrity: sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} @@ -766,33 +976,33 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@turbo/darwin-64@2.9.6': - resolution: {integrity: sha512-X/56SnVXIQZBLKwniGTwEQTGmtE5brSACnKMBWpY3YafuxVYefrC2acamfjgxP7BG5w3I+6jf0UrLoSzgPcSJg==} + '@turbo/darwin-64@2.10.12': + resolution: {integrity: sha512-9nKgKoF6ZOUsM+or0OtNf+TTJSfGvDNP7ZFv/ZGWVwOSCkumyctQiTeHwB4UNljHTnC41AqylgbunLDHoccNrA==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.6': - resolution: {integrity: sha512-aalBeSl4agT/QtYGDyf/XLajedWzUC9Vg/pm/YO6QQ93vkQ91Vz5uK1ta5RbVRDozQSz4njxUNqRNmOXDzW+qw==} + '@turbo/darwin-arm64@2.10.12': + resolution: {integrity: sha512-H4Elb1jqTZVeIC9bbcNwjSzemZ6RegoTOVHeuV5Osirt2Z8UguTyisMEkvZjPVZgMeN9J4ERZBFad40tFnkb7w==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.6': - resolution: {integrity: sha512-YKi05jnNHaD7vevgYwahpzGwbsNNTwzU2c7VZdmdFm7+cGDP4oREUWSsainiMfRqjRuolQxBwRn8wf1jmu+YZA==} + '@turbo/linux-64@2.10.12': + resolution: {integrity: sha512-lr7KIotukvjZwEXiFSYAeOH3BWzjFVBbSzTbv0fuGFsNukYyH0+g1hB5ecqnJkgkYU+KHEMG1edOhnjiKON1wQ==} cpu: [x64] - os: [linux] + os: [android, linux] - '@turbo/linux-arm64@2.9.6': - resolution: {integrity: sha512-02o/ZS69cOYEDczXvOB2xmyrtzjQ2hVFtWZK1iqxXUfzMmTjZK4UumrfNnjckSg+gqeBfnPRHa0NstA173Ik3g==} + '@turbo/linux-arm64@2.10.12': + resolution: {integrity: sha512-f0pZDTtvzB5SuNwuXBaKbZHUCMCukgc8nMlHEuvLmj91Fzec+MEbr3cAvGNor5htEDqZnO6Lxt9N/GPI/77oGA==} cpu: [arm64] - os: [linux] + os: [android, linux] - '@turbo/windows-64@2.9.6': - resolution: {integrity: sha512-wVdQjvnBI15wB6JrA+43CtUtagjIMmX6XYO758oZHAsCNSxqRlJtdyujih0D8OCnwCRWiGWGI63zAxR0hO6s9g==} + '@turbo/windows-64@2.10.12': + resolution: {integrity: sha512-SDOueJRjS/QcykWf2KCRtTLmIl5YMKsLbXkXQGhDwcTXvKXZiS5ih5lBl/gkwZIpYFjqA/rAlfMzlAFcVHNe0g==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.6': - resolution: {integrity: sha512-1XUUyWW0W6FTSqGEhU8RHVqb2wP1SPkr7hIvBlMEwH9jr+sJQK5kqeosLJ/QaUv4ecSAd1ZhIrLoW7qslAzT4A==} + '@turbo/windows-arm64@2.10.12': + resolution: {integrity: sha512-0i0mVUa4kKk+/B3RwEwPMf9CB+T7ul56hn5FFHNA4VUNTOoLBEd6aNf3FaKfCatDNZ6cicCEf6if9QUTVyzzcA==} cpu: [arm64] os: [win32] @@ -817,6 +1027,9 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + '@types/node@25.6.0': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} @@ -826,24 +1039,149 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@vercel/oidc@3.2.0': resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} - '@vitest/coverage-v8@4.1.6': - resolution: {integrity: sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==} + '@vitest/coverage-v8@5.0.0': + resolution: {integrity: sha512-toMg6PZGCIa/lQNCDoASrfb1ly4hsUKXFtFYC9kD4t78o5Y6LyNJU7AENt8eHPr3quYdxaxK7hj2mnbFfUk9NA==} peerDependencies: - '@vitest/browser': 4.1.6 - vitest: 4.1.6 + '@vitest/browser': 5.0.0 + vitest: 5.0.0 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.6': - resolution: {integrity: sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==} + '@vitest/istanbul-lib-coverage@1.0.1': + resolution: {integrity: sha512-k3DJZ8LhMBK9NS4SclF1ASD3OgXEWDorbIcPTRDK0/Zae6fRvu+fJRxtFdLfHsa9Y24beCdPnoNZ4LviTNstfA==} + engines: {node: '>=22'} + + '@vitest/istanbul-lib-report@1.0.1': + resolution: {integrity: sha512-1EOLRfsTMnyAr3+kEAsP4o9dhaDlGPpD7H5iLBBeq//YpNB1VIahkPhB+eRp9N2Dkfw8oySROjE3yf9XDeaIkQ==} + engines: {node: '>=22'} - '@vitest/mocker@4.1.6': - resolution: {integrity: sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==} + '@vitest/mocker@5.0.0': + resolution: {integrity: sha512-66PGTMIiVJP3t4a5yxU9qPtf7MdTBs8jmToMvy+HVflB3Yy13WJZTtPePdvU+wjRV02SKK5doLbSA6o9pwOmiA==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -853,20 +1191,8 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.6': - resolution: {integrity: sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==} - - '@vitest/runner@4.1.6': - resolution: {integrity: sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==} - - '@vitest/snapshot@4.1.6': - resolution: {integrity: sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==} - - '@vitest/spy@4.1.6': - resolution: {integrity: sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==} - - '@vitest/utils@4.1.6': - resolution: {integrity: sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==} + '@vitest/spy@5.0.0': + resolution: {integrity: sha512-uy+luWBAPw9XfthoHi5AkfHUnuPYEESjl0p/r+meoBnU8bxg5GDQ3Ey8MjcJ6sqahkL4PFyrvfMJJBw7LbU06g==} '@workflow/serde@4.1.0-beta.2': resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} @@ -881,8 +1207,8 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-v8-to-istanbul@1.0.0: - resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + ast-v8-to-istanbul@1.0.5: + resolution: {integrity: sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==} bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -912,13 +1238,25 @@ packages: zod: optional: true + chat@4.40.0: + resolution: {integrity: sha512-slu3VDxItlelEZ8A5vqzlmtT2WErqj2YCGuhhcNx+Ev0+wHeBUqUDUA7hXkca+BfFtW1ZX7ECcySCTG2q2gefg==} + engines: {node: '>=20'} + peerDependencies: + ai: ^6.0.182 || ^7.0.0 + workflow: ^5.0.0-beta.35 + zod: ^3.0.0 || ^4.0.0 + peerDependenciesMeta: + ai: + optional: true + workflow: + optional: true + zod: + optional: true + consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - crossws@0.4.5: resolution: {integrity: sha512-wUR89x/Rw7/8t+vn0CmGDYM9TD6VtARGb0LD5jq2wjtMy1vCP4M+sm6N6TigWeTYvnA8MoW29NqqXD0ep0rfBA==} peerDependencies: @@ -985,8 +1323,8 @@ packages: miniflare: optional: true - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} @@ -999,8 +1337,8 @@ packages: resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==} engines: {node: '>=18.0.0'} - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} exsolve@1.0.8: @@ -1043,9 +1381,6 @@ packages: hookable@6.1.1: resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - httpxy@0.5.1: resolution: {integrity: sha512-JPhqYiixe1A1I+MXDewWDZqeudBGU8Q9jCHYN8ML+779RQzLjTi78HBvWz4jMxUD6h2/vUL12g4q/mFM0OUw1A==} @@ -1053,18 +1388,6 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-reports@3.2.0: - resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} - engines: {node: '>=8'} - jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -1081,30 +1404,60 @@ packages: cpu: [arm64] os: [android] + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-darwin-arm64@1.32.0: resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.32.0: resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.32.0: resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.32.0: resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} @@ -1112,6 +1465,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} @@ -1119,6 +1479,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} @@ -1126,6 +1493,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} @@ -1133,34 +1507,53 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.32.0: resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.32.0: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@1.2.3: + resolution: {integrity: sha512-Bpb0W2TbLKOZ7vJnOUnVRGq3WL2p+ISV29M6hYPL1AFCpyKZpdr5ytiXoTSSxRVhg8YW7f65+6gbG8WG6PCa/g==} - magicast@0.5.3: - resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} - - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} + magicast@0.5.4: + resolution: {integrity: sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==} markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} @@ -1290,6 +1683,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + nf3@0.3.16: resolution: {integrity: sha512-Gs0xRPpUm2nDkqbi40NJ9g7qDIcjcJzgExiydnq6LAyqhI2jfno8wG3NKTL+IiJsx799UHOb1CnSd4Wg4SG4Pw==} @@ -1324,8 +1722,9 @@ packages: zephyr-agent: optional: true - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} + engines: {node: '>=12.20.0'} ocache@0.1.4: resolution: {integrity: sha512-e7geNdWjxSnvsSgvLuPvgKgu7ubM10ZmTPOgpr7mz2BXYtvjMKTiLhjFi/gWU8chkuP6hNkZBsa9LzOusyaqkQ==} @@ -1336,25 +1735,31 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - oxfmt@0.50.0: - resolution: {integrity: sha512-owwjTnhfM5aCOJhYeqDvk7iM504OeYFZpdRU7cxx7xtZMo4uVpjlryTUon+Cf76CugsvnqA32e6rC73pr1hXaw==} + oxfmt@0.67.0: + resolution: {integrity: sha512-vV7sSiPsaO0mSxdoUdayipVDFPzW/UQ+hrezEHa20+Tx1dnMdZLSRHMT0PdS67FFbhd74M1n08asW21aLGeCrA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: svelte: ^5.0.0 + vite-plus: '*' peerDependenciesMeta: svelte: optional: true + vite-plus: + optional: true - oxlint@1.65.0: - resolution: {integrity: sha512-ChUuE3Q7XnAbscvT4XLMsH7HFJmLgLVv9lu+RRgFL5wSXnDqUOzTp5IS8qWDBGd/ZDSzQ2tbX8fjAmijlGLC7A==} + oxlint@1.82.0: + resolution: {integrity: sha512-+iFM1BGw1ntYJt3QngbJmjbrGxPaKMUADOXOijpWGnYcBPq8YZnQftSS1C+pVcDYy9YxqDVJKQqQkTazTQMboQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - oxlint-tsgolint: '>=0.22.1' + oxlint-tsgolint: '>=7.0.2001' + vite-plus: '*' peerDependenciesMeta: oxlint-tsgolint: optional: true + vite-plus: + optional: true pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -1400,10 +1805,18 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + postcss@8.5.14: resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.28: + resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} + engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -1442,6 +1855,11 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rolldown@1.2.7: + resolution: {integrity: sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.60.2: resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1450,11 +1868,6 @@ packages: rou3@0.8.1: resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==} - semver@7.8.0: - resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} - engines: {node: '>=10'} - hasBin: true - siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -1477,30 +1890,38 @@ packages: standardwebhooks@1.0.0: resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + standardwebhooks@1.1.1: + resolution: {integrity: sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==} + + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinybench@6.1.4: + resolution: {integrity: sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==} + engines: {node: '>=20.0.0'} - tinyexec@1.1.2: - resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} engines: {node: '>=18'} tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} - tinypool@2.1.0: - resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@2.1.2: + resolution: {integrity: sha512-9YodfrxS9g9IbFr/KOjE5bAeJ0p61n3bW6mqvy0jtoeKd1kTW1Cxm0oulm6KX2lyM9Gl6WIe8nEbY7LWv5ZJww==} engines: {node: ^20.0.0 || >=22.0.0} - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} trough@2.2.0: @@ -1509,15 +1930,18 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - turbo@2.9.6: - resolution: {integrity: sha512-+v2QJey7ZUeUiuigkU+uFfklvNUyPI2VO2vBpMYJA+a1hKFLFiKtUYlRHdb3P9CrAvMzi0upbjI4WT+zKtqkBg==} + turbo@2.10.12: + resolution: {integrity: sha512-AswgMPnpOoaVZHrrSBejETzEbuIA69OVGwfkHwfrY0A23VjWXBANzgq9+OymWOHAIArB7D1+1z498WY8fGg1Jw==} hasBin: true - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} hasBin: true + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} @@ -1662,23 +2086,66 @@ packages: yaml: optional: true - vitest@4.1.6: - resolution: {integrity: sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + vite@8.2.2: + resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.4.0 || ^0.5.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@5.0.0: + resolution: {integrity: sha512-gpsMNoRhMjMktVxPtstOH4/PJuPyovVaMDr4oDilXaGH1EcqM2OE96SoHT2VIQ6fTGtTjqmHDrEu2X9RQiXf8Q==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.6 - '@vitest/browser-preview': 4.1.6 - '@vitest/browser-webdriverio': 4.1.6 - '@vitest/coverage-istanbul': 4.1.6 - '@vitest/coverage-v8': 4.1.6 - '@vitest/ui': 4.1.6 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.0 + '@vitest/browser-preview': 5.0.0 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.0 + '@vitest/coverage-v8': 5.0.0 + '@vitest/ui': 5.0.0 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -1743,18 +2210,18 @@ snapshots: dependencies: json-schema: 0.4.0 - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/parser@7.29.3': + '@babel/parser@7.29.8': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 - '@babel/types@7.29.0': + '@babel/types@7.29.8': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 '@bcoe/v8-coverage@1.0.2': {} @@ -1767,6 +2234,15 @@ snapshots: - workflow - zod + '@chat-adapter/shared@4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3)': + dependencies: + chat: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) + transitivePeerDependencies: + - ai + - supports-color + - workflow + - zod + '@chat-adapter/state-pg@4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3)': dependencies: chat: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) @@ -1825,6 +2301,10 @@ snapshots: '@linqapp/sdk@0.44.3': {} + '@linqapp/sdk@0.62.0': + dependencies: + standardwebhooks: 1.0.0 + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -1838,118 +2318,123 @@ snapshots: '@oxc-project/types@0.130.0': {} - '@oxfmt/binding-android-arm-eabi@0.50.0': + '@oxc-project/types@0.148.0': {} + + '@oxfmt/binding-android-arm-eabi@0.67.0': optional: true - '@oxfmt/binding-android-arm64@0.50.0': + '@oxfmt/binding-android-arm64@0.67.0': optional: true - '@oxfmt/binding-darwin-arm64@0.50.0': + '@oxfmt/binding-darwin-arm64@0.67.0': optional: true - '@oxfmt/binding-darwin-x64@0.50.0': + '@oxfmt/binding-darwin-x64@0.67.0': optional: true - '@oxfmt/binding-freebsd-x64@0.50.0': + '@oxfmt/binding-freebsd-x64@0.67.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.50.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.67.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.50.0': + '@oxfmt/binding-linux-arm-musleabihf@0.67.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.50.0': + '@oxfmt/binding-linux-arm64-gnu@0.67.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.50.0': + '@oxfmt/binding-linux-arm64-musl@0.67.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.50.0': + '@oxfmt/binding-linux-ppc64-gnu@0.67.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.50.0': + '@oxfmt/binding-linux-riscv64-gnu@0.67.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.50.0': + '@oxfmt/binding-linux-riscv64-musl@0.67.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.50.0': + '@oxfmt/binding-linux-s390x-gnu@0.67.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.50.0': + '@oxfmt/binding-linux-x64-gnu@0.67.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.50.0': + '@oxfmt/binding-linux-x64-musl@0.67.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.50.0': + '@oxfmt/binding-openharmony-arm64@0.67.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.50.0': + '@oxfmt/binding-win32-arm64-msvc@0.67.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.50.0': + '@oxfmt/binding-win32-ia32-msvc@0.67.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.50.0': + '@oxfmt/binding-win32-x64-msvc@0.67.0': optional: true - '@oxlint/binding-android-arm-eabi@1.65.0': + '@oxlint/binding-android-arm-eabi@1.82.0': optional: true - '@oxlint/binding-android-arm64@1.65.0': + '@oxlint/binding-android-arm64@1.82.0': optional: true - '@oxlint/binding-darwin-arm64@1.65.0': + '@oxlint/binding-darwin-arm64@1.82.0': optional: true - '@oxlint/binding-darwin-x64@1.65.0': + '@oxlint/binding-darwin-x64@1.82.0': optional: true - '@oxlint/binding-freebsd-x64@1.65.0': + '@oxlint/binding-freebsd-x64@1.82.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.65.0': + '@oxlint/binding-linux-arm-gnueabihf@1.82.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.65.0': + '@oxlint/binding-linux-arm-musleabihf@1.82.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.65.0': + '@oxlint/binding-linux-arm64-gnu@1.82.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.65.0': + '@oxlint/binding-linux-arm64-musl@1.82.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.65.0': + '@oxlint/binding-linux-ppc64-gnu@1.82.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.65.0': + '@oxlint/binding-linux-riscv64-gnu@1.82.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.65.0': + '@oxlint/binding-linux-riscv64-musl@1.82.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.65.0': + '@oxlint/binding-linux-s390x-gnu@1.82.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.65.0': + '@oxlint/binding-linux-x64-gnu@1.82.0': optional: true - '@oxlint/binding-linux-x64-musl@1.65.0': + '@oxlint/binding-linux-x64-musl@1.82.0': optional: true - '@oxlint/binding-openharmony-arm64@1.65.0': + '@oxlint/binding-openharmony-arm64@1.82.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.65.0': + '@oxlint/binding-win32-arm64-msvc@1.82.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.65.0': + '@oxlint/binding-win32-ia32-msvc@1.82.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.65.0': + '@oxlint/binding-win32-x64-msvc@1.82.0': + optional: true + + '@rolldown/binding-android-arm-eabi@1.2.7': optional: true '@rolldown/binding-android-arm64@1.0.0-rc.17': @@ -1958,22 +2443,34 @@ snapshots: '@rolldown/binding-android-arm64@1.0.1': optional: true + '@rolldown/binding-android-arm64@1.2.7': + optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true '@rolldown/binding-darwin-arm64@1.0.1': optional: true + '@rolldown/binding-darwin-arm64@1.2.7': + optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true '@rolldown/binding-darwin-x64@1.0.1': optional: true + '@rolldown/binding-darwin-x64@1.2.7': + optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-freebsd-x64@1.0.1': + '@rolldown/binding-freebsd-x64@1.0.1': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.7': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': @@ -1982,48 +2479,72 @@ snapshots: '@rolldown/binding-linux-arm-gnueabihf@1.0.1': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.2.7': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.1': optional: true + '@rolldown/binding-linux-arm64-gnu@1.2.7': + optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm64-musl@1.0.1': optional: true + '@rolldown/binding-linux-arm64-musl@1.2.7': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-ppc64-gnu@1.0.1': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.2.7': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-s390x-gnu@1.0.1': optional: true + '@rolldown/binding-linux-s390x-gnu@1.2.7': + optional: true + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-x64-gnu@1.0.1': optional: true + '@rolldown/binding-linux-x64-gnu@1.2.7': + optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true '@rolldown/binding-linux-x64-musl@1.0.1': optional: true + '@rolldown/binding-linux-x64-musl@1.2.7': + optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true '@rolldown/binding-openharmony-arm64@1.0.1': optional: true + '@rolldown/binding-openharmony-arm64@1.2.7': + optional: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': dependencies: '@emnapi/core': 1.10.0 @@ -2044,12 +2565,18 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.0.1': optional: true + '@rolldown/binding-win32-arm64-msvc@1.2.7': + optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true '@rolldown/binding-win32-x64-msvc@1.0.1': optional: true + '@rolldown/binding-win32-x64-msvc@1.2.7': + optional: true + '@rolldown/pluginutils@1.0.0-rc.17': {} '@rolldown/pluginutils@1.0.1': {} @@ -2133,22 +2660,22 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@turbo/darwin-64@2.9.6': + '@turbo/darwin-64@2.10.12': optional: true - '@turbo/darwin-arm64@2.9.6': + '@turbo/darwin-arm64@2.10.12': optional: true - '@turbo/linux-64@2.9.6': + '@turbo/linux-64@2.10.12': optional: true - '@turbo/linux-arm64@2.9.6': + '@turbo/linux-arm64@2.10.12': optional: true - '@turbo/windows-64@2.9.6': + '@turbo/windows-64@2.10.12': optional: true - '@turbo/windows-arm64@2.9.6': + '@turbo/windows-arm64@2.10.12': optional: true '@tybys/wasm-util@0.10.1': @@ -2175,6 +2702,10 @@ snapshots: '@types/ms@2.1.0': {} + '@types/node@22.20.1': + dependencies: + undici-types: 6.21.0 + '@types/node@25.6.0': dependencies: undici-types: 7.19.2 @@ -2187,62 +2718,96 @@ snapshots: '@types/unist@3.0.3': {} + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true + '@vercel/oidc@3.2.0': {} - '@vitest/coverage-v8@4.1.6(vitest@4.1.6)': + '@vitest/coverage-v8@5.0.0(vitest@5.0.0)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.6 - ast-v8-to-istanbul: 1.0.0 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-reports: 3.2.0 - magicast: 0.5.3 - obug: 2.1.1 - std-env: 4.1.0 - tinyrainbow: 3.1.0 - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0)) - - '@vitest/expect@4.1.6': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.1.6 - '@vitest/utils': 4.1.6 - chai: 6.2.2 - tinyrainbow: 3.1.0 - - '@vitest/mocker@4.1.6(vite@8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0))': - dependencies: - '@vitest/spy': 4.1.6 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0) + '@vitest/istanbul-lib-coverage': 1.0.1 + '@vitest/istanbul-lib-report': 1.0.1 + ast-v8-to-istanbul: 1.0.5 + magicast: 0.5.4 + obug: 2.1.4 + std-env: 4.2.0 + tinyrainbow: 3.1.1 + vitest: 5.0.0(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/coverage-v8@5.0.0)(vite@8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0)) - '@vitest/pretty-format@4.1.6': - dependencies: - tinyrainbow: 3.1.0 + '@vitest/istanbul-lib-coverage@1.0.1': {} - '@vitest/runner@4.1.6': + '@vitest/istanbul-lib-report@1.0.1': dependencies: - '@vitest/utils': 4.1.6 - pathe: 2.0.3 + '@vitest/istanbul-lib-coverage': 1.0.1 - '@vitest/snapshot@4.1.6': + '@vitest/mocker@5.0.0(vite@8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0))': dependencies: - '@vitest/pretty-format': 4.1.6 - '@vitest/utils': 4.1.6 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.1.6': {} + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.0 + estree-walker: 3.0.3 + magic-string: 1.2.3 + optionalDependencies: + vite: 8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0) - '@vitest/utils@4.1.6': - dependencies: - '@vitest/pretty-format': 4.1.6 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 + '@vitest/spy@5.0.0': {} '@workflow/serde@4.1.0-beta.2': {} @@ -2256,7 +2821,7 @@ snapshots: assertion-error@2.0.1: {} - ast-v8-to-istanbul@1.0.0: + ast-v8-to-istanbul@1.0.5: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -2285,9 +2850,22 @@ snapshots: transitivePeerDependencies: - supports-color - consola@3.4.2: {} + chat@4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3): + dependencies: + '@workflow/serde': 4.1.0-beta.2 + mdast-util-to-string: 4.0.0 + remark-gfm: 4.0.1(supports-color@7.2.0) + remark-parse: 11.0.0(supports-color@7.2.0) + remark-stringify: 11.0.0 + remend: 1.3.0 + unified: 11.0.5 + optionalDependencies: + ai: 6.0.184(zod@4.4.3) + zod: 4.4.3 + transitivePeerDependencies: + - supports-color - convert-source-map@2.0.0: {} + consola@3.4.2: {} crossws@0.4.5(srvx@0.11.15): optionalDependencies: @@ -2299,6 +2877,12 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3(supports-color@7.2.0): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -2318,7 +2902,7 @@ snapshots: httpxy: 0.5.1 srvx: 0.11.15 - es-module-lexer@2.1.0: {} + es-module-lexer@2.3.2: {} escape-string-regexp@5.0.0: {} @@ -2328,7 +2912,7 @@ snapshots: eventsource-parser@3.0.8: {} - expect-type@1.3.0: {} + expect-type@1.4.0: {} exsolve@1.0.8: {} @@ -2350,29 +2934,15 @@ snapshots: optionalDependencies: crossws: 0.4.5(srvx@0.11.15) - has-flag@4.0.0: {} + has-flag@4.0.0: + optional: true hookable@6.1.1: {} - html-escaper@2.0.2: {} - httpxy@0.5.1: {} is-plain-obj@4.1.0: {} - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-reports@3.2.0: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - jiti@2.6.1: optional: true @@ -2383,36 +2953,69 @@ snapshots: lightningcss-android-arm64@1.32.0: optional: true + lightningcss-android-arm64@1.33.0: + optional: true + lightningcss-darwin-arm64@1.32.0: optional: true + lightningcss-darwin-arm64@1.33.0: + optional: true + lightningcss-darwin-x64@1.32.0: optional: true + lightningcss-darwin-x64@1.33.0: + optional: true + lightningcss-freebsd-x64@1.32.0: optional: true + lightningcss-freebsd-x64@1.33.0: + optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + lightningcss-linux-arm64-gnu@1.32.0: optional: true + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + lightningcss-linux-arm64-musl@1.32.0: optional: true + lightningcss-linux-arm64-musl@1.33.0: + optional: true + lightningcss-linux-x64-gnu@1.32.0: optional: true + lightningcss-linux-x64-gnu@1.33.0: + optional: true + lightningcss-linux-x64-musl@1.32.0: optional: true + lightningcss-linux-x64-musl@1.33.0: + optional: true + lightningcss-win32-arm64-msvc@1.32.0: optional: true + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + lightningcss-win32-x64-msvc@1.32.0: optional: true + lightningcss-win32-x64-msvc@1.33.0: + optional: true + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 @@ -2429,22 +3032,34 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + longest-streak@3.1.0: {} - magic-string@0.30.21: + magic-string@1.2.3: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - magicast@0.5.3: + magicast@0.5.4: dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 source-map-js: 1.2.1 - make-dir@4.0.0: - dependencies: - semver: 7.8.0 - markdown-table@3.0.4: {} mdast-util-find-and-replace@3.0.2: @@ -2471,6 +3086,23 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-from-markdown@2.0.3(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2(supports-color@7.2.0) + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + mdast-util-gfm-autolink-literal@2.0.1: dependencies: '@types/mdast': 4.0.4 @@ -2489,6 +3121,16 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm-footnote@2.1.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 @@ -2497,6 +3139,14 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm-strikethrough@2.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-gfm-table@2.0.0: dependencies: '@types/mdast': 4.0.4 @@ -2507,6 +3157,16 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm-table@2.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-gfm-task-list-item@2.0.0: dependencies: '@types/mdast': 4.0.4 @@ -2516,6 +3176,15 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm-task-list-item@2.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-gfm@3.1.0: dependencies: mdast-util-from-markdown: 2.0.3 @@ -2528,6 +3197,18 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-gfm@3.1.0(supports-color@7.2.0): + dependencies: + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0(supports-color@7.2.0) + mdast-util-gfm-strikethrough: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-table: 2.0.0(supports-color@7.2.0) + mdast-util-gfm-task-list-item: 2.0.0(supports-color@7.2.0) + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + mdast-util-phrasing@4.1.0: dependencies: '@types/mdast': 4.0.4 @@ -2740,10 +3421,34 @@ snapshots: transitivePeerDependencies: - supports-color + micromark@4.0.2(supports-color@7.2.0): + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3(supports-color@7.2.0) + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + ms@2.1.3: {} nanoid@3.3.12: {} + nanoid@3.3.18: {} + nf3@0.3.16: {} nitro@3.0.260415-beta(jiti@2.6.1)(rollup@4.60.2)(vite@8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0)): @@ -2797,7 +3502,7 @@ snapshots: - sqlite3 - uploadthing - obug@2.1.1: {} + obug@2.1.4: {} ocache@0.1.4: dependencies: @@ -2807,51 +3512,51 @@ snapshots: ohash@2.0.11: {} - oxfmt@0.50.0: + oxfmt@0.67.0: dependencies: - tinypool: 2.1.0 + tinypool: 2.1.2 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.50.0 - '@oxfmt/binding-android-arm64': 0.50.0 - '@oxfmt/binding-darwin-arm64': 0.50.0 - '@oxfmt/binding-darwin-x64': 0.50.0 - '@oxfmt/binding-freebsd-x64': 0.50.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.50.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.50.0 - '@oxfmt/binding-linux-arm64-gnu': 0.50.0 - '@oxfmt/binding-linux-arm64-musl': 0.50.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.50.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.50.0 - '@oxfmt/binding-linux-riscv64-musl': 0.50.0 - '@oxfmt/binding-linux-s390x-gnu': 0.50.0 - '@oxfmt/binding-linux-x64-gnu': 0.50.0 - '@oxfmt/binding-linux-x64-musl': 0.50.0 - '@oxfmt/binding-openharmony-arm64': 0.50.0 - '@oxfmt/binding-win32-arm64-msvc': 0.50.0 - '@oxfmt/binding-win32-ia32-msvc': 0.50.0 - '@oxfmt/binding-win32-x64-msvc': 0.50.0 - - oxlint@1.65.0: + '@oxfmt/binding-android-arm-eabi': 0.67.0 + '@oxfmt/binding-android-arm64': 0.67.0 + '@oxfmt/binding-darwin-arm64': 0.67.0 + '@oxfmt/binding-darwin-x64': 0.67.0 + '@oxfmt/binding-freebsd-x64': 0.67.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.67.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.67.0 + '@oxfmt/binding-linux-arm64-gnu': 0.67.0 + '@oxfmt/binding-linux-arm64-musl': 0.67.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.67.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.67.0 + '@oxfmt/binding-linux-riscv64-musl': 0.67.0 + '@oxfmt/binding-linux-s390x-gnu': 0.67.0 + '@oxfmt/binding-linux-x64-gnu': 0.67.0 + '@oxfmt/binding-linux-x64-musl': 0.67.0 + '@oxfmt/binding-openharmony-arm64': 0.67.0 + '@oxfmt/binding-win32-arm64-msvc': 0.67.0 + '@oxfmt/binding-win32-ia32-msvc': 0.67.0 + '@oxfmt/binding-win32-x64-msvc': 0.67.0 + + oxlint@1.82.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.65.0 - '@oxlint/binding-android-arm64': 1.65.0 - '@oxlint/binding-darwin-arm64': 1.65.0 - '@oxlint/binding-darwin-x64': 1.65.0 - '@oxlint/binding-freebsd-x64': 1.65.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.65.0 - '@oxlint/binding-linux-arm-musleabihf': 1.65.0 - '@oxlint/binding-linux-arm64-gnu': 1.65.0 - '@oxlint/binding-linux-arm64-musl': 1.65.0 - '@oxlint/binding-linux-ppc64-gnu': 1.65.0 - '@oxlint/binding-linux-riscv64-gnu': 1.65.0 - '@oxlint/binding-linux-riscv64-musl': 1.65.0 - '@oxlint/binding-linux-s390x-gnu': 1.65.0 - '@oxlint/binding-linux-x64-gnu': 1.65.0 - '@oxlint/binding-linux-x64-musl': 1.65.0 - '@oxlint/binding-openharmony-arm64': 1.65.0 - '@oxlint/binding-win32-arm64-msvc': 1.65.0 - '@oxlint/binding-win32-ia32-msvc': 1.65.0 - '@oxlint/binding-win32-x64-msvc': 1.65.0 + '@oxlint/binding-android-arm-eabi': 1.82.0 + '@oxlint/binding-android-arm64': 1.82.0 + '@oxlint/binding-darwin-arm64': 1.82.0 + '@oxlint/binding-darwin-x64': 1.82.0 + '@oxlint/binding-freebsd-x64': 1.82.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.82.0 + '@oxlint/binding-linux-arm-musleabihf': 1.82.0 + '@oxlint/binding-linux-arm64-gnu': 1.82.0 + '@oxlint/binding-linux-arm64-musl': 1.82.0 + '@oxlint/binding-linux-ppc64-gnu': 1.82.0 + '@oxlint/binding-linux-riscv64-gnu': 1.82.0 + '@oxlint/binding-linux-riscv64-musl': 1.82.0 + '@oxlint/binding-linux-s390x-gnu': 1.82.0 + '@oxlint/binding-linux-x64-gnu': 1.82.0 + '@oxlint/binding-linux-x64-musl': 1.82.0 + '@oxlint/binding-openharmony-arm64': 1.82.0 + '@oxlint/binding-win32-arm64-msvc': 1.82.0 + '@oxlint/binding-win32-ia32-msvc': 1.82.0 + '@oxlint/binding-win32-x64-msvc': 1.82.0 pathe@2.0.3: {} @@ -2894,12 +3599,20 @@ snapshots: picomatch@4.0.4: {} + picomatch@4.0.7: {} + postcss@8.5.14: dependencies: nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.28: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postgres-array@2.0.0: {} postgres-bytea@1.0.1: {} @@ -2921,6 +3634,17 @@ snapshots: transitivePeerDependencies: - supports-color + remark-gfm@4.0.1(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0(supports-color@7.2.0) + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0(supports-color@7.2.0) + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 @@ -2930,6 +3654,15 @@ snapshots: transitivePeerDependencies: - supports-color + remark-parse@11.0.0(supports-color@7.2.0): + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3(supports-color@7.2.0) + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + remark-stringify@11.0.0: dependencies: '@types/mdast': 4.0.4 @@ -2980,6 +3713,27 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.1 '@rolldown/binding-win32-x64-msvc': 1.0.1 + rolldown@1.2.7: + dependencies: + '@oxc-project/types': 0.148.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.7 + '@rolldown/binding-android-arm64': 1.2.7 + '@rolldown/binding-darwin-arm64': 1.2.7 + '@rolldown/binding-darwin-x64': 1.2.7 + '@rolldown/binding-freebsd-x64': 1.2.7 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.7 + '@rolldown/binding-linux-arm64-gnu': 1.2.7 + '@rolldown/binding-linux-arm64-musl': 1.2.7 + '@rolldown/binding-linux-ppc64-gnu': 1.2.7 + '@rolldown/binding-linux-s390x-gnu': 1.2.7 + '@rolldown/binding-linux-x64-gnu': 1.2.7 + '@rolldown/binding-linux-x64-musl': 1.2.7 + '@rolldown/binding-openharmony-arm64': 1.2.7 + '@rolldown/binding-win32-arm64-msvc': 1.2.7 + '@rolldown/binding-win32-x64-msvc': 1.2.7 + rollup@4.60.2: dependencies: '@types/estree': 1.0.8 @@ -3014,8 +3768,6 @@ snapshots: rou3@0.8.1: {} - semver@7.8.0: {} - siginfo@2.0.0: {} source-map-js@1.2.1: {} @@ -3031,40 +3783,74 @@ snapshots: '@stablelib/base64': 1.0.1 fast-sha256: 1.3.0 - std-env@4.1.0: {} + standardwebhooks@1.1.1: + dependencies: + '@stablelib/base64': 1.0.1 + fast-sha256: 1.3.0 + + std-env@4.2.0: {} supports-color@7.2.0: dependencies: has-flag: 4.0.0 + optional: true - tinybench@2.9.0: {} + tinybench@6.1.4: {} - tinyexec@1.1.2: {} + tinyexec@1.3.0: {} tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - tinypool@2.1.0: {} + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinypool@2.1.2: {} - tinyrainbow@3.1.0: {} + tinyrainbow@3.1.1: {} trough@2.2.0: {} tslib@2.8.1: optional: true - turbo@2.9.6: + turbo@2.10.12: optionalDependencies: - '@turbo/darwin-64': 2.9.6 - '@turbo/darwin-arm64': 2.9.6 - '@turbo/linux-64': 2.9.6 - '@turbo/linux-arm64': 2.9.6 - '@turbo/windows-64': 2.9.6 - '@turbo/windows-arm64': 2.9.6 - - typescript@5.9.3: {} + '@turbo/darwin-64': 2.10.12 + '@turbo/darwin-arm64': 2.10.12 + '@turbo/linux-64': 2.10.12 + '@turbo/linux-arm64': 2.10.12 + '@turbo/windows-64': 2.10.12 + '@turbo/windows-arm64': 2.10.12 + + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 + + undici-types@6.21.0: {} undici-types@7.19.2: {} @@ -3129,32 +3915,39 @@ snapshots: jiti: 2.6.1 yaml: 2.9.0 - vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/coverage-v8@4.1.6)(vite@8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0)): - dependencies: - '@vitest/expect': 4.1.6 - '@vitest/mocker': 4.1.6(vite@8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.6 - '@vitest/runner': 4.1.6 - '@vitest/snapshot': 4.1.6 - '@vitest/spy': 4.1.6 - '@vitest/utils': 4.1.6 - es-module-lexer: 2.1.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 - tinyrainbow: 3.1.0 - vite: 8.0.13(@types/node@25.6.0)(jiti@2.6.1)(yaml@2.9.0) + vite@8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.28 + rolldown: 1.2.7 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 22.20.1 + fsevents: 2.3.3 + jiti: 2.6.1 + yaml: 2.9.0 + + vitest@5.0.0(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(@vitest/coverage-v8@5.0.0)(vite@8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0)): + dependencies: + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.0(vite@8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0)) + chai: 6.2.2 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.2.3 + obug: 2.1.4 + picomatch: 4.0.7 + std-env: 4.2.0 + tinybench: 6.1.4 + tinyexec: 1.3.0 + tinyglobby: 0.2.17 + vite: 8.2.2(@types/node@22.20.1)(jiti@2.6.1)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.6.0 - '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) + '@types/node': 22.20.1 + '@vitest/coverage-v8': 5.0.0(vitest@5.0.0) transitivePeerDependencies: - msw diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 286cf7f..3f4793f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,52 @@ packages: - apps/* - packages/* +minimumReleaseAgeExclude: + - '@oxfmt/binding-android-arm-eabi@0.67.0' + - '@oxfmt/binding-android-arm64@0.67.0' + - '@oxfmt/binding-darwin-arm64@0.67.0' + - '@oxfmt/binding-darwin-x64@0.67.0' + - '@oxfmt/binding-freebsd-x64@0.67.0' + - '@oxfmt/binding-linux-arm-gnueabihf@0.67.0' + - '@oxfmt/binding-linux-arm-musleabihf@0.67.0' + - '@oxfmt/binding-linux-arm64-gnu@0.67.0' + - '@oxfmt/binding-linux-arm64-musl@0.67.0' + - '@oxfmt/binding-linux-ppc64-gnu@0.67.0' + - '@oxfmt/binding-linux-riscv64-gnu@0.67.0' + - '@oxfmt/binding-linux-riscv64-musl@0.67.0' + - '@oxfmt/binding-linux-s390x-gnu@0.67.0' + - '@oxfmt/binding-linux-x64-gnu@0.67.0' + - '@oxfmt/binding-linux-x64-musl@0.67.0' + - '@oxfmt/binding-openharmony-arm64@0.67.0' + - '@oxfmt/binding-win32-arm64-msvc@0.67.0' + - '@oxfmt/binding-win32-ia32-msvc@0.67.0' + - '@oxfmt/binding-win32-x64-msvc@0.67.0' + - '@oxlint/binding-android-arm-eabi@1.82.0' + - '@oxlint/binding-android-arm64@1.82.0' + - '@oxlint/binding-darwin-arm64@1.82.0' + - '@oxlint/binding-darwin-x64@1.82.0' + - '@oxlint/binding-freebsd-x64@1.82.0' + - '@oxlint/binding-linux-arm-gnueabihf@1.82.0' + - '@oxlint/binding-linux-arm-musleabihf@1.82.0' + - '@oxlint/binding-linux-arm64-gnu@1.82.0' + - '@oxlint/binding-linux-arm64-musl@1.82.0' + - '@oxlint/binding-linux-ppc64-gnu@1.82.0' + - '@oxlint/binding-linux-riscv64-gnu@1.82.0' + - '@oxlint/binding-linux-riscv64-musl@1.82.0' + - '@oxlint/binding-linux-s390x-gnu@1.82.0' + - '@oxlint/binding-linux-x64-gnu@1.82.0' + - '@oxlint/binding-linux-x64-musl@1.82.0' + - '@oxlint/binding-openharmony-arm64@1.82.0' + - '@oxlint/binding-win32-arm64-msvc@1.82.0' + - '@oxlint/binding-win32-ia32-msvc@1.82.0' + - '@oxlint/binding-win32-x64-msvc@1.82.0' + - oxfmt@0.67.0 + - oxlint@1.82.0 + +# Require review for future release-age exceptions. Entries above pin requested tooling. +minimumReleaseAgeStrict: true + +# Validation commands must never install or resolve dependencies implicitly. +verifyDepsBeforeRun: error +# Reviewed adapter/tooling graph ships binaries; no dependency lifecycle scripts needed. +allowBuilds: {} From 94ce84e72fec1da5de44363a2db6f4ab66772a06 Mon Sep 17 00:00:00 2001 From: Filip Pilar Date: Tue, 8 Sep 2026 09:36:31 +0400 Subject: [PATCH 2/3] fix(repo): restore full CI and durable release guidance --- .github/workflows/ci.yml | 4 +- README.md | 15 ++- packages/adapter-linq/MODERNIZATION.md | 137 +++++++++---------------- 3 files changed, 55 insertions(+), 101 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c0d533..7e3fee3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,5 +24,5 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: pnpm - - run: pnpm --filter @forma/linq-chat-sdk-adapter... install --frozen-lockfile - - run: pnpm check:adapter + - run: pnpm install --frozen-lockfile + - run: pnpm check diff --git a/README.md b/README.md index c257241..630b984 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,13 @@ pnpm check:adapter ``` `pnpm check:adapter` runs the canonical webhook event-name drift check, adapter lint, formatting, -tests, TypeScript contracts, and build. CI runs this adapter-only check on Node.js 22.12 and 24. -The example application is maintained separately and is outside this validation target. - -The adapter pins Linq SDK `0.62.0`, Chat/shared `4.40.0`, and `standardwebhooks@1.1.1`. -Development uses pnpm `12.3.4`, TypeScript `7.0.2`, and Vitest `5.0.0` with Vite `8.2.2`. -The SDK now exposes `webhooks.unwrap()`; the adapter retains its verified boundary for exact bytes, -explicit trusted forwarding, stable errors, and lossless future events. See the adapter -[modernization notes](packages/adapter-linq/MODERNIZATION.md) for migration and local release checks. +tests, TypeScript contracts, and build. CI installs the full workspace and runs `pnpm check` on +Node.js 22.12 and 24, including the example application's typecheck and build. + +Exact toolchain and dependency versions live in the [root manifest](package.json), +[adapter manifest](packages/adapter-linq/package.json), and [lockfile](pnpm-lock.yaml). +See the adapter [consumer README](packages/adapter-linq/README.md) for supported contracts and +[maintenance guide](packages/adapter-linq/MODERNIZATION.md) for toolchain policy and release checks. ## Maintenance diff --git a/packages/adapter-linq/MODERNIZATION.md b/packages/adapter-linq/MODERNIZATION.md index cdda28e..b47c1e1 100644 --- a/packages/adapter-linq/MODERNIZATION.md +++ b/packages/adapter-linq/MODERNIZATION.md @@ -1,117 +1,72 @@ -# Adapter modernization: 0.1.0-forma.8 +# Adapter maintenance and release verification -This adapter-only change starts from `main` at -`7f5285207b4a737680a1d9cad1968e9deaf35e86` (`0.1.0-forma.7`). -Example applications, Nitro, databases, provider configuration, and deployments are separate work. +Consumer behavior and compatibility live in [README.md](README.md), capability status and provider +evidence in [FEATURE_PARITY.md](FEATURE_PARITY.md), and application boundaries in the repository +[scope](../../scope.md). Exact runtime, peer, and development versions are owned by the +[adapter manifest](package.json), [root manifest](../../package.json), and +[lockfile](../../pnpm-lock.yaml); do not maintain a second version inventory here. -## Pinned baseline - -| Component | Version | -| --------------------------------- | --------------- | -| Chat and shared adapter utilities | 4.40.0 | -| Linq SDK | 0.62.0 | -| Standard Webhooks | 1.1.1 | -| pnpm | 12.3.4 | -| TypeScript native compiler | 7.0.2 | -| Vitest and V8 coverage | 5.0.0 | -| Vite | 8.2.2 | -| Turbo | 2.10.12 | -| oxlint / oxfmt | 1.82.0 / 0.67.0 | -| Node types | 22.20.1 | - -The supported runtime lines are Node 22.12+ and 24. The tested Chat minimum is 4.40.0; -older versions are outside the peer range. Runtime dependencies are exact pins. +## Toolchain constraints The TypeScript build and test configs explicitly include Node types. The build retains ESM, declarations, declaration maps, and JavaScript source maps. Package sources are included so map references resolve in a clean consumer. The adapter tooling has no required legacy TypeScript -compiler-API consumer, so no TypeScript 6 alias is installed. `ChatWithThreads` remains necessary: -Chat 4.40.0 implements `thread()` but still omits it from `ChatInstance`. - -pnpm 12 uses a multi-document lockfile that also records the package manager. The example app's -importer retains its existing dependency specifications and resolved versions. The adapter/tooling -install graph needs no dependency lifecycle scripts (`allowBuilds: {}`). New scripts remain -unreviewed and fail under pnpm's strict default. Release-age exceptions name only the requested -oxlint/oxfmt versions and their platform bindings; further exceptions require review. -`verifyDepsBeforeRun: error` prevents validation commands from installing dependencies implicitly. - -## Contract changes +compiler-API consumer, so no legacy compiler alias is installed. `ChatWithThreads` remains +necessary while the installed Chat runtime implements `thread()` but omits it from `ChatInstance`. +Recheck both declarations and runtime before removing that bridge. -- Authenticated inbound `mentions[]` takes precedence over deprecated first-mention fields. An - owner entry requires `is_me: true`, exact owner-handle equality, and a bounded non-empty UTF-16 - range with intact surrogate pairs. Multiple mentions and formatting are allowed inbound. Only - omission of the modern field permits the deprecated singular fallback. Outbound remains singular. -- `contact_card.received` is one of the 46 canonical named events and receives raw-only dispatch. - It belongs to a line, does not establish a chat, and adds no contact/media workflow. Unknown - sticker/reaction and `zero_retention` facts remain lossless raw data. -- Standard Webhooks still performs signature verification. Version 1.1.1 rejects empty decoded - secrets and returns undefined for an authenticated empty body. Explicit post-authentication JSON - parsing preserves `invalid_json` for that body. Lossy UTF-8 input cannot authenticate through - replacement characters. Trusted forwarding remains an explicit, exclusive authority. -- Tests call the production `compileLinqMessage()` path; the two internal test-only wrappers and - permissive option parsing are removed. No public compiler export was removed. -- Chat 4.40.0 callback storage includes action/conversation scope and uses a seven-day TTL. The - actual Chat integration assertion follows that runtime while continuing to verify Linq metadata - preservation. This does not add interactive-card support to Linq. +pnpm uses a multi-document lockfile that also records the package manager. Changes to shared +tooling or adapter interfaces must retain the example application’s CI coverage; expand example +maintenance only within the authorized scope. Lifecycle scripts and release-age exceptions require review in +[pnpm-workspace.yaml](../../pnpm-workspace.yaml). `verifyDepsBeforeRun: error` prevents validation +commands from installing dependencies implicitly. -## Evidence +The SDK's `webhooks.unwrap()` does not supersede the adapter's exact-byte verification boundary. +When provider guides disagree, reconcile the primary webhook guide, canonical OpenAPI, and pinned +implementation. Inspect shipped SDK/runtime declarations as well as documentation before changing +contracts; an index summary is not evidence of pinned-package support. -Provider contracts were checked on 2026-09-07 against the -[Linq channel index](https://docs.linqapp.com/llms.txt), its -[iMessage index](https://docs.linqapp.com/channel/imessage/llms.txt), and -[canonical OpenAPI](https://cdn.linqapp.com/openapi/linq-api-v3.yaml). -Relevant provider pages are [mentions](https://docs.linqapp.com/channel/imessage/guides/messaging/mentions/), -[webhooks](https://docs.linqapp.com/channel/imessage/guides/webhooks/), and -[zero-day retention](https://docs.linqapp.com/channel/imessage/guides/platform/zero-day-retention/). -The contact-card schema and example are `ContactCardReceivedEvent` and -`contact_card.received.v2026-02-03` in OpenAPI. +## Local validation and candidate verification -Versions and runtime behavior were checked against the exact npm registry tarballs for -[Chat 4.40.0](https://registry.npmjs.org/chat/4.40.0), -[Linq SDK 0.62.0](https://registry.npmjs.org/@linqapp/sdk/0.62.0), -[Standard Webhooks 1.1.1](https://registry.npmjs.org/standardwebhooks/1.1.1), and -[TypeScript 7.0.2](https://registry.npmjs.org/typescript/7.0.2), including their shipped declarations, -runtime, and relevant bundled Chat docs. The Linq SDK now exposes `webhooks.unwrap()`; this does -not supersede the adapter's verification boundary. Linq's Chat integration page still describes -an older signature shape; the primary webhook guide and pinned Standard Webhooks implementation -are authoritative. pnpm policy behavior follows its [build settings](https://pnpm.io/settings/build). - -## Local validation and candidate handoff - -Run under both Node 22.12 and 24: +Run on both runtime lines in the [CI matrix](../../.github/workflows/ci.yml): ```bash -pnpm --filter @forma/linq-chat-sdk-adapter... install --frozen-lockfile -pnpm check:adapter +pnpm install --frozen-lockfile +pnpm check pnpm --filter @forma/linq-chat-sdk-adapter exec vitest run --coverage --coverage.include "src/**/*.ts" ``` -Before handoff, commit the validated source, build from that revision, and pack once to a unique +For scoped adapter development, use the filtered install and `pnpm check:adapter` documented in the +[root README](../../README.md). This does not replace full-workspace CI coverage. + +Before release, commit the validated source, build from that revision, and pack once to a unique local candidate directory. Record the exact package version, full source revision, absolute archive path, and SHA256 in an adjacent verification manifest. Inspect exports, declarations, -map targets, and package contents. Install those exact bytes with Chat 4.40.0 in a clean consumer -and validate types and actual Chat webhook/post behavior on both runtime lines. The consumer -must use the packed package, not a workspace link. Keep tests for authentication, hostile input, -identity, mentions, callbacks/dedupe, errors, groups/polls, history, media, and native-client access. +map targets, and package contents. Install those exact bytes with the minimum supported Chat peer +in a clean consumer and validate types and actual Chat webhook/post behavior on both runtime lines. +The consumer must use the packed package, not a workspace link. Keep coverage for authentication, +hostile input, identity, mentions, callbacks/dedupe, errors, groups/polls, history, media, and +native-client access. -Send the manifest and archive identity to the coordinating Locky task. Locky integrates those -exact bytes locally before any release; a changed archive requires fresh verification and a new -handoff. Provider/device/live behavior is not claimed by local checks. +Consumer applications must verify the same archive bytes before release; any changed archive +requires fresh verification and a new manifest. Provider/device/live behavior is not established +by local checks. -## Publication preparation only +## Publication -Publication requires separate owner approval after consumer feedback. The intended repository is +Publication requires separate owner approval after consumer verification. The repository is `formacity/linq-chat-sdk`, using an owner-controlled GitHub release asset rather than npm or an -upstream Linq release. For an owner-created release named `adapter-v0.1.0-forma.8`, the later upload -command is: +upstream Linq release. Existing adapter tags use `adapter-linq-v` (for example, +`adapter-linq-v0.1.0-forma.7`). Use the owner-approved tag of the existing release: ```bash -gh release upload adapter-v0.1.0-forma.8 "$VERIFIED_ABSOLUTE_TARBALL_PATH" \ +gh release upload "$APPROVED_RELEASE_TAG" "$VERIFIED_ABSOLUTE_TARBALL_PATH" \ --repo formacity/linq-chat-sdk ``` -This uploads the approved bytes to that existing release. It does not create the release, push or -merge code, publish npm packages, or deploy anything. Do not add `--clobber`: existing assets must -remain immutable. Recheck SHA256 against the handed-off manifest immediately before any approved -upload. The release must describe the candidate's exact source revision and verification; its -Git tag is chosen separately by the owner. No publication command is run during local preparation. +The release tag must resolve to the candidate's recorded source revision. This command uploads the +approved bytes to an existing release; creating the release/tag, pushing, merging, npm publication, +and deployment require their own authority. Do not add `--clobber`: existing assets must remain +immutable. Recheck SHA256 against the manifest immediately before an approved upload. The release +must identify the exact source revision and verification. No publication command is part of local +preparation. From 550414568932fad84110a38e8f698e8ebf40124c Mon Sep 17 00:00:00 2001 From: Filip Pilar Date: Tue, 8 Sep 2026 09:48:02 +0400 Subject: [PATCH 3/3] fix(demo): align Chat dependencies with adapter contracts --- apps/api/package.json | 8 ++++---- pnpm-lock.yaml | 44 +++++++++++++++++++++---------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index 344726f..bb38dce 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -11,13 +11,13 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@chat-adapter/state-pg": "^4.38.1", - "@chat-adapter/telegram": "^4.38.1", - "@chat-adapter/whatsapp": "^4.38.1", + "@chat-adapter/state-pg": "^4.40.0", + "@chat-adapter/telegram": "^4.40.0", + "@chat-adapter/whatsapp": "^4.40.0", "@forma/linq-chat-sdk-adapter": "workspace:*", "@linqapp/sdk": "^0.44.3", "ai": "^6.0.184", - "chat": "^4.38.1", + "chat": "^4.40.0", "pg": "^8.20.0", "zod": "^4.4.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc9a708..56461c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -122,14 +122,14 @@ importers: apps/api: dependencies: '@chat-adapter/state-pg': - specifier: ^4.38.1 - version: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + specifier: ^4.40.0 + version: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) '@chat-adapter/telegram': - specifier: ^4.38.1 - version: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + specifier: ^4.40.0 + version: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) '@chat-adapter/whatsapp': - specifier: ^4.38.1 - version: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + specifier: ^4.40.0 + version: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) '@forma/linq-chat-sdk-adapter': specifier: workspace:* version: link:../../packages/adapter-linq @@ -140,8 +140,8 @@ importers: specifier: ^6.0.184 version: 6.0.184(zod@4.4.3) chat: - specifier: ^4.38.1 - version: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + specifier: ^4.40.0 + version: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) pg: specifier: ^8.20.0 version: 8.20.0 @@ -240,16 +240,16 @@ packages: resolution: {integrity: sha512-uTDl9p+PVkGtAw9dgvRdkydifvYVp98R26vGHhU4V5HuS7DBTedTdb1COUOh6vfP0SrC+xSozp4O/IyfbXZSKw==} engines: {node: '>=20'} - '@chat-adapter/state-pg@4.38.1': - resolution: {integrity: sha512-kwr6gfwhp1DjJXlWuMbGq5f36MF0v9A19/gPXLUh/1n188MGoR4eYPFE+QS/VKWl9Pimxh564i+rZ5m41zE5kw==} + '@chat-adapter/state-pg@4.40.0': + resolution: {integrity: sha512-EmUAgJNLF0dpF1cm4sw4NKxVmtunYiqGoNADiasW/T/JhKiJLCH9KMhjtxG5ZgEwORGvcKGEOCnhocTY/fylcw==} engines: {node: '>=20'} - '@chat-adapter/telegram@4.38.1': - resolution: {integrity: sha512-twFrW8s+2+93jBhKlLcuLudqD986jjJgLHjHGxHnRWqx20jKEx7BlGSgx/Y8jH1UAhOyPZGaJd6cYYoj07U4Lg==} + '@chat-adapter/telegram@4.40.0': + resolution: {integrity: sha512-SbAjiGIMWEK+nR7tdMenmAvnaUDSNQM8cqXc7zFBSbc5lCWtkcBEDsfpMGueqVR3FSsEnwOpOdWFHCsGgseiCQ==} engines: {node: '>=20'} - '@chat-adapter/whatsapp@4.38.1': - resolution: {integrity: sha512-ctYjkpFO0S9MIPwI00T9gB6hECx3aGdgHN87UI+2QR8oww3RkNYvrxf3EJ6owKafpnj1puE0NlRiLXLjvPKTew==} + '@chat-adapter/whatsapp@4.40.0': + resolution: {integrity: sha512-gu8M7klCSNwU/oAGiKio8MokiIFBgZXDMjj5GvKnp5fgaXP/i5vdahru2H4vdE7uWrZf3UEwpBHBTPoxfXm+Lw==} engines: {node: '>=20'} '@emnapi/core@1.10.0': @@ -2243,9 +2243,9 @@ snapshots: - workflow - zod - '@chat-adapter/state-pg@4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3)': + '@chat-adapter/state-pg@4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3)': dependencies: - chat: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + chat: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) pg: 8.20.0 transitivePeerDependencies: - ai @@ -2254,20 +2254,20 @@ snapshots: - workflow - zod - '@chat-adapter/telegram@4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3)': + '@chat-adapter/telegram@4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3)': dependencies: - '@chat-adapter/shared': 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) - chat: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + '@chat-adapter/shared': 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) + chat: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) transitivePeerDependencies: - ai - supports-color - workflow - zod - '@chat-adapter/whatsapp@4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3)': + '@chat-adapter/whatsapp@4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3)': dependencies: - '@chat-adapter/shared': 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) - chat: 4.38.1(ai@6.0.184(zod@4.4.3))(zod@4.4.3) + '@chat-adapter/shared': 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) + chat: 4.40.0(ai@6.0.184(zod@4.4.3))(supports-color@7.2.0)(zod@4.4.3) transitivePeerDependencies: - ai - supports-color