From c673015be91956cdf6c39d4d2a92bd3e2a306191 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 26 Jun 2026 10:58:40 +0200 Subject: [PATCH 1/5] test(truapi): adopt Vitest testing style for @parity/truapi Migrate the JS package tests from the bespoke Bun runner to Vitest, matching the product-sdk testing style: colocated src/**/*.test.ts files, describe/it blocks, and expect() assertions. - Add vitest devDep + vitest.config.ts; test script runs `vitest run`. - Move the five test/*.test.mjs suites next to the code they cover and rewrite them with describe/it + expect. The wire-table loop becomes an it.each over every generated frame id. - The explorer registry test imports the source module so it runs without a prior build. - Exclude src/**/*.test.ts from the build tsconfig so tests never land in dist. - Scope a Prettier override (4-space, 100 width) to the test files. - Drop the unused setup-bun step from the ts-client CI job and refresh the docs and ts-client-checks skill. --- .claude/skills/ts-client-checks/SKILL.md | 24 +- .github/workflows/ci.yml | 4 - .prettierrc | 11 +- CLAUDE.md | 2 +- docs/local-e2e-testing.md | 10 +- js/packages/truapi/README.md | 2 +- js/packages/truapi/package.json | 6 +- js/packages/truapi/src/client.test.ts | 392 ++++ .../truapi/src/explorer/versions.test.ts | 53 + js/packages/truapi/src/transport.test.ts | 143 ++ js/packages/truapi/src/wire-equality.test.ts | 125 ++ js/packages/truapi/src/wire-table.test.ts | 65 + .../truapi/test/explorer-versions.test.mjs | 49 - js/packages/truapi/test/provider.test.mjs | 151 -- .../truapi/test/transport-versioning.test.mjs | 439 ---- .../truapi/test/wire-equality.test.mjs | 156 -- .../truapi/test/wire-table-loop.test.mjs | 67 - js/packages/truapi/tsconfig.json | 3 +- js/packages/truapi/vitest.config.ts | 7 + package-lock.json | 1800 ++++++++++++++++- 20 files changed, 2537 insertions(+), 972 deletions(-) create mode 100644 js/packages/truapi/src/client.test.ts create mode 100644 js/packages/truapi/src/explorer/versions.test.ts create mode 100644 js/packages/truapi/src/transport.test.ts create mode 100644 js/packages/truapi/src/wire-equality.test.ts create mode 100644 js/packages/truapi/src/wire-table.test.ts delete mode 100644 js/packages/truapi/test/explorer-versions.test.mjs delete mode 100644 js/packages/truapi/test/provider.test.mjs delete mode 100644 js/packages/truapi/test/transport-versioning.test.mjs delete mode 100644 js/packages/truapi/test/wire-equality.test.mjs delete mode 100644 js/packages/truapi/test/wire-table-loop.test.mjs create mode 100644 js/packages/truapi/vitest.config.ts diff --git a/.claude/skills/ts-client-checks/SKILL.md b/.claude/skills/ts-client-checks/SKILL.md index c1a97e31..7f7ace15 100644 --- a/.claude/skills/ts-client-checks/SKILL.md +++ b/.claude/skills/ts-client-checks/SKILL.md @@ -1,6 +1,6 @@ --- name: ts-client-checks -description: Build and smoke-test the @parity/truapi TypeScript package (tsc, wire-equality, wire-table-loop). Use after regenerating the client or after touching js/packages/truapi/. +description: Build and smoke-test the @parity/truapi TypeScript package (tsc + Vitest). Use after regenerating the client or after touching js/packages/truapi/. --- # `@parity/truapi` build + smoke tests @@ -13,23 +13,25 @@ npm run build npm test ``` +`npm test` runs the [Vitest](https://vitest.dev/) suite (`src/**/*.test.ts`), +which loads the source `.ts` files directly (no build step required). + Expected: -- `tsc` exits cleanly with no diagnostics. -- `wire-equality.test.mjs`: `all 6 wire-equality tests passed`. -- `wire-table-loop.test.mjs`: - `programmatic wire-table loop: (id, tag) pairs round-tripped`. - `` should match the size of `WIRE_TABLE`. Adding a method grows it - by 2 (request + response) or 4 (subscribe). +- `tsc` (the `build` step) exits cleanly with no diagnostics. +- Vitest reports `Test Files N passed` / `Tests M passed` with no failures. +- `src/wire-table.test.ts` emits one `round-trips .` case per + generated frame id. The case count tracks `WIRE_TABLE`: adding a method + grows it by 2 (request + response) or 4 (subscribe). ## Failure modes - `tsc` errors here usually mean codegen was skipped or out of sync. Re-run the `regen-codegen` skill, then retry. -- A wire-equality failure (golden hex mismatch) is a wire-breaking - change. That is a protocol decision, not a regression to "fix" by - tweaking the test. -- A wire-table-loop count mismatch means a versioned wrapper variant is +- A `src/wire-equality.test.ts` failure (golden hex mismatch) is a + wire-breaking change. That is a protocol decision, not a regression to + "fix" by tweaking the test. +- A `src/wire-table.test.ts` count drop means a versioned wrapper variant is missing, not extra. V0.2-only methods (e.g. `host_get_user_id`, `host_chat_create_simple_group`, all `EntropyDerivation`, all `Payment`) intentionally lack a V1 variant. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec6fe06d..5a2dbc24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,10 +117,6 @@ jobs: with: node-version: 22 - - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 - with: - bun-version: latest - - name: Download codegen output uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: diff --git a/.prettierrc b/.prettierrc index 895bc485..8224a16a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -7,5 +7,14 @@ "useTabs": false, "bracketSpacing": true, "arrowParens": "always", - "endOfLine": "lf" + "endOfLine": "lf", + "overrides": [ + { + "files": "js/packages/truapi/src/**/*.test.ts", + "options": { + "tabWidth": 4, + "printWidth": 100 + } + } + ] } diff --git a/CLAUDE.md b/CLAUDE.md index f7624763..f6642454 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,7 +80,7 @@ cargo test --workspace ```bash cd js/packages/truapi npm run build -npm test # wire-equality + wire-table-loop smoke tests +npm test # Vitest suite (src/**/*.test.ts) ``` ### Explorer diff --git a/docs/local-e2e-testing.md b/docs/local-e2e-testing.md index c832bfc3..3dd0e5be 100644 --- a/docs/local-e2e-testing.md +++ b/docs/local-e2e-testing.md @@ -104,11 +104,11 @@ npm test Expected: -- `tsc` exits cleanly with no diagnostics. -- `wire-equality.test.mjs`: `all 6 wire-equality tests passed`. -- `wire-table-loop.test.mjs`: `programmatic wire-table loop: (id, tag) pairs round-tripped` - — `` should match the size of `WIRE_TABLE`. When you add a method, - `` grows by 2 (request + response) or 4 (subscribe). +- `tsc` (the `build` step) exits cleanly with no diagnostics. +- Vitest reports `Test Files N passed` / `Tests M passed` with no failures. +- `src/wire-table.test.ts` emits one `round-trips .` case per + generated frame id; the count tracks `WIRE_TABLE`. When you add a method, + it grows by 2 (request + response) or 4 (subscribe). `tsc` errors here usually mean the codegen was skipped or out of sync. If a wire-equality test fails (golden hex mismatch) the wire format diff --git a/js/packages/truapi/README.md b/js/packages/truapi/README.md index 6455fefc..54632f76 100644 --- a/js/packages/truapi/README.md +++ b/js/packages/truapi/README.md @@ -127,7 +127,7 @@ npm run build npm test ``` -On a clean checkout, the first build or test run will generate the ignored TypeScript outputs from the Rust sources, so Rust stable + nightly must be installed locally. `npm test` runs the package's smoke tests under [bun](https://bun.sh/), so bun must also be installed (`curl -fsSL https://bun.sh/install | bash`). The tests load the source `.ts` files directly without a build step. +On a clean checkout, the first build or test run will generate the ignored TypeScript outputs from the Rust sources, so Rust stable + nightly must be installed locally. `npm test` runs the package's [Vitest](https://vitest.dev/) suite (`src/**/*.test.ts`), which loads the source `.ts` files directly without a build step. ## License diff --git a/js/packages/truapi/package.json b/js/packages/truapi/package.json index 0554fcfd..68a539c0 100644 --- a/js/packages/truapi/package.json +++ b/js/packages/truapi/package.json @@ -71,10 +71,12 @@ "codegen": "cargo run -p truapi-codegen -- --input ../../../target/doc/truapi.json --output src/generated --playground-output src/playground --explorer-output src/explorer", "typecheck": "npm run build", "pretest": "npm run ensure-generated", - "test": "for f in test/*.test.mjs; do echo \"=== $f ===\" && bun \"$f\" || exit 1; done" + "test": "vitest run", + "test:watch": "vitest" }, "devDependencies": { - "typescript": "^6.0" + "typescript": "^6.0", + "vitest": "^3.2.0" }, "dependencies": { "neverthrow": "^8.2.0", diff --git a/js/packages/truapi/src/client.test.ts b/js/packages/truapi/src/client.test.ts new file mode 100644 index 00000000..4075c0ae --- /dev/null +++ b/js/packages/truapi/src/client.test.ts @@ -0,0 +1,392 @@ +import type { Result } from "neverthrow"; +import { describe, expect, it } from "vitest"; + +import { createTransport } from "./client.js"; +import { indexedTaggedUnion, Result as ScaleResult, str, _void } from "./scale.js"; +import { createClient, SubscriptionError } from "./generated/client.js"; +import * as T from "./generated/types.js"; +import * as W from "./generated/wire-table.js"; +import { encodeWireMessage } from "./transport.js"; + +function toHex(u: Uint8Array): string { + return Array.from(u) + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); +} + +/** Return the successful result value or fail the test with context. */ +function unwrap(result: Result, message: string): T { + return result.match( + (value) => value, + (error): never => { + throw new Error(`${message}: ${error.message}`); + }, + ); +} + +/** Create an in-memory provider plus helpers for injecting frames and closes. */ +function providerFixture() { + const sent: Uint8Array[] = []; + let listener: (message: Uint8Array) => void = () => {}; + let closeListener: (error: Error) => void = () => {}; + return { + sent, + provider: { + postMessage(message: Uint8Array) { + sent.push(message); + }, + subscribe(callback: (message: Uint8Array) => void) { + listener = callback; + return () => {}; + }, + subscribeClose(callback: (error: Error) => void) { + closeListener = callback; + return () => {}; + }, + dispose() {}, + }, + receive(message: Uint8Array) { + listener(message); + }, + close(error: Error) { + closeListener(error); + }, + }; +} + +/** Encode a V1 host-handshake response result payload. */ +function handshakeResponsePayload(value: { success: true; value: undefined }): Uint8Array { + return indexedTaggedUnion({ + V1: [0, ScaleResult(_void, T.HostHandshakeError)], + }).enc({ tag: "V1", value }); +} + +describe("generated client transport", () => { + it("encodes unit-only enums as a single-byte SCALE discriminant", () => { + // Unit-only enums expose a string union on the public API while + // preserving the same single-byte SCALE discriminant encoding. + expect(toHex(T.HostDevicePermissionRequest.enc("Camera"))).toBe("01"); + expect(T.HostDevicePermissionRequest.dec(new Uint8Array([1]))).toBe("Camera"); + }); + + it("wraps generated method requests in the selected wire wrapper", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + + const request = { + productAccountId: { dotNsIdentifier: "foo", derivationIndex: 0 }, + }; + void client.account.getAccount(request); + + const expectedPayload = T.VersionedHostAccountGetRequest.enc({ tag: "V1", value: request }); + const expectedFrame = new Uint8Array(str.enc("p:1").length + 1 + expectedPayload.length); + expectedFrame.set(str.enc("p:1"), 0); + expectedFrame[str.enc("p:1").length] = 22; + expectedFrame.set(expectedPayload, str.enc("p:1").length + 1); + + expect(toHex(fixture.sent[0])).toBe(toHex(expectedFrame)); + expect(transport.truapiVersion).toBe(1); + expect(transport.codecVersion).toBe(1); + }); + + it("uses the transport codec version for generated handshake calls", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + + void client.system.handshake(); + + const expectedPayload = T.VersionedHostHandshakeRequest.enc({ + tag: "V1", + value: { codecVersion: 1 }, + }); + const expectedFrame = new Uint8Array(str.enc("p:1").length + 1 + expectedPayload.length); + expectedFrame.set(str.enc("p:1"), 0); + expectedFrame[str.enc("p:1").length] = 0; + expectedFrame.set(expectedPayload, str.enc("p:1").length + 1); + + expect(toHex(fixture.sent[0])).toBe(toHex(expectedFrame)); + }); + + it("resolves a request from its versioned response envelope", async () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + + const response = client.system.handshake(); + const frame = unwrap( + encodeWireMessage({ + requestId: "p:1", + payload: { + id: W.SYSTEM_HANDSHAKE.response, + value: handshakeResponsePayload({ success: true, value: undefined }), + }, + }), + "encode handshake_response", + ); + fixture.receive(frame); + + const result = await response; + expect(result.isOk()).toBe(true); + }); + + it("auto-responds to an inbound handshake with the versioned-result shape", () => { + const fixture = providerFixture(); + createTransport(fixture.provider); + + const requestPayload = T.VersionedHostHandshakeRequest.enc({ + tag: "V1", + value: { codecVersion: 1 }, + }); + const requestFrame = unwrap( + encodeWireMessage({ + requestId: "h:1", + payload: { id: W.SYSTEM_HANDSHAKE.request, value: requestPayload }, + }), + "encode inbound handshake_request", + ); + fixture.receive(requestFrame); + + const expectedFrame = unwrap( + encodeWireMessage({ + requestId: "h:1", + payload: { + id: W.SYSTEM_HANDSHAKE.response, + value: handshakeResponsePayload({ success: true, value: undefined }), + }, + }), + "encode expected handshake_response", + ); + expect(toHex(fixture.sent[0])).toBe(toHex(expectedFrame)); + }); + + it("decodes receive frames as wire wrappers and delivers inner values", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + const events: unknown[] = []; + + const sub = client.account + .connectionStatusSubscribe() + .subscribe({ next: (value) => events.push(value) }); + + const frame = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.receive, + value: T.VersionedHostAccountConnectionStatusSubscribeItem.enc({ + tag: "V1", + value: "Connected", + }), + }, + }), + "encode receive", + ); + fixture.receive(frame); + + expect(events).toEqual(["Connected"]); + }); + + it("completes the observable on a payloadless interrupt terminator", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + const completions: unknown[][] = []; + + const sub = client.account + .connectionStatusSubscribe() + .subscribe({ complete: (...args) => completions.push(args) }); + + const frame = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.interrupt, + value: _void.enc(undefined), + }, + }), + "encode interrupt", + ); + fixture.receive(frame); + + expect(completions).toEqual([[]]); + }); + + it("surfaces a typed payment interrupt as an observable error", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + const completions: boolean[] = []; + const errors: Error[] = []; + + const sub = client.payment.balanceSubscribe({ request: {} }).subscribe({ + complete: () => completions.push(true), + error: (error) => errors.push(error), + }); + + const reason = { tag: "PermissionDenied", value: undefined } as const; + const frame = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.PAYMENT_BALANCE_SUBSCRIBE.interrupt, + value: T.VersionedHostPaymentBalanceSubscribeError.enc({ + tag: "V1", + value: reason, + }), + }, + }), + "encode typed payment interrupt", + ); + fixture.receive(frame); + + expect(completions).toEqual([]); + expect(errors).toHaveLength(1); + expect(errors[0]).toBeInstanceOf(SubscriptionError); + expect((errors[0] as SubscriptionError).reason).toEqual(reason); + expect(fixture.sent).toHaveLength(1); + }); + + it("uses the same typed-interrupt envelope for RFC0017 coin-payment streams", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + const errors: Error[] = []; + + const sub = client.coinPayment + .rebalancePurse({ request: { from: 1, to: 2, amount: 1000 } }) + .subscribe({ error: (error) => errors.push(error) }); + + const reason = "Denied"; + const frame = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.COIN_PAYMENT_REBALANCE_PURSE.interrupt, + value: T.VersionedHostCoinPaymentRebalancePurseError.enc({ + tag: "V1", + value: reason, + }), + }, + }), + "encode typed coin payment interrupt", + ); + fixture.receive(frame); + + expect(errors).toHaveLength(1); + expect(errors[0]).toBeInstanceOf(SubscriptionError); + expect((errors[0] as SubscriptionError).reason).toEqual(reason); + }); + + it("treats a malformed receive payload as terminal and sends _stop", () => { + // After the error, the generated wrapper sends `_stop` and ignores later + // receive frames for that subscription. + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + const events: unknown[] = []; + const errors: Error[] = []; + + const sub = client.account.connectionStatusSubscribe().subscribe({ + next: (value) => events.push(value), + error: (error) => errors.push(error), + }); + + const malformedFrame = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.receive, + value: _void.enc(undefined), + }, + }), + "encode malformed receive", + ); + fixture.receive(malformedFrame); + + expect(events).toEqual([]); + expect(errors).toHaveLength(1); + expect(errors[0]).toBeInstanceOf(SubscriptionError); + expect((errors[0] as SubscriptionError).reason).toBeUndefined(); + expect(fixture.sent).toHaveLength(2); + + const expectedStop = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.stop, + value: _void.enc(undefined), + }, + }), + "encode stop after malformed receive", + ); + expect(toHex(fixture.sent[1])).toBe(toHex(expectedStop)); + + const validFrame = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.receive, + value: T.VersionedHostAccountConnectionStatusSubscribeItem.enc({ + tag: "V1", + value: "Connected", + }), + }, + }), + "encode receive after malformed receive", + ); + fixture.receive(validFrame); + + expect(events).toEqual([]); + }); + + it("sends _stop on unsubscribe without invoking terminal callbacks locally", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + const completions: boolean[] = []; + const errors: Error[] = []; + + const sub = client.account.connectionStatusSubscribe().subscribe({ + complete: () => completions.push(true), + error: (error) => errors.push(error), + }); + sub.unsubscribe(); + + const expectedStop = unwrap( + encodeWireMessage({ + requestId: sub.subscriptionId, + payload: { + id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.stop, + value: _void.enc(undefined), + }, + }), + "encode explicit unsubscribe stop", + ); + expect(toHex(fixture.sent[1])).toBe(toHex(expectedStop)); + expect(completions).toEqual([]); + expect(errors).toEqual([]); + }); + + it("propagates a provider close/error as a terminal observable error", () => { + const fixture = providerFixture(); + const transport = createTransport(fixture.provider); + const client = createClient(transport); + const errors: Error[] = []; + + client.account + .connectionStatusSubscribe() + .subscribe({ error: (error) => errors.push(error) }); + + const providerError = new Error("provider closed"); + fixture.close(providerError); + + expect(errors).toHaveLength(1); + expect(errors[0]).toBeInstanceOf(SubscriptionError); + expect(errors[0].message).toBe("provider closed"); + expect((errors[0] as SubscriptionError).reason).toBeUndefined(); + expect(errors[0].cause).toBe(providerError); + }); +}); diff --git a/js/packages/truapi/src/explorer/versions.test.ts b/js/packages/truapi/src/explorer/versions.test.ts new file mode 100644 index 00000000..1f36eef5 --- /dev/null +++ b/js/packages/truapi/src/explorer/versions.test.ts @@ -0,0 +1,53 @@ +// Smoke test for the @parity/truapi explorer registry. +// +// Verifies that the published `main` entry leads the list, and that every +// `MethodInfo.requestType`/`responseType`/`errorType` id references a real +// `DataType` in the same version. That cross-reference is the load-bearing +// invariant the explorer site relies on for type navigation. + +import { describe, expect, it } from "vitest"; + +import { packageVersion, versions } from "./versions.js"; + +describe("explorer versions registry", () => { + it("exposes a populated versions array led by `main`", () => { + expect(Array.isArray(versions)).toBe(true); + expect(versions.length).toBeGreaterThanOrEqual(1); + expect(versions[0].id).toBe("main"); + expect(typeof packageVersion).toBe("string"); + expect(packageVersion.length).toBeGreaterThan(0); + }); + + it.each(versions)("version $id resolves every method type reference to a DataType", (entry) => { + expect(typeof entry.id).toBe("string"); + expect(entry.id.length).toBeGreaterThan(0); + expect(Array.isArray(entry.services)).toBe(true); + expect(Array.isArray(entry.types)).toBe(true); + + const typeIds = new Set(entry.types.map((t) => t.id)); + for (const service of entry.services) { + for (const method of service.methods) { + for (const field of ["requestType", "responseType", "errorType"] as const) { + const ref = method[field]; + if (ref == null) continue; + expect(typeIds.has(ref), `${service.name}.${method.name} ${field}=${ref}`).toBe( + true, + ); + } + } + } + }); + + it.each(versions)( + "version $id gives every type a kebab id, definition, and category", + (entry) => { + for (const t of entry.types) { + expect(t.id).toMatch(/^[a-z0-9][a-z0-9-]*$/); + expect(typeof t.definition).toBe("string"); + expect(t.definition.length).toBeGreaterThan(0); + expect(typeof t.category).toBe("string"); + expect(t.category.length).toBeGreaterThan(0); + } + }, + ); +}); diff --git a/js/packages/truapi/src/transport.test.ts b/js/packages/truapi/src/transport.test.ts new file mode 100644 index 00000000..4f4d6ffd --- /dev/null +++ b/js/packages/truapi/src/transport.test.ts @@ -0,0 +1,143 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; + +import { createIframeProvider, createMessagePortProvider } from "./transport.js"; + +/** + * Install a minimal stub for the global `window` used by `createIframeProvider`. + * Returns a dispatch helper and a snapshot of the registered message listeners + * so individual tests can inspect cleanup. + */ +function installFakeWindow() { + const listeners = new Set<(event: unknown) => void>(); + const prior = globalThis.window; + globalThis.window = { + addEventListener(name: string, cb: (event: unknown) => void) { + if (name === "message") listeners.add(cb); + }, + removeEventListener(name: string, cb: (event: unknown) => void) { + if (name === "message") listeners.delete(cb); + }, + } as unknown as Window & typeof globalThis; + return { + listeners, + dispatch(event: unknown) { + for (const cb of [...listeners]) cb(event); + }, + restore() { + if (prior === undefined) { + delete (globalThis as { window?: unknown }).window; + } else { + globalThis.window = prior; + } + }, + }; +} + +describe("createIframeProvider", () => { + let win: ReturnType; + + beforeEach(() => { + win = installFakeWindow(); + }); + + afterEach(() => { + win.restore(); + }); + + it("filters by source/origin/type and pins the outbound origin", () => { + const sent: { msg: Uint8Array; origin: string }[] = []; + const target = { + postMessage(msg: Uint8Array, origin: string) { + sent.push({ msg, origin }); + }, + } as unknown as Window; + const provider = createIframeProvider({ + target, + hostOrigin: "https://host.example", + }); + + const received: Uint8Array[] = []; + provider.subscribe((m) => received.push(m)); + + win.dispatch({ + source: target, + origin: "https://host.example", + data: new Uint8Array([1, 2, 3]), + }); + expect([...received[0]]).toEqual([1, 2, 3]); + + // Bad source, bad origin, and non-bytes payloads are all dropped. + win.dispatch({ source: {}, origin: "https://host.example", data: new Uint8Array([9]) }); + win.dispatch({ + source: target, + origin: "https://attacker.example", + data: new Uint8Array([9]), + }); + win.dispatch({ source: target, origin: "https://host.example", data: "not bytes" }); + expect(received).toHaveLength(1); + + provider.postMessage(new Uint8Array([7])); + expect(sent).toHaveLength(1); + expect(sent[0].origin).toBe("https://host.example"); + expect([...sent[0].msg]).toEqual([7]); + + provider.dispose(); + }); + + it("disposes idempotently and reports the close error to late subscribers", () => { + const provider = createIframeProvider({ + target: { postMessage() {} } as unknown as Window, + hostOrigin: "https://host.example", + }); + + let closeError: unknown = null; + provider.subscribeClose?.((e) => (closeError = e)); + + expect(win.listeners.size).toBeGreaterThan(0); + provider.dispose(); + expect(closeError).toBeInstanceOf(Error); + expect(win.listeners.size).toBe(0); + + // Idempotent: a second dispose is a no-op, and sends after close throw. + provider.dispose(); + expect(() => provider.postMessage(new Uint8Array([1]))).toThrow(); + + // Post-close subscribeClose fires immediately with the stored error. + let late: unknown = null; + provider.subscribeClose?.((e) => (late = e)); + expect(late).toBeInstanceOf(Error); + }); +}); + +describe("createMessagePortProvider", () => { + it("queues sends, round-trips inbound frames, and errors after dispose", async () => { + const { port1, port2 } = new MessageChannel(); + const provider = createMessagePortProvider(port1); + + provider.postMessage(new Uint8Array([42])); + + const drained = await new Promise((resolve) => { + port2.onmessage = (e) => resolve(e.data); + port2.start(); + }); + expect([...drained]).toEqual([42]); + + const inboundOnce = new Promise((resolve) => { + const unsubscribe = provider.subscribe((m) => { + unsubscribe(); + resolve(m); + }); + }); + port2.postMessage(new Uint8Array([55])); + expect([...(await inboundOnce)]).toEqual([55]); + + provider.dispose(); + let lateClose: unknown = null; + provider.subscribeClose?.((e) => (lateClose = e)); + expect(lateClose).toBeInstanceOf(Error); + expect(() => provider.postMessage(new Uint8Array([1]))).toThrow(); + + // Free the receiver port so the runtime exits cleanly. + port2.close(); + }); +}); diff --git a/js/packages/truapi/src/wire-equality.test.ts b/js/packages/truapi/src/wire-equality.test.ts new file mode 100644 index 00000000..bdec5f0e --- /dev/null +++ b/js/packages/truapi/src/wire-equality.test.ts @@ -0,0 +1,125 @@ +// Wire byte-equality smoke test. +// +// `encodeWireMessage` must produce the same bytes as the Rust `ProtocolMessage` +// encoder for the canonical reference vectors. The Rust side pins these in +// `crates/truapi-server/src/frame.rs` (`mod tests`); we compute them here +// independently and compare. + +import type { Result } from "neverthrow"; +import { describe, expect, it } from "vitest"; + +import { str } from "./scale.js"; +import { decodeWireMessage, encodeWireMessage } from "./transport.js"; +import * as W from "./generated/wire-table.js"; + +function toHex(u: Uint8Array): string { + return Array.from(u) + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); +} + +function expectedWire(tagId: number, valueBytes: Uint8Array): Uint8Array { + const reqId = str.enc("p:1"); + const out = new Uint8Array(reqId.length + 1 + valueBytes.length); + out.set(reqId, 0); + out[reqId.length] = tagId; + out.set(valueBytes, reqId.length + 1); + return out; +} + +/** Return the successful result value or fail the test with context. */ +function unwrap(result: Result, message: string): T { + return result.match( + (value) => value, + (error): never => { + throw new Error(`${message}: ${error.message}`); + }, + ); +} + +describe("encodeWireMessage / decodeWireMessage wire equality", () => { + it("encodes handshake_request (discriminant 0) to match the Rust reference", () => { + const inner = new Uint8Array([0x00, 0x01]); // V1 variant + codec_version=1 + const encoded = unwrap( + encodeWireMessage({ + requestId: "p:1", + payload: { id: W.SYSTEM_HANDSHAKE.request, value: inner }, + }), + "encode handshake_request", + ); + expect(toHex(encoded)).toBe(toHex(expectedWire(0, inner))); + }); + + it("encodes account_get_request (discriminant 22) to match the golden fixture", () => { + // payload = V1(("foo", 0u32)); same vector as the Rust golden fixture. + const inner = new Uint8Array([ + 0x00, // V1 variant + ...str.enc("foo"), // compact-len + utf8 + 0x00, + 0x00, + 0x00, + 0x00, // u32 = 0 LE + ]); + const encoded = unwrap( + encodeWireMessage({ + requestId: "p:1", + payload: { id: W.ACCOUNT_GET_ACCOUNT.request, value: inner }, + }), + "encode account_get_request", + ); + expect(toHex(encoded)).toBe(toHex(expectedWire(22, inner))); + expect(toHex(encoded)).toBe("0c703a3116000c666f6f00000000"); + }); + + it("round-trips a local_storage_read frame through encode + decode", () => { + const inner = new Uint8Array([0x00, 0x42, 0xab, 0xcd]); + const encoded = unwrap( + encodeWireMessage({ + requestId: "p:1", + payload: { id: W.LOCAL_STORAGE_READ.request, value: inner }, + }), + "encode local_storage_read_request", + ); + const decoded = unwrap(decodeWireMessage(encoded), "decode local_storage_read_request"); + expect(decoded.requestId).toBe("p:1"); + expect(decoded.payload.id).toBe(W.LOCAL_STORAGE_READ.request); + expect(toHex(decoded.payload.value)).toBe(toHex(inner)); + }); + + it("rejects an invalid outbound discriminant", () => { + const result = encodeWireMessage({ + requestId: "p:1", + payload: { id: 256, value: new Uint8Array() }, + }); + expect(result.isErr()).toBe(true); + expect(result._unsafeUnwrapErr().message).toMatch(/Invalid wire discriminant/); + }); + + it("rejects a truncated frame with no discriminant byte", () => { + const truncated = str.enc("p:1"); // just the requestId, nothing after. + const result = decodeWireMessage(truncated); + expect(result.isErr()).toBe(true); + expect(result._unsafeUnwrapErr().message).toMatch(/missing discriminant byte/); + }); + + it("round-trips a 32 KiB requestId via the mode-2 compact-len prefix", () => { + // Mirrors Rust `max_length_request_id_mode_two_round_trips` so both sides + // agree the high-shift branch in scanStrEnd is correct. + const longId = "y".repeat(32 * 1024); + const inner = new Uint8Array([0x00, 0xab, 0xcd]); + const encoded = unwrap( + encodeWireMessage({ + requestId: longId, + payload: { id: W.ACCOUNT_GET_ACCOUNT.request, value: inner }, + }), + "encode long-id account_get_request", + ); + // Confirm a mode-2 prefix was actually emitted; otherwise the test would + // silently exercise mode-0/1 and the assertion would be hollow. + expect(encoded[0] & 0b11).toBe(0b10); + const decoded = unwrap(decodeWireMessage(encoded), "decode long-id account_get_request"); + expect(decoded.requestId).toBe(longId); + expect(decoded.payload.id).toBe(W.ACCOUNT_GET_ACCOUNT.request); + expect(toHex(decoded.payload.value)).toBe(toHex(inner)); + }); +}); diff --git a/js/packages/truapi/src/wire-table.test.ts b/js/packages/truapi/src/wire-table.test.ts new file mode 100644 index 00000000..31d768c4 --- /dev/null +++ b/js/packages/truapi/src/wire-table.test.ts @@ -0,0 +1,65 @@ +// Programmatic wire-equality loop. +// +// `wire-equality.test.ts` exercises a handful of hand-picked frames. This file +// iterates every generated numeric frame id and asserts the codec round-trips a +// sentinel payload and produces the expected byte layout for each. + +import type { Result } from "neverthrow"; +import { describe, expect, it } from "vitest"; + +import { str } from "./scale.js"; +import { decodeWireMessage, encodeWireMessage } from "./transport.js"; +import * as W from "./generated/wire-table.js"; + +function toHex(u: Uint8Array): string { + return Array.from(u) + .map((b) => b.toString(16).padStart(2, "0")) + .join(""); +} + +function expectedWire(reqId: string, tagId: number, valueBytes: Uint8Array): Uint8Array { + const idBytes = str.enc(reqId); + const out = new Uint8Array(idBytes.length + 1 + valueBytes.length); + out.set(idBytes, 0); + out[idBytes.length] = tagId; + out.set(valueBytes, idBytes.length + 1); + return out; +} + +/** Return the successful result value or fail the test with context. */ +function unwrap(result: Result, message: string): T { + return result.match( + (value) => value, + (error): never => { + throw new Error(`${message}: ${error.message}`); + }, + ); +} + +const frames = Object.entries(W as Record>).flatMap( + ([method, ids]) => Object.entries(ids).map(([kind, id]) => ({ method, kind, id })), +); + +describe("generated wire-table round-trip", () => { + it("exposes a non-empty set of wire frame constants", () => { + expect(frames.length).toBeGreaterThan(0); + }); + + // Per-id sentinel payload so any cross-talk between ids surfaces as a + // concrete byte mismatch rather than a silent equality. + it.each(frames)("round-trips $method.$kind (id $id)", ({ id }) => { + const sentinel = new Uint8Array([id, 0xa5, ~id & 0xff, 0x5a]); + const requestId = `r:${id}`; + + const encoded = unwrap( + encodeWireMessage({ requestId, payload: { id, value: sentinel } }), + "encode", + ); + expect(toHex(encoded)).toBe(toHex(expectedWire(requestId, id, sentinel))); + + const decoded = unwrap(decodeWireMessage(encoded), "decode"); + expect(decoded.requestId).toBe(requestId); + expect(decoded.payload.id).toBe(id); + expect(toHex(decoded.payload.value)).toBe(toHex(sentinel)); + }); +}); diff --git a/js/packages/truapi/test/explorer-versions.test.mjs b/js/packages/truapi/test/explorer-versions.test.mjs deleted file mode 100644 index 16c12a3a..00000000 --- a/js/packages/truapi/test/explorer-versions.test.mjs +++ /dev/null @@ -1,49 +0,0 @@ -// Smoke test for the @parity/truapi explorer registry. -// -// Verifies: -// - The `./explorer/versions` subpath export resolves. -// - The `main` entry is always at index 0 and has the same package version -// string we publish under `packageVersion`. -// - Every `MethodInfo.requestType`/`responseType`/`errorType` id references a -// real `DataType` in the same version. This is the load-bearing invariant -// the explorer site relies on for type navigation. -import assert from "node:assert/strict"; - -const mod = await import("../dist/explorer/versions.js"); -const { versions, packageVersion } = mod; - -assert.ok(Array.isArray(versions), "versions must be an array"); -assert.ok(versions.length >= 1, "versions must have at least one entry"); -assert.equal(versions[0].id, "main", "first entry must be `main`"); -assert.equal(typeof packageVersion, "string"); -assert.ok(packageVersion.length > 0, "packageVersion is empty"); - -for (const entry of versions) { - assert.ok(typeof entry.id === "string" && entry.id.length > 0); - assert.ok(Array.isArray(entry.services)); - assert.ok(Array.isArray(entry.types)); - - const typeIds = new Set(entry.types.map((t) => t.id)); - - for (const service of entry.services) { - for (const method of service.methods) { - for (const field of ["requestType", "responseType", "errorType"]) { - const ref = method[field]; - if (ref == null) continue; - assert.ok( - typeIds.has(ref), - `version ${entry.id} method ${service.name}.${method.name} ${field}=${ref} has no matching DataType`, - ); - } - } - } - - // Every type must have a non-empty kebab id and a non-empty definition. - for (const t of entry.types) { - assert.ok(/^[a-z0-9][a-z0-9-]*$/.test(t.id), `bad id: ${t.id}`); - assert.ok(typeof t.definition === "string" && t.definition.length > 0); - assert.ok(typeof t.category === "string" && t.category.length > 0); - } -} - -console.log(`explorer versions smoke: ${versions.length} version(s), main has ${versions[0].services.length} services / ${versions[0].types.length} types`); diff --git a/js/packages/truapi/test/provider.test.mjs b/js/packages/truapi/test/provider.test.mjs deleted file mode 100644 index 916f9470..00000000 --- a/js/packages/truapi/test/provider.test.mjs +++ /dev/null @@ -1,151 +0,0 @@ -import assert from "node:assert/strict"; - -import { - createIframeProvider, - createMessagePortProvider, -} from "../src/transport.ts"; - -/** - * Install a minimal stub for the global `window` used by - * `createIframeProvider`. Returns a dispatch helper and a snapshot of the - * registered message listeners so individual tests can inspect cleanup. - **/ -function installFakeWindow() { - const listeners = new Set(); - const prior = globalThis.window; - globalThis.window = { - addEventListener(name, cb) { - if (name === "message") listeners.add(cb); - }, - removeEventListener(name, cb) { - if (name === "message") listeners.delete(cb); - }, - }; - return { - listeners, - dispatch(event) { - for (const cb of [...listeners]) cb(event); - }, - restore() { - if (prior === undefined) delete globalThis.window; - else globalThis.window = prior; - }, - }; -} - -// --- iframe: source/origin filter + outbound origin pin --- -{ - const win = installFakeWindow(); - try { - const sent = []; - const target = { - postMessage(msg, origin) { - sent.push({ msg, origin }); - }, - }; - const provider = createIframeProvider({ - target, - hostOrigin: "https://host.example", - }); - - const received = []; - provider.subscribe((m) => received.push(m)); - - win.dispatch({ - source: target, - origin: "https://host.example", - data: new Uint8Array([1, 2, 3]), - }); - assert.deepEqual([...received[0]], [1, 2, 3]); - - win.dispatch({ - source: {}, - origin: "https://host.example", - data: new Uint8Array([9]), - }); - win.dispatch({ - source: target, - origin: "https://attacker.example", - data: new Uint8Array([9]), - }); - win.dispatch({ - source: target, - origin: "https://host.example", - data: "not bytes", - }); - assert.equal(received.length, 1, "filter must drop bad source/origin/type"); - - provider.postMessage(new Uint8Array([7])); - assert.equal(sent.length, 1); - assert.equal(sent[0].origin, "https://host.example"); - assert.deepEqual([...sent[0].msg], [7]); - - provider.dispose(); - } finally { - win.restore(); - } -} - -// --- iframe: dispose semantics --- -{ - const win = installFakeWindow(); - try { - const provider = createIframeProvider({ - target: { postMessage() {} }, - hostOrigin: "https://host.example", - }); - - let closeError = null; - provider.subscribeClose((e) => (closeError = e)); - - assert.ok(win.listeners.size > 0, "window listener registered"); - provider.dispose(); - assert.ok(closeError instanceof Error, "subscribeClose fired on dispose"); - assert.equal(win.listeners.size, 0, "window listener removed on dispose"); - - // Idempotent. - provider.dispose(); - assert.throws(() => provider.postMessage(new Uint8Array([1]))); - - // Post-close subscribeClose fires immediately with the stored error. - let late = null; - provider.subscribeClose((e) => (late = e)); - assert.ok(late instanceof Error); - } finally { - win.restore(); - } -} - -// --- message port: pending queue + round trip + post-close subscribeClose --- -{ - const { port1, port2 } = new MessageChannel(); - const provider = createMessagePortProvider(port1); - - provider.postMessage(new Uint8Array([42])); - - const drained = await new Promise((resolve) => { - port2.onmessage = (e) => resolve(e.data); - port2.start(); - }); - assert.deepEqual([...drained], [42], "queued message drained after resolve"); - - const inboundOnce = new Promise((resolve) => { - const unsubscribe = provider.subscribe((m) => { - unsubscribe(); - resolve(m); - }); - }); - port2.postMessage(new Uint8Array([55])); - assert.deepEqual([...(await inboundOnce)], [55]); - - provider.dispose(); - let lateClose = null; - provider.subscribeClose((e) => (lateClose = e)); - assert.ok(lateClose instanceof Error, "post-close subscribeClose fires immediately"); - assert.throws(() => provider.postMessage(new Uint8Array([1]))); - - // Free the receiver port so the runtime exits cleanly. - port2.close(); -} - -console.log("all provider tests passed"); diff --git a/js/packages/truapi/test/transport-versioning.test.mjs b/js/packages/truapi/test/transport-versioning.test.mjs deleted file mode 100644 index 00b87427..00000000 --- a/js/packages/truapi/test/transport-versioning.test.mjs +++ /dev/null @@ -1,439 +0,0 @@ -import assert from "node:assert/strict"; - -import { createTransport } from "../src/client.ts"; -import { indexedTaggedUnion, Result, str, _void } from "../src/scale.ts"; -import { - createClient, - SubscriptionError, -} from "../src/generated/client.ts"; -import * as T from "../src/generated/types.ts"; -import * as W from "../src/generated/wire-table.ts"; -import { encodeWireMessage } from "../src/transport.ts"; - -/** Convert bytes to a lower-case hex string for readable assertions. */ -function toHex(u) { - return Array.from(u) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); -} - -/** Return the successful result value or fail the assertion with context. */ -function unwrap(result, message) { - return result.match( - (value) => value, - (error) => assert.fail(`${message}: ${error.message}`), - ); -} - -/** Create an in-memory provider plus helpers for injecting frames and closes. */ -function providerFixture() { - const sent = []; - let listener = () => {}; - let closeListener = () => {}; - return { - sent, - provider: { - postMessage(message) { - sent.push(message); - }, - subscribe(callback) { - listener = callback; - return () => {}; - }, - subscribeClose(callback) { - closeListener = callback; - return () => {}; - }, - dispose() {}, - }, - receive(message) { - listener(message); - }, - close(error) { - closeListener(error); - }, - }; -} - -/** Encode a V1 host-handshake response result payload. */ -function handshakeResponsePayload(value) { - return indexedTaggedUnion({ - V1: [0, Result(_void, T.HostHandshakeError)], - }).enc({ tag: "V1", value }); -} - -// Unit-only enums expose a string union on the public API while preserving the -// same single-byte SCALE discriminant encoding. -{ - assert.equal(toHex(T.HostDevicePermissionRequest.enc("Camera")), "01"); - assert.equal(T.HostDevicePermissionRequest.dec(new Uint8Array([1])), "Camera"); -} - -// Generated methods pass inner values and encode the selected wire wrapper -// before handing bytes to the transport. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - - const request = { - productAccountId: { - dotNsIdentifier: "foo", - derivationIndex: 0, - }, - }; - - void client.account.getAccount(request); - - const expectedPayload = T.VersionedHostAccountGetRequest.enc({ - tag: "V1", - value: request, - }); - const expectedFrame = new Uint8Array( - str.enc("p:1").length + 1 + expectedPayload.length, - ); - expectedFrame.set(str.enc("p:1"), 0); - expectedFrame[str.enc("p:1").length] = 22; - expectedFrame.set(expectedPayload, str.enc("p:1").length + 1); - - assert.equal(toHex(fixture.sent[0]), toHex(expectedFrame)); - assert.equal(transport.truapiVersion, 1); - assert.equal(transport.codecVersion, 1); -} - -// Generated handshake calls use the transport's generated codec version; the -// caller does not pass `1` manually. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - - void client.system.handshake(); - - const expectedPayload = T.VersionedHostHandshakeRequest.enc({ - tag: "V1", - value: { codecVersion: 1 }, - }); - const expectedFrame = new Uint8Array( - str.enc("p:1").length + 1 + expectedPayload.length, - ); - expectedFrame.set(str.enc("p:1"), 0); - expectedFrame[str.enc("p:1").length] = 0; - expectedFrame.set(expectedPayload, str.enc("p:1").length + 1); - - assert.equal(toHex(fixture.sent[0]), toHex(expectedFrame)); -} - -// Request responses are a versioned envelope around the result payload. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - - const response = client.system.handshake(); - const frame = unwrap( - encodeWireMessage({ - requestId: "p:1", - payload: { - id: W.SYSTEM_HANDSHAKE.response, - value: handshakeResponsePayload({ success: true, value: undefined }), - }, - }), - "encode handshake_response", - ); - fixture.receive(frame); - - const result = await response; - assert.equal(result.isOk(), true); -} - -// Inbound handshake auto-response uses the same versioned-result response shape. -{ - const fixture = providerFixture(); - createTransport(fixture.provider); - - const requestPayload = T.VersionedHostHandshakeRequest.enc({ - tag: "V1", - value: { codecVersion: 1 }, - }); - const requestFrame = unwrap( - encodeWireMessage({ - requestId: "h:1", - payload: { - id: W.SYSTEM_HANDSHAKE.request, - value: requestPayload, - }, - }), - "encode inbound handshake_request", - ); - fixture.receive(requestFrame); - - const expectedResponsePayload = handshakeResponsePayload({ - success: true, - value: undefined, - }); - const expectedFrame = unwrap( - encodeWireMessage({ - requestId: "h:1", - payload: { - id: W.SYSTEM_HANDSHAKE.response, - value: expectedResponsePayload, - }, - }), - "encode expected handshake_response", - ); - - assert.equal(toHex(fixture.sent[0]), toHex(expectedFrame)); -} - -// Receive frames are decoded as wire wrappers by the generated observable, then -// delivered as inner values. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - const events = []; - - const sub = client.account - .connectionStatusSubscribe() - .subscribe({ - next: (value) => events.push(value), - }); - - const frame = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.receive, - value: T.VersionedHostAccountConnectionStatusSubscribeItem.enc({ - tag: "V1", - value: "Connected", - }), - }, - }), - "encode receive", - ); - fixture.receive(frame); - - assert.deepEqual(events, ["Connected"]); -} - -// Interrupt frames are payloadless terminators and complete the observable. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - const completions = []; - - const sub = client.account - .connectionStatusSubscribe() - .subscribe({ - complete: (...args) => completions.push(args), - }); - - const frame = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.interrupt, - value: _void.enc(undefined), - }, - }), - "encode interrupt", - ); - fixture.receive(frame); - - assert.deepEqual(completions, [[]]); -} - -// Payment subscriptions carry typed interrupt payloads. Those are observable -// errors, not normal completion. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - const completions = []; - const errors = []; - - const sub = client.payment.balanceSubscribe({ request: {} }).subscribe({ - complete: () => completions.push(true), - error: (error) => errors.push(error), - }); - - const reason = { tag: "PermissionDenied", value: undefined }; - const frame = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.PAYMENT_BALANCE_SUBSCRIBE.interrupt, - value: T.VersionedHostPaymentBalanceSubscribeError.enc({ - tag: "V1", - value: reason, - }), - }, - }), - "encode typed payment interrupt", - ); - fixture.receive(frame); - - assert.deepEqual(completions, []); - assert.equal(errors.length, 1); - assert.ok(errors[0] instanceof SubscriptionError); - assert.deepEqual(errors[0].reason, reason); - assert.equal(fixture.sent.length, 1); -} - -// CoinPayment subscriptions use the same typed interrupt envelope for RFC0017 -// resolvable status streams. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - const errors = []; - - const sub = client.coinPayment - .rebalancePurse({ - request: { from: 1, to: 2, amount: 1000 }, - }) - .subscribe({ - error: (error) => errors.push(error), - }); - - const reason = "Denied"; - const frame = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.COIN_PAYMENT_REBALANCE_PURSE.interrupt, - value: T.VersionedHostCoinPaymentRebalancePurseError.enc({ - tag: "V1", - value: reason, - }), - }, - }), - "encode typed coin payment interrupt", - ); - fixture.receive(frame); - - assert.equal(errors.length, 1); - assert.ok(errors[0] instanceof SubscriptionError); - assert.deepEqual(errors[0].reason, reason); -} - -// Malformed receive payloads are terminal observable errors. The generated -// wrapper sends `_stop` and ignores later receive frames for that subscription. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - const events = []; - const errors = []; - - const sub = client.account - .connectionStatusSubscribe() - .subscribe({ - next: (value) => events.push(value), - error: (error) => errors.push(error), - }); - - const malformedFrame = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.receive, - value: _void.enc(undefined), - }, - }), - "encode malformed receive", - ); - fixture.receive(malformedFrame); - - assert.deepEqual(events, []); - assert.equal(errors.length, 1); - assert.ok(errors[0] instanceof SubscriptionError); - assert.equal(errors[0].reason, undefined); - assert.equal(fixture.sent.length, 2); - const expectedStop = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.stop, - value: _void.enc(undefined), - }, - }), - "encode stop after malformed receive", - ); - assert.equal(toHex(fixture.sent[1]), toHex(expectedStop)); - - const validFrame = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.receive, - value: T.VersionedHostAccountConnectionStatusSubscribeItem.enc({ - tag: "V1", - value: "Connected", - }), - }, - }), - "encode receive after malformed receive", - ); - fixture.receive(validFrame); - - assert.deepEqual(events, []); -} - -// Unsubscribe sends the protocol `_stop` frame and does not call terminal -// observer callbacks locally. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - const completions = []; - const errors = []; - - const sub = client.account - .connectionStatusSubscribe() - .subscribe({ - complete: () => completions.push(true), - error: (error) => errors.push(error), - }); - sub.unsubscribe(); - - const expectedStop = unwrap( - encodeWireMessage({ - requestId: sub.subscriptionId, - payload: { - id: W.ACCOUNT_CONNECTION_STATUS_SUBSCRIBE.stop, - value: _void.enc(undefined), - }, - }), - "encode explicit unsubscribe stop", - ); - assert.equal(toHex(fixture.sent[1]), toHex(expectedStop)); - assert.deepEqual(completions, []); - assert.deepEqual(errors, []); -} - -// Provider close/error is a terminal observable error. -{ - const fixture = providerFixture(); - const transport = createTransport(fixture.provider); - const client = createClient(transport); - const errors = []; - - client.account.connectionStatusSubscribe().subscribe({ - error: (error) => errors.push(error), - }); - - const providerError = new Error("provider closed"); - fixture.close(providerError); - - assert.equal(errors.length, 1); - assert.ok(errors[0] instanceof SubscriptionError); - assert.equal(errors[0].message, "provider closed"); - assert.equal(errors[0].reason, undefined); - assert.equal(errors[0].cause, providerError); -} - -console.log("transport version wrapping tests passed"); diff --git a/js/packages/truapi/test/wire-equality.test.mjs b/js/packages/truapi/test/wire-equality.test.mjs deleted file mode 100644 index 68d1593e..00000000 --- a/js/packages/truapi/test/wire-equality.test.mjs +++ /dev/null @@ -1,156 +0,0 @@ -// Wire byte-equality smoke test. -// -// `encodeWireMessage` must produce the same bytes as the Rust -// `ProtocolMessage` encoder for the canonical reference vectors. The Rust side -// pins these in `crates/truapi-server/src/frame.rs` (`mod tests`). We compute -// them here independently and compare. -// -// Run via: `npm test` (which loops over `test/*.test.mjs`) or `bun -// test/wire-equality.test.mjs` directly. No external test framework: bare -// `assert` is enough for the round-trip and the loop in package.json keeps -// future *.test.mjs files from being silently skipped. -// -// This file imports the *source* TS modules directly. Bun transpiles them on -// the fly, so the test does not depend on `npm run build` having run first. - -import assert from "node:assert/strict"; -import { decodeWireMessage, encodeWireMessage } from "../src/transport.ts"; -import { str } from "../src/scale.ts"; -import * as W from "../src/generated/wire-table.ts"; - -function toHex(u) { - return Array.from(u) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); -} - -function expectedWire(tagId, valueBytes) { - const reqId = str.enc("p:1"); - const out = new Uint8Array(reqId.length + 1 + valueBytes.length); - out.set(reqId, 0); - out[reqId.length] = tagId; - out.set(valueBytes, reqId.length + 1); - return out; -} - -/** Return the successful result value or fail the assertion with context. */ -function unwrap(result, message) { - return result.match( - (value) => value, - (error) => assert.fail(`${message}: ${error.message}`), - ); -} - -// 1) handshake_request, discriminant = 0 -{ - const inner = new Uint8Array([0x00, 0x01]); // V1 variant + codec_version=1 - const encoded = unwrap( - encodeWireMessage({ - requestId: "p:1", - payload: { id: W.SYSTEM_HANDSHAKE.request, value: inner }, - }), - "encode handshake_request", - ); - assert.equal( - toHex(encoded), - toHex(expectedWire(0, inner)), - "handshake_request encoding mismatch with Rust reference", - ); -} - -// 2) account_get_request, discriminant = 22, payload = V1(("foo", 0u32)) -// This is the same vector pinned in `tests/snapshots/golden-account-get.bin`. -{ - const inner = new Uint8Array([ - 0x00, // V1 variant - ...str.enc("foo"), // compact-len + utf8 - 0x00, - 0x00, - 0x00, - 0x00, // u32 = 0 LE - ]); - const encoded = unwrap( - encodeWireMessage({ - requestId: "p:1", - payload: { id: W.ACCOUNT_GET_ACCOUNT.request, value: inner }, - }), - "encode account_get_request", - ); - const expected = expectedWire(22, inner); - assert.equal( - toHex(encoded), - toHex(expected), - "account_get_request encoding mismatch with Rust reference", - ); - // Also assert the absolute byte sequence matches the Rust golden fixture. - const golden = "0c703a3116000c666f6f00000000"; - assert.equal( - toHex(encoded), - golden, - `golden frame mismatch: expected ${golden}, got ${toHex(encoded)}`, - ); -} - -// 3) round-trip -{ - const inner = new Uint8Array([0x00, 0x42, 0xab, 0xcd]); - const encoded = unwrap( - encodeWireMessage({ - requestId: "p:1", - payload: { id: W.LOCAL_STORAGE_READ.request, value: inner }, - }), - "encode local_storage_read_request", - ); - const decoded = unwrap( - decodeWireMessage(encoded), - "decode local_storage_read_request", - ); - assert.equal(decoded.requestId, "p:1"); - assert.equal(decoded.payload.id, W.LOCAL_STORAGE_READ.request); - assert.equal(toHex(decoded.payload.value), toHex(inner)); -} - -// 4) invalid outbound discriminant must surface as Err. -{ - const result = encodeWireMessage({ - requestId: "p:1", - payload: { id: 256, value: new Uint8Array() }, - }); - assert.ok(result.isErr(), "encode of id 256 should be Err"); - assert.match(result.error.message, /Invalid wire discriminant/); -} - -// 5) truncated frame (no discriminant byte) must surface as Err. -{ - const truncated = str.enc("p:1"); // just the requestId, nothing after. - const result = decodeWireMessage(truncated); - assert.ok(result.isErr(), "decode of truncated frame should be Err"); - assert.match(result.error.message, /missing discriminant byte/); -} - -// 6) 32 KiB requestId exercises scanStrEnd mode-2 (4-byte compact-len prefix). -// Mirrors Rust `max_length_request_id_mode_two_round_trips` so both sides agree -// the high-shift branch in scanStrEnd is correct. -{ - const longId = "y".repeat(32 * 1024); - const inner = new Uint8Array([0x00, 0xab, 0xcd]); - const encoded = unwrap( - encodeWireMessage({ - requestId: longId, - payload: { id: W.ACCOUNT_GET_ACCOUNT.request, value: inner }, - }), - "encode long-id account_get_request", - ); - // Confirm the encoder actually emitted a mode-2 prefix; otherwise the test - // is silently exercising mode-0/1 and the assertion is hollow. - assert.equal(encoded[0] & 0b11, 0b10, "expected mode-2 compact-len prefix"); - const decoded = unwrap( - decodeWireMessage(encoded), - "decode long-id account_get_request", - ); - assert.equal(decoded.requestId, longId); - assert.equal(decoded.payload.id, W.ACCOUNT_GET_ACCOUNT.request); - assert.equal(toHex(decoded.payload.value), toHex(inner)); -} - -console.log("all 6 wire-equality tests passed"); diff --git a/js/packages/truapi/test/wire-table-loop.test.mjs b/js/packages/truapi/test/wire-table-loop.test.mjs deleted file mode 100644 index db0ae4c0..00000000 --- a/js/packages/truapi/test/wire-table-loop.test.mjs +++ /dev/null @@ -1,67 +0,0 @@ -// Programmatic wire-equality loop. -// -// `wire-equality.test.mjs` exercises a handful of hand-picked frames. This file -// iterates every generated numeric frame id and asserts the codec round-trips a -// sentinel payload and produces the expected byte layout for each. -// -// Run via: `bun run test`. - -import assert from "node:assert/strict"; -import { decodeWireMessage, encodeWireMessage } from "../src/transport.ts"; -import * as W from "../src/generated/wire-table.ts"; -import { str } from "../src/scale.ts"; - -function toHex(u) { - return Array.from(u) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); -} - -function expectedWire(reqId, tagId, valueBytes) { - const idBytes = str.enc(reqId); - const out = new Uint8Array(idBytes.length + 1 + valueBytes.length); - out.set(idBytes, 0); - out[idBytes.length] = tagId; - out.set(valueBytes, idBytes.length + 1); - return out; -} - -/** Return the successful result value or fail the assertion with context. */ -function unwrap(result, message) { - return result.match( - (value) => value, - (error) => assert.fail(`${message}: ${error.message}`), - ); -} - -const frames = Object.entries(W).flatMap(([method, ids]) => - Object.entries(ids).map(([kind, id]) => ({ method, kind, id })), -); -assert.ok(frames.length > 0, "wire frame constants must not be empty"); - -// Use a per-id sentinel payload so any cross-talk between ids surfaces as a -// concrete byte mismatch rather than a silent equality. -let checked = 0; -for (const { method, kind, id } of frames) { - const sentinel = new Uint8Array([id, 0xa5, ~id & 0xff, 0x5a]); - const message = { - requestId: `r:${id}`, - payload: { id, value: sentinel }, - }; - const label = `${method}.${kind}`; - const encoded = unwrap(encodeWireMessage(message), `encode ${label}`); - const expected = expectedWire(`r:${id}`, id, sentinel); - assert.equal(toHex(encoded), toHex(expected), `encode mismatch for ${label}`); - - const decoded = unwrap(decodeWireMessage(encoded), `decode ${label}`); - assert.equal(decoded.requestId, `r:${id}`, `requestId mismatch for ${label}`); - assert.equal(decoded.payload.id, id, `id mismatch for ${label}`); - assert.equal( - toHex(decoded.payload.value), - toHex(sentinel), - `payload mismatch for ${label}`, - ); - checked++; -} - -console.log(`programmatic wire-table loop: ${checked} frame ids round-tripped`); diff --git a/js/packages/truapi/tsconfig.json b/js/packages/truapi/tsconfig.json index 71725ac1..79d35ea5 100644 --- a/js/packages/truapi/tsconfig.json +++ b/js/packages/truapi/tsconfig.json @@ -12,5 +12,6 @@ "esModuleInterop": true, "skipLibCheck": true }, - "include": ["src"] + "include": ["src"], + "exclude": ["src/**/*.test.ts"] } diff --git a/js/packages/truapi/vitest.config.ts b/js/packages/truapi/vitest.config.ts new file mode 100644 index 00000000..ae847ff6 --- /dev/null +++ b/js/packages/truapi/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/**/*.test.ts"], + }, +}); diff --git a/package-lock.json b/package-lock.json index d3b7cc93..ea2e08ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,8 @@ "scale-ts": "^1.6.1" }, "devDependencies": { - "typescript": "^6.0" + "typescript": "^6.0", + "vitest": "^3.2.0" } }, "js/packages/truapi/node_modules/typescript": { @@ -284,135 +285,1098 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/external-editor": { "version": "1.0.3", "dev": true, "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@manypkg/find-root/node_modules/@types/node": { + "version": "12.20.55", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/find-root/node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parity/truapi": { + "resolved": "js/packages/truapi", + "link": true + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@manypkg/find-root": { - "version": "1.1.0", + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.5.5", - "@types/node": "^12.7.1", - "find-up": "^4.1.0", - "fs-extra": "^8.1.0" + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/@manypkg/find-root/node_modules/@types/node": { - "version": "12.20.55", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, - "node_modules/@manypkg/find-root/node_modules/fs-extra": { - "version": "8.1.0", + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" }, - "engines": { - "node": ">=6 <7 || >=8" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@manypkg/get-packages": { - "version": "1.1.3", + "node_modules/@vitest/mocker": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.5.5", - "@changesets/types": "^4.0.1", - "@manypkg/find-root": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "^11.0.0", - "read-yaml-file": "^1.1.0" + "@vitest/spy": "3.2.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { - "version": "4.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@manypkg/get-packages/node_modules/fs-extra": { - "version": "8.1.0", + "node_modules/@vitest/pretty-format": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "tinyrainbow": "^2.0.0" }, - "engines": { - "node": ">=6 <7 || >=8" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", + "node_modules/@vitest/runner": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@vitest/utils": "3.2.6", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", + "node_modules/@vitest/snapshot": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", + "node_modules/@vitest/spy": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "tinyspy": "^4.0.3" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@parity/truapi": { - "resolved": "js/packages/truapi", - "link": true - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.3", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], + "node_modules/@vitest/utils": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, "node_modules/ansi-colors": { "version": "4.1.3", @@ -443,6 +1407,16 @@ "node": ">=8" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/better-path-resolve": { "version": "1.0.0", "dev": true, @@ -465,11 +1439,48 @@ "node": ">=8" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/chardet": { "version": "2.1.1", "dev": true, "license": "MIT" }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "dev": true, @@ -483,6 +1494,34 @@ "node": ">= 8" } }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-indent": { "version": "6.1.0", "dev": true, @@ -514,6 +1553,55 @@ "node": ">=8.6" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, "node_modules/esprima": { "version": "4.0.1", "dev": true, @@ -526,6 +1614,26 @@ "node": ">=4" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/extendable-error": { "version": "0.1.7", "dev": true, @@ -587,7 +1695,22 @@ "universalify": "^0.1.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/glob-parent": { @@ -707,6 +1830,13 @@ "dev": true, "license": "ISC" }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.1", "dev": true, @@ -742,6 +1872,23 @@ "dev": true, "license": "MIT" }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/merge2": { "version": "1.4.1", "dev": true, @@ -770,6 +1917,32 @@ "node": ">=4" } }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/neverthrow": { "version": "8.2.0", "license": "MIT", @@ -869,6 +2042,23 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { "version": "1.1.1", "dev": true, @@ -893,6 +2083,35 @@ "node": ">=6" } }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/prettier": { "version": "3.8.3", "dev": true, @@ -992,6 +2211,51 @@ "node": ">=0.10.0" } }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "dev": true, @@ -1053,6 +2317,13 @@ "node": ">=8" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "dev": true, @@ -1072,6 +2343,16 @@ "node": ">=8" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spawndamnit": { "version": "3.0.1", "dev": true, @@ -1086,6 +2367,20 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/strip-ansi": { "version": "6.0.1", "dev": true, @@ -1105,6 +2400,19 @@ "node": ">=4" } }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/term-size": { "version": "2.2.1", "dev": true, @@ -1116,6 +2424,98 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "dev": true, @@ -1135,6 +2535,221 @@ "node": ">= 4.0.0" } }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.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 + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/which": { "version": "2.0.2", "dev": true, @@ -1148,6 +2763,23 @@ "engines": { "node": ">= 8" } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } } } } From 96af0a074cdfb18c57a0cd24f7e4d7d571a4ebd9 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 26 Jun 2026 11:16:47 +0200 Subject: [PATCH 2/5] test(truapi): run the suite with bun test instead of Vitest Use Bun's built-in test runner: the repo already depends on bun, so this drops the Vitest devDependency (and its config) while keeping the same product-sdk-style describe/it/expect tests. - Imports come from "bun:test"; add @types/bun for editor support. - test script runs `bun test` (auto-discovers src/**/*.test.ts, no config). - Restore the setup-bun step on the ts-client CI job. - Refresh docs and the ts-client-checks skill. --- .claude/skills/ts-client-checks/SKILL.md | 9 +- .github/workflows/ci.yml | 4 + CLAUDE.md | 2 +- docs/local-e2e-testing.md | 2 +- js/packages/truapi/README.md | 2 +- js/packages/truapi/package.json | 8 +- js/packages/truapi/src/client.test.ts | 2 +- .../truapi/src/explorer/versions.test.ts | 2 +- js/packages/truapi/src/transport.test.ts | 2 +- js/packages/truapi/src/wire-equality.test.ts | 2 +- js/packages/truapi/src/wire-table.test.ts | 2 +- js/packages/truapi/vitest.config.ts | 7 - package-lock.json | 1820 ++--------------- 13 files changed, 135 insertions(+), 1729 deletions(-) delete mode 100644 js/packages/truapi/vitest.config.ts diff --git a/.claude/skills/ts-client-checks/SKILL.md b/.claude/skills/ts-client-checks/SKILL.md index 7f7ace15..450f6b25 100644 --- a/.claude/skills/ts-client-checks/SKILL.md +++ b/.claude/skills/ts-client-checks/SKILL.md @@ -1,6 +1,6 @@ --- name: ts-client-checks -description: Build and smoke-test the @parity/truapi TypeScript package (tsc + Vitest). Use after regenerating the client or after touching js/packages/truapi/. +description: Build and smoke-test the @parity/truapi TypeScript package (tsc + bun test). Use after regenerating the client or after touching js/packages/truapi/. --- # `@parity/truapi` build + smoke tests @@ -13,13 +13,14 @@ npm run build npm test ``` -`npm test` runs the [Vitest](https://vitest.dev/) suite (`src/**/*.test.ts`), -which loads the source `.ts` files directly (no build step required). +`npm test` runs the [`bun test`](https://bun.sh/docs/cli/test) suite +(`src/**/*.test.ts`) directly against the source `.ts` files (no build step +required), so bun must be installed. Expected: - `tsc` (the `build` step) exits cleanly with no diagnostics. -- Vitest reports `Test Files N passed` / `Tests M passed` with no failures. +- `bun test` reports `N pass` / `0 fail` across the `src/**/*.test.ts` files. - `src/wire-table.test.ts` emits one `round-trips .` case per generated frame id. The case count tracks `WIRE_TABLE`: adding a method grows it by 2 (request + response) or 4 (subscribe). diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a2dbc24..ec6fe06d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,6 +117,10 @@ jobs: with: node-version: 22 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: latest + - name: Download codegen output uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: diff --git a/CLAUDE.md b/CLAUDE.md index f6642454..0116c828 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,7 +80,7 @@ cargo test --workspace ```bash cd js/packages/truapi npm run build -npm test # Vitest suite (src/**/*.test.ts) +npm test # bun test suite (src/**/*.test.ts) ``` ### Explorer diff --git a/docs/local-e2e-testing.md b/docs/local-e2e-testing.md index 3dd0e5be..f646e2db 100644 --- a/docs/local-e2e-testing.md +++ b/docs/local-e2e-testing.md @@ -105,7 +105,7 @@ npm test Expected: - `tsc` (the `build` step) exits cleanly with no diagnostics. -- Vitest reports `Test Files N passed` / `Tests M passed` with no failures. +- `bun test` reports `N pass` / `0 fail` across the `src/**/*.test.ts` files. - `src/wire-table.test.ts` emits one `round-trips .` case per generated frame id; the count tracks `WIRE_TABLE`. When you add a method, it grows by 2 (request + response) or 4 (subscribe). diff --git a/js/packages/truapi/README.md b/js/packages/truapi/README.md index 54632f76..dae112d2 100644 --- a/js/packages/truapi/README.md +++ b/js/packages/truapi/README.md @@ -127,7 +127,7 @@ npm run build npm test ``` -On a clean checkout, the first build or test run will generate the ignored TypeScript outputs from the Rust sources, so Rust stable + nightly must be installed locally. `npm test` runs the package's [Vitest](https://vitest.dev/) suite (`src/**/*.test.ts`), which loads the source `.ts` files directly without a build step. +On a clean checkout, the first build or test run will generate the ignored TypeScript outputs from the Rust sources, so Rust stable + nightly must be installed locally. `npm test` runs the package's [`bun test`](https://bun.sh/docs/cli/test) suite (`src/**/*.test.ts`) directly against the source `.ts` files (no build step), so [bun](https://bun.sh/) must also be installed. ## License diff --git a/js/packages/truapi/package.json b/js/packages/truapi/package.json index 68a539c0..b462528b 100644 --- a/js/packages/truapi/package.json +++ b/js/packages/truapi/package.json @@ -71,12 +71,12 @@ "codegen": "cargo run -p truapi-codegen -- --input ../../../target/doc/truapi.json --output src/generated --playground-output src/playground --explorer-output src/explorer", "typecheck": "npm run build", "pretest": "npm run ensure-generated", - "test": "vitest run", - "test:watch": "vitest" + "test": "bun test", + "test:watch": "bun test --watch" }, "devDependencies": { - "typescript": "^6.0", - "vitest": "^3.2.0" + "@types/bun": "^1.3.0", + "typescript": "^6.0" }, "dependencies": { "neverthrow": "^8.2.0", diff --git a/js/packages/truapi/src/client.test.ts b/js/packages/truapi/src/client.test.ts index 4075c0ae..2f8d2023 100644 --- a/js/packages/truapi/src/client.test.ts +++ b/js/packages/truapi/src/client.test.ts @@ -1,5 +1,5 @@ import type { Result } from "neverthrow"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it } from "bun:test"; import { createTransport } from "./client.js"; import { indexedTaggedUnion, Result as ScaleResult, str, _void } from "./scale.js"; diff --git a/js/packages/truapi/src/explorer/versions.test.ts b/js/packages/truapi/src/explorer/versions.test.ts index 1f36eef5..57d3ce1c 100644 --- a/js/packages/truapi/src/explorer/versions.test.ts +++ b/js/packages/truapi/src/explorer/versions.test.ts @@ -5,7 +5,7 @@ // `DataType` in the same version. That cross-reference is the load-bearing // invariant the explorer site relies on for type navigation. -import { describe, expect, it } from "vitest"; +import { describe, expect, it } from "bun:test"; import { packageVersion, versions } from "./versions.js"; diff --git a/js/packages/truapi/src/transport.test.ts b/js/packages/truapi/src/transport.test.ts index 4f4d6ffd..215817bc 100644 --- a/js/packages/truapi/src/transport.test.ts +++ b/js/packages/truapi/src/transport.test.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { createIframeProvider, createMessagePortProvider } from "./transport.js"; diff --git a/js/packages/truapi/src/wire-equality.test.ts b/js/packages/truapi/src/wire-equality.test.ts index bdec5f0e..af656c48 100644 --- a/js/packages/truapi/src/wire-equality.test.ts +++ b/js/packages/truapi/src/wire-equality.test.ts @@ -6,7 +6,7 @@ // independently and compare. import type { Result } from "neverthrow"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it } from "bun:test"; import { str } from "./scale.js"; import { decodeWireMessage, encodeWireMessage } from "./transport.js"; diff --git a/js/packages/truapi/src/wire-table.test.ts b/js/packages/truapi/src/wire-table.test.ts index 31d768c4..579d3bd9 100644 --- a/js/packages/truapi/src/wire-table.test.ts +++ b/js/packages/truapi/src/wire-table.test.ts @@ -5,7 +5,7 @@ // sentinel payload and produces the expected byte layout for each. import type { Result } from "neverthrow"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it } from "bun:test"; import { str } from "./scale.js"; import { decodeWireMessage, encodeWireMessage } from "./transport.js"; diff --git a/js/packages/truapi/vitest.config.ts b/js/packages/truapi/vitest.config.ts deleted file mode 100644 index ae847ff6..00000000 --- a/js/packages/truapi/vitest.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - include: ["src/**/*.test.ts"], - }, -}); diff --git a/package-lock.json b/package-lock.json index ea2e08ef..d72aab67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,8 +25,8 @@ "scale-ts": "^1.6.1" }, "devDependencies": { - "typescript": "^6.0", - "vitest": "^3.2.0" + "@types/bun": "^1.3.0", + "typescript": "^6.0" } }, "js/packages/truapi/node_modules/typescript": { @@ -285,1097 +285,156 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/external-editor": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@manypkg/find-root": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.5.5", - "@types/node": "^12.7.1", - "find-up": "^4.1.0", - "fs-extra": "^8.1.0" - } - }, - "node_modules/@manypkg/find-root/node_modules/@types/node": { - "version": "12.20.55", - "dev": true, - "license": "MIT" - }, - "node_modules/@manypkg/find-root/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@manypkg/get-packages": { - "version": "1.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.5.5", - "@changesets/types": "^4.0.1", - "@manypkg/find-root": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "^11.0.0", - "read-yaml-file": "^1.1.0" - } - }, - "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { - "version": "4.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@manypkg/get-packages/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@parity/truapi": { - "resolved": "js/packages/truapi", - "link": true - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", - "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", - "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", - "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", - "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", - "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", - "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", - "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", - "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", - "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", - "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", - "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", - "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", - "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", - "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", - "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", - "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", - "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", - "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", - "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", - "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", - "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", - "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", - "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", - "cpu": [ - "ia32" - ], + "node_modules/@manypkg/find-root": { + "version": "1.1.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", - "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", - "cpu": [ - "x64" - ], + "node_modules/@manypkg/find-root/node_modules/@types/node": { + "version": "12.20.55", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", - "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", - "cpu": [ - "x64" - ], + "node_modules/@manypkg/find-root/node_modules/fs-extra": { + "version": "8.1.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", "dev": true, "license": "MIT", "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" } }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", "dev": true, "license": "MIT" }, - "node_modules/@vitest/expect": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", - "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", "dev": true, "license": "MIT", "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.6", - "@vitest/utils": "3.2.6", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=6 <7 || >=8" } }, - "node_modules/@vitest/mocker": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", - "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.2.6", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } + "engines": { + "node": ">= 8" } }, - "node_modules/@vitest/pretty-format": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", - "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", "dev": true, "license": "MIT", - "dependencies": { - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">= 8" } }, - "node_modules/@vitest/runner": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", - "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.2.6", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">= 8" } }, - "node_modules/@vitest/snapshot": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", - "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", - "dev": true, + "node_modules/@parity/truapi": { + "resolved": "js/packages/truapi", + "link": true + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "3.2.6", - "magic-string": "^0.30.17", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@vitest/spy": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", - "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", + "node_modules/@types/bun": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.3.14.tgz", + "integrity": "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw==", "dev": true, "license": "MIT", "dependencies": { - "tinyspy": "^4.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "bun-types": "1.3.14" } }, - "node_modules/@vitest/utils": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", - "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "node_modules/@types/node": { + "version": "26.0.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.1.tgz", + "integrity": "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.6", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "undici-types": "~8.3.0" } }, "node_modules/ansi-colors": { @@ -1407,16 +466,6 @@ "node": ">=8" } }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/better-path-resolve": { "version": "1.0.0", "dev": true, @@ -1439,31 +488,14 @@ "node": ">=8" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "node_modules/bun-types": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.3.14.tgz", + "integrity": "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==", "dev": true, "license": "MIT", "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, - "engines": { - "node": ">=18" + "@types/node": "*" } }, "node_modules/chardet": { @@ -1471,16 +503,6 @@ "dev": true, "license": "MIT" }, - "node_modules/check-error": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", - "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "dev": true, @@ -1494,34 +516,6 @@ "node": ">= 8" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/detect-indent": { "version": "6.1.0", "dev": true, @@ -1553,55 +547,6 @@ "node": ">=8.6" } }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" - } - }, "node_modules/esprima": { "version": "4.0.1", "dev": true, @@ -1614,26 +559,6 @@ "node": ">=4" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/extendable-error": { "version": "0.1.7", "dev": true, @@ -1698,21 +623,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "dev": true, @@ -1828,14 +738,7 @@ "node_modules/isexe": { "version": "2.0.0", "dev": true, - "license": "ISC" - }, - "node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" + "license": "ISC" }, "node_modules/js-yaml": { "version": "4.1.1", @@ -1872,23 +775,6 @@ "dev": true, "license": "MIT" }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/merge2": { "version": "1.4.1", "dev": true, @@ -1917,32 +803,6 @@ "node": ">=4" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/neverthrow": { "version": "8.2.0", "license": "MIT", @@ -2042,23 +902,6 @@ "node": ">=8" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.16" - } - }, "node_modules/picocolors": { "version": "1.1.1", "dev": true, @@ -2083,35 +926,6 @@ "node": ">=6" } }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/prettier": { "version": "3.8.3", "dev": true, @@ -2211,51 +1025,6 @@ "node": ">=0.10.0" } }, - "node_modules/rollup": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", - "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.2", - "@rollup/rollup-android-arm64": "4.62.2", - "@rollup/rollup-darwin-arm64": "4.62.2", - "@rollup/rollup-darwin-x64": "4.62.2", - "@rollup/rollup-freebsd-arm64": "4.62.2", - "@rollup/rollup-freebsd-x64": "4.62.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", - "@rollup/rollup-linux-arm-musleabihf": "4.62.2", - "@rollup/rollup-linux-arm64-gnu": "4.62.2", - "@rollup/rollup-linux-arm64-musl": "4.62.2", - "@rollup/rollup-linux-loong64-gnu": "4.62.2", - "@rollup/rollup-linux-loong64-musl": "4.62.2", - "@rollup/rollup-linux-ppc64-gnu": "4.62.2", - "@rollup/rollup-linux-ppc64-musl": "4.62.2", - "@rollup/rollup-linux-riscv64-gnu": "4.62.2", - "@rollup/rollup-linux-riscv64-musl": "4.62.2", - "@rollup/rollup-linux-s390x-gnu": "4.62.2", - "@rollup/rollup-linux-x64-gnu": "4.62.2", - "@rollup/rollup-linux-x64-musl": "4.62.2", - "@rollup/rollup-openbsd-x64": "4.62.2", - "@rollup/rollup-openharmony-arm64": "4.62.2", - "@rollup/rollup-win32-arm64-msvc": "4.62.2", - "@rollup/rollup-win32-ia32-msvc": "4.62.2", - "@rollup/rollup-win32-x64-gnu": "4.62.2", - "@rollup/rollup-win32-x64-msvc": "4.62.2", - "fsevents": "~2.3.2" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "dev": true, @@ -2317,13 +1086,6 @@ "node": ">=8" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, "node_modules/signal-exit": { "version": "4.1.0", "dev": true, @@ -2343,16 +1105,6 @@ "node": ">=8" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/spawndamnit": { "version": "3.0.1", "dev": true, @@ -2367,20 +1119,6 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, "node_modules/strip-ansi": { "version": "6.0.1", "dev": true, @@ -2400,19 +1138,6 @@ "node": ">=4" } }, - "node_modules/strip-literal": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", - "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/term-size": { "version": "2.2.1", "dev": true, @@ -2424,98 +1149,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, - "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", - "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "dev": true, @@ -2527,6 +1160,13 @@ "node": ">=8.0" } }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, "node_modules/universalify": { "version": "0.1.2", "dev": true, @@ -2535,221 +1175,6 @@ "node": ">= 4.0.0" } }, - "node_modules/vite": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", - "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0 || ^0.28.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.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 - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", - "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", - "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.6", - "@vitest/mocker": "3.2.6", - "@vitest/pretty-format": "^3.2.6", - "@vitest/runner": "3.2.6", - "@vitest/snapshot": "3.2.6", - "@vitest/spy": "3.2.6", - "@vitest/utils": "3.2.6", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.6", - "@vitest/ui": "3.2.6", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/which": { "version": "2.0.2", "dev": true, @@ -2763,23 +1188,6 @@ "engines": { "node": ">= 8" } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } } } } From 9fbaaf404226cf96da68beadac5c1b4b61fb5cd7 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Fri, 26 Jun 2026 11:36:53 +0200 Subject: [PATCH 3/5] refactor(truapi): iframe MessagePort handshake and SCALE codec additions Switch the in-iframe client to the host-transferred MessagePort handshake (truapi-ready / truapi-init) used by the WASM host runtime, and extend the SCALE primitives (Struct, _void, str, hex helpers) consumed by the generated codecs. Pulls @noble/hashes in as a hex-codec dependency. --- js/packages/truapi/package.json | 1 + js/packages/truapi/src/sandbox.ts | 115 ++++++++++-- js/packages/truapi/src/scale.ts | 71 +++++-- js/packages/truapi/src/transport.ts | 4 + package-lock.json | 13 ++ playground/CLAUDE.md | 3 + playground/src/app/page.tsx | 2 + playground/src/components/DiagnosisView.tsx | 33 +++- playground/src/components/ServiceTable.tsx | 1 + playground/src/lib/auto-test.ts | 32 ++-- playground/src/lib/diagnosis-report.ts | 5 +- playground/src/lib/e2e-hooks.ts | 198 ++++++++++++++++++++ playground/src/lib/example-runner.ts | 5 +- playground/tests/e2e/handshake.spec.ts | 6 +- playground/tests/e2e/helpers.ts | 2 +- playground/tests/e2e/login-modal.spec.ts | 68 +++++++ playground/tests/e2e/subscription.spec.ts | 7 +- playground/tests/e2e/unary.spec.ts | 6 +- playground/yarn.lock | 5 + 19 files changed, 510 insertions(+), 67 deletions(-) create mode 100644 playground/src/lib/e2e-hooks.ts create mode 100644 playground/tests/e2e/login-modal.spec.ts diff --git a/js/packages/truapi/package.json b/js/packages/truapi/package.json index b462528b..6b8e2f61 100644 --- a/js/packages/truapi/package.json +++ b/js/packages/truapi/package.json @@ -79,6 +79,7 @@ "typescript": "^6.0" }, "dependencies": { + "@noble/hashes": "^2.2.0", "neverthrow": "^8.2.0", "scale-ts": "^1.6.1" } diff --git a/js/packages/truapi/src/sandbox.ts b/js/packages/truapi/src/sandbox.ts index 51861e4e..1e338fea 100644 --- a/js/packages/truapi/src/sandbox.ts +++ b/js/packages/truapi/src/sandbox.ts @@ -11,7 +11,6 @@ */ import { - createIframeProvider, createMessagePortProvider, type WireProvider, } from "./transport.js"; @@ -62,10 +61,7 @@ export function isCorrectEnvironment(): boolean { } /** - * Origin used as the `targetOrigin` for outbound `postMessage` frames. Frames - * carry signed payloads and account ids, so this fails closed: when no concrete - * origin can be pinned it returns `null` (rather than falling back to `"*"`) and - * provider construction throws. + * Origin used as the `targetOrigin` for iframe bootstrap messages. */ function resolveHostOrigin(): string | null { if (typeof document !== "undefined" && document.referrer) { @@ -80,7 +76,8 @@ function resolveHostOrigin(): string | null { return null; } -const WEBVIEW_PORT_TIMEOUT_MS = 20_000; +const HOST_PORT_TIMEOUT_MS = 20_000; +let iframePortPromise: Promise | null = null; /** * Resolve the host-injected `MessagePort`, polling `window.__HOST_API_PORT__` @@ -93,7 +90,7 @@ const WEBVIEW_PORT_TIMEOUT_MS = 20_000; */ async function waitForWebviewPort( signal?: AbortSignal, - timeoutMs = WEBVIEW_PORT_TIMEOUT_MS, + timeoutMs = HOST_PORT_TIMEOUT_MS, ): Promise { const start = Date.now(); while (Date.now() - start < timeoutMs) { @@ -107,18 +104,93 @@ async function waitForWebviewPort( ); } +/** + * Resolve the iframe `MessagePort` transferred by `createIframeHost`. + */ +function waitForIframePort( + signal?: AbortSignal, + timeoutMs = HOST_PORT_TIMEOUT_MS, +): Promise { + const existing = hostWindow()?.__HOST_API_PORT__; + if (existing) return Promise.resolve(existing); + if (iframePortPromise) return iframePortPromise; + + iframePortPromise = new Promise((resolve, reject) => { + const win = hostWindow(); + if (!win) { + reject(new Error("window is unavailable")); + return; + } + + const hostOrigin = resolveHostOrigin(); + let done = false; + const cleanup = (): void => { + win.removeEventListener("message", onMessage); + signal?.removeEventListener("abort", onAbort); + clearTimeout(timer); + }; + const finish = (result: MessagePort | Error): void => { + if (done) return; + done = true; + cleanup(); + if (result instanceof Error) { + reject(result); + } else { + win.__HOST_API_PORT__ = result; + resolve(result); + } + }; + const onAbort = (): void => { + finish(new Error("waitForIframePort aborted")); + }; + const onMessage = (event: MessageEvent): void => { + if (event.source !== win.parent) return; + if ( + hostOrigin !== null && + event.origin !== hostOrigin && + event.origin !== "null" + ) { + return; + } + if (event.data?.type !== "truapi-init") return; + const [port] = event.ports; + if (!port) { + finish(new Error("truapi-init did not include a MessagePort")); + return; + } + finish(port); + }; + const timer = setTimeout(() => { + finish( + new Error(`Timed out waiting for iframe MessagePort (${timeoutMs}ms)`), + ); + }, timeoutMs); + + win.addEventListener("message", onMessage); + signal?.addEventListener("abort", onAbort, { once: true }); + win.parent.postMessage({ type: "truapi-ready" }, hostOrigin ?? "*"); + }).catch((error: unknown) => { + iframePortPromise = null; + throw error; + }); + + return iframePortPromise; +} + /** Build the {@link WireProvider} matching the detected environment (iframe or webview). */ function createSandboxProvider(): WireProvider { + const portController = new AbortController(); if (isIframe()) { - const hostOrigin = resolveHostOrigin(); - if (!hostOrigin) { - throw new Error( - "TrUAPI iframe provider could not resolve the host origin from document.referrer / ancestorOrigins.", - ); - } - return createIframeProvider({ target: window.parent, hostOrigin }); + const provider = createMessagePortProvider( + waitForIframePort(portController.signal), + ); + const baseDispose = provider.dispose; + provider.dispose = () => { + portController.abort(); + baseDispose?.(); + }; + return provider; } - const portController = new AbortController(); const provider = createMessagePortProvider( waitForWebviewPort(portController.signal), ); @@ -166,14 +238,21 @@ export function getClientSync(): TrUApiClient | null { export function subscribeConnectionStatus( callback: (status: ConnectionStatus) => void, ): () => void { - statusListeners.add(callback); - callback(status); + let emitted = false; + const listener = (next: ConnectionStatus) => { + emitted = true; + callback(next); + }; + statusListeners.add(listener); if (status === "disconnected") { setStatus(getClientSync() ? "connected" : "disconnected"); } + if (!emitted) { + callback(status); + } return () => { - statusListeners.delete(callback); + statusListeners.delete(listener); }; } diff --git a/js/packages/truapi/src/scale.ts b/js/packages/truapi/src/scale.ts index ac92039b..f5670ffa 100644 --- a/js/packages/truapi/src/scale.ts +++ b/js/packages/truapi/src/scale.ts @@ -8,17 +8,25 @@ import { Bytes, Enum, + Struct, + _void, createCodec, createDecoder, enhanceCodec, + str as scaleStr, u8, type Codec, } from "scale-ts"; +import { + bytesToHex as encodeHex, + hexToBytes as decodeHex, +} from "@noble/hashes/utils.js"; export type { Codec }; export type { ResultPayload } from "scale-ts"; export { + Bytes, Enum, Option, Result, @@ -59,7 +67,9 @@ export const OptionBool: Codec = enhanceCodec( case 2: return false; default: - throw new Error(`Unknown OptionBool byte: ${byte}. Expected 0, 1, or 2.`); + throw new Error( + `Unknown OptionBool byte: ${byte}. Expected 0, 1, or 2.`, + ); } }, ); @@ -79,22 +89,12 @@ export function toHexString(value: string): HexString { /** Encode a byte array as a lower-case hex string with a `0x` prefix. */ export function bytesToHex(bytes: Uint8Array): HexString { - let hex = "0x"; - for (let i = 0; i < bytes.length; i++) { - hex += bytes[i]!.toString(16).padStart(2, "0"); - } - return hex as HexString; + return `0x${encodeHex(bytes)}`; } /** Decode a hex string into a byte array. Tolerates a missing `0x` prefix. */ export function hexToBytes(hex: string): Uint8Array { - const start = hex.startsWith("0x") ? 2 : 0; - const length = (hex.length - start) >> 1; - const bytes = new Uint8Array(length); - for (let i = 0; i < length; i++) { - bytes[i] = parseInt(hex.substring(start + i * 2, start + i * 2 + 2), 16); - } - return bytes; + return decodeHex(hex.startsWith("0x") ? hex.slice(2) : hex); } /** @@ -123,6 +123,51 @@ export function TaggedUnion( return Enum(inner) as unknown as Codec>; } +/** + * Wire codec for Rust `CallError`, projected to the public domain error `D`. + * + * Generated TypeScript APIs expose only the domain error union in + * `ResultAsync`. The Rust host still wraps that value in + * `CallError::Domain` on the wire so framework errors can share the response + * channel. Encoding always emits `Domain`; decoding returns the inner domain + * value and throws for framework-level failures that have no public `D` shape. + */ +export function CallError(domain: Codec): Codec { + type WireCallError = + | { tag: "Domain"; value: D } + | { tag: "Denied"; value?: undefined } + | { tag: "Unsupported"; value?: undefined } + | { tag: "MalformedFrame"; value: { reason: string } } + | { tag: "HostFailure"; value: { reason: string } }; + + const wire = Enum({ + Domain: domain, + Denied: _void, + Unsupported: _void, + MalformedFrame: Struct({ reason: scaleStr }), + HostFailure: Struct({ reason: scaleStr }), + }) as unknown as Codec; + + return enhanceCodec( + wire, + (value: D): WireCallError => ({ tag: "Domain", value }), + (value: WireCallError): D => { + switch (value.tag) { + case "Domain": + return value.value; + case "Denied": + throw new Error("Host denied the request"); + case "Unsupported": + throw new Error("Host does not support this request"); + case "MalformedFrame": + throw new Error(`Malformed request frame: ${value.value.reason}`); + case "HostFailure": + throw new Error(`Host failure: ${value.value.reason}`); + } + }, + ); +} + type TaggedUnionCodecs = { [Sym: symbol]: never; [Num: number]: never; diff --git a/js/packages/truapi/src/transport.ts b/js/packages/truapi/src/transport.ts index f2059342..3b1d5c93 100644 --- a/js/packages/truapi/src/transport.ts +++ b/js/packages/truapi/src/transport.ts @@ -279,6 +279,10 @@ export interface WireProvider { /** * Register a callback for provider-level close or failure events. + * + * Providers keep a terminal close reason. The callback fires at most once + * for an active subscription, and fires immediately when registered after + * the provider has already closed. **/ subscribeClose?(callback: (error: Error) => void): () => void; diff --git a/package-lock.json b/package-lock.json index d72aab67..51905f9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "version": "0.3.1", "license": "MIT", "dependencies": { + "@noble/hashes": "^2.2.0", "neverthrow": "^8.2.0", "scale-ts": "^1.6.1" }, @@ -365,6 +366,18 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, diff --git a/playground/CLAUDE.md b/playground/CLAUDE.md index a5d6ce72..093e4c60 100644 --- a/playground/CLAUDE.md +++ b/playground/CLAUDE.md @@ -7,6 +7,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co An interactive explorer for the TrUAPI, the Host API surface exposed to products running inside the Polkadot Desktop Browser webview. The app must be opened from within a Host environment. It talks to the host over iframe `postMessage` frames or the native webview `window.__HOST_API_PORT__` MessagePort. To develop locally, run `yarn dev` and open the app via `https://dot.li/localhost:3000` inside the Desktop Host. +For host-backed diagnosis/e2e runs, signer-bot settings may live in the +repo-root `.env`; if they are not present in the current worktree environment, +load or copy them from that file before treating signer-bot as unavailable. ## Commands diff --git a/playground/src/app/page.tsx b/playground/src/app/page.tsx index 9df8e0be..d8205f86 100644 --- a/playground/src/app/page.tsx +++ b/playground/src/app/page.tsx @@ -23,6 +23,7 @@ import { runDiagnosis, runSingleTest, } from "@/src/lib/auto-test"; +import { installE2EHooks } from "@/src/lib/e2e-hooks"; import packageJson from "../../package.json"; const VERSION_LABEL = `v${packageJson.version}`; @@ -188,6 +189,7 @@ export default function PlaygroundPage() { useEffect(() => { try { + installE2EHooks(); return subscribeConnectionStatus(setStatus); } catch { setStatus("disconnected"); diff --git a/playground/src/components/DiagnosisView.tsx b/playground/src/components/DiagnosisView.tsx index 7cbfa7bf..0200a0b6 100644 --- a/playground/src/components/DiagnosisView.tsx +++ b/playground/src/components/DiagnosisView.tsx @@ -72,13 +72,17 @@ export function DiagnosisView({ }; }, [services, testResults]); + const reportMarkdown = useMemo( + () => + hasResults && !isRunning + ? renderReportMarkdown(services, testResults) + : "", + [hasResults, isRunning, services, testResults], + ); + const handleCopyReport = async () => { try { - // Rendered on demand: the full report is only needed on copy, not on - // every per-method result update during a run. - await navigator.clipboard.writeText( - renderReportMarkdown(services, testResults), - ); + await navigator.clipboard.writeText(reportMarkdown); setCopied(true); setTimeout(() => setCopied(false), 1500); } catch { @@ -92,7 +96,7 @@ export function DiagnosisView({ // Copy the report to the clipboard first as a fallback if the body is // truncated. const handleSubmitReport = () => { - const report = renderReportMarkdown(services, testResults); + const report = reportMarkdown; void navigator.clipboard?.writeText(report).catch(() => {}); const url = reportIssueUrl(report, detectHostMode()); // No-op outside a host container; navigation is best-effort. @@ -143,7 +147,12 @@ export function DiagnosisView({ Stop ) : ( - @@ -151,6 +160,7 @@ export function DiagnosisView({ {hasResults && ( 0} > {passCount} success · {failCount} failed @@ -158,9 +168,17 @@ export function DiagnosisView({ )} {hasResults && !isRunning && (
+