diff --git a/.github/workflows/integration-protect-ffi.yml b/.github/workflows/integration-protect-ffi.yml index f95d4c743..cd7bb98c8 100644 --- a/.github/workflows/integration-protect-ffi.yml +++ b/.github/workflows/integration-protect-ffi.yml @@ -14,17 +14,17 @@ name: Integration — protect-ffi (native + WASM) # `packages/protect-ffi/src/integrationSuiteCi.test.ts` asserts this file (or a # successor) still invokes it. # -# WHY THERE IS npm IN A pnpm REPO. `integration-tests/` is deliberately NOT a -# pnpm workspace member: it pins `@cipherstash/auth ^0.39.0`, `vitest ^3.1.3` -# and `@cipherstash/eql 3.0.2` independently of the repo catalog, which is part -# of what it tests — the suite proves the published FFI surface works for a -# consumer resolving its own dependency tree, not the one the monorepo happens -# to hoist. So it keeps its own `package-lock.json` and `mise run setup` installs -# it with `npm ci`. That is not a supply-chain regression: `npm ci` installs the -# lockfile exactly (it fails rather than resolving anything new) and verifies -# every tarball against the `integrity` hash recorded there, and the registry is -# npmjs. Absorbing the suite into the pnpm workspace is a follow-up that changes -# those pins, and changed pins can only be validated by a credentialed run. +# WHERE THE SUITE'S DEPENDENCIES COME FROM. `integration-tests/` is a pnpm +# workspace member (CIP-3744) and installs with the repo's own +# `pnpm install --frozen-lockfile`, like everything else here. It used to sit +# outside the workspace with its own `package-lock.json` and an `npm ci`, pinning +# `@cipherstash/auth ^0.39.0`, `vitest ^3.1.3` and `@cipherstash/eql 3.0.2` +# against the repo catalog. That last pin was the point: `tests/postgres-v3.test.ts` +# queried SQL installed from the PUBLISHED EQL bundle while the payloads under +# test were emitted by the in-tree `eql-bindings`, so the two halves of EQL could +# disagree — and would have disagreed in a database, not in CI. `@cipherstash/eql` +# now resolves `workspace:^`, and `@cipherstash/auth` and `vitest` take +# `catalog:repo`. # # Separate from `tests.yml` on purpose, and separate from `tests-rust.yml`: this # needs CipherStash credentials AND Docker, and the suites THROW rather than @@ -36,8 +36,24 @@ on: branches: [main] paths: # The suite itself: tests, fixtures, its compose file, its `tasks.toml` - # and its lockfile. + # and its manifest. - 'packages/protect-ffi/integration-tests/**' + # The suite's dependency versions, now that it is a pnpm workspace member: + # `@cipherstash/auth`, `vitest` and `typescript` reach it through + # `catalog:repo`, so a catalog bump changes what this job runs while + # editing no file under the suite. Same entry, same reason, as the other + # integration workflows — and like them, `pnpm-lock.yaml` is deliberately + # NOT listed: it moves on roughly every dependency bump in the monorepo, + # and a catalog version cannot reach it without this file changing first. + - 'pnpm-workspace.yaml' + # The EQL v3 SQL this suite installs into its database, which + # `tests/postgres-v3.test.ts` then queries. It came from a published + # tarball until the suite joined the workspace; it now resolves + # `workspace:^`, which is what makes it an input to this job rather than a + # pinned external. Not narrowed to `sql/` — `tasks.toml` reads the bundle + # through `@cipherstash/eql/sql`, i.e. through the package's tsup build, + # so the build config and its asset copier are inputs too. + - 'packages/eql/packages/eql/**' # The Rust the suite round-trips every payload through, and the manifests # that change what cargo builds without touching a .rs file. Matching the # filter in tests-rust.yml. @@ -81,6 +97,8 @@ on: # on `main` — the exact inversion of what you want. paths: - 'packages/protect-ffi/integration-tests/**' + - 'pnpm-workspace.yaml' + - 'packages/eql/packages/eql/**' - 'packages/protect-ffi/crates/**' - 'packages/protect-ffi/Cargo.toml' - 'packages/protect-ffi/Cargo.lock' @@ -185,11 +203,9 @@ jobs: # Not `./.github/actions/integration-setup`, and the difference is # deliberate: that action builds the `stash` CLI because the stack # integration harness installs EQL v3 by shelling out to it. This suite - # installs EQL from its own pinned `@cipherstash/eql` instead (see - # `eql:v3:install` in integration-tests/tasks.toml), so the CLI build - # would be minutes of runner time for nothing — and it pins Node 24, - # where this suite's `npm ci` is verified against the npm that ships with - # 22 (see the Node step below). + # reads the SQL straight out of the workspace `@cipherstash/eql` instead + # (see `eql:v3:install` in integration-tests/tasks.toml), so the CLI build + # would be minutes of runner time for nothing. - uses: actions/checkout@v6 with: persist-credentials: false @@ -198,14 +214,14 @@ jobs: with: run_install: false - # Node 22, not the 24 the other integration jobs use. `integration-tests` - # is installed with `npm ci` against a lockfile whose `".."` entry - # records an OLDER manifest of this very package (protect-ffi 0.29.0, and - # different devDependencies) — a link entry npm re-reads from disk. That - # resolves cleanly under npm 10, which ships with Node 22 and is what the - # lockfile was last verified against; npm 11's stricter - # manifest-vs-lockfile agreement check is an unforced risk for a job whose - # point is the encryption coverage, not the installer. + # Node 22, not the 24 `.github/actions/integration-setup` defaults to. + # This used to be an npm-version argument — the suite installed with + # `npm ci` against a lockfile npm 11 reads more strictly than npm 10 — and + # that argument died with the lockfile. What is left is the plainer one: + # 22 is `engines`' floor and what every other workflow in this repo pins, + # so it is the version this job's Rust binding and WASM artifacts are + # built and cached against everywhere else. 24 is covered for the JS + # surface by `tests.yml`'s matrix. - uses: actions/setup-node@v6.5.0 with: node-version: 22 @@ -226,12 +242,18 @@ jobs: - name: Install node-gyp run: npm install -g node-gyp - # The workspace install, needed before the binding build: `build-ffi-binding` - # runs `pnpm --filter @cipherstash/protect-ffi run build`, i.e. the repo's - # tsc and neon. It is also what puts `@neon-rs/load` in - # packages/protect-ffi/node_modules — the suite reaches the package by - # symlink, so the parent's own dependencies come from pnpm, not from - # `npm ci`. + # The one install for this job, and it now covers the suite too: since + # CIP-3744 `integration-tests` is a pnpm workspace member, so this is what + # puts its `vitest`, `pg` and `dotenv` on disk and symlinks + # `@cipherstash/protect-ffi` and `@cipherstash/eql` to the packages in + # this tree. It is also required before the binding build — + # `build-ffi-binding` runs `pnpm --filter @cipherstash/protect-ffi run + # build` — and is what puts `@neon-rs/load` in + # packages/protect-ffi/node_modules. + # + # `mise run setup` below runs the same command again, deliberately: the + # task has to stand on its own for a contributor running it locally. On + # the runner it is a no-op. - name: Install dependencies run: pnpm install --frozen-lockfile @@ -295,9 +317,10 @@ jobs: working_directory: packages/protect-ffi # One task, four things the suite cannot run without (see - # integration-tests/tasks.toml): `npm ci` for the suite's own dependency - # tree, `docker compose up` for Postgres, the EQL **v2** bundle from a - # GitHub release, and EQL **v3** from the pinned `@cipherstash/eql`. + # integration-tests/tasks.toml): `pnpm install --frozen-lockfile` (a + # no-op here — the step above already ran it), `docker compose up` for + # Postgres, the EQL **v2** bundle from a GitHub release, and EQL **v3** + # built from the in-tree `@cipherstash/eql`. # # BOTH EQL versions are required and nothing else in this repo installs # v2: `tests/postgres.test.ts` creates `eql_v2_encrypted` columns and @@ -313,23 +336,24 @@ jobs: # `integration-db`'s per-job project names deliberately do not produce. # The fixed host port (5436) that comes with it cannot collide with the # shared stacks, which publish on ephemeral ports. - - name: Provision the suite (npm ci, Postgres, EQL v2 + v3) + - name: Provision the suite (Postgres, EQL v2 + v3) working-directory: packages/protect-ffi run: mise run setup # vitest directly rather than `mise run test:integration:all`, because # that task's first two steps are the debug cargo build and a wasm-pack # rebuild that `build-ffi-binding` has already done (above). What it runs - # after those is exactly this: `npx vitest`, the whole directory, INCLUDING + # after those is exactly this: vitest over the whole directory, INCLUDING # `tests/lock-context.test.ts`. Its sibling `test:integration` excludes # that file; upstream CI ran `:all` for a reason, and an invocation that # inherits the exclusion silently drops the identity-aware coverage. # - # `npx` resolves the vitest 3 pinned in integration-tests/package-lock.json, - # not the workspace catalog's — that pin is part of what the suite fixes. + # `pnpm exec`, which resolves the catalog `vitest` the workspace install + # put in this package's `node_modules/.bin`. It was `npx` against the + # suite's own `package-lock.json` until CIP-3744 retired that lockfile. - name: Integration suite (live ZeroKMS + Postgres, native and WASM) working-directory: packages/protect-ffi/integration-tests - run: npx vitest run + run: pnpm exec vitest run # `-v` drops the volume too. The runner is ephemeral, so this is not about # reclaiming it: it is so a re-run on a warm runner cannot inherit a diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1e782fe9d..9b71c9f89 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -217,6 +217,26 @@ jobs: - name: Typecheck (e2e) run: pnpm exec turbo run typecheck --filter @cipherstash/e2e + # The protect-ffi live integration suite, compiled but NOT run here — it + # needs Docker and CipherStash credentials, so it runs in + # integration-protect-ffi.yml behind a `paths:` filter. + # + # Which is exactly why this step exists. The suite's `tsc` used to ride + # along on its own `npm test`; CI invoked vitest directly, so it compiled + # nowhere, and the credentialed job is path-filtered — a repo-wide change + # that broke the suite's types (an `@cipherstash/auth` catalog bump moving + # `AccessKeyStrategy.create` to a `Result`, say) would not have started + # anything that noticed. Cheap: `tsc --noEmit` over the suite, no + # credentials, no database. + # + # That includes the two `.cjs` fixtures — the tsconfig sets `checkJs` and + # globs them deliberately. One of them is a real `AccessKeyStrategy` call + # site and was among the four the auth bump broke, so a `tests/**/*.ts` + # scope would have left this step green over it. + - name: Typecheck (protect-ffi integration suite) + run: > + pnpm exec turbo run typecheck --filter @cipherstash/ffi-integration-tests + # Everything else typechecks against SOURCE. This one reads the emitted # `.d.ts`, which is what customers consume — and where typed `encryptQuery` # sat broken for every column through the whole rc series, because `tsc` diff --git a/AGENTS.md b/AGENTS.md index fd1555778..6457c044d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -82,7 +82,7 @@ If these variables are missing, tests that require live encryption will fail or - `packages/nextjs`: Next.js helpers and Clerk integration (`./clerk` export) - `packages/utils`: Shared config (`utils/config`) and logger (`utils/logger`) - `packages/bench`: Performance / index-engagement benchmarks (private, not published) -- `packages/protect-ffi`: Native FFI bindings to the CipherStash Client SDK (`@cipherstash/protect-ffi`) — the Rust core that `packages/stack` encrypts and decrypts through, absorbed from `cipherstash/protectjs-ffi`. Contains a **nested Cargo workspace** (`crates/`) and six per-platform binary packages under `platforms/*`, each published as `@cipherstash/protect-ffi-` and linked here via `workspace:*`. See the "Working on protect-ffi" notes below before touching it — its default `test` and `build` are deliberately Rust-free. +- `packages/protect-ffi`: Native FFI bindings to the CipherStash Client SDK (`@cipherstash/protect-ffi`) — the Rust core that `packages/stack` encrypts and decrypts through, absorbed from `cipherstash/protectjs-ffi`. Contains a **nested Cargo workspace** (`crates/`) and six per-platform binary packages under `platforms/*`, each published as `@cipherstash/protect-ffi-` and linked here via `workspace:*`. Also holds the repo's live FFI integration suite at `integration-tests/` — a private workspace member (`@cipherstash/ffi-integration-tests`) enrolled by its own literal entry in `pnpm-workspace.yaml`, needing Docker and credentials, and deliberately carrying **no `test` script** so `pnpm test` cannot reach it. See the "Working on protect-ffi" notes below before touching it — its default `test` and `build` are deliberately Rust-free. - `packages/eql`: The Encrypt Query Language subtree — the SQL bundle that stores and queries encrypted payloads — absorbed from `cipherstash/encrypt-query-language`. **The directory is the subtree root, not the package.** It was imported at a *verbatim prefix* so its repo-root-relative paths (mise tasks, `Doxyfile`, `sync-generated.mjs`) keep resolving, which puts the npm package `@cipherstash/eql` two levels down at `packages/eql/packages/eql` — the same shape as `packages/protect-ffi/platforms/*`, and enrolled the same way, by an explicit `packages/eql/packages/*` glob in `pnpm-workspace.yaml`. The subtree root deliberately carries no `package.json`. Also contains a **nested Cargo workspace** at `packages/eql/crates/` (`eql-bindings`, published in lockstep with the npm package, plus `eql-domains` / `eql-codegen` / `eql-tests-macros`, which are not), a SQLx test crate at `packages/eql/tests/sqlx`, an ~900-line `mise.toml` task surface, its own `AGENTS.md`, and `docs/`. See the "Working on EQL" notes below before touching it. - `e2e/*`: Cross-package end-to-end tests (package managers, supply chain, Prisma example README) - `examples/*`: Working apps (basic, prisma, supabase-worker) @@ -213,17 +213,36 @@ several of those paths are exercised at all. It needs three things a normal `pnpm test` does not have: **Docker**, **CipherStash credentials**, and **both EQL versions installed** in the database. -- **It is not a pnpm workspace member.** `pnpm-workspace.yaml` globs - `packages/*` (one level) plus `packages/protect-ffi/platforms/*`, so this - directory is invisible to pnpm and has its own `package-lock.json` with pins - that deliberately differ from the repo catalog (`@cipherstash/auth ^0.39.0`, - `vitest ^3.1.3`, `@cipherstash/eql 3.0.2`). `npm ci` installs it. Absorbing it - into the workspace is a follow-up, not a tidy-up: it changes those pins, and - only a credentialed run can prove the change is neutral. +- **It is a pnpm workspace member, and `pnpm test` must never reach it.** Named + literally in `pnpm-workspace.yaml` (the `packages/*` glob is one level deep and + stops short of it), so its dependencies come from the repo lockfile: + `@cipherstash/eql` at `workspace:^`, `@cipherstash/protect-ffi` at + `workspace:*`, `@cipherstash/auth` / `vitest` / `typescript` from + `catalog:repo`. It had its own `package-lock.json` and an `npm ci` until + CIP-3744; the pin that mattered was `@cipherstash/eql 3.0.2`, the last place in + the tree where the SQL that STORES a payload could disagree with the Rust that + EMITS it — and it would have disagreed in a database, not in CI. + + The cost of membership: root `pnpm test` is `turbo test --filter + './packages/**'`, which now reaches this package. It is kept out by **naming no + live script after a turbo task** — the suite's runners are `vitest:live` and + `vitest:live:coverage`, which `turbo.json` knows nothing about. `test` is the + obvious trap and `test:integration` is the less obvious one (a real turbo task, + invoked by four integration workflows — all `--filter`ed today, so an + unfiltered `turbo run test:integration` is what would bite). + `src/integrationSuiteCi.test.ts` derives the forbidden set from `turbo.json` + rather than listing it, so a task added there tomorrow is covered. + + `typecheck` is the deliberate exception: it *should* run under `turbo run + typecheck`, and does, from `tests.yml`, on every PR. It needs no credentials + and no database, and its tsconfig sets `checkJs` so the suite's two `.cjs` + fixtures are compiled too — one of them is a real `AccessKeyStrategy` call + site, and a `tests/**/*.ts` scope would leave it checked by nothing but the + path-filtered credentialed job. - **Run it locally** from `packages/protect-ffi`: ```bash - mise run setup # npm ci, docker compose up, EQL v2 + v3 + mise run setup # pnpm install, docker compose up, EQL v2 + v3 mise run test:integration:all # includes tests/lock-context.test.ts ``` @@ -252,6 +271,12 @@ EQL versions installed** in the database. `eql_v2.add_encrypted_constraint`) while `tests/postgres-v3.test.ts` needs the `eql_v3_*` domains. Skip either and half the suite fails on missing SQL functions. +- **`eql:v3:install` builds `@cipherstash/eql` first, and has to.** The task + reads the bundle through `@cipherstash/eql/sql`, which the package's `exports` + map resolves to `dist/sql.js` — a tsup output. That was free while `npm ci` + unpacked a published tarball with `dist/` already in it; from the workspace it + is a build. Without it the task dies on `ERR_MODULE_NOT_FOUND`, which reads as + a broken dependency rather than an unbuilt one. - **`src/integrationSuiteCi.test.ts` asserts a root workflow still runs it.** The suite ran on every upstream PR and then ran *nowhere* for the whole absorption, because the workflow that drove it was deposited under @@ -457,10 +482,13 @@ monorepo, which is where the silent failures are. ignored, so it is the one place a workspace-wide pin can be written and take effect). It exits **2**, not 0, when its own configuration has gone stale — a source it could not read, a declaration it expected and no longer sees, or - an exemption excusing nothing. There is one exemption today - (`packages/protect-ffi/integration-tests`, which installs with `npm ci` and - cannot take a `workspace:` specifier); adding another means writing the reason - down. + an exemption excusing nothing. There are **no exemptions today**: the only one + there had ever been (`packages/protect-ffi/integration-tests`, which installed + with `npm ci` and could not take a `workspace:` specifier) was retired when + that directory joined the pnpm workspace, and the guard's own staleness rule — + keyed on "excuses nothing", not "names nothing" — is what forced it out in the + same commit rather than leaving a standing permission behind. Adding one means + writing the reason down. It also reads the Cargo redirect tables — `[patch.*]` (including `[patch."https://…"]` and the dotted `[patch.crates-io.eql-bindings]` form) and `[replace]` — plus **`.cargo/config.toml`**, because cargo honours a diff --git a/docs/plans/2026-08-04-protect-ffi-monorepo-absorption.md b/docs/plans/2026-08-04-protect-ffi-monorepo-absorption.md index 5b1645a85..0ae23592c 100644 --- a/docs/plans/2026-08-04-protect-ffi-monorepo-absorption.md +++ b/docs/plans/2026-08-04-protect-ffi-monorepo-absorption.md @@ -1993,22 +1993,27 @@ The Rust emitting EQL payloads is generated from a different catalog commit than Each of these was in reach and deliberately left, with the reason. -1. **pnpm-absorb `packages/protect-ffi/integration-tests`.** It is not a workspace - member — `packages/*` globs one level and the only deeper entry is - `platforms/*` — so it carries its own `package-lock.json` and installs with - `npm ci`. Absorbing it means adding it to `pnpm-workspace.yaml`, reconciling - `@cipherstash/auth ^0.39.0` / `vitest ^3.1.3` / `@cipherstash/eql 3.0.2` with - the catalog, and dropping both the lockfile and the `npm ci` step. **Not done - because it changes the suite's dependency versions, and only a credentialed - run can show that change is neutral** — doing it blind would confound a - wiring fix with a semantic one. Two things resolve with it: the second - package manager in CI, and the five npm advisories osv-scanner reports in - that lockfile today. - -2. **`integration-tests/package-lock.json` gets no Dependabot PRs.** Covered at - the ecosystem level, but the npm entry follows the pnpm workspace and this - directory is not in it. Adding a second npm entry is ~10 lines; left because - (1) deletes the file. +1. ~~**pnpm-absorb `packages/protect-ffi/integration-tests`.**~~ **Done + 2026-08-26, CIP-3744.** It was not a workspace member — `packages/*` globs one + level and the only deeper entry was `platforms/*` — so it carried its own + `package-lock.json` and installed with `npm ci`. It is now named literally in + `pnpm-workspace.yaml`; `@cipherstash/eql` resolves `workspace:^`, + `@cipherstash/protect-ffi` `workspace:*`, and `@cipherstash/auth` / `vitest` / + `typescript` come from `catalog:repo`. The lockfile and the `npm ci` step are + gone, and with them the second package manager in CI and the npm advisories + osv-scanner reported in that lockfile. + + The caution above was right: it was **not** neutral. `@cipherstash/auth` + `^0.39.0 → 0.42.0` is a breaking API move (Result returns on + `AccessKeyStrategy.create`, `OidcFederationStrategy.create` and `getToken`; + `OidcFederationStrategy.create` re-signatured to take a whole CRN), touching + four call sites in the suite. A credentialed local run closed it — 20 files, + 232 tests, zero skips, EQL v2 and v3 both installed. + +2. ~~**`integration-tests/package-lock.json` gets no Dependabot PRs.**~~ + **Resolved by (1)** — the file is deleted, and the suite's dependencies now + reach Dependabot's npm entry at `/` through the root `pnpm-lock.yaml` like + every other workspace member's. 3. **CI and `tasks.toml` have forked.** `test:integration:all` still builds the binding (debug) and the WASM itself, while CI builds once via diff --git a/docs/plans/2026-08-13-eql-monorepo-absorption.md b/docs/plans/2026-08-13-eql-monorepo-absorption.md index cffeaf553..000b8cc3e 100644 --- a/docs/plans/2026-08-13-eql-monorepo-absorption.md +++ b/docs/plans/2026-08-13-eql-monorepo-absorption.md @@ -392,3 +392,5 @@ All three were measured against the two trees on 2026-08-13 and closed the same 1. **The private `@cipherstash/eql-workspace` root manifest is deleted.** Once the `version` hook moves to this repo's root — which Changesets forces regardless — nothing load-bearing is left: three scripts conflict with the root, two are already defined there under the same names, and the remaining four are thin delegations CI does not call. The subtree needs no `node_modules` for its mise tasks to run. The precedent cited for keeping it was mistaken: `packages/protect-ffi/package.json` is a published package, not a private workspace root. See the finding above for the accounting. 2. **The two Cargo workspaces stay separate this round.** The path dep in Phase 3 is what buys the anti-skew guarantee; unification buys build hygiene, and it would make `dead_code = "deny"` and `default-members` repo-wide policy as a side effect of a move. The lockfiles already agree on the dependency that matters. See Phase 3 for the reopening signal. 3. **`packages/protect-ffi/integration-tests` is absorbed in a separate PR, immediately after.** Absorbing it moves `@cipherstash/auth`, `vitest` and `@cipherstash/eql` simultaneously, and only a run with Docker plus `CS_*` credentials can show that is neutral — bundling it makes the absorption PR unreviewable without a live credentialed result attached. The reason to do it soon is real and has strengthened: after Phase 2 this is the **last** registry pin of `@cipherstash/eql` in the tree, and it is the pin used by `tests/postgres.test.ts` and `tests/postgres-v3.test.ts`, the repo's only EQL v2 *and* v3 SQL coverage — precisely where a mismatch between the npm-pinned bundle and the in-tree SQL would surface as an expensive-to-diagnose failure. Until then it carries a named, reasoned exemption in the Phase 3 registry-pin guard. + + **Done — CIP-3744.** The directory is a workspace member, `package-lock.json` is deleted, `@cipherstash/eql` resolves `workspace:^`, and the guard's exemption list is now empty (the `staleExemptions` spelling above is what forced the entry out in the same commit). It was **not** neutral, and the non-neutral half was the one predicted: `@cipherstash/auth` `^0.39.0 → 0.42.0` moved `AccessKeyStrategy.create` / `OidcFederationStrategy.create` / `getToken` to `@byteslice/result` `Result` returns, and `OidcFederationStrategy.create` from `(region, workspaceId, getJwt)` to `(workspaceCrn, getJwt)` — four call sites across `js-strategy`, `oidc-federation`, `wasm-round-trip` and the event-loop fixture, none of which a `tsc` in CI would have caught, because the suite compiled nowhere. It compiles in `tests.yml` now — **including the fixture**, which took `checkJs` and a JSDoc annotation to reach: the tsconfig's `include` was `tests/**/*.ts`, so the first draft of that step covered three of the four sites while this paragraph claimed all of them. Verified by a local credentialed run: `mise run test:integration:all`, 20 files / 232 tests, **zero skips**, with EQL v2 and v3 both installed. The rc.2 binding failure mode did not recur — `dedupe-peer-dependents` keeps one `@cipherstash/auth` instance shared by `stack`, `cli`, `wizard` and the suite. diff --git a/e2e/tests/supply-chain.e2e.test.ts b/e2e/tests/supply-chain.e2e.test.ts index b5f2bec96..c9b92d278 100644 --- a/e2e/tests/supply-chain.e2e.test.ts +++ b/e2e/tests/supply-chain.e2e.test.ts @@ -129,6 +129,39 @@ describe('supply chain — pnpm configuration', () => { ).toBe(1) }) + it('vitest and @vitest/coverage-v8 are catalog-pinned in lockstep', () => { + // The same shape as the auth set above, one dependency along, and it needs + // its own assertion because that one filters on the `@cipherstash/auth` + // prefix and cannot see this pair. + // + // `@vitest/coverage-v8` is versioned against the runner, not + // independently: vitest refuses to start against a mismatched provider + // ("Vitest failed to load @vitest/coverage-v8"). Both are in the + // `dev-dependencies` Dependabot group, which is free to move one and not + // the other, and the only consumer of the provider is the protect-ffi + // integration suite's `vitest:live:coverage` — a developer tool nothing in + // CI runs. So a skew would sit in the catalog looking deliberate until + // someone reached for coverage and got a startup error. + const ws = readYaml('pnpm-workspace.yaml') as { + catalogs?: Record> + } + const repo = ws.catalogs?.repo ?? {} + const runner = repo.vitest + const provider = repo['@vitest/coverage-v8'] + + // Floor on the lookup: two undefineds compare equal, so a renamed or + // removed entry would pass the comparison below silently. + expect(runner, 'no `vitest` entry in the repo catalog').toBeTruthy() + expect( + provider, + 'no `@vitest/coverage-v8` entry in the repo catalog', + ).toBeTruthy() + expect( + provider, + `@vitest/coverage-v8@${provider} does not match vitest@${runner}; the coverage provider is versioned in lockstep with the runner`, + ).toBe(runner) + }) + it('security overrides stay range-scoped and remain a small allowlist (≤12 entries)', () => { // Every override must be scoped to the advisory's vulnerable range // (`pkg@`), never a blanket `pkg` pin — a blanket pin silently @@ -728,11 +761,12 @@ describe('supply chain — automated dependency updates (Dependabot)', () => { // routine version bumps. // // Coverage is asserted per ECOSYSTEM, not per directory. Dependabot's npm - // entry at `/` follows the pnpm workspace, which does not include - // packages/protect-ffi/integration-tests — that lockfile therefore sits - // under a monitored ecosystem but is not itself updated. Deliberate: it is - // a standalone `npm install` harness with no published surface, and its - // advisories are still visible via osv-scanner. + // entry at `/` follows the pnpm workspace, so it reaches every member's + // manifest through the single root `pnpm-lock.yaml`. The one lockfile that + // sat outside that — packages/protect-ffi/integration-tests's own + // `package-lock.json`, a standalone `npm ci` harness — is gone as of + // CIP-3744, and the suite now resolves from the repo lockfile like + // everything else. const ecosystems = new Set(db.updates.map((u) => u['package-ecosystem'])) const unmonitored: string[] = [] const unrecognised: string[] = [] diff --git a/packages/protect-ffi/README.md b/packages/protect-ffi/README.md index c6b687deb..892225a36 100644 --- a/packages/protect-ffi/README.md +++ b/packages/protect-ffi/README.md @@ -325,6 +325,8 @@ protect-ffi/ Integration tests live in the `./integration-tests` directory. These tests use the local build of Rust and JavaScript artifacts to test `@cipherstash/protect-ffi` as API consumers would. +The directory is its own private pnpm workspace member (`@cipherstash/ffi-integration-tests`), so `pnpm install` at the repo root installs it, and both `@cipherstash/protect-ffi` and `@cipherstash/eql` resolve to the packages in this tree rather than to published tarballs. It has **no `test` script** on purpose — root `pnpm test` would otherwise try to run a suite that needs Docker and live credentials. Use the `mise` tasks below. + These tests rely on: - CipherStash to be configured (via `.toml` config or environment variables), and diff --git a/packages/protect-ffi/integration-tests/package-lock.json b/packages/protect-ffi/integration-tests/package-lock.json deleted file mode 100644 index feabd27ab..000000000 --- a/packages/protect-ffi/integration-tests/package-lock.json +++ /dev/null @@ -1,2759 +0,0 @@ -{ - "name": "integration-tests", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "integration-tests", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@cipherstash/auth": "^0.39.0", - "@cipherstash/protect-ffi": "..", - "pg": "^8.13.3" - }, - "devDependencies": { - "@cipherstash/eql": "3.0.2", - "@types/pg": "^8.11.11", - "@vitest/coverage-v8": "^3.1.3", - "dotenv": "^16.4.7", - "typescript": "^5.3.3", - "vitest": "^3.1.3" - } - }, - "..": { - "name": "@cipherstash/protect-ffi", - "version": "0.29.0", - "license": "MIT", - "dependencies": { - "@neon-rs/load": "^0.1.82" - }, - "devDependencies": { - "@biomejs/biome": "1.9.4", - "@neon-rs/cli": "^0.1.82", - "@tsconfig/node20": "^20.1.4", - "@types/node": "^20.11.16", - "typescript": "^5.3.3", - "vitest": "^4.1.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@cipherstash/auth": { - "version": "0.39.0", - "resolved": "https://registry.npmjs.org/@cipherstash/auth/-/auth-0.39.0.tgz", - "integrity": "sha512-pn2HhF8T1xZdEOpHlOb9hamFwKI/r0gYaKZEswnTyjOahIT5uqV86M7Iu4Py4n88pAMRZUsvW7h1r5I3zBsFdg==", - "peerDependencies": { - "@cipherstash/auth-darwin-arm64": "0.39.0", - "@cipherstash/auth-darwin-x64": "0.39.0", - "@cipherstash/auth-linux-arm64-gnu": "0.39.0", - "@cipherstash/auth-linux-x64-gnu": "0.39.0", - "@cipherstash/auth-linux-x64-musl": "0.39.0", - "@cipherstash/auth-win32-x64-msvc": "0.39.0" - }, - "peerDependenciesMeta": { - "@cipherstash/auth-darwin-arm64": { - "optional": true - }, - "@cipherstash/auth-darwin-x64": { - "optional": true - }, - "@cipherstash/auth-linux-arm64-gnu": { - "optional": true - }, - "@cipherstash/auth-linux-x64-gnu": { - "optional": true - }, - "@cipherstash/auth-linux-x64-musl": { - "optional": true - }, - "@cipherstash/auth-win32-x64-msvc": { - "optional": true - } - } - }, - "node_modules/@cipherstash/eql": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@cipherstash/eql/-/eql-3.0.2.tgz", - "integrity": "sha512-E85o0aoOqgCW6RReLtJ0YLh/ExRlmDJo7LlJGpWPoMTVaw+CW8o11DJ4oJIF1vFtuxSVxNULuPzzBuVmpTvvcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cipherstash/protect-ffi": { - "resolved": "..", - "link": true - }, - "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/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "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": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "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.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.13.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", - "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/pg": { - "version": "8.11.11", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.11.tgz", - "integrity": "sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^4.0.1" - } - }, - "node_modules/@types/pg/node_modules/pg-types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", - "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", - "dev": true, - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "pg-numeric": "1.0.2", - "postgres-array": "~3.0.1", - "postgres-bytea": "~3.0.0", - "postgres-date": "~2.1.0", - "postgres-interval": "^3.0.0", - "postgres-range": "^1.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@types/pg/node_modules/postgres-array": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", - "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/@types/pg/node_modules/postgres-bytea": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", - "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "obuf": "~1.1.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/pg/node_modules/postgres-date": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", - "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/@types/pg/node_modules/postgres-interval": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", - "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.7.tgz", - "integrity": "sha512-NEGWJS2XNu2PfRLQwOO3CTKj1tTETxNBdk454vDxVBhxJYhPaA/eS0nAI0c+1El1P7a60z8+i+ZrQoGESweGKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@bcoe/v8-coverage": "^1.0.2", - "ast-v8-to-istanbul": "^0.3.3", - "debug": "^4.4.1", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^5.0.6", - "istanbul-reports": "^3.1.7", - "magic-string": "^0.30.17", - "magicast": "^0.3.5", - "std-env": "^3.9.0", - "test-exclude": "^7.0.1", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "3.2.7", - "vitest": "3.2.7" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz", - "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.7", - "@vitest/utils": "3.2.7", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz", - "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "3.2.7", - "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/@vitest/pretty-format": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz", - "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz", - "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "3.2.7", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz", - "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "3.2.7", - "magic-string": "^0.30.17", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz", - "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyspy": "^4.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz", - "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "3.2.7", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "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/ast-v8-to-istanbul": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", - "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^9.0.1" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "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/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/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "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/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/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/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.2.1", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", - "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "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/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "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/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/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", - "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.25.4", - "@babel/types": "^7.25.4", - "source-map-js": "^1.2.0" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "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.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", - "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/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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/pg": { - "version": "8.13.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.3.tgz", - "integrity": "sha512-P6tPt9jXbL9HVu/SSRERNYaYG++MjnscnegFh9pPHihfoBSujsrka0hyuymMzeJKFWrcG8wvCKy8rCe8e5nDUQ==", - "license": "MIT", - "dependencies": { - "pg-connection-string": "^2.7.0", - "pg-pool": "^3.7.1", - "pg-protocol": "^1.7.1", - "pg-types": "^2.1.0", - "pgpass": "1.x" - }, - "engines": { - "node": ">= 8.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.1.1" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", - "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", - "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-numeric": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", - "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/pg-pool": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz", - "integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==", - "license": "MIT", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz", - "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "license": "MIT", - "dependencies": { - "split2": "^4.1.0" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", - "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.16", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-range": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", - "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "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", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "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.9.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", - "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", - "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^10.4.1", - "minimatch": "^9.0.4" - }, - "engines": { - "node": ">=18" - } - }, - "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.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "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/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, - "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/vitest": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz", - "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.7", - "@vitest/mocker": "3.2.7", - "@vitest/pretty-format": "^3.2.7", - "@vitest/runner": "3.2.7", - "@vitest/snapshot": "3.2.7", - "@vitest/spy": "3.2.7", - "@vitest/utils": "3.2.7", - "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.7", - "@vitest/ui": "3.2.7", - "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/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "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" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - } - } -} diff --git a/packages/protect-ffi/integration-tests/package.json b/packages/protect-ffi/integration-tests/package.json index fc372b4ef..8ece03acd 100644 --- a/packages/protect-ffi/integration-tests/package.json +++ b/packages/protect-ffi/integration-tests/package.json @@ -1,29 +1,25 @@ { - "name": "integration-tests", + "name": "@cipherstash/ffi-integration-tests", "version": "1.0.0", "private": true, - "main": "index.js", + "description": "Live integration coverage for @cipherstash/protect-ffi — real ZeroKMS, real Postgres, EQL v2 and v3", + "license": "MIT", "scripts": { - "test": "tsc && vitest test", - "test:coverage": "tsc && vitest test --coverage" + "typecheck": "tsc", + "vitest:live": "vitest run", + "vitest:live:coverage": "vitest run --coverage" }, - "author": "", - "license": "MIT", - "description": "", "dependencies": { - "@cipherstash/auth": "^0.39.0", - "@cipherstash/protect-ffi": "..", - "pg": "^8.13.3" + "@cipherstash/auth": "catalog:repo", + "@cipherstash/protect-ffi": "workspace:*", + "pg": "8.23.0" }, "devDependencies": { - "@cipherstash/eql": "3.0.2", - "@types/pg": "^8.11.11", - "@vitest/coverage-v8": "^3.1.3", - "dotenv": "^16.4.7", - "typescript": "^5.3.3", - "vitest": "^3.1.3" - }, - "overrides": { - "vite": "^7.3.5" + "@cipherstash/eql": "workspace:^", + "@types/pg": "^8.23.1", + "@vitest/coverage-v8": "catalog:repo", + "dotenv": "17.4.2", + "typescript": "catalog:repo", + "vitest": "catalog:repo" } } diff --git a/packages/protect-ffi/integration-tests/tasks.toml b/packages/protect-ffi/integration-tests/tasks.toml index 30c69df0e..0ba49f62e 100644 --- a/packages/protect-ffi/integration-tests/tasks.toml +++ b/packages/protect-ffi/integration-tests/tasks.toml @@ -23,11 +23,18 @@ description = "Install CipherStash encrypt SQL into the database" dir = "{{ config_root }}/integration-tests" run = "cat sql/cipherstash-encrypt.sql | docker exec -i protect-ffi-postgres psql postgresql://cipherstash:password@postgres:5432/cipherstash -f-" +# EQL v3 comes from the IN-TREE @cipherstash/eql (`workspace:^`), not from a +# published tarball. `@cipherstash/eql/sql` resolves through the package's +# `exports` map to `dist/sql.js`, which is a build output — so the build below +# is not optional here the way it was when `npm ci` unpacked a prebuilt tarball. +# Without it this task fails with ERR_MODULE_NOT_FOUND on `dist/sql.js`, which +# reads as a broken dependency rather than an unbuilt one. ["eql:v3:install"] -description = "Install EQL v3 from the locked @cipherstash/eql package" +description = "Install EQL v3 from the in-tree @cipherstash/eql workspace package" dir = "{{ config_root }}/integration-tests" run = """ set -e +pnpm --filter @cipherstash/eql run build tmp=$(mktemp) trap 'rm -f "$tmp"' EXIT node --input-type=module -e "import { readInstallSql } from '@cipherstash/eql/sql'; process.stdout.write(readInstallSql())" > "$tmp" @@ -38,11 +45,19 @@ fi docker exec -i protect-ffi-postgres psql postgresql://cipherstash:password@postgres:5432/cipherstash -f- < "$tmp" """ +# `pnpm install`, not `npm ci`: this directory is a pnpm workspace member as of +# CIP-3744, so its dependencies come from the repo lockfile and its +# `@cipherstash/protect-ffi` and `@cipherstash/eql` resolve to the packages in +# this tree rather than to published tarballs. `--frozen-lockfile` matches what +# CI does and fails on a manifest the lockfile does not cover, which is the half +# of `npm ci` worth keeping. It installs the WHOLE workspace — pnpm resolves the +# workspace root from here — so a contributor who has already run it at the repo +# root pays a no-op. [setup] description = "Set up the integration test environment" dir = "{{ config_root }}/integration-tests" run = [ - "npm ci", + "pnpm install --frozen-lockfile", "mise run start-db", "mise run eql:download", "mise run eql:install", @@ -56,10 +71,15 @@ depends = ["start-db"] # The wasm-round-trip suite reads `dist/wasm/protect_ffi_inline.js`, so # the wasm artifacts must exist before vitest runs even though the rest # of the integration tests only need the Neon binding. +# +# `pnpm exec vitest`, not `pnpm run vitest:live`, only because of the extra +# flag: pnpm forwards a trailing `--` to the command rather than swallowing it, +# so `pnpm run vitest:live -- --exclude …` would hand vitest a bare `--`. The +# `:all` task below, which needs no flag, goes through the script. run = [ "mise run build:debug", - "npm run --prefix .. build:wasm", - "npx vitest --exclude tests/lock-context.test.ts", + "pnpm --filter @cipherstash/protect-ffi run build:wasm", + "pnpm exec vitest run --exclude tests/lock-context.test.ts", ] ["test:integration:all"] @@ -68,6 +88,6 @@ dir = "{{ config_root }}/integration-tests" depends = ["start-db"] run = [ "mise run build:debug", - "npm run --prefix .. build:wasm", - "npx vitest", + "pnpm --filter @cipherstash/protect-ffi run build:wasm", + "pnpm run vitest:live", ] diff --git a/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-auto.cjs b/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-auto.cjs index c9d39add6..7afedb7f8 100644 --- a/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-auto.cjs +++ b/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-auto.cjs @@ -10,6 +10,7 @@ require('dotenv/config') const { newClient, encrypt, decrypt } = require('@cipherstash/protect-ffi') +/** @type {import('@cipherstash/protect-ffi').EncryptConfig} */ const encryptConfig = { v: 1, tables: { diff --git a/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-jsbacked.cjs b/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-jsbacked.cjs index b09ed717e..3a2ec2e1e 100644 --- a/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-jsbacked.cjs +++ b/packages/protect-ffi/integration-tests/tests/fixtures/event-loop-exit-jsbacked.cjs @@ -9,6 +9,7 @@ require('dotenv/config') const { newClient, encrypt, decrypt } = require('@cipherstash/protect-ffi') +/** @type {import('@cipherstash/protect-ffi').EncryptConfig} */ const encryptConfig = { v: 1, tables: { @@ -24,9 +25,8 @@ const encryptConfig = { // Use the wasm-inline build of @cipherstash/auth — it has no native // binary dep, works on any Node target, and lets us exercise the // `opts.strategy` (JsBacked) code path with a real getToken. - // @cipherstash/auth 0.39 takes the full workspace CRN and parses the - // region from it (earlier versions took only the `.` - // segment, requiring callers to split the CRN themselves). + // The CRN is passed whole: auth parses the region out of it (versions before + // 0.39 took only the `.` segment). const { AccessKeyStrategy } = await import('@cipherstash/auth/wasm-inline') const accessKey = process.env.CS_CLIENT_ACCESS_KEY const workspaceCrn = process.env.CS_WORKSPACE_CRN @@ -35,7 +35,17 @@ const encryptConfig = { 'event-loop-exit-jsbacked fixture needs CS_CLIENT_ACCESS_KEY and CS_WORKSPACE_CRN', ) } - const strategy = AccessKeyStrategy.create(workspaceCrn, accessKey) + // Since 0.41 `create` returns a `Result`. + // Unwrapped here — the envelope has no `getToken`, and this fixture's whole + // job is to prove the event loop drains after a real JsBacked round-trip, so + // a construction failure has to fail loudly rather than as a contract error. + const created = AccessKeyStrategy.create(workspaceCrn, accessKey) + if (created.failure) { + throw new Error( + `AccessKeyStrategy.create failed (${created.failure.type}): ${created.failure.error.message}`, + ) + } + const strategy = created.data const client = await newClient({ encryptConfig, strategy }) diff --git a/packages/protect-ffi/integration-tests/tests/js-strategy.test.ts b/packages/protect-ffi/integration-tests/tests/js-strategy.test.ts index 6b8548a0d..f5b29df53 100644 --- a/packages/protect-ffi/integration-tests/tests/js-strategy.test.ts +++ b/packages/protect-ffi/integration-tests/tests/js-strategy.test.ts @@ -37,10 +37,18 @@ function buildAccessKeyStrategy(): AccessKeyStrategy { if (!crn || !accessKey) { throw new Error('unreachable: skipIf gates this') } - // @cipherstash/auth 0.39 takes the full workspace CRN and parses the - // region from it (earlier versions took only the `.` - // segment, requiring callers to split the CRN themselves). - return AccessKeyStrategy.create(crn, accessKey) + // The CRN is passed whole: auth parses the region out of it (versions before + // 0.39 took only the `.` segment). Since 0.41 `create` + // returns a `Result` rather than the strategy + // — unwrap it here, because the envelope has no `getToken` and handing it to + // `newClient` would fail as a wiring error naming nothing useful. + const created = AccessKeyStrategy.create(crn, accessKey) + if (created.failure) { + throw new Error( + `AccessKeyStrategy.create failed (${created.failure.type}): ${created.failure.error.message}`, + ) + } + return created.data } const clientOpts: ClientOpts = { @@ -53,9 +61,24 @@ describe.skipIf(missingEnv.length > 0)('opts.strategy (JsBacked)', () => { const inner = buildAccessKeyStrategy() let callCount = 0 const strategy: AuthStrategy = { + // Resolves the BARE `{ token }` arm, deliberately. `AuthStrategy.getToken` + // (src/types.ts) is `Promise` — both + // shapes are contract, and the bare one is what a hand-rolled consumer + // strategy returns. It used to be covered here for free, because auth 0.39 + // resolved `{ token }` and this test forwarded it; on 0.42 a forward + // resolves the envelope instead, which would leave both live tests in this + // file exercising the same arm and no integration test round-tripping the + // documented one at all. Unwrapping back to `{ token }` restores the split: + // this test owns the bare arm, the test below owns the envelope. async getToken() { callCount++ - return await inner.getToken() + const result = await inner.getToken() + if (result.failure) { + throw new Error( + `getToken failed (${result.failure.type}): ${result.failure.error.message}`, + ) + } + return { token: result.data.token } }, } @@ -82,9 +105,20 @@ describe.skipIf(missingEnv.length > 0)('opts.strategy (JsBacked)', () => { // Wrap the real token in `@cipherstash/auth` 0.41's `@byteslice/result` // success envelope; protect-ffi must unwrap `data.token` and still // complete a round-trip. + // + // Unwrapped and RE-wrapped, not forwarded. `inner.getToken()` already + // returns that envelope on 0.41+, so `return inner.getToken()` would + // still pass this test on a build that had stopped unwrapping — it would + // be asserting auth's shape rather than protect-ffi's handling of it. + // Constructing the envelope here keeps the subject on this side. getToken: (async () => { - const { token } = await inner.getToken() - return { data: { token } } + const result = await inner.getToken() + if (result.failure) { + throw new Error( + `getToken failed (${result.failure.type}): ${result.failure.error.message}`, + ) + } + return { data: { token: result.data.token } } }) as unknown as AuthStrategy['getToken'], } diff --git a/packages/protect-ffi/integration-tests/tests/oidc-federation.test.ts b/packages/protect-ffi/integration-tests/tests/oidc-federation.test.ts index 36a593f6d..a920707dc 100644 --- a/packages/protect-ffi/integration-tests/tests/oidc-federation.test.ts +++ b/packages/protect-ffi/integration-tests/tests/oidc-federation.test.ts @@ -45,20 +45,30 @@ import { describe, expect, test } from 'vitest' describe('OidcFederation strategy contract', () => { test('the published strategy constructs and exposes getToken', () => { // Exercises the real `@cipherstash/auth` factory + signature, not a stand-in. - // `OidcFederationStrategy.create(region, workspaceId, getJwt)` takes the - // region (`.`) and workspace id as separate args. Both are - // arbitrary here — `.create` does no I/O, so this stays offline; the - // federation call would only happen on `getToken()`. - const strategy = OidcFederationStrategy.create( - 'ap-southeast-2.aws', - 'ZVATKW3VHMFG27DY', + // `OidcFederationStrategy.create(workspaceCrn, getJwt)` takes the whole CRN + // and parses the region and workspace id out of it — 0.39 and earlier took + // those two as separate arguments. The CRN is arbitrary here: `.create` does + // no I/O, so this stays offline; the federation call would only happen on + // `getToken()`. + const created = OidcFederationStrategy.create( + 'crn:ap-southeast-2.aws:ZVATKW3VHMFG27DY', () => 'third-party.oidc.jwt', ) + // Since 0.41 `create` returns a `Result`. + // Asserted rather than unwrapped blind: a CRN this factory rejects would + // otherwise surface as "`getToken` is not a function" below, which reads as + // a broken contract rather than a bad argument. + if (created.failure) { + throw new Error( + `OidcFederationStrategy.create failed (${created.failure.type}): ${created.failure.error.message}`, + ) + } + // Compile-time: the wasm strategy is structurally assignable to the FFI's // `AuthStrategy`. Runtime: `getToken` — the only member the FFI calls — is // callable on that contract-typed handle. - const asStrategy: AuthStrategy = strategy + const asStrategy: AuthStrategy = created.data expect(typeof asStrategy.getToken).toBe('function') }) }) diff --git a/packages/protect-ffi/integration-tests/tests/wasm-round-trip.test.ts b/packages/protect-ffi/integration-tests/tests/wasm-round-trip.test.ts index 4d780b6ba..d64ba12f2 100644 --- a/packages/protect-ffi/integration-tests/tests/wasm-round-trip.test.ts +++ b/packages/protect-ffi/integration-tests/tests/wasm-round-trip.test.ts @@ -8,7 +8,8 @@ // // # Prerequisites // -// 1. Build the wasm artifacts from the repo root: `npm run build:wasm`. +// 1. Build the wasm artifacts: `pnpm --filter @cipherstash/protect-ffi run +// build:wasm`, or just `mise run test:integration:all`, which does it. // Without `dist/wasm/protect_ffi_inline.js` the suite fails fast with // a clear error rather than skipping silently. // 2. Set `CS_WORKSPACE_CRN`, `CS_CLIENT_ACCESS_KEY`, `CS_CLIENT_ID`, and @@ -53,6 +54,30 @@ function requireEnv() { } } +/** + * The strategy every test here hands the wasm client. + * + * `AccessKeyStrategy.create` returns a `@byteslice/result` + * `Result` — `{ data }` on success, `{ failure }` + * on error — as of `@cipherstash/auth` 0.41. The envelope is NOT a strategy: + * it has no `getToken`, so handing it straight to `newClient` fails inside the + * Rust with a "getToken is not a function" error that names nothing useful. + * Unwrap at the boundary, and throw the failure's own message when it is the + * credentials that are wrong rather than the wiring. + * + * The CRN is passed whole: auth parses the region out of it. Versions before + * 0.39 took only the `.` segment and made the caller split it. + */ +function buildStrategy(env: ReturnType): AccessKeyStrategy { + const created = AccessKeyStrategy.create(env.workspaceCrn, env.accessKey) + if (created.failure) { + throw new Error( + `AccessKeyStrategy.create failed (${created.failure.type}): ${created.failure.error.message}`, + ) + } + return created.data +} + // `__dirname` (CJS) instead of `import.meta.url` because the // integration-tests tsconfig inherits `module: "node16"` and the package // has no `"type": "module"`, so .ts files compile as CJS. @@ -74,7 +99,7 @@ const WASM_INLINE_PATH = resolve( async function loadWasm(): Promise { if (!existsSync(WASM_INLINE_PATH)) { throw new Error( - `wasm-inline build not found at ${WASM_INLINE_PATH}. Run \`npm run build:wasm\` from the repo root before running the integration tests.`, + `wasm-inline build not found at ${WASM_INLINE_PATH}. Run \`pnpm --filter @cipherstash/protect-ffi run build:wasm\` before running the integration tests.`, ) } return (await import(WASM_INLINE_PATH)) as T @@ -125,10 +150,7 @@ describe('wasm round-trip', () => { test('encrypts and decrypts a scalar value end-to-end', async () => { const env = requireEnv() - // @cipherstash/auth 0.39 takes the full workspace CRN and parses the - // region from it (earlier versions took only the `.` - // segment, requiring callers to split the CRN themselves). - const strategy = AccessKeyStrategy.create(env.workspaceCrn, env.accessKey) + const strategy = buildStrategy(env) const client = await wasm.newClient({ strategy, @@ -207,7 +229,7 @@ describe('wasm round-trip', () => { test('round-trips a bigint plaintext exactly and rejects out-of-range values', async () => { const env = requireEnv() - const strategy = AccessKeyStrategy.create(env.workspaceCrn, env.accessKey) + const strategy = buildStrategy(env) const client = await wasm.newClient({ authStrategy: strategy, @@ -269,7 +291,7 @@ describe('wasm round-trip', () => { test('bulk round-trips a mixed bigint / string / number batch', async () => { const env = requireEnv() - const strategy = AccessKeyStrategy.create(env.workspaceCrn, env.accessKey) + const strategy = buildStrategy(env) const client = await wasm.newClient({ authStrategy: strategy, @@ -332,7 +354,7 @@ describe('wasm round-trip', () => { test('json plaintexts follow JSON.stringify semantics (Neon parity)', async () => { const env = requireEnv() - const strategy = AccessKeyStrategy.create(env.workspaceCrn, env.accessKey) + const strategy = buildStrategy(env) const client = await wasm.newClient({ authStrategy: strategy, @@ -398,7 +420,7 @@ describe('wasm round-trip', () => { // value encrypts UNBOUND while the caller believes it is identity-bound, // and nothing in the output tells the two apart. const env = requireEnv() - const strategy = AccessKeyStrategy.create(env.workspaceCrn, env.accessKey) + const strategy = buildStrategy(env) const client = await wasm.newClient({ authStrategy: strategy, diff --git a/packages/protect-ffi/integration-tests/tsconfig.json b/packages/protect-ffi/integration-tests/tsconfig.json index dcddde99e..4c0093a12 100644 --- a/packages/protect-ffi/integration-tests/tsconfig.json +++ b/packages/protect-ffi/integration-tests/tsconfig.json @@ -1,7 +1,20 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "noEmit": true + "noEmit": true, + // The suite's two `.cjs` fixtures are real call sites of the same APIs the + // `.ts` tests use — `event-loop-exit-jsbacked.cjs` constructs an + // `AccessKeyStrategy` and hands it to `newClient`, and it was one of the + // four sites the `@cipherstash/auth` 0.42 bump broke. Without `checkJs` it + // is parsed and ignored, so the only thing that would have caught the break + // is a live run of the credentialed, path-filtered integration job. + // + // The fixtures need one JSDoc annotation each for this to pass: a plain + // object literal widens `cast_as: 'string'` to `string`, which does not + // satisfy `EncryptConfig`'s `CastAs` union. That is the annotation at the + // top of each file, not a workaround to remove. + "allowJs": true, + "checkJs": true }, - "include": ["tests/**/*.ts"] + "include": ["tests/**/*.ts", "tests/**/*.cjs"] } diff --git a/packages/protect-ffi/scripts/sync-eql-v3-types.sh b/packages/protect-ffi/scripts/sync-eql-v3-types.sh index b5fc71610..82cc88e56 100755 --- a/packages/protect-ffi/scripts/sync-eql-v3-types.sh +++ b/packages/protect-ffi/scripts/sync-eql-v3-types.sh @@ -11,8 +11,10 @@ # crate ships its ts-rs output (`bindings/**`), and `cargo metadata` resolves # the exact copy in the cargo registry that Cargo.lock pins. The vendored TS # types therefore cannot drift from the release the Rust conversion code links -# against. Integration SQL comes independently from the matching exact -# @cipherstash/eql version in integration-tests/package-lock.json. +# against. Integration SQL comes from the in-tree @cipherstash/eql, which +# integration-tests resolves at `workspace:^` — so the SQL the suite installs +# and the crate these types come from are the same commit, not two versions +# that happen to agree. # # Passing a path to an encrypt-query-language checkout as $1 overrides the # source for local development against unreleased bindings — regenerate the diff --git a/packages/protect-ffi/src/integrationSuiteCi.test.ts b/packages/protect-ffi/src/integrationSuiteCi.test.ts index 8d9fbaa20..edca6218c 100644 --- a/packages/protect-ffi/src/integrationSuiteCi.test.ts +++ b/packages/protect-ffi/src/integrationSuiteCi.test.ts @@ -26,6 +26,45 @@ import { describe, expect, it } from 'vitest' const packageRoot = process.cwd() const workflowDir = join(packageRoot, '../../.github/workflows') +/** + * `//` line comments removed, so `JSON.parse` accepts `turbo.json`. + * + * String-aware, and that is not defensive coding: `turbo.json`'s second line is + * `"$schema": "https://turbo.build/schema.json"`, so a regex for `//` truncates + * the file at its first key and every task lookup below goes quietly empty. + * Same reasoning, and the same character scan, as `readJsonc` in + * `scripts/lint-typecheck-scope.mjs` — reproduced rather than imported because + * that is an untyped `.mjs` outside this package's tsconfig. + */ +function stripJsonComments(raw: string): string { + let out = '' + let inString = false + let escaped = false + + for (let i = 0; i < raw.length; i++) { + const ch = raw[i] + if (inString) { + out += ch + if (escaped) escaped = false + else if (ch === '\\') escaped = true + else if (ch === '"') inString = false + continue + } + if (ch === '"') { + inString = true + out += ch + continue + } + if (ch === '/' && raw[i + 1] === '/') { + while (i < raw.length && raw[i] !== '\n') i++ + out += '\n' + continue + } + out += ch + } + return out +} + /** * The part of a workflow that actually does something: `jobs:` and everything * under it, with comment lines stripped. @@ -114,6 +153,96 @@ describe('integration-tests suite runs in CI', () => { expect(testFiles.length).toBeGreaterThanOrEqual(15) }) + it('names no script after a turbo task, so `pnpm test` stays credential-free', () => { + // The cost of workspace membership, and it is not hypothetical. Root + // `pnpm test` is `turbo test --filter './packages/**'`, which now REACHES + // this package — turbo already lists `#test` in the graph and skips it only + // because no script answers to that name. Give one that name and the repo's + // ordinary unit-test command starts demanding Docker, a Postgres on 5436 + // with both EQL versions installed, and live CipherStash credentials. The + // suites throw rather than skip when unconfigured, so the failure is loud, + // universal, and nowhere near the change that caused it. + // + // Derived from `turbo.json` rather than a list of names to avoid, because + // the list was wrong the first time it was written: this guard originally + // forbade `test` alone, while the suite's own live script was called + // `test:integration` — which is ALSO a turbo task, invoked by four + // integration workflows. Every one of them passes `--filter`, so nothing + // reached the suite in practice; an unfiltered `turbo run test:integration` + // (the shape of the root `"test:e2e": "turbo run test:e2e"` script) would + // have. Reading the task keys means a task added to `turbo.json` tomorrow is + // covered without anyone remembering this file. + // + // `typecheck` is the deliberate exception, and the reason the rule is + // "no LIVE script named after a task" rather than "no script named after a + // task": the suite's `tsc` gate is *meant* to run under + // `turbo run typecheck`, from tests.yml, on every PR. It needs no + // credentials and no database. The live entry points are `vitest:live` / + // `vitest:live:coverage`, which turbo knows nothing about. + const turboTasks = new Set( + Object.keys( + ( + JSON.parse( + stripJsonComments( + readFileSync(join(packageRoot, '../../turbo.json'), 'utf8'), + ), + ) as { tasks?: Record } + ).tasks ?? {}, + ), + ) + const suiteManifest = JSON.parse( + readFileSync(join(packageRoot, 'integration-tests/package.json'), 'utf8'), + ) as { scripts?: Record } + + // The floor on the derivation. An empty or mis-parsed `turbo.json` makes + // every assertion below vacuous, and it is read through a hand-rolled + // comment stripper, so it is exactly the kind of thing that fails silently. + expect(turboTasks).toContain('test') + expect(turboTasks).toContain('test:integration') + + const live = Object.keys(suiteManifest.scripts ?? {}).filter( + (name) => name !== 'typecheck', + ) + expect(live.length).toBeGreaterThan(0) + expect(live.filter((name) => turboTasks.has(name))).toEqual([]) + }) + + it('installs the suite from the workspace, not a second npm tree', () => { + // `integration-tests` became a pnpm workspace member in CIP-3744: its + // dependencies come from the repo lockfile, `@cipherstash/eql` resolves + // `workspace:^` and `@cipherstash/protect-ffi` `workspace:*`. The failure + // mode worth guarding is a half-revert that reinstates the npm install + // alongside the workspace one and re-resolves `@cipherstash/eql` from the + // registry — the emit/store skew the absorption existed to make + // unrepresentable, and one that would run GREEN in the credentialed job. + // + // Asserted against `tasks.toml`, which is where the `npm ci` actually was — + // step 1 of `[setup]`. An earlier draft of this test scanned the workflow + // body instead, which never contained the string: the workflow says + // `run: mise run setup` and delegates, so the guard would have stayed green + // through exactly the revert it names. That is the same defect + // `executablePart` exists to prevent one file over — a check pointed at + // prose rather than at the thing. + // + // And COMMENTS ARE STRIPPED, for the other half of that same lesson: this + // assertion failed on its first run against the file's own comments + // explaining why `npm ci` is gone. A substring search cannot tell a + // reinstated command from a sentence about one. Whole-line `#` only, which + // is how every comment in this file is written; a shell comment inside a + // `"""` block would be stripped too, and none of these tasks has one. + const tasks = readFileSync( + join(packageRoot, 'integration-tests/tasks.toml'), + 'utf8', + ).replace(/^[ \t]*#.*$/gm, '') + + // Floor on the read: a renamed or moved file, or a strip that ate the whole + // file, would make the assertions below vacuous. `[setup]` is the table the + // install lives in. + expect(tasks).toContain('[setup]') + expect(tasks).not.toMatch(/npm ci/) + expect(tasks).toMatch(/pnpm install --frozen-lockfile/) + }) + it('is invoked by at least one root workflow', () => { expect( suiteRunners.map((workflow) => workflow.name), @@ -136,10 +265,9 @@ describe('integration-tests suite runs in CI', () => { }) it(`${name} provisions the database and both EQL versions`, () => { - // `mise setup` is the whole preamble: `npm ci` (the suite is not a pnpm - // workspace member, so it has no node_modules otherwise), docker compose - // up, the EQL **v2** bundle from a GitHub release, and EQL **v3** from - // the pinned `@cipherstash/eql`. Both versions matter — + // `mise setup` is the whole preamble: the workspace install, docker + // compose up, the EQL **v2** bundle from a GitHub release, and EQL **v3** + // built from the in-tree `@cipherstash/eql`. Both versions matter — // `tests/postgres.test.ts` needs `eql_v2_encrypted`, and // `tests/postgres-v3.test.ts` needs the `eql_v3_*` domains. Nothing // else in this repo installs v2, so dropping this step fails half the diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3ea84908..4648cbc7f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,6 +30,9 @@ catalogs: '@types/node': specifier: 22.20.1 version: 22.20.1 + '@vitest/coverage-v8': + specifier: 3.2.7 + version: 3.2.7 tsup: specifier: 8.5.1 version: 8.5.1 @@ -405,6 +408,37 @@ importers: specifier: workspace:* version: link:platforms/win32-x64-msvc + packages/protect-ffi/integration-tests: + dependencies: + '@cipherstash/auth': + specifier: catalog:repo + version: 0.42.0(@cipherstash/auth-darwin-arm64@0.42.0)(@cipherstash/auth-darwin-x64@0.42.0)(@cipherstash/auth-linux-arm64-gnu@0.42.0)(@cipherstash/auth-linux-x64-gnu@0.42.0)(@cipherstash/auth-linux-x64-musl@0.42.0)(@cipherstash/auth-win32-x64-msvc@0.42.0) + '@cipherstash/protect-ffi': + specifier: workspace:* + version: link:.. + pg: + specifier: 8.23.0 + version: 8.23.0 + devDependencies: + '@cipherstash/eql': + specifier: workspace:^ + version: link:../../eql/packages/eql + '@types/pg': + specifier: ^8.23.1 + version: 8.23.1 + '@vitest/coverage-v8': + specifier: catalog:repo + version: 3.2.7(vitest@3.2.7(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) + dotenv: + specifier: 17.4.2 + version: 17.4.2 + typescript: + specifier: catalog:repo + version: 5.9.3 + vitest: + specifier: catalog:repo + version: 3.2.7(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0) + packages/protect-ffi/platforms/darwin-arm64: {} packages/protect-ffi/platforms/darwin-x64: {} @@ -562,13 +596,13 @@ importers: version: link:../stack '@prisma/orm-family-sql': specifier: 0.17.0 - version: 0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) + version: 0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) '@prisma/orm-framework': specifier: 0.17.0 version: 0.17.0(typescript@5.9.3) '@prisma/orm-toolchain': specifier: 0.17.0 - version: 0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) + version: 0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) arktype: specifier: ^2.2.3 version: 2.2.3 @@ -578,7 +612,7 @@ importers: version: link:../test-kit '@prisma/orm-target-postgres': specifier: 0.17.0 - version: 0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) + version: 0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) dotenv: specifier: 17.4.2 version: 17.4.2 @@ -730,6 +764,10 @@ importers: packages: + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.234': resolution: {integrity: sha512-6BJAbSOD5yGOzn1hU62ZfpybZhPlxcAe0r1w6qeGkAi/W3MD3Wl/TuVZ/y9/xvAwtfDmADDfbcHO0v6i0rjNIw==} cpu: [arm64] @@ -801,10 +839,31 @@ packages: '@ark/util@0.56.2': resolution: {integrity: sha512-9kU2sUE38FZEGG7l3hamYMBieLYEJh2L1mrYD2eXpT+78EnQSV1bhjxJhnxGBMSTbtwpBSDNSK+K60WvaI/DTQ==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/runtime@7.29.7': resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + '@biomejs/biome@2.5.9': resolution: {integrity: sha512-KkgCvdHB4IhtpHpF564plA9jo6fDOwWGQ/3jvreLzgOtRLEDoPqr7QO9qejNA8jKwDsSkAKr77hqBHnyUbIw4g==} engines: {node: '>=14.21.3'} @@ -1354,6 +1413,14 @@ packages: '@types/node': optional: true + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1470,6 +1537,10 @@ packages: '@petamoriken/float16@3.9.3': resolution: {integrity: sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@posthog/core@1.48.2': resolution: {integrity: sha512-zZNvsEg+YCezvJKeWdaZ77ngjKJvGnAEo31DIy2guYeDtZ5kNjJ4c6CkwqtmXmwNXjzOFGJyshzv3Fv2gHVJYA==} @@ -1790,6 +1861,15 @@ packages: resolution: {integrity: sha512-VYNCgUc0nOmC4WJmWw9GkrKdfr8Zl4/rxhC5SvgacBgxiW9W/9NRttUoHHXV8xdII3MaRgkZZVX8Ikzc/Jmjag==} engines: {node: '>=14'} + '@vitest/coverage-v8@3.2.7': + resolution: {integrity: sha512-NEGWJS2XNu2PfRLQwOO3CTKj1tTETxNBdk454vDxVBhxJYhPaA/eS0nAI0c+1El1P7a60z8+i+ZrQoGESweGKg==} + peerDependencies: + '@vitest/browser': 3.2.7 + vitest: 3.2.7 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@3.2.7': resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} @@ -1851,6 +1931,10 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -1878,6 +1962,9 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-v8-to-istanbul@0.3.12: + resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + aws-ssl-profiles@1.1.2: resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} engines: {node: '>= 6.0.0'} @@ -1972,6 +2059,13 @@ packages: closest-match@1.3.3: resolution: {integrity: sha512-RSdHrZwNOvt2uMQgqJDJdM/I+5MlJ1tQJEXYrbRjSMXWiCRo06g2hwObJ7+WKt2J9ySK9/pJ0Q2vbL+BPkofDA==} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -2167,9 +2261,18 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -2332,6 +2435,10 @@ packages: fix-dts-default-cjs-exports@1.0.1: resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -2395,6 +2502,11 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} @@ -2410,6 +2522,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -2422,6 +2538,9 @@ packages: resolution: {integrity: sha512-JydRilDRkYBQMt9qR9U92mXxmbGqsqSn/IKOrh4e7/gEbn+0zSr8igTu0obwJoNGN4sez28DIql7FBHWydoJpA==} engines: {node: '>=16.9.0'} + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -2461,6 +2580,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2502,6 +2625,25 @@ packages: resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} engines: {node: '>=18'} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true @@ -2517,6 +2659,9 @@ packages: resolution: {integrity: sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==} engines: {node: '>=20'} + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} @@ -2650,6 +2795,9 @@ packages: loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.3.6: resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} engines: {node: 20 || >=22} @@ -2661,6 +2809,13 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -2693,6 +2848,10 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2831,6 +2990,10 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -3197,6 +3360,14 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string-width@8.2.2: resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==} engines: {node: '>=20'} @@ -3238,6 +3409,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -3247,6 +3422,10 @@ packages: engines: {node: '>=10'} hasBin: true + test-exclude@7.0.2: + resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} + engines: {node: '>=18'} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -3486,6 +3665,14 @@ packages: resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} engines: {node: '>=20'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -3512,6 +3699,11 @@ packages: snapshots: + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.234': optional: true @@ -3570,8 +3762,23 @@ snapshots: '@ark/util@0.56.2': {} + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + '@babel/runtime@7.29.7': {} + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bcoe/v8-coverage@1.0.2': {} + '@biomejs/biome@2.5.9': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.5.9 @@ -4033,6 +4240,17 @@ snapshots: optionalDependencies: '@types/node': 22.20.1 + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/schema@0.1.6': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4140,16 +4358,19 @@ snapshots: '@petamoriken/float16@3.9.3': optional: true + '@pkgjs/parseargs@0.11.0': + optional: true + '@posthog/core@1.48.2': dependencies: '@posthog/types': 1.404.1 '@posthog/types@1.404.1': {} - '@prisma/orm-family-sql@0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0))': + '@prisma/orm-family-sql@0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0))': dependencies: '@prisma/orm-framework': 0.17.0(typescript@5.9.3) - '@prisma/orm-toolchain': 0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) + '@prisma/orm-toolchain': 0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) '@standard-schema/spec': 1.1.0 arktype: 2.2.3 pathe: 2.0.3 @@ -4204,11 +4425,11 @@ snapshots: - typanion - vite - '@prisma/orm-target-postgres@0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0))': + '@prisma/orm-target-postgres@0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0))': dependencies: - '@prisma/orm-family-sql': 0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) + '@prisma/orm-family-sql': 0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) '@prisma/orm-framework': 0.17.0(typescript@5.9.3) - '@prisma/orm-toolchain': 0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) + '@prisma/orm-toolchain': 0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0)) '@standard-schema/spec': 1.1.0 '@types/pg': 8.20.0 arktype: 2.2.3 @@ -4242,13 +4463,13 @@ snapshots: - typanion - vite - '@prisma/orm-toolchain@0.17.0(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0))': + '@prisma/orm-toolchain@0.17.0(magicast@0.3.5)(typanion@3.14.0)(typescript@5.9.3)(vite@7.3.6(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0))': dependencies: '@clack/prompts': 1.7.0 '@prisma/orm-framework': 0.17.0(typescript@5.9.3) '@vercel/detect-agent': 1.2.3 arktype: 2.2.3 - c12: 3.3.4 + c12: 3.3.4(magicast@0.3.5) ci-info: 4.4.0 clipanion: 4.0.0-rc.4(typanion@3.14.0) closest-match: 1.3.3 @@ -4277,7 +4498,7 @@ snapshots: '@prisma/orm-framework': 0.17.0(typescript@5.9.3) '@vercel/detect-agent': 1.2.3 arktype: 2.2.3 - c12: 3.3.4 + c12: 3.3.4(magicast@0.3.5) ci-info: 4.4.0 clipanion: 4.0.0-rc.4(typanion@3.14.0) closest-match: 1.3.3 @@ -4488,6 +4709,25 @@ snapshots: '@vercel/detect-agent@1.2.3': {} + '@vitest/coverage-v8@3.2.7(vitest@3.2.7(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.12 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.2 + tinyrainbow: 2.0.0 + vitest: 3.2.7(@types/node@26.2.0)(jiti@2.7.0)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.12)(yaml@2.9.0) + transitivePeerDependencies: + - supports-color + '@vitest/expect@3.2.7': dependencies: '@types/chai': 5.2.3 @@ -4562,6 +4802,10 @@ snapshots: ansi-regex@6.2.2: {} + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + ansi-styles@6.2.3: {} any-promise@1.3.0: {} @@ -4586,6 +4830,12 @@ snapshots: assertion-error@2.0.1: {} + ast-v8-to-istanbul@0.3.12: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + aws-ssl-profiles@1.1.2: optional: true @@ -4627,7 +4877,7 @@ snapshots: bytes@3.1.2: {} - c12@3.3.4: + c12@3.3.4(magicast@0.3.5): dependencies: chokidar: 5.0.0 confbox: 0.2.4 @@ -4641,6 +4891,8 @@ snapshots: perfect-debounce: 2.1.0 pkg-types: 2.3.1 rc9: 3.0.1 + optionalDependencies: + magicast: 0.3.5 cac@6.7.14: {} @@ -4686,6 +4938,12 @@ snapshots: closest-match@1.3.3: {} + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + colorette@2.0.20: {} commander@15.0.0: {} @@ -4764,8 +5022,14 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + encodeurl@2.0.0: {} enquirer@2.4.1: @@ -4964,6 +5228,11 @@ snapshots: mlly: 1.8.2 rollup: 4.60.4 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + forwarded@0.2.0: {} fresh@2.0.0: {} @@ -5037,6 +5306,15 @@ snapshots: glob-to-regexp@0.4.1: {} + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + glob@13.0.6: dependencies: minimatch: 10.2.5 @@ -5056,6 +5334,8 @@ snapshots: graceful-fs@4.2.11: {} + has-flag@4.0.0: {} + has-symbols@1.1.0: {} hasown@2.0.4: @@ -5064,6 +5344,8 @@ snapshots: hono@4.13.2: {} + html-escaper@2.0.2: {} + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -5092,6 +5374,8 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -5120,6 +5404,33 @@ snapshots: isexe@3.1.5: optional: true + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jiti@2.7.0: {} jose@6.2.9: {} @@ -5128,6 +5439,8 @@ snapshots: js-cookie@3.0.7: {} + js-tokens@10.0.0: {} + js-tokens@9.0.1: {} js-yaml@3.15.1: @@ -5235,6 +5548,8 @@ snapshots: loupe@3.2.1: {} + lru-cache@10.4.3: {} + lru-cache@11.3.6: {} lru.min@1.1.4: @@ -5244,6 +5559,16 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.3.5: + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.8.5 + math-intrinsics@1.1.0: {} media-typer@1.1.1: {} @@ -5267,6 +5592,10 @@ snapshots: dependencies: brace-expansion: 5.0.9 + minimatch@9.0.9: + dependencies: + brace-expansion: 5.0.9 + minimist@1.2.8: {} minipass@7.1.3: {} @@ -5394,6 +5723,11 @@ snapshots: path-key@4.0.0: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + path-scurry@2.0.2: dependencies: lru-cache: 11.3.6 @@ -5785,6 +6119,18 @@ snapshots: std-env@3.10.0: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + string-width@8.2.2: dependencies: get-east-asian-width: 1.5.0 @@ -5821,6 +6167,10 @@ snapshots: tinyglobby: 0.2.16 ts-interface-checker: 0.1.13 + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + term-size@2.2.1: {} terser@5.44.1: @@ -5831,6 +6181,12 @@ snapshots: source-map-support: 0.5.21 optional: true + test-exclude@7.0.2: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 10.5.0 + minimatch: 10.2.5 + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -6142,6 +6498,18 @@ snapshots: string-width: 8.2.2 strip-ansi: 7.2.0 + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + wrappy@1.0.2: {} xtend@4.0.2: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5fc67237a..8ac49a998 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,6 +11,19 @@ packages: # package.json by design — the private @cipherstash/eql-workspace manifest was # deleted so this glob contributes exactly one member. - packages/eql/packages/* + # The protect-ffi live integration suite. Nested a level deeper than + # `packages/*` reaches, like the two entries above, and named literally + # rather than globbed because `packages/protect-ffi/*` would also select + # `crates/`, `docs/`, `lib/`, `scripts/` and `src/` — directories with no + # package.json, which pnpm rejects rather than skips. + # + # It kept its own `package-lock.json` and installed with `npm ci` until + # CIP-3744. That was the last registry pin of `@cipherstash/eql` in the tree: + # the suite's `tests/postgres-v3.test.ts` queried SQL installed from the + # published bundle while the payloads under test came from the in-tree + # `eql-bindings` — exactly the skew the subtree import exists to make + # unrepresentable. + - packages/protect-ffi/integration-tests - examples/* - e2e @@ -40,6 +53,13 @@ catalogs: tsx: 4.23.12 typescript: 5.9.3 vitest: 3.2.7 + # Must track `vitest` exactly: the coverage provider is versioned in + # lockstep with the runner, and vitest refuses to start against a mismatched + # one ("Vitest failed to load @vitest/coverage-v8"). Catalogued for the same + # reason the auth bindings are, and enforced the same way — by a test rather + # than by this comment: see `e2e/tests/supply-chain.e2e.test.ts`. Dependabot + # groups both under `dev-dependencies` and will otherwise move one alone. + '@vitest/coverage-v8': 3.2.7 security: '@clerk/nextjs': 7.7.7 next: 15.5.23 @@ -157,10 +177,11 @@ blockExoticSubdeps: true # # @cipherstash/eql was listed here until the encrypt-query-language subtree # landed. It is now a workspace package, so no pnpm install ever resolves it -# from the registry and the entry became dead config. Note this stays true even -# though packages/protect-ffi/integration-tests still pins it by version: -# that directory is not a workspace member and installs with `npm ci`, and -# minimumReleaseAge is a pnpm setting that never applied to it. +# from the registry and the entry became dead config. The last holdout was +# packages/protect-ffi/integration-tests, which pinned it by version and +# installed with `npm ci` — outside pnpm entirely, so minimumReleaseAge never +# applied there either. That directory is a workspace member as of CIP-3744 and +# resolves `workspace:^`, so there is now nothing in the tree that could. minimumReleaseAgeExclude: - '@prisma-next/*' - '@prisma/orm-*' diff --git a/scripts/__tests__/frozen-publisher-runtime-pins.test.mjs b/scripts/__tests__/frozen-publisher-runtime-pins.test.mjs index c4b9dc564..54140ae7c 100644 --- a/scripts/__tests__/frozen-publisher-runtime-pins.test.mjs +++ b/scripts/__tests__/frozen-publisher-runtime-pins.test.mjs @@ -116,15 +116,24 @@ describe('frozen-publisher runtime pins', () => { }) it('does not fault a devDependency, which no consumer installs', () => { - // `packages/stack` declares `@cipherstash/eql` under `devDependencies`. It - // is the case that proves the narrowing above is a decision rather than an - // oversight: if this ever appears in the finding list, RUNTIME_TABLES has - // drifted from release-gate's INSTALLED_TABLES. + // `packages/stack` and the protect-ffi integration suite both declare + // `@cipherstash/eql` under `devDependencies`. They are the cases that prove + // the narrowing above is a decision rather than an oversight: if either + // appears in the finding list, RUNTIME_TABLES has drifted from + // release-gate's INSTALLED_TABLES. + // + // The two are exempt for DIFFERENT reasons, and the list is spelled out so + // adding a third forces someone to say which applies. `@cipherstash/stack` + // is published, and `devDependencies` simply are not installed by a + // consumer. `@cipherstash/ffi-integration-tests` is private and packs into + // no tarball at all — `consumerPrivate` already excuses it one filter up, + // so it would not be a finding even in a runtime table. const dev = frozenDeclarations().filter( (d) => d.dependency === '@cipherstash/eql' && d.table === 'devDependencies', ) - expect(dev.map(declarationId)).toEqual([ + expect(dev.map(declarationId).sort()).toEqual([ + '@cipherstash/ffi-integration-tests [devDependencies] :: @cipherstash/eql', '@cipherstash/stack [devDependencies] :: @cipherstash/eql', ]) expect(RUNTIME_TABLES.has('devDependencies')).toBe(false) diff --git a/scripts/__tests__/lint-no-eql-registry-pins.test.mjs b/scripts/__tests__/lint-no-eql-registry-pins.test.mjs index e59ee499c..a248f333a 100644 --- a/scripts/__tests__/lint-no-eql-registry-pins.test.mjs +++ b/scripts/__tests__/lint-no-eql-registry-pins.test.mjs @@ -79,9 +79,14 @@ const cargoForms = (body) => cargoDeclarations('Cargo.toml', body).map((d) => d.form) describe('the tree it actually guards', () => { - it('passes: every EQL dependency resolves in-tree or is exempt', () => { + it('passes: every EQL dependency resolves in-tree, with nothing exempt', () => { const { exitCode, output } = run() expect(output).toContain('resolves in-tree') + // No `(N exempt: …)` suffix. The exemption list is empty as of CIP-3744 + // and the success line reports what it excused, so this is the assertion + // that the tree needs no standing permission at all — not merely that the + // one it had is still described accurately. + expect(output).not.toContain('exempt') expect(exitCode).toBe(0) }) @@ -111,11 +116,29 @@ describe('the tree it actually guards', () => { ) }) - it('lists the exempt declaration in its success output', () => { - // An exemption that produces silence is an exemption nobody re-reads. - expect(run().output).toContain( - 'packages/protect-ffi/integration-tests/package.json', + it('resolves the integration suite in-tree, not from the registry', () => { + // What retiring the exemption was FOR. This suite's `postgres-v3.test.ts` + // queries SQL installed from `@cipherstash/eql` while the payloads under + // test are emitted by the in-tree `eql-bindings`, so a registry pin here + // was the one remaining place the two halves could disagree — and it + // disagreed in a database, not in CI. + const declaration = lint().declarations.find( + (d) => + d.file === 'packages/protect-ffi/integration-tests/package.json' && + d.dependency === '@cipherstash/eql', ) + expect(declaration).toBeDefined() + expect(declaration.inTree).toBe(true) + expect(declaration.spec).toContain('workspace:') + }) + + it('lists any exempt declaration in its success output', () => { + // An exemption that produces silence is an exemption nobody re-reads. + // Vacuous while the map is empty, which is the point: it is the assertion + // that has to keep passing if an entry is ever added back. + for (const id of EXEMPT_DECLARATIONS.keys()) { + expect(run().output).toContain(id.split(' :: ')[0]) + } }) it('has a written reason for every exemption', () => { @@ -851,14 +874,14 @@ describe('the linter fails when its own configuration goes stale', () => { }) it('detects an exemption whose manifest went in-tree', () => { - // The case that will actually happen. `integration-tests` is exempt - // because it installs with `npm ci` and cannot resolve `workspace:`; - // absorbing it into the pnpm workspace is a scheduled follow-up. On that - // day the manifest still DECLARES `@cipherstash/eql` — it just no longer - // needs excusing — so an existence-based staleness check would keep - // passing and leave a standing permission behind. Mutation-checked against - // the real tree: flipping that pin to `workspace:^` moved the linter from - // exit 0 to exit 2, where the looser spelling had left it at 0. + // The case that DID happen. `integration-tests` was exempt because it + // installed with `npm ci` and could not resolve `workspace:`; absorbing it + // into the pnpm workspace was a scheduled follow-up. When that landed the + // manifest still DECLARED `@cipherstash/eql` — it just no longer needed + // excusing — so an existence-based staleness check would have kept passing + // and left a standing permission behind. Mutation-checked against the real + // tree at the time: flipping that pin to `workspace:^` moved the linter + // from exit 0 to exit 2, where the looser spelling had left it at 0. const root = tree({ 'a/package.json': '{"dependencies":{"@cipherstash/eql":"workspace:^"}}', }) diff --git a/scripts/lint-no-eql-registry-pins.mjs b/scripts/lint-no-eql-registry-pins.mjs index aacc6a669..830993e28 100644 --- a/scripts/lint-no-eql-registry-pins.mjs +++ b/scripts/lint-no-eql-registry-pins.mjs @@ -58,7 +58,9 @@ * * `EXEMPT_DECLARATIONS`, keyed ` :: ` with a mandatory * written reason, in the shape of `BINDING_EXEMPT_JOBS` in - * `scripts/__tests__/ffi-binding-step-order.test.mjs`. One entry today. + * `scripts/__tests__/ffi-binding-step-order.test.mjs`. NONE today — the one + * entry there had ever been was retired when its directory joined the pnpm + * workspace. * * The alternative — narrowing the scan so it never reaches the directory — was * rejected for the reason this whole absorption keeps rediscovering: a scan @@ -165,22 +167,21 @@ export const EXPECTED_SOURCES = [WORKSPACE_FILE] /** * Declarations allowed to name a registry version, each with the reason. * - * Keep this at one entry if at all possible. Every entry is a place the two - * halves of EQL can drift apart again, and the reason is what a later reader - * needs in order to decide whether it is still true. + * EMPTY, and that is the goal state rather than an oversight. Every entry is a + * place the two halves of EQL can drift apart again, and the reason is what a + * later reader needs in order to decide whether it is still true. + * + * There was one, for `packages/protect-ffi/integration-tests`: it was not a + * pnpm workspace member, installed with `npm ci`, and so could not resolve a + * `workspace:` specifier at all. Absorbing it into the workspace (CIP-3744) was + * what retired the exemption — and the `staleExemptions` spelling below is what + * forced the entry to be deleted in the same change, since the manifest still + * DECLARES `@cipherstash/eql` and an existence-based check would have gone on + * passing over a standing permission nothing needed. + * + * Adding one back means writing the reason down here. Prefer not to. */ -export const EXEMPT_DECLARATIONS = new Map([ - [ - `packages/protect-ffi/integration-tests/package.json :: ${NPM_DEPENDENCY}`, - 'Not a pnpm workspace member: `pnpm-workspace.yaml` globs one level under ' + - '`packages/`, so this directory is invisible to pnpm, installs with `npm ' + - 'ci`, and cannot resolve a `workspace:` specifier. Absorbing it into the ' + - 'workspace is open decision 3 in ' + - 'docs/plans/2026-08-13-eql-monorepo-absorption.md — it moves ' + - '`@cipherstash/auth`, `vitest` and this pin at once, and only a run with ' + - 'Docker plus CS_* credentials can show that is neutral.', - ], -]) +export const EXEMPT_DECLARATIONS = new Map([]) /** Files this scan reads, by name. */ const SCANNED_FILES = new Set(['Cargo.toml', 'package.json', WORKSPACE_FILE]) @@ -645,14 +646,14 @@ export function lint({ // oversight. // // Measured against the declarations that are ACTUALLY registry-pinned, not - // against every declaration found. The difference is the case that will - // really happen: `packages/protect-ffi/integration-tests` is exempt because - // it installs with `npm ci` and cannot take a `workspace:` specifier, and - // absorbing it into the workspace is a scheduled follow-up. On the day that - // lands, the manifest still declares `@cipherstash/eql` — so an - // existence-based check would keep passing and leave the exemption behind, - // permanently permitting a pin nothing has needed since. This spelling - // fails that PR until the entry is deleted. + // against every declaration found. The difference is the case that already + // happened: `packages/protect-ffi/integration-tests` was exempt because it + // installed with `npm ci` and could not take a `workspace:` specifier, and + // absorbing it into the workspace was a scheduled follow-up. When that + // landed the manifest still declared `@cipherstash/eql` — so an + // existence-based check would have kept passing and left the exemption + // behind, permanently permitting a pin nothing needed any more. This + // spelling failed that PR until the entry was deleted. staleExemptions: [...exemptions.keys()].filter( (id) => !registryPinned.includes(id), ), @@ -783,8 +784,10 @@ export function report(result) { 'is nothing in-tree for it to move to that the workspace protocol does\n' + 'not already say.\n\n' + 'If the manifest genuinely cannot take an in-tree specifier, add it to\n' + - 'EXEMPT_DECLARATIONS in this script WITH the reason. There is one such\n' + - 'case today and it is written up there.\n', + 'EXEMPT_DECLARATIONS in this script WITH the reason. That list is empty\n' + + 'today — the last entry was retired when its directory joined the pnpm\n' + + 'workspace — so an addition is a new standing permission, not a\n' + + 'precedent being followed.\n', } } diff --git a/scripts/lint-typecheck-scope.mjs b/scripts/lint-typecheck-scope.mjs index d608b824f..1dee35582 100644 --- a/scripts/lint-typecheck-scope.mjs +++ b/scripts/lint-typecheck-scope.mjs @@ -31,12 +31,18 @@ const REPO_ROOT = resolve(import.meta.dirname, '..') // with argv[2..] for tests / ad-hoc checks (each arg is a package directory). // // NESTED roots are listed separately because the walk below is one level deep, -// matching how pnpm globs `packages/*`. Two subtrees put packages a level +// matching how pnpm globs `packages/*`. Three sets of packages sit a level // further down and need their own entry here for the same reason they need one // in `pnpm-workspace.yaml`: // // packages/protect-ffi/platforms/* the six per-platform binary packages // packages/eql/packages/* @cipherstash/eql, from the EQL subtree +// packages/protect-ffi/* the live integration suite +// +// The last is spelled as its PARENT rather than as the member, because the walk +// takes roots and lists their children. That sweeps protect-ffi's non-package +// siblings (`crates`, `docs`, `src`, …) into the candidate list too; they carry +// no package.json / tsconfig.json pair, so the loop below skips them. // // Getting this wrong is silent in the direction that matters: a package outside // the scan is never reported, which reads exactly like a package that passed. @@ -46,6 +52,7 @@ const REPO_ROOT = resolve(import.meta.dirname, '..') const WORKSPACE_ROOTS = [ 'packages', 'examples', + 'packages/protect-ffi', 'packages/protect-ffi/platforms', 'packages/eql/packages', ]