From f24fddae7c8f8970a8b5dbc5afb101ef831d17eb Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Fri, 23 Oct 2026 09:48:21 +0000 Subject: [PATCH 1/8] fix(zero-cache): key CRUD writes by the table's primary key Mono-Internal-Commit: ed0aab36c4430cdeb99cfa6c5bef6ee8f17793d3 --- .../zero-cache/src/auth/write-authorizer.ts | 18 ++++++++++++------ .../zero-cache/src/services/mutagen/mutagen.ts | 7 +++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/zero-cache/src/auth/write-authorizer.ts b/packages/zero-cache/src/auth/write-authorizer.ts index 842974f287..1f257f1083 100644 --- a/packages/zero-cache/src/auth/write-authorizer.ts +++ b/packages/zero-cache/src/auth/write-authorizer.ts @@ -71,10 +71,14 @@ export interface WriteAuthorizer { normalizeOps(ops: CRUDOp[]): Exclude[]; /** - * Validates that all table names in the operations exist in the schema. + * Validates that all table names in the operations exist in the schema and + * returns the operations with `primaryKey` replaced by the table's primary + * key from the replica. The client-supplied `primaryKey` is not trusted: the + * authorizer checks the row identified by the replica's primary key, so the + * writes must target that same row. * @throws Error if any table name is invalid */ - validateTableNames(ops: CRUDOp[]): void; + validateOps(ops: CRUDOp[]): CRUDOp[]; } export class WriteAuthorizerImpl implements WriteAuthorizer { @@ -261,12 +265,14 @@ export class WriteAuthorizerImpl implements WriteAuthorizer { }); } - validateTableNames(ops: CRUDOp[]): void { - for (const op of ops) { - if (!this.#tableSpecs.has(op.tableName)) { + validateOps(ops: CRUDOp[]): CRUDOp[] { + return ops.map(op => { + const tableSpec = this.#tableSpecs.get(op.tableName); + if (!tableSpec) { throw new Error(`Table '${op.tableName}' is not a valid table.`); } - } + return {...op, primaryKey: tableSpec.tableSpec.primaryKey}; + }); } #canInsert(phase: Phase, authData: JWTPayload | undefined, op: InsertOp) { diff --git a/packages/zero-cache/src/services/mutagen/mutagen.ts b/packages/zero-cache/src/services/mutagen/mutagen.ts index 257467aa37..00b726fa3a 100644 --- a/packages/zero-cache/src/services/mutagen/mutagen.ts +++ b/packages/zero-cache/src/services/mutagen/mutagen.ts @@ -355,10 +355,9 @@ export async function processMutationWithTx( authorizer.reloadPermissions(); if (!errorMode) { - const {ops} = mutation.args[0]; - - // Validate all table names before processing - authorizer.validateTableNames(ops); + // Validates table names and keys every op by the replica's primary key, + // which is what the authorizer checks. + const ops = authorizer.validateOps(mutation.args[0].ops); const normalizedOps = authorizer.normalizeOps(ops); const [canPre, canPost] = await Promise.all([ From 874e1ec9d75bb40d38447cc760ce4bcd564f669e Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Fri, 23 Oct 2026 11:52:38 +0000 Subject: [PATCH 2/8] fix(zero-cache): keep an initConnection whose validation an updateAuth overtakes Closes rocicorp/mono#6727 Co-authored-by: Yevhenii Mono-Internal-Commit: b1fa4b7b58136a0e19d928d8f4b3cbb527109326 --- .../src/services/view-syncer/view-syncer.ts | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/zero-cache/src/services/view-syncer/view-syncer.ts b/packages/zero-cache/src/services/view-syncer/view-syncer.ts index 51158986d5..c805b8b1fd 100644 --- a/packages/zero-cache/src/services/view-syncer/view-syncer.ts +++ b/packages/zero-cache/src/services/view-syncer/view-syncer.ts @@ -1493,7 +1493,9 @@ export class ViewSyncerService implements ViewSyncer, ActivityBasedService { // queries, but that may hit the transform cache so do not rely on // it for validation. This also ensures shared maintenance always has // a validated connection to fall back to. - if (!(await this.#validateConnection(connCtx))) { + const validatedConnCtx = + await this.#validateCurrentConnection(connCtx); + if (!validatedConnCtx) { return; } await this.#handleConfigUpdate( @@ -1506,8 +1508,8 @@ export class ViewSyncerService implements ViewSyncer, ActivityBasedService { // `cg${clientGroupID}`, as is done in the schema migration. // As clients update to the zero version with the profileID logic, // the value will be correspondingly in the CVR db. - connCtx.profileID ?? `cg${this.id}`, - connCtx, + validatedConnCtx.profileID ?? `cg${this.id}`, + validatedConnCtx, ); // this.#authData and cvr (in particular cvr.clientSchema) have been // initialized, signal the run loop to run. @@ -4331,6 +4333,28 @@ export class ViewSyncerService implements ViewSyncer, ActivityBasedService { } } + /** + * Validates the connection's credential as it stands once validation ends. + * An `updateAuth` handled while a validation is in flight moves the + * connection to a newer revision, which makes a failure of the older one + * stale, as is its success; the newer credential is then validated in its + * place, so the `initConnection` waiting on it is not dropped. + */ + async #validateCurrentConnection( + selector: ConnectionSelector, + ): Promise { + let connCtx = this.connContextManager.getConnectionContext(selector); + while (connCtx) { + const valid = await this.#validateConnection(connCtx); + const current = this.connContextManager.getConnectionContext(selector); + if (current?.revision === connCtx.revision) { + return valid ? connCtx : undefined; + } + connCtx = current; + } + return undefined; + } + #failMaintenanceConnection(connCtx: ConnectionContext, error: ProtocolError) { const failed = this.connContextManager.failConnection( connCtx, From 14aaece1b3287ac5efceec48f6fc101e2f5f0b2c Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Fri, 23 Oct 2026 13:23:31 +0000 Subject: [PATCH 3/8] chore: add knip config for finding unused files, deps and exports Mono-Internal-Commit: d92a4bef4b59bfbc2d2738b608258251e84ebdd9 --- package.json | 2 + pnpm-lock.yaml | 530 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 529 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 53ec14a5bc..444f1fcf3d 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "start-zero-cache": "cd packages/zero-cache && pnpm run start", "verify-deps": "cd tools/verify-package-deps && pnpm run verify", "verify-deps:fix": "cd tools/verify-package-deps && pnpm run verify:fix", + "knip": "knip", "api-snapshot": "vitest run --config tools/tsnapi/vitest.config.ts", "api-snapshot:update": "vitest run -u --config tools/tsnapi/vitest.config.ts", "bench": "turbo run bench --concurrency=1", @@ -34,6 +35,7 @@ "@vitest/browser-playwright": "^5.0.5", "@vitest/coverage-v8": "^5.0.5", "baseline-browser-mapping": "^2.11.29", + "knip": "^6.42.1", "oxfmt": "^0.74.0", "oxlint": "^1.80.0", "oxlint-tsgolint": "^7.0.2001", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7526256302..059be0e628 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: baseline-browser-mapping: specifier: ^2.11.29 version: 2.11.29 + knip: + specifier: ^6.42.1 + version: 6.42.1 oxfmt: specifier: ^0.74.0 version: 0.74.0 @@ -3608,12 +3611,21 @@ packages: '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/core@1.11.2': + resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} + '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.11.2': + resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.hirok.io' @@ -4319,6 +4331,13 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@napi-rs/wasm-runtime@1.2.5': + resolution: {integrity: sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + '@noble/ciphers@1.3.0': resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} @@ -4937,42 +4956,84 @@ packages: cpu: [arm] os: [android] + '@oxc-parser/binding-android-arm-eabi@0.154.0': + resolution: {integrity: sha512-sDdEtDl7vKdCvf54j72RJbowE3jCmyRz/+oOB6IAwQxAHZ0eI+Dcj4hvVnm0b9Dy31plUkdmfds9C+/Zt895Tg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + '@oxc-parser/binding-android-arm64@0.129.0': resolution: {integrity: sha512-DVyLFN2+S0VOhT6lm5++tFqlu3x2Njiby6y5DhTzjV5uRsZWpifsBn6+yjtwAxl105peEjs5BHE3ToBJuQjLTg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] + '@oxc-parser/binding-android-arm64@0.154.0': + resolution: {integrity: sha512-UHrDPELzvWZoVkIDdSycj4bzcTMCJG3IbN++mSUgVBaUtNtWHjQ98U6Vz5bpF/1Ic3FYJyYhMr74huO5tVvpZw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@oxc-parser/binding-darwin-arm64@0.129.0': resolution: {integrity: sha512-QeqThtB8qax4IL+NFBWgshudyKkj5c076L8vyd8PCEx7U1wHyIbH49MEQ5J5iURFhUW5jiFmdnLKEwyOo0GAJA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@oxc-parser/binding-darwin-arm64@0.154.0': + resolution: {integrity: sha512-mokYzajOSXxtSRDWCdHARGdntrKH+rZZ24Jzo8AtafyNzz0NARmpMm26Tc5B6qiGrr6UliWibHCOif1qRN2vaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@oxc-parser/binding-darwin-x64@0.129.0': resolution: {integrity: sha512-zn5+7nv4DlK4uFgblmhKm6xRV0QUHXOHyIDkjmhxJ53xSA9ahkb3pHNiHesNPXn/nK/VWU+C+Z6JYHdatZBh7g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@oxc-parser/binding-darwin-x64@0.154.0': + resolution: {integrity: sha512-WbtUBrclOVItWfLRSvs+Z/WLtXxJ2Ctv50PyuX894HzDN5/e0qzxVpTNPIVMzOerBhgKtFsSMcfxlYIAbvdVgg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@oxc-parser/binding-freebsd-x64@0.129.0': resolution: {integrity: sha512-SPTcDBiHWlgRpWFC1jnoi0sBWqCw4DFR+4b8+dV+NAhUu2ONERWyIVIOCfcE9a8BlvZsDCuXf3l/x7wQUs1Rsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@oxc-parser/binding-freebsd-x64@0.154.0': + resolution: {integrity: sha512-YooHZSLawOe2fqm+lDdG8oAaQh2NYV/RMYTYzWRLy72stm2BgE9O/8Al6kFENjkmzyyBccDLLBirGxVtpzQfrw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@oxc-parser/binding-linux-arm-gnueabihf@0.129.0': resolution: {integrity: sha512-Rgc9+WNKLbc+chyDTXyyJ7gbgLo+ve27CrRnmIwGgucGflrBZbutge5jdPPegcgf46RrR4dkBbMCp0/x16mdig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@oxc-parser/binding-linux-arm-gnueabihf@0.154.0': + resolution: {integrity: sha512-hKOwhZbrXdTwc4bGVfbLCXl9f2swl6zWdISocLQSNX9MgPmwHE3qGzOUkCrkuGpwdCVHPnkfOwsqTuYsrP5uNg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@oxc-parser/binding-linux-arm-musleabihf@0.129.0': resolution: {integrity: sha512-YtSsJ51VysXqlO8Cs2mWTyXvxBRemTHj4WDQjXwKl0SAxh+CVrEdXrdH+RnjxLj3JCUMFeYuHs5c+/DImfbKkg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@oxc-parser/binding-linux-arm-musleabihf@0.154.0': + resolution: {integrity: sha512-tnjiooXEU013349O/yxKbF5Cusp1CfHWQ8kYR8tGeRzR/P4sOpQGQo21fsS71M0fMD6ESLq+lbvXFWi43PuKeQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@oxc-parser/binding-linux-arm64-gnu@0.129.0': resolution: {integrity: sha512-9oK8iQr9KtgI5JhaJ+5IwiQsXEo6NuasFgovtJGrdK/RxbA0bO4YKRvVY7M+8lozUCVz1U7XrFFODv3emIOPRA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4980,6 +5041,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-parser/binding-linux-arm64-gnu@0.154.0': + resolution: {integrity: sha512-Cao2kj+8d7BT6XJU1gV9eVQjV+Cr+e8vQm3tddDRZiM2hHrMDxwy3j6t+ofaSl0idyuPPCZ4AlpmQoj8yOT1QA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@oxc-parser/binding-linux-arm64-musl@0.129.0': resolution: {integrity: sha512-GghE/bf9ZqgqZFxLacgP0ImVD6UiLKQOpvpgUoIsqjopu2ms/+p1L0d0Dv2Sck+8p0FbKS2WE3IjqmIlLbxJgA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4987,6 +5055,13 @@ packages: os: [linux] libc: [musl] + '@oxc-parser/binding-linux-arm64-musl@0.154.0': + resolution: {integrity: sha512-uiwA0V3q8llWA7/8r+a9BBjk4j5YMDmi6wfOsyQfGOJMQSLHEiZ3HI8ulea766ykUa9wJFWk9XWEl4uJrZLQqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@oxc-parser/binding-linux-ppc64-gnu@0.129.0': resolution: {integrity: sha512-A2PW0UbERzKGV6fKX1zoe2Tkc1zVcEJSSPW9IUSKbZAPuPe+M5/5hTA+6fQbWmevabe2B3IDky66a1lFGjpBKA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4994,6 +5069,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-parser/binding-linux-ppc64-gnu@0.154.0': + resolution: {integrity: sha512-LICfN0Xs4Zdko+bJy6eOAEQojDuIR26suF2JtOsMaXjgbCrpRSH7/NCvJhY13YvYBx12V6hnwrL8n0lk0rbNJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@oxc-parser/binding-linux-riscv64-gnu@0.129.0': resolution: {integrity: sha512-omwxd9H+jrl1T72RI666k4ho7Eli2iHdELzf+dL0D+uXThNZXYJCbKjm5rK2hrHmDy4O+NWv7+khBrEkorLsgw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5001,6 +5083,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-parser/binding-linux-riscv64-gnu@0.154.0': + resolution: {integrity: sha512-gbbSYxLF8ssRbQ2qQPy+2EhGNwNH1bAoRdkk6cnWaKHqmCikpSIPtpXjFbCCtjTi0uojqOM3ghFQwQPbDQsU0Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@oxc-parser/binding-linux-riscv64-musl@0.129.0': resolution: {integrity: sha512-v2hi8id+M8C0uY8uuG2t2a5vr8H9XyHXiHL12yMdMNtgn04nnM/8hlOGuoJuxVc07PhClNiaoSaY2eXehSRa7w==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5008,6 +5097,13 @@ packages: os: [linux] libc: [musl] + '@oxc-parser/binding-linux-riscv64-musl@0.154.0': + resolution: {integrity: sha512-nSnRYYDLCcRVjSQzF3g6rKqCNYwo5o+aQgnn8BBXfe+ofCgMGlGqkfRyvXm6ptZvoxNkkWtLlqM8W7Xc3j6ZnQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + '@oxc-parser/binding-linux-s390x-gnu@0.129.0': resolution: {integrity: sha512-UXrdDyLh1Obgj5X+IVVXWoo5/FJbFsU8/uLQ/M9lkVUwBUKpRFxNEhzwBNv21qqdKgAh+pr2CCVD8J1JfRPsIQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5015,6 +5111,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-parser/binding-linux-s390x-gnu@0.154.0': + resolution: {integrity: sha512-BxBQoJKtzRQgZEKQIt6CDUm8RGKC5T8Qo4576yDa5/xgc10X3fBDItMbRabzLtbUBfTqKLl+8AVr/H6CF7W22g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@oxc-parser/binding-linux-x64-gnu@0.129.0': resolution: {integrity: sha512-hsL/3/kdX9FGLqOj8DR3Eki4Y6zO1i3+ZHhiPwX0hDt4n+18abkfUzePCv3h8SShprwCmwdxPnlrebZ5+MZ+cw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5022,6 +5125,13 @@ packages: os: [linux] libc: [glibc] + '@oxc-parser/binding-linux-x64-gnu@0.154.0': + resolution: {integrity: sha512-/whkust2vYy+GjRUVL5cWaJmEu6jkdFfo5mkxgckyeOX61eMwo4iBoiwzeJZeMWAdzb/XOtQyLApHhFht3sOWA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@oxc-parser/binding-linux-x64-musl@0.129.0': resolution: {integrity: sha512-kdXvJ4crOeRld3vWl0J0VU4nmnT4pZ3lKGA5tZ1y0UPWsBtElDYd+jsz4lE36tpAbCiWm0M0PG0laUNBSE+Wlw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5029,12 +5139,25 @@ packages: os: [linux] libc: [musl] + '@oxc-parser/binding-linux-x64-musl@0.154.0': + resolution: {integrity: sha512-EXURTyW9riw4B/kZnnE+58emAtw6+3VEszQfXUZkRqGaKIcmWDYkZtKB+xY/blHvuZ+Qy/fDclc31nmUCgtkSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@oxc-parser/binding-openharmony-arm64@0.129.0': resolution: {integrity: sha512-DusJfcK7EGwf9TEakB+z6SXCLdHGvDZ8U8882bzWb4oVrORHpbkFl9npS7cN3YC2axcVKoktbxZevS1nxVCKFw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@oxc-parser/binding-openharmony-arm64@0.154.0': + resolution: {integrity: sha512-ZRFooyH3qsR6vuR4jFGlG3XM36490SvvXtNaUahBK4zHpooMdTHNaOMtGGJI0EW38m5hi4rOco9kw7ZwCIp28w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@oxc-parser/binding-wasm32-wasi@0.129.0': resolution: {integrity: sha512-Iie9CcII+ELSinKFnxTR15xhI9qriVivEhbFh3driRNbzms/5ioDAU0fwe8Mf1FEaz3n2FtiUVX0h0nwKLYk0A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5046,24 +5169,145 @@ packages: cpu: [arm64] os: [win32] + '@oxc-parser/binding-win32-arm64-msvc@0.154.0': + resolution: {integrity: sha512-U0Vp+4lvwUa/PnOCJTZOjydj1rX2+VLHz4Y2vSFqlN8/7LTiURgD7z4uQ9yNv9O/NlU3mELBnPDlu7aaSYG1zQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@oxc-parser/binding-win32-ia32-msvc@0.129.0': resolution: {integrity: sha512-tmSBR1A4yH697qV291xKyDe4OAWFchJ+cXf2wuipx/vK3n5d5Ej9MVLRtXlIcZ38n8qAjsF0/AnskaYgxM151A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] + '@oxc-parser/binding-win32-ia32-msvc@0.154.0': + resolution: {integrity: sha512-Hc8QgsFY5eUUP25we8TISUruibG2cDt0H4IcPG9RKdabb6odkCzIqjV6Gk9beGWGuOwMVCr81H/Su1q363LCCg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + '@oxc-parser/binding-win32-x64-msvc@0.129.0': resolution: {integrity: sha512-Z1PbJvkPeLASIUxa3AnrQ5H+vv1K9zC0IGnQqoKfM0ZvsvCSe0d3u5m7d9iuy+HB7GrcElHuwKb0d0qFdtG0iA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@oxc-parser/binding-win32-x64-msvc@0.154.0': + resolution: {integrity: sha512-hD7judkUMA/hZPoamvKADs6+an1smp8UTK0aMYRijkvi00K/1vl7vEtmyn2JyQ9S+vibtnfcNzxqTLGyJUZCRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@oxc-project/types@0.129.0': resolution: {integrity: sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==} '@oxc-project/types@0.154.0': resolution: {integrity: sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==} + '@oxc-resolver/binding-android-arm-eabi@11.24.2': + resolution: {integrity: sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==} + cpu: [arm] + os: [android] + + '@oxc-resolver/binding-android-arm64@11.24.2': + resolution: {integrity: sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg==} + cpu: [arm64] + os: [android] + + '@oxc-resolver/binding-darwin-arm64@11.24.2': + resolution: {integrity: sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w==} + cpu: [arm64] + os: [darwin] + + '@oxc-resolver/binding-darwin-x64@11.24.2': + resolution: {integrity: sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q==} + cpu: [x64] + os: [darwin] + + '@oxc-resolver/binding-freebsd-x64@11.24.2': + resolution: {integrity: sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw==} + cpu: [x64] + os: [freebsd] + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2': + resolution: {integrity: sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2': + resolution: {integrity: sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-gnu@11.24.2': + resolution: {integrity: sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-arm64-musl@11.24.2': + resolution: {integrity: sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2': + resolution: {integrity: sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2': + resolution: {integrity: sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-riscv64-musl@11.24.2': + resolution: {integrity: sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-resolver/binding-linux-s390x-gnu@11.24.2': + resolution: {integrity: sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-x64-gnu@11.24.2': + resolution: {integrity: sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-resolver/binding-linux-x64-musl@11.24.2': + resolution: {integrity: sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-resolver/binding-openharmony-arm64@11.24.2': + resolution: {integrity: sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg==} + cpu: [arm64] + os: [openharmony] + + '@oxc-resolver/binding-wasm32-wasi@11.24.2': + resolution: {integrity: sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': + resolution: {integrity: sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg==} + cpu: [arm64] + os: [win32] + + '@oxc-resolver/binding-win32-x64-msvc@11.24.2': + resolution: {integrity: sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw==} + cpu: [x64] + os: [win32] + '@oxfmt/binding-android-arm-eabi@0.65.0': resolution: {integrity: sha512-M10Gs1SSpTNI6ahGx3M/OlIdUF4hkaP6OgUb+MS79t/Pgflk3r1nW5gPFqsZGUAXg0H1AfANT9AvLdBSTIhZKg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -6240,6 +6484,9 @@ packages: '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + '@tybys/wasm-util@0.10.4': + resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} + '@types/argparse@1.0.38': resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} @@ -8628,6 +8875,9 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fd-package-json@2.0.0: + resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -8753,6 +9003,11 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} + formatly@0.11.4: + resolution: {integrity: sha512-TeCC10lP8KCgoX+Fe5lryILIT0/Dy+nP0OSVnsuB5CwXoLuOdqxCYlPFF1inR8S/zTy1ec7TjhS2TeRKWzzImA==} + engines: {node: '>=18.14.0'} + hasBin: true + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -8843,6 +9098,9 @@ packages: get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + get-tsconfig@4.14.3: + resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} + get-uri@6.0.5: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} engines: {node: '>= 14'} @@ -9521,6 +9779,11 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + knip@6.42.1: + resolution: {integrity: sha512-gKJVsiT4LJQ0lfc8uSHOCzkOY8adAXNFGarIeODZbJOkBnQRVsG3e0UZFnO4LMwjA82A5tBWX/VgoeTYcjdKiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + kysely@0.28.17: resolution: {integrity: sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==} engines: {node: '>=20.0.0'} @@ -10381,6 +10644,13 @@ packages: resolution: {integrity: sha512-S6eFI+VLkpyA+/Lf8z6qURjDV6Mgo74SLNznNopHTlQW3hedv2MB/z31kBRuBCCTqZN9HHdva0ojljEhPnBKFA==} engines: {node: ^20.19.0 || >=22.12.0} + oxc-parser@0.154.0: + resolution: {integrity: sha512-Gr/6fkjZwi937c4Tsz8y0iO4U0FLPkZI6JSVucLAIvQyqh379px7RS8ORIc0HOORbFjXZ6zyqWLl53qxhSeofw==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-resolver@11.24.2: + resolution: {integrity: sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw==} + oxfmt@0.65.0: resolution: {integrity: sha512-SgS5VgnP42T0zl3zWD+xoH8FCqg1SAFnSRoOT/qeoa6gxcYIqrDMOmcXIg/EWSN92Du4ogB4riuKhKd6Y4CGhw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -10474,6 +10744,9 @@ packages: resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} engines: {node: '>=14.16'} + package-manager-detector@1.9.0: + resolution: {integrity: sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==} + param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -12013,6 +12286,10 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smol-toml@1.9.1: + resolution: {integrity: sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==} + engines: {node: '>= 18'} + snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -12215,6 +12492,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + strnum@2.3.0: resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} @@ -12616,6 +12897,10 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + unbash@6.0.1: + resolution: {integrity: sha512-0db9eS5iqybux41zLkX69nk90KTci7F7eZ+gXzEG/Q7E0tAqEBhRh5fkZvk1N7jT7QkGWqq34i8SFGPFEe1V8A==} + engines: {node: '>=14'} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -12916,6 +13201,10 @@ packages: vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -13181,6 +13470,9 @@ packages: zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} + zstd-codec@0.1.5: resolution: {integrity: sha512-v3fyjpK8S/dpY/X5WxqTK3IoCnp/ZOLxn144GZVlNUjtwAchzrVo03h+oMATFhCIiJ5KTr4V3vDQQYz4RU684g==} @@ -15867,14 +16159,30 @@ snapshots: '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 + '@emnapi/core@1.11.2': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 + '@emnapi/runtime@1.11.2': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.28.2 @@ -16813,6 +17121,13 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true + '@napi-rs/wasm-runtime@1.2.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + dependencies: + '@emnapi/core': 1.11.2 + '@emnapi/runtime': 1.11.2 + '@tybys/wasm-util': 0.10.4 + optional: true + '@noble/ciphers@1.3.0': {} '@noble/curves@1.9.7': @@ -17597,51 +17912,99 @@ snapshots: '@oxc-parser/binding-android-arm-eabi@0.129.0': optional: true + '@oxc-parser/binding-android-arm-eabi@0.154.0': + optional: true + '@oxc-parser/binding-android-arm64@0.129.0': optional: true + '@oxc-parser/binding-android-arm64@0.154.0': + optional: true + '@oxc-parser/binding-darwin-arm64@0.129.0': optional: true + '@oxc-parser/binding-darwin-arm64@0.154.0': + optional: true + '@oxc-parser/binding-darwin-x64@0.129.0': optional: true + '@oxc-parser/binding-darwin-x64@0.154.0': + optional: true + '@oxc-parser/binding-freebsd-x64@0.129.0': optional: true + '@oxc-parser/binding-freebsd-x64@0.154.0': + optional: true + '@oxc-parser/binding-linux-arm-gnueabihf@0.129.0': optional: true + '@oxc-parser/binding-linux-arm-gnueabihf@0.154.0': + optional: true + '@oxc-parser/binding-linux-arm-musleabihf@0.129.0': optional: true + '@oxc-parser/binding-linux-arm-musleabihf@0.154.0': + optional: true + '@oxc-parser/binding-linux-arm64-gnu@0.129.0': optional: true + '@oxc-parser/binding-linux-arm64-gnu@0.154.0': + optional: true + '@oxc-parser/binding-linux-arm64-musl@0.129.0': optional: true + '@oxc-parser/binding-linux-arm64-musl@0.154.0': + optional: true + '@oxc-parser/binding-linux-ppc64-gnu@0.129.0': optional: true + '@oxc-parser/binding-linux-ppc64-gnu@0.154.0': + optional: true + '@oxc-parser/binding-linux-riscv64-gnu@0.129.0': optional: true + '@oxc-parser/binding-linux-riscv64-gnu@0.154.0': + optional: true + '@oxc-parser/binding-linux-riscv64-musl@0.129.0': optional: true + '@oxc-parser/binding-linux-riscv64-musl@0.154.0': + optional: true + '@oxc-parser/binding-linux-s390x-gnu@0.129.0': optional: true + '@oxc-parser/binding-linux-s390x-gnu@0.154.0': + optional: true + '@oxc-parser/binding-linux-x64-gnu@0.129.0': optional: true + '@oxc-parser/binding-linux-x64-gnu@0.154.0': + optional: true + '@oxc-parser/binding-linux-x64-musl@0.129.0': optional: true + '@oxc-parser/binding-linux-x64-musl@0.154.0': + optional: true + '@oxc-parser/binding-openharmony-arm64@0.129.0': optional: true + '@oxc-parser/binding-openharmony-arm64@0.154.0': + optional: true + '@oxc-parser/binding-wasm32-wasi@0.129.0': dependencies: '@emnapi/core': 1.10.0 @@ -17652,16 +18015,86 @@ snapshots: '@oxc-parser/binding-win32-arm64-msvc@0.129.0': optional: true + '@oxc-parser/binding-win32-arm64-msvc@0.154.0': + optional: true + '@oxc-parser/binding-win32-ia32-msvc@0.129.0': optional: true + '@oxc-parser/binding-win32-ia32-msvc@0.154.0': + optional: true + '@oxc-parser/binding-win32-x64-msvc@0.129.0': optional: true + '@oxc-parser/binding-win32-x64-msvc@0.154.0': + optional: true + '@oxc-project/types@0.129.0': {} '@oxc-project/types@0.154.0': {} + '@oxc-resolver/binding-android-arm-eabi@11.24.2': + optional: true + + '@oxc-resolver/binding-android-arm64@11.24.2': + optional: true + + '@oxc-resolver/binding-darwin-arm64@11.24.2': + optional: true + + '@oxc-resolver/binding-darwin-x64@11.24.2': + optional: true + + '@oxc-resolver/binding-freebsd-x64@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-arm64-gnu@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-arm64-musl@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-riscv64-musl@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-s390x-gnu@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@11.24.2': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@11.24.2': + optional: true + + '@oxc-resolver/binding-openharmony-arm64@11.24.2': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@11.24.2': + dependencies: + '@emnapi/core': 1.11.2 + '@emnapi/runtime': 1.11.2 + '@napi-rs/wasm-runtime': 1.2.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@11.24.2': + optional: true + '@oxfmt/binding-android-arm-eabi@0.65.0': optional: true @@ -18824,6 +19257,11 @@ snapshots: tslib: 2.8.1 optional: true + '@tybys/wasm-util@0.10.4': + dependencies: + tslib: 2.8.1 + optional: true + '@types/argparse@1.0.38': {} '@types/aria-query@5.0.4': {} @@ -20847,7 +21285,7 @@ snapshots: docker-compose@0.24.8: dependencies: - yaml: 2.9.0 + yaml: 2.9.1 docker-modem@5.0.7: dependencies: @@ -21515,6 +21953,10 @@ snapshots: dependencies: bser: 2.1.1 + fd-package-json@2.0.0: + dependencies: + walk-up-path: 4.0.0 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -21642,6 +22084,11 @@ snapshots: format@0.2.2: {} + formatly@0.11.4: + dependencies: + fd-package-json: 2.0.0 + package-manager-detector: 1.9.0 + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -21729,6 +22176,10 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-tsconfig@4.14.3: + dependencies: + resolve-pkg-maps: 1.0.0 + get-uri@6.0.5: dependencies: basic-ftp: 6.2.3 @@ -22434,6 +22885,21 @@ snapshots: kleur@3.0.3: {} + knip@6.42.1: + dependencies: + formatly: 0.11.4 + get-tsconfig: 4.14.3 + jiti: 2.7.0 + oxc-parser: 0.154.0 + oxc-resolver: 11.24.2 + picomatch: 4.0.7 + smol-toml: 1.9.1 + strip-json-comments: 5.0.3 + tinyglobby: 0.2.17 + unbash: 6.0.1 + yaml: 2.9.1 + zod: 4.6.7 + kysely@0.28.17: {} lan-network@0.2.1: {} @@ -23709,6 +24175,52 @@ snapshots: '@oxc-parser/binding-win32-ia32-msvc': 0.129.0 '@oxc-parser/binding-win32-x64-msvc': 0.129.0 + oxc-parser@0.154.0: + dependencies: + '@oxc-project/types': 0.154.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.154.0 + '@oxc-parser/binding-android-arm64': 0.154.0 + '@oxc-parser/binding-darwin-arm64': 0.154.0 + '@oxc-parser/binding-darwin-x64': 0.154.0 + '@oxc-parser/binding-freebsd-x64': 0.154.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.154.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.154.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.154.0 + '@oxc-parser/binding-linux-arm64-musl': 0.154.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.154.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.154.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.154.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.154.0 + '@oxc-parser/binding-linux-x64-gnu': 0.154.0 + '@oxc-parser/binding-linux-x64-musl': 0.154.0 + '@oxc-parser/binding-openharmony-arm64': 0.154.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.154.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.154.0 + '@oxc-parser/binding-win32-x64-msvc': 0.154.0 + + oxc-resolver@11.24.2: + optionalDependencies: + '@oxc-resolver/binding-android-arm-eabi': 11.24.2 + '@oxc-resolver/binding-android-arm64': 11.24.2 + '@oxc-resolver/binding-darwin-arm64': 11.24.2 + '@oxc-resolver/binding-darwin-x64': 11.24.2 + '@oxc-resolver/binding-freebsd-x64': 11.24.2 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.24.2 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.24.2 + '@oxc-resolver/binding-linux-arm64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-arm64-musl': 11.24.2 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-riscv64-musl': 11.24.2 + '@oxc-resolver/binding-linux-s390x-gnu': 11.24.2 + '@oxc-resolver/binding-linux-x64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-x64-musl': 11.24.2 + '@oxc-resolver/binding-openharmony-arm64': 11.24.2 + '@oxc-resolver/binding-wasm32-wasi': 11.24.2 + '@oxc-resolver/binding-win32-arm64-msvc': 11.24.2 + '@oxc-resolver/binding-win32-x64-msvc': 11.24.2 + oxfmt@0.65.0: dependencies: tinypool: 2.2.0 @@ -23847,6 +24359,8 @@ snapshots: registry-url: 6.0.1 semver: 7.8.5 + package-manager-detector@1.9.0: {} + param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -25655,6 +26169,8 @@ snapshots: smart-buffer@4.2.0: {} + smol-toml@1.9.1: {} + snake-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -25870,6 +26386,8 @@ snapshots: strip-json-comments@3.1.1: {} + strip-json-comments@5.0.3: {} + strnum@2.3.0: {} structured-headers@0.4.1: {} @@ -26135,8 +26653,8 @@ snapshots: tinyglobby@0.2.16: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 tinyglobby@0.2.17: dependencies: @@ -26295,6 +26813,8 @@ snapshots: uc.micro@2.1.0: {} + unbash@6.0.1: {} + undici-types@6.21.0: {} undici@6.29.1: {} @@ -26675,6 +27195,8 @@ snapshots: vlq@1.0.1: {} + walk-up-path@4.0.0: {} + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -26986,6 +27508,8 @@ snapshots: zod@4.4.3: {} + zod@4.6.7: {} + zstd-codec@0.1.5: {} zustand@4.5.7(@types/react@19.3.0)(react@19.3.1): From b977f6cd99fca31cb9837991ba26747b603e8483 Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Fri, 23 Oct 2026 13:23:33 +0000 Subject: [PATCH 4/8] chore: delete unused source files found by knip Mono-Internal-Commit: 0855b68f1571f58da90ca6ac06b2aefcdd144813 --- .../src/components/markdown-internal.tsx | 9 - apps/zbugs/src/lru-cache.ts | 29 --- packages/datadog/src/mod.ts | 4 - packages/otel/src/maybe-time.ts | 22 -- packages/otel/src/noop-metric-exporter.ts | 20 -- packages/otel/src/noop-span-exporter.ts | 22 -- .../shared/src/events/connection-seconds.ts | 39 --- packages/shared/src/mod.ts | 1 - packages/shared/src/read-json-file.js | 20 -- packages/shared/src/time.ts | 17 -- packages/shared/src/timed.ts | 29 --- packages/shared/src/tool/inject-require.ts | 14 -- .../src/tool/vitest-perf-json-to-bmf.ts | 199 ---------------- packages/shared/src/tuple.ts | 32 --- packages/zero-cache/src/db/query-test-util.ts | 6 - .../src/services/replicator/registry.ts | 18 -- .../zero-client/src/client/connect-checks.ts | 222 ------------------ .../zero-client/src/types/client-mutation.ts | 6 - packages/zero-client/src/util/rand.ts | 5 - packages/zero-protocol/src/mod.ts | 15 -- packages/zero-protocol/src/query.ts | 75 ------ packages/zero-react-native/package.json | 1 - packages/zero-react-native/src/mod.ts | 4 - packages/zero-react/package.json | 4 +- .../zero-react/src/components/inspector.tsx | 42 ---- .../zero-react/src/components/mark-icon.tsx | 20 -- .../src/components/zero-inspector.tsx | 51 ---- packages/zero-react/src/test-helpers.ts | 88 ------- packages/zero-schema/src/default-format.ts | 1 - packages/zero/src/server/change-streamer.ts | 1 - packages/zero/src/server/main.ts | 1 - packages/zero/src/server/reaper.ts | 1 - packages/zero/src/server/replicator.ts | 1 - packages/zero/src/server/syncer.ts | 1 - packages/zql/src/ivm/stopable-iterator.ts | 23 -- packages/zqlite/src/options.ts | 10 - pnpm-lock.yaml | 9 - 37 files changed, 1 insertion(+), 1061 deletions(-) delete mode 100644 apps/zbugs/src/components/markdown-internal.tsx delete mode 100644 apps/zbugs/src/lru-cache.ts delete mode 100644 packages/datadog/src/mod.ts delete mode 100644 packages/otel/src/maybe-time.ts delete mode 100644 packages/otel/src/noop-metric-exporter.ts delete mode 100644 packages/otel/src/noop-span-exporter.ts delete mode 100644 packages/shared/src/events/connection-seconds.ts delete mode 100644 packages/shared/src/mod.ts delete mode 100644 packages/shared/src/read-json-file.js delete mode 100644 packages/shared/src/time.ts delete mode 100644 packages/shared/src/timed.ts delete mode 100644 packages/shared/src/tool/inject-require.ts delete mode 100644 packages/shared/src/tool/vitest-perf-json-to-bmf.ts delete mode 100644 packages/shared/src/tuple.ts delete mode 100644 packages/zero-cache/src/db/query-test-util.ts delete mode 100644 packages/zero-cache/src/services/replicator/registry.ts delete mode 100644 packages/zero-client/src/client/connect-checks.ts delete mode 100644 packages/zero-client/src/types/client-mutation.ts delete mode 100644 packages/zero-client/src/util/rand.ts delete mode 100644 packages/zero-protocol/src/mod.ts delete mode 100644 packages/zero-protocol/src/query.ts delete mode 100644 packages/zero-react-native/src/mod.ts delete mode 100644 packages/zero-react/src/components/inspector.tsx delete mode 100644 packages/zero-react/src/components/mark-icon.tsx delete mode 100644 packages/zero-react/src/components/zero-inspector.tsx delete mode 100644 packages/zero-react/src/test-helpers.ts delete mode 100644 packages/zero-schema/src/default-format.ts delete mode 100644 packages/zero/src/server/change-streamer.ts delete mode 100644 packages/zero/src/server/main.ts delete mode 100644 packages/zero/src/server/reaper.ts delete mode 100644 packages/zero/src/server/replicator.ts delete mode 100644 packages/zero/src/server/syncer.ts delete mode 100644 packages/zql/src/ivm/stopable-iterator.ts delete mode 100644 packages/zqlite/src/options.ts diff --git a/apps/zbugs/src/components/markdown-internal.tsx b/apps/zbugs/src/components/markdown-internal.tsx deleted file mode 100644 index 438dd8a32c..0000000000 --- a/apps/zbugs/src/components/markdown-internal.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import MarkdownBase from 'react-markdown'; -import remarkGfm from 'remark-gfm'; - -/** - * Do not import this component directly. Use `Markdown` instead. - */ -export default function Markdown({children}: {children: string}) { - return {children}; -} diff --git a/apps/zbugs/src/lru-cache.ts b/apps/zbugs/src/lru-cache.ts deleted file mode 100644 index 41238bed5e..0000000000 --- a/apps/zbugs/src/lru-cache.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {must} from '../../../packages/shared/src/must.js'; - -export class LRUCache { - readonly #maxSize: number; - readonly #cache: Map; - - constructor(maxSize: number) { - this.#maxSize = maxSize; - this.#cache = new Map(); - } - - get(key: K): V | undefined { - const value = this.#cache.get(key); - if (value === undefined) { - return undefined; - } - this.#cache.delete(key); - this.#cache.set(key, value); - return value; - } - - set(key: K, value: V): void { - if (this.#cache.size >= this.#maxSize) { - const firstKey = must(this.#cache.keys().next().value); - this.#cache.delete(firstKey); - } - this.#cache.set(key, value); - } -} diff --git a/packages/datadog/src/mod.ts b/packages/datadog/src/mod.ts deleted file mode 100644 index 31e01ba5d0..0000000000 --- a/packages/datadog/src/mod.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - DatadogLogSink, - type DatadogLogSinkOptions, -} from './datadog-log-sink.ts'; diff --git a/packages/otel/src/maybe-time.ts b/packages/otel/src/maybe-time.ts deleted file mode 100644 index 4c2d60af94..0000000000 --- a/packages/otel/src/maybe-time.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type {LogContext} from '@rocicorp/logger'; - -export function timeSampled( - lc: LogContext, - numerator: number, - denominator: number, - cb: () => T, - threshold: number = 0, - prefix: () => string = () => '', -) { - if (denominator > 0 && numerator % denominator === 0) { - const start = performance.now(); - const result = cb(); - const duration = performance.now() - start; - if (duration > threshold) { - lc.warn?.(`${prefix()} duration: ${duration}ms`); - } - - return result; - } - return cb(); -} diff --git a/packages/otel/src/noop-metric-exporter.ts b/packages/otel/src/noop-metric-exporter.ts deleted file mode 100644 index d6a1c7c509..0000000000 --- a/packages/otel/src/noop-metric-exporter.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type {ExportResult} from '@opentelemetry/core'; -import { - type PushMetricExporter, - type ResourceMetrics, -} from '@opentelemetry/sdk-metrics'; - -export class NoopMetricExporter implements PushMetricExporter { - export( - _metrics: ResourceMetrics, - _resultCallback: (result: ExportResult) => void, - ): void {} - - forceFlush(): Promise { - return Promise.resolve(); - } - - shutdown(): Promise { - return Promise.resolve(); - } -} diff --git a/packages/otel/src/noop-span-exporter.ts b/packages/otel/src/noop-span-exporter.ts deleted file mode 100644 index 2dc609e5a6..0000000000 --- a/packages/otel/src/noop-span-exporter.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {ExportResultCode, type ExportResult} from '@opentelemetry/core'; -import { - type SpanExporter, - type ReadableSpan, -} from '@opentelemetry/sdk-trace-node'; - -export class NoopSpanExporter implements SpanExporter { - export( - _spans: ReadableSpan[], - resultCallback: (result: ExportResult) => void, - ): void { - resultCallback({code: ExportResultCode.SUCCESS}); - } - - forceFlush(): Promise { - return Promise.resolve(); - } - - shutdown(): Promise { - return Promise.resolve(); - } -} diff --git a/packages/shared/src/events/connection-seconds.ts b/packages/shared/src/events/connection-seconds.ts deleted file mode 100644 index 0ef355d8f6..0000000000 --- a/packages/shared/src/events/connection-seconds.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as v from '../valita.ts'; - -// Increment when making non-backwards compatible changes to the schema. -const SCHEMA_VERSION = 2; - -export const connectionSecondsReportSchema = v.object({ - /** Reporting period, in seconds. */ - period: v.number(), - - /** - * Connection-seconds elapsed during the interval. - * It follows that `elapsed / interval` is equal to the - * average number of connections during the interval. - */ - elapsed: v.number(), - - /** Room ID of the connection. */ - roomID: v.string(), -}); - -export type ConnectionSecondsReport = v.Infer< - typeof connectionSecondsReportSchema ->; - -export const CONNECTION_SECONDS_CHANNEL_NAME = `connection-seconds@v${SCHEMA_VERSION}`; - -// Historic schemas for processing old Workers. -export const CONNECTION_SECONDS_V1_CHANNEL_NAME = `connection-seconds@v1`; -export const connectionSecondsReportV1Schema = v.object({ - /** Reporting interval, in seconds. */ - interval: v.number(), - - /** - * Connection-seconds elapsed during the interval. - * It follows that `elapsed / interval` is equal to the - * average number of connections during the interval. - */ - elapsed: v.number(), -}); diff --git a/packages/shared/src/mod.ts b/packages/shared/src/mod.ts deleted file mode 100644 index cb0ff5c3b5..0000000000 --- a/packages/shared/src/mod.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/packages/shared/src/read-json-file.js b/packages/shared/src/read-json-file.js deleted file mode 100644 index 831c172b8f..0000000000 --- a/packages/shared/src/read-json-file.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check - -import {readFile} from 'node:fs/promises'; - -/** - * @typedef {{ - * [key: string]: any; - * name: string; - * version: string; - * }} PackageJSON - */ - -/** - * @param {string} pathLike - * @returns {Promise} - */ -export async function readJSONFile(pathLike) { - const s = await readFile(pathLike, 'utf-8'); - return JSON.parse(s); -} diff --git a/packages/shared/src/time.ts b/packages/shared/src/time.ts deleted file mode 100644 index afda01ed56..0000000000 --- a/packages/shared/src/time.ts +++ /dev/null @@ -1,17 +0,0 @@ -// TODO(arv): Add support for https://jsr.io/@unplugin/macros - -export function seconds(s: number) { - return s * 1000; -} - -export function minutes(m: number) { - return seconds(m * 60); -} - -export function hours(h: number) { - return minutes(h * 60); -} - -export function days(d: number) { - return hours(d * 24); -} diff --git a/packages/shared/src/timed.ts b/packages/shared/src/timed.ts deleted file mode 100644 index 61c1428eee..0000000000 --- a/packages/shared/src/timed.ts +++ /dev/null @@ -1,29 +0,0 @@ -type LogFunction = ((...args: unknown[]) => void) | undefined; - -declare const performance: { - now(): number; -}; - -/** - * Times some async function and writes the result to a provided log function. - * The log function can be undefined to simplify use with OptionalLogger. - * @param log Log function to write to (ie LogContext.log) - * @param label Label to write at start and end of function - * @param fn Function to time - * @returns The result of fn - */ -export async function timed( - log: LogFunction | undefined, - label: string, - fn: () => Promise, -): Promise { - log?.(`Starting ${label}`); - const clock = typeof performance !== 'undefined' ? performance : Date; - const t0 = clock.now(); - try { - return await fn(); - } finally { - const t1 = clock.now(); - log?.(`Finished ${label} in ${t1 - t0}ms`); - } -} diff --git a/packages/shared/src/tool/inject-require.ts b/packages/shared/src/tool/inject-require.ts deleted file mode 100644 index 09689df3d1..0000000000 --- a/packages/shared/src/tool/inject-require.ts +++ /dev/null @@ -1,14 +0,0 @@ -function createRandomIdentifier(name: string): string { - return `${name}_${Math.random() * 10000}`.replace('.', ''); -} - -/** - * Injects a global `require` function into the bundle. This is sometimes needed - * if the dependencies are incorrectly using require. - */ -export function injectRequire(): string { - const createRequireAlias = createRandomIdentifier('createRequire'); - return `import {createRequire as ${createRequireAlias}} from 'node:module'; -var require = ${createRequireAlias}(import.meta.url); -`; -} diff --git a/packages/shared/src/tool/vitest-perf-json-to-bmf.ts b/packages/shared/src/tool/vitest-perf-json-to-bmf.ts deleted file mode 100644 index 32ffe229d3..0000000000 --- a/packages/shared/src/tool/vitest-perf-json-to-bmf.ts +++ /dev/null @@ -1,199 +0,0 @@ -import fs from 'node:fs'; - -// BMF - Bencher Metric Format -// with json schema: -/* - -{ - "$id": "https://bencher.dev/bmf.json", - "$schema": "http://json-schema.org/draft-07/schema", - "type": "object", - "patternProperties": { - ".+": { - "type": "object", - "patternProperties": { - ".+": { - "type": "object", - "properties": { - "value": { - "type": "number" - }, - "lower_value": { - "type": "number" - }, - "upper_value": { - "type": "number" - } - }, - "required": ["value"] - } - } - } - } -} - -*/ -// vitest bench --run --outputJSON output.json produces: -/* - -{ - "files": [ - { - "filepath": "/Users/arv/src/rocicorp/mono/packages/zero-client/src/client/zero.bench.ts", - "groups": [ - { - "fullName": "src/client/zero.bench.ts > basics", - "benchmarks": [ - { - "id": "1889292170_0_0", - "name": "All 1000 rows x 10 columns (numbers)", - "rank": 1, - "rme": 22.99615963676964, - "samples": [], - "totalTime": 509.60000014305115, - "min": 16.09999990463257, - "max": 72.20000004768372, - "hz": 47.095761368255296, - "period": 21.233333339293797, - "mean": 21.233333339293797, - "variance": 133.67101490532144, - "sd": 11.561618178495666, - "sem": 2.360005428183389, - "df": 23, - "critical": 2.069, - "moe": 4.882851230911432, - "p75": 19.09999990463257, - "p99": 72.20000004768372, - "p995": 72.20000004768372, - "p999": 72.20000004768372, - "sampleCount": 24, - "median": 18.40000009536743 - } - ] - }, - { - "fullName": "src/client/zero.bench.ts > with filter", - "benchmarks": [ - { - "id": "1889292170_1_0", - "name": "Lower rows 500 x 10 columns (numbers)", - "rank": 1, - "rme": 24.258926361493792, - "samples": [], - "totalTime": 516.9000000953674, - "min": 26.40000009536743, - "max": 74.09999990463257, - "hz": 29.01915263538889, - "period": 34.46000000635783, - "mean": 34.46000000635783, - "variance": 227.82971388912205, - "sd": 15.09402908070347, - "sem": 3.8972615504489987, - "df": 14, - "critical": 2.145, - "moe": 8.359626025713101, - "p75": 31.40000009536743, - "p99": 74.09999990463257, - "p995": 74.09999990463257, - "p999": 74.09999990463257, - "sampleCount": 15, - "median": 28.100000143051147 - } - ] - } - ] - } - ] -} - */ - -type VitestBenchmark = { - id: string; - name: string; - rank: number; - rme: number; - samples: unknown[]; - totalTime: number; - min: number; - max: number; - hz: number; - period: number; - mean: number; - variance: number; - sd: number; - sem: number; - df: number; - critical: number; - moe: number; - p75: number; - p99: number; - p995: number; - p999: number; - sampleCount: number; - median: number; -}; - -type VitestGroup = { - fullName: string; - benchmarks: VitestBenchmark[]; -}; - -type VitestFile = { - filepath: string; - groups: VitestGroup[]; -}; - -type VitestOutput = { - files: VitestFile[]; -}; - -type BMFMetric = { - [key: string]: { - throughput: { - value: number; - ['lower_value']: number; - ['upper_value']: number; - }; - }; -}; - -function convertVitestToBMF(vitestOutput: VitestOutput): BMFMetric { - const bmf: BMFMetric = {}; - - vitestOutput.files.forEach(file => { - file.groups.forEach(group => { - group.benchmarks.forEach(benchmark => { - const metricName = `${group.fullName} > ${benchmark.name}`; - - bmf[metricName] = { - // benchmark outputs are the time in milliseconds it took to run. - // If we want to convert to throughput, we need to divide 1000 by the time. - // This is the inverse of the time taken. - // So if it took 100ms to run, the throughput is 1000 / 100 = 10 - throughput: { - value: 1000 / benchmark.mean, - ['lower_value']: 1000 / benchmark.min, - ['upper_value']: 1000 / benchmark.max, - }, - }; - }); - }); - }); - - return bmf; -} - -try { - const vitestOutputContent = fs.readFileSync(process.stdin.fd, 'utf-8'); - const vitestOutput: VitestOutput = JSON.parse(vitestOutputContent); - const bmfOutput = convertVitestToBMF(vitestOutput); - fs.writeFileSync( - process.stdout.fd, - JSON.stringify(bmfOutput, null, 2), - 'utf-8', - ); -} catch (error) { - // oxlint-disable-next-line no-console - console.error('Error converting Vitest output to BMF:', error); - process.exit(1); -} diff --git a/packages/shared/src/tuple.ts b/packages/shared/src/tuple.ts deleted file mode 100644 index 08d2fd1daa..0000000000 --- a/packages/shared/src/tuple.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Generic tuple utility types - */ - -/** - * Get the last element type from a tuple type. - * Works with tuples of length 1, 2, or 3. - */ -export type LastInTuple = T extends readonly [ - infer L, -] - ? L - : T extends readonly [unknown, infer L] - ? L - : T extends readonly [unknown, unknown, infer L] - ? L - : never; - -/** - * A tuple type that requires at least one element. - */ -export type AtLeastOne = readonly [T, ...T[]]; - -/** - * Type guard to ensure an array has at least one element. - */ -export function atLeastOne(arr: readonly T[]): AtLeastOne { - if (arr.length === 0) { - throw new Error('Expected at least one element'); - } - return arr as AtLeastOne; -} diff --git a/packages/zero-cache/src/db/query-test-util.ts b/packages/zero-cache/src/db/query-test-util.ts deleted file mode 100644 index 64dfac0549..0000000000 --- a/packages/zero-cache/src/db/query-test-util.ts +++ /dev/null @@ -1,6 +0,0 @@ -export function stripCommentsAndWhitespace(query: string = '') { - return query - .trim() - .replaceAll(/--.*\n/g, '') - .replaceAll(/\s+/g, ' '); -} diff --git a/packages/zero-cache/src/services/replicator/registry.ts b/packages/zero-cache/src/services/replicator/registry.ts deleted file mode 100644 index b5ea78d7fc..0000000000 --- a/packages/zero-cache/src/services/replicator/registry.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type {Replicator} from './replicator.ts'; - -export interface ReplicatorRegistry { - /** - * Gets the global Replicator. - * - * In v0, everything is running in a single ServiceRunnerDO and thus this will always be - * an in memory object. - * - * When sharding is added, a stub object that communicates with the Replicator in - * another DO (via rpc / websocket) may be returned. - * - * Note that callers should be wary of caching the returned object, as the Replicator may - * shut down and restart, etc. Generally, the registry should be queried from the registry - * whenever attempting to communicate with it. - */ - getReplicator(): Promise; -} diff --git a/packages/zero-client/src/client/connect-checks.ts b/packages/zero-client/src/client/connect-checks.ts deleted file mode 100644 index 5f6497baf2..0000000000 --- a/packages/zero-client/src/client/connect-checks.ts +++ /dev/null @@ -1,222 +0,0 @@ -import type {LogContext} from '@rocicorp/logger'; -import {resolver} from '@rocicorp/resolver'; -import {navigator} from '../../../shared/src/navigator.ts'; -import {sleep} from '../../../shared/src/sleep.ts'; -import {PROTOCOL_VERSION} from '../../../zero-protocol/src/protocol-version.ts'; -import {nanoid} from '../util/nanoid.ts'; -import { - type HTTPString, - type WSString, - appendPath, - assertHTTPString, - assertWSString, - toWSString, -} from './http-string.ts'; - -type CheckResult = {success: boolean; detail: string}; -type Check = (l: LogContext) => Promise; -type Checks = Record; - -export async function checkConnectivity( - reason: string, - server: HTTPString, - lc: LogContext, - signal: AbortSignal, - enableAnalytics: boolean, -): Promise { - const id = nanoid(); - lc = lc.withContext('connectCheckID', id).withContext('checkReason', reason); - lc.info?.('Starting connectivity checks', { - navigatorOnline: navigator?.onLine, - }); - const socketOrigin = toWSString(server); - const cfChecks: Checks = { - cfGet: _ => checkCfGet(id, server, signal), - cfWebSocket: l => checkCfSocket(id, socketOrigin, false, l, signal), - cfWebSocketWSecWebSocketProtocolHeader: l => - checkCfSocket(id, socketOrigin, true, l, signal), - }; - const renderChecks: Checks = { - renderGet: _ => checkRenderGet(id, signal), - renderWebSocket: l => checkRenderSocket(id, false, l, signal), - renderWebSocketWSecWebSocketProtocolHeader: l => - checkRenderSocket(id, true, l, signal), - }; - // When analytics are disabled don't make requests to external web - // service hosted on render for checking connectivity. - const checks: Checks = enableAnalytics - ? { - ...cfChecks, - ...renderChecks, - } - : cfChecks; - - const resultPs: Promise[] = []; - for (const [checkName, check] of Object.entries(checks)) { - resultPs.push( - (async () => { - const checkLc = lc.withContext('checkName', checkName); - checkLc.info?.('Starting check'); - let result: CheckResult; - try { - result = await check(checkLc); - } catch (e) { - const detail = `Error: ${ - e instanceof Error ? `{name: ${e.name}, message: ${e.message}}` : e - }`; - result = {success: false, detail}; - } - checkLc.info?.(checkName, result); - return result; - })(), - ); - } - - const results = await Promise.all(resultPs); - if (signal.aborted) { - return; - } - - lc.info?.( - 'Connectivity checks summary\n', - ...Object.keys(checks).map( - (checkName, i) => `${checkName}=${results[i].success}\n`, - ), - { - navigatorOnline: navigator?.onLine, - }, - ); - lc.info?.( - 'Connectivity checks detail\n', - ...Object.keys(checks).flatMap( - (checkName, i) => `${checkName}=${results[i].detail}\n`, - ), - { - navigatorOnline: navigator?.onLine, - }, - ); -} - -function checkRenderGet(id: string, signal: AbortSignal) { - return checkGet( - id, - 'https://networkcheck.reflect-server.net/canary/get', - signal, - ); -} - -function checkCfGet(id: string, server: HTTPString, signal: AbortSignal) { - const cfGetCheckBaseURL = new URL( - appendPath(server, `/canary/v${PROTOCOL_VERSION}/get`), - ); - const url = cfGetCheckBaseURL.toString(); - assertHTTPString(url); - return checkGet(id, url, signal); -} - -function checkGet(id: string, baseURL: HTTPString, signal: AbortSignal) { - const getCheckURL = new URL(baseURL); - getCheckURL.searchParams.set('id', id); - return Promise.race([ - timeout(signal), - (async () => { - const response = await fetch(getCheckURL, {signal}); - return { - success: response.status === 200, - detail: `Got response ${response.status} "${await response.text()}"`, - }; - })(), - ]); -} - -function checkRenderSocket( - id: string, - wSecWebSocketProtocolHeader: boolean, - lc: LogContext, - signal: AbortSignal, -) { - return checkSocket( - id, - 'wss://networkcheck.reflect-server.net/canary/websocket', - wSecWebSocketProtocolHeader, - lc, - signal, - ); -} - -function checkCfSocket( - id: string, - socketOrigin: WSString, - wSecWebSocketProtocolHeader: boolean, - lc: LogContext, - signal: AbortSignal, -) { - const cfSocketCheckBaseURL = new URL( - appendPath(socketOrigin, `/canary/v${PROTOCOL_VERSION}/websocket`), - ); - const url = cfSocketCheckBaseURL.toString(); - assertWSString(url); - return checkSocket(id, url, wSecWebSocketProtocolHeader, lc, signal); -} - -async function checkSocket( - id: string, - socketBaseURL: WSString, - wSecWebSocketProtocolHeader: boolean, - lc: LogContext, - signal: AbortSignal, -) { - const socketCheckURL = new URL(socketBaseURL); - socketCheckURL.searchParams.set('id', id); - socketCheckURL.searchParams.set( - 'wSecWebSocketProtocolHeader', - wSecWebSocketProtocolHeader ? 'true' : 'false', - ); - - const cfWebSocket = wSecWebSocketProtocolHeader - ? new WebSocket(socketCheckURL, 'check-' + id) - : new WebSocket(socketCheckURL); - - const {promise, resolve} = resolver(); - const onMessage = (e: MessageEvent) => { - lc.info?.('Received message', e.data); - resolve({ - success: true, - detail: `Connected and received message "${e.data}"`, - }); - }; - const onOpen = () => { - lc.info?.('Open event'); - }; - const onClose = (e: CloseEvent) => { - const {code, reason, wasClean} = e; - const closeInfo = { - code, - reason, - wasClean, - }; - lc.info?.('Received close', closeInfo); - resolve({ - success: false, - detail: `Closed before connected ${JSON.stringify(closeInfo)}.`, - }); - }; - try { - cfWebSocket.addEventListener('message', onMessage); - cfWebSocket.addEventListener('open', onOpen); - cfWebSocket.addEventListener('close', onClose); - return await Promise.race([timeout(signal), promise]); - } finally { - cfWebSocket.removeEventListener('message', onMessage); - cfWebSocket.removeEventListener('open', onOpen); - cfWebSocket.removeEventListener('close', onClose); - cfWebSocket.close(); - } -} - -const TIMEOUT_MS = 10_000; - -async function timeout(signal: AbortSignal): Promise { - await sleep(TIMEOUT_MS, signal); - return {success: false, detail: 'Timed out.'}; -} diff --git a/packages/zero-client/src/types/client-mutation.ts b/packages/zero-client/src/types/client-mutation.ts deleted file mode 100644 index 30e433d874..0000000000 --- a/packages/zero-client/src/types/client-mutation.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type {Mutation} from '../../../zero-protocol/src/mutation.ts'; -import type {ClientID} from './client-state.ts'; - -export type ClientMutation = Mutation & { - clientID: ClientID; -}; diff --git a/packages/zero-client/src/util/rand.ts b/packages/zero-client/src/util/rand.ts deleted file mode 100644 index f439467501..0000000000 --- a/packages/zero-client/src/util/rand.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function randInt(min: number, max: number) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min + 1) + min); //The maximum is inclusive and the minimum is inclusive -} diff --git a/packages/zero-protocol/src/mod.ts b/packages/zero-protocol/src/mod.ts deleted file mode 100644 index 426d4abe69..0000000000 --- a/packages/zero-protocol/src/mod.ts +++ /dev/null @@ -1,15 +0,0 @@ -// TODO: Remove this file -export * from './change-desired-queries.ts'; -export * from './connect.ts'; -export * from './down.ts'; -export * from './error.ts'; -export * from './ping.ts'; -export * from './poke.ts'; -export * from './pong.ts'; -export * from './pull.ts'; -export * from './push.ts'; -export * from './queries-patch.ts'; -export * from './row-patch.ts'; -export * from './up.ts'; -export * from './update-auth.ts'; -export * from './version.ts'; diff --git a/packages/zero-protocol/src/query.ts b/packages/zero-protocol/src/query.ts deleted file mode 100644 index e410657c1e..0000000000 --- a/packages/zero-protocol/src/query.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {jsonSchema} from '../../shared/src/json-schema.ts'; -import * as v from '../../shared/src/valita.ts'; -import {astSchema} from './ast.ts'; -import {transformFailedBodySchema} from './error.ts'; - -export const transformRequestBodySchema = v.array( - v.object({ - id: v.string(), - name: v.string(), - args: v.readonly(v.array(jsonSchema)), - }), -); -export type TransformRequestBody = v.Infer; - -export const transformedQuerySchema = v.object({ - id: v.string(), - name: v.string(), - ast: astSchema, -}); - -export const appErroredQuerySchema = v.object({ - error: v.literal('app'), - id: v.string(), - name: v.string(), - // optional for backwards compatibility - message: v.string().optional(), - details: jsonSchema.optional(), -}); -export const parseErroredQuerySchema = v.object({ - error: v.literal('parse'), - id: v.string(), - name: v.string(), - message: v.string(), - details: jsonSchema.optional(), -}); -export const erroredQuerySchema = v.union( - appErroredQuerySchema, - parseErroredQuerySchema, -); -export type ErroredQuery = v.Infer; - -export const transformResponseBodySchema = v.array( - v.union(transformedQuerySchema, erroredQuerySchema), -); -export type TransformResponseBody = v.Infer; - -export const transformRequestMessageSchema = v.tuple([ - v.literal('transform'), - transformRequestBodySchema, -]); -export type TransformRequestMessage = v.Infer< - typeof transformRequestMessageSchema ->; -export const transformErrorMessageSchema = v.tuple([ - v.literal('transformError'), - v.array(erroredQuerySchema), -]); -export type TransformErrorMessage = v.Infer; - -const transformFailedMessageSchema = v.tuple([ - v.literal('transformFailed'), - transformFailedBodySchema, -]); -const transformOkMessageSchema = v.tuple([ - v.literal('transformed'), - transformResponseBodySchema, -]); - -export const transformResponseMessageSchema = v.union( - transformOkMessageSchema, - transformFailedMessageSchema, -); -export type TransformResponseMessage = v.Infer< - typeof transformResponseMessageSchema ->; diff --git a/packages/zero-react-native/package.json b/packages/zero-react-native/package.json index 4e0fa1cbe4..ec6aa127f6 100644 --- a/packages/zero-react-native/package.json +++ b/packages/zero-react-native/package.json @@ -20,7 +20,6 @@ }, "devDependencies": { "oxfmt": "^0.74.0", - "replicache": "workspace:*", "shared": "workspace:*" }, "packageManager": "pnpm@11.11.0" diff --git a/packages/zero-react-native/src/mod.ts b/packages/zero-react-native/src/mod.ts deleted file mode 100644 index 3bd1930769..0000000000 --- a/packages/zero-react-native/src/mod.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - expoSQLiteStoreProvider, - type ExpoSQLiteStoreOptions, -} from '../../replicache/src/kv/expo-sqlite/store.ts'; diff --git a/packages/zero-react/package.json b/packages/zero-react/package.json index f678b5ede0..3c1e84d894 100644 --- a/packages/zero-react/package.json +++ b/packages/zero-react/package.json @@ -32,9 +32,7 @@ "react": "^19.3.1", "shared": "workspace:*", "vitest": "^5.0.5", - "zero-client": "workspace:*", - "zero-schema": "workspace:*", - "zql": "workspace:*" + "zero-client": "workspace:*" }, "peerDependencies": { "react": "^19.3.1", diff --git a/packages/zero-react/src/components/inspector.tsx b/packages/zero-react/src/components/inspector.tsx deleted file mode 100644 index 3c19b30e95..0000000000 --- a/packages/zero-react/src/components/inspector.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { - CustomMutatorDefs, - DefaultContext, - DefaultSchema, - Schema, - Zero, -} from '../zero.ts'; -import {MarkIcon} from './mark-icon.tsx'; - -export default function Inspector< - S extends Schema = DefaultSchema, - MD extends CustomMutatorDefs | undefined = undefined, - Context = DefaultContext, ->({zero, onClose}: {zero: Zero; onClose: () => void}) { - return ( - - -
Zero v{zero.version}
- -
- ); -} diff --git a/packages/zero-react/src/components/mark-icon.tsx b/packages/zero-react/src/components/mark-icon.tsx deleted file mode 100644 index e1a1e30f58..0000000000 --- a/packages/zero-react/src/components/mark-icon.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type {FC, SVGProps} from 'react'; - -export const MarkIcon: FC> = props => ( - - Show Zero Inspector - - -); diff --git a/packages/zero-react/src/components/zero-inspector.tsx b/packages/zero-react/src/components/zero-inspector.tsx deleted file mode 100644 index 12029d3ba3..0000000000 --- a/packages/zero-react/src/components/zero-inspector.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import {lazy, Suspense, useState, type JSX} from 'react'; -import type { - CustomMutatorDefs, - DefaultContext, - DefaultSchema, - Schema, - Zero, -} from '../zero.ts'; -import {MarkIcon} from './mark-icon.tsx'; - -const Inspector = lazy(() => import('./inspector.tsx')); - -export function ZeroInspector< - S extends Schema = DefaultSchema, - MD extends CustomMutatorDefs | undefined = undefined, - Context = DefaultContext, ->({zero}: {zero: Zero}): JSX.Element { - const [show, setShow] = useState(false); - return show ? ( - Loading Inspector...}> - setShow(false)} - /> - - ) : ( - - ); -} diff --git a/packages/zero-react/src/test-helpers.ts b/packages/zero-react/src/test-helpers.ts deleted file mode 100644 index b8549ff198..0000000000 --- a/packages/zero-react/src/test-helpers.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {createSchema} from '../../zero-schema/src/builder/schema-builder.ts'; -import {string, table} from '../../zero-schema/src/builder/table-builder.ts'; -import {defineMutatorsWithType} from '../../zql/src/mutate/mutator-registry.ts'; -import {defineMutatorWithType} from '../../zql/src/mutate/mutator.ts'; -import {createBuilder} from '../../zql/src/query/create-builder.ts'; -import { - defineQueriesWithType, - defineQuery, -} from '../../zql/src/query/query-registry.ts'; -import type {Row} from '../../zql/src/query/query.ts'; - -export const schema = createSchema({ - tables: [ - table('item') - .columns({ - id: string(), - name: string(), - }) - .primaryKey('id'), - ], -}); - -export type Item = Row<(typeof schema)['tables']['item']>; -export type StartRow = {name: string}; - -export const zql = createBuilder(schema); - -export const queries = defineQueriesWithType()({ - items: defineQuery( - ({ - args, - }: { - args: { - limit: number; - startName: string | null; - direction: 'forward' | 'backward'; - }; - }) => { - const order = args.direction === 'forward' ? 'asc' : 'desc'; - const operator = args.direction === 'forward' ? '>' : '<'; - let q = zql.item.orderBy('name', order); - if (args.startName !== null) { - q = q.where('name', operator, args.startName); - } - return q.limit(args.limit); - }, - ), - item: defineQuery(({args}: {args: {id: string}}) => - zql.item.where('id', args.id).one(), - ), -}); - -export const mutators = defineMutatorsWithType()({ - populateItems: defineMutatorWithType()<{count: number}>( - async ({tx, args}) => { - for (let i = 0; i < args.count; i++) { - const id = `${i + 1}`; - const paddedNum = String(i + 1).padStart(4, '0'); - await tx.mutate.item.insert({ - id, - name: `Item ${paddedNum}`, - }); - } - }, - ), - addItem: defineMutatorWithType()<{ - id: string; - name: string; - }>(async ({tx, args}) => { - await tx.mutate.item.insert(args); - }), -}); - -// Query helper functions -export const getPageQuery = ( - limit: number, - start: StartRow | null, - dir: 'forward' | 'backward', -) => - queries.items({ - limit, - startName: start?.name ?? null, - direction: dir, - }); - -export const getSingleQuery = (id: string) => queries.item({id}); - -export const toStartRow = (row: Item): StartRow => ({name: row.name}); diff --git a/packages/zero-schema/src/default-format.ts b/packages/zero-schema/src/default-format.ts deleted file mode 100644 index ac3d79c261..0000000000 --- a/packages/zero-schema/src/default-format.ts +++ /dev/null @@ -1 +0,0 @@ -export const defaultFormat = {singular: false, relationships: {}} as const; diff --git a/packages/zero/src/server/change-streamer.ts b/packages/zero/src/server/change-streamer.ts deleted file mode 100644 index e8d0c92d24..0000000000 --- a/packages/zero/src/server/change-streamer.ts +++ /dev/null @@ -1 +0,0 @@ -import '../../../zero-cache/src/server/change-streamer.ts'; diff --git a/packages/zero/src/server/main.ts b/packages/zero/src/server/main.ts deleted file mode 100644 index ee1db1f038..0000000000 --- a/packages/zero/src/server/main.ts +++ /dev/null @@ -1 +0,0 @@ -import '../../../zero-cache/src/server/main.ts'; diff --git a/packages/zero/src/server/reaper.ts b/packages/zero/src/server/reaper.ts deleted file mode 100644 index 41ab57975b..0000000000 --- a/packages/zero/src/server/reaper.ts +++ /dev/null @@ -1 +0,0 @@ -import '../../../zero-cache/src/server/reaper.ts'; diff --git a/packages/zero/src/server/replicator.ts b/packages/zero/src/server/replicator.ts deleted file mode 100644 index 00df30080e..0000000000 --- a/packages/zero/src/server/replicator.ts +++ /dev/null @@ -1 +0,0 @@ -import '../../../zero-cache/src/server/replicator.ts'; diff --git a/packages/zero/src/server/syncer.ts b/packages/zero/src/server/syncer.ts deleted file mode 100644 index 34f4704e66..0000000000 --- a/packages/zero/src/server/syncer.ts +++ /dev/null @@ -1 +0,0 @@ -import '../../../zero-cache/src/server/syncer.ts'; diff --git a/packages/zql/src/ivm/stopable-iterator.ts b/packages/zql/src/ivm/stopable-iterator.ts deleted file mode 100644 index a9b0959063..0000000000 --- a/packages/zql/src/ivm/stopable-iterator.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * An iterator that can be stopped. Useful if the data backing the iterator - * changes and you don't want clients to be able to keep iterating. - */ -export class StoppableIterator { - #iterator: Iterator; - #stopped = false; - - constructor(iterator: Iterator) { - this.#iterator = iterator; - } - - next() { - if (this.#stopped) { - throw new Error('Iterator has been stopped'); - } - return this.#iterator.next(); - } - - stop() { - this.#stopped = true; - } -} diff --git a/packages/zqlite/src/options.ts b/packages/zqlite/src/options.ts deleted file mode 100644 index 8415f20235..0000000000 --- a/packages/zqlite/src/options.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type {Schema} from '../../zero-types/src/schema.ts'; -import type {Database} from './db.ts'; - -/** - * Configuration for [[ZqlLiteZero]]. - */ -export interface ZQLiteZeroOptions { - schema: S; - db: Database; -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 059be0e628..e3e939a1f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1461,12 +1461,6 @@ importers: zero-client: specifier: workspace:* version: link:../zero-client - zero-schema: - specifier: workspace:* - version: link:../zero-schema - zql: - specifier: workspace:* - version: link:../zql packages/zero-react-native: dependencies: @@ -1477,9 +1471,6 @@ importers: oxfmt: specifier: ^0.74.0 version: 0.74.0 - replicache: - specifier: workspace:* - version: link:../replicache shared: specifier: workspace:* version: link:../shared From fdd783d29161ecd018ca859fd7b1b489a00f23ad Mon Sep 17 00:00:00 2001 From: Cesar Alaestante Date: Fri, 23 Oct 2026 17:00:08 +0000 Subject: [PATCH 5/8] fix(otel): zero view syncer telemetry pinning version Mono-Internal-Commit: 2ff922fd4c0d654f3a2eee26a4e8409168532fe6 --- .syncpackrc | 20 +++++++++++++ packages/otel/package.json | 8 +++--- packages/zero-cache/package.json | 20 ++++++------- packages/zero/package.json | 18 ++++++------ packages/zqlite/package.json | 2 +- pnpm-lock.yaml | 48 ++++++++++++++++---------------- 6 files changed, 68 insertions(+), 48 deletions(-) diff --git a/.syncpackrc b/.syncpackrc index 5aeae05581..54f20abd28 100644 --- a/.syncpackrc +++ b/.syncpackrc @@ -1,5 +1,15 @@ { "versionGroups": [ + { + "label": "OpenTelemetry API 1.10 splits ESM and CommonJS tracing state, leaving tracers created before NodeSDK.start() as no-ops. Keep the published Zero dependency pinned until this is fixed upstream.", + "dependencies": [ + "@opentelemetry/api" + ], + "packages": [ + "**" + ], + "pinVersion": "1.9.1" + }, { "label": "packages/zql-benchmarks/rn is an Expo app that is deliberately not a pnpm workspace member (see packages/replicache-perf/rn/README.md). It pins the React, TypeScript and Expo versions its React Native release needs, independently of the workspace's.", "packages": [ @@ -26,6 +36,16 @@ } ], "semverGroups": [ + { + "label": "Pin the tested OpenTelemetry runtime packages and upgrade them together.", + "range": "", + "dependencies": [ + "@opentelemetry/*" + ], + "packages": [ + "**" + ] + }, { "range": "~", "dependencies": [ diff --git a/packages/otel/package.json b/packages/otel/package.json index 3f47392d02..15beeff0a3 100644 --- a/packages/otel/package.json +++ b/packages/otel/package.json @@ -13,10 +13,10 @@ "check-fmt": "oxfmt --check ." }, "dependencies": { - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/core": "^2.12.0", - "@opentelemetry/sdk-metrics": "^2.12.0", - "@opentelemetry/sdk-trace-node": "^2.12.0", + "@opentelemetry/api": "1.9.1", + "@opentelemetry/core": "2.12.0", + "@opentelemetry/sdk-metrics": "2.12.0", + "@opentelemetry/sdk-trace-node": "2.12.0", "@rocicorp/logger": "^6.1.0" }, "devDependencies": { diff --git a/packages/zero-cache/package.json b/packages/zero-cache/package.json index cbe44c96d6..63ae57a553 100644 --- a/packages/zero-cache/package.json +++ b/packages/zero-cache/package.json @@ -43,16 +43,16 @@ "@fastify/cors": "^10.1.0", "@fastify/websocket": "^11.2.0", "@google-cloud/precise-date": "^4.0.0", - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/api-logs": "^0.223.0", - "@opentelemetry/auto-instrumentations-node": "^0.81.2", - "@opentelemetry/exporter-metrics-otlp-http": "^0.223.0", - "@opentelemetry/otlp-exporter-base": "^0.223.0", - "@opentelemetry/resources": "^2.12.0", - "@opentelemetry/sdk-metrics": "^2.12.0", - "@opentelemetry/sdk-node": "^0.223.0", - "@opentelemetry/sdk-trace-node": "^2.12.0", - "@opentelemetry/semantic-conventions": "^1.43.0", + "@opentelemetry/api": "1.9.1", + "@opentelemetry/api-logs": "0.223.0", + "@opentelemetry/auto-instrumentations-node": "0.81.2", + "@opentelemetry/exporter-metrics-otlp-http": "0.223.0", + "@opentelemetry/otlp-exporter-base": "0.223.0", + "@opentelemetry/resources": "2.12.0", + "@opentelemetry/sdk-metrics": "2.12.0", + "@opentelemetry/sdk-node": "0.223.0", + "@opentelemetry/sdk-trace-node": "2.12.0", + "@opentelemetry/semantic-conventions": "1.43.0", "@postgresql-typed/oids": "^0.2.0", "@rocicorp/lock": "^1.0.4", "@rocicorp/logger": "^6.1.0", diff --git a/packages/zero/package.json b/packages/zero/package.json index 9d869fd260..301c11b7c1 100644 --- a/packages/zero/package.json +++ b/packages/zero/package.json @@ -127,15 +127,15 @@ "@fastify/cors": "^10.1.0", "@fastify/websocket": "^11.2.0", "@google-cloud/precise-date": "^4.0.0", - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/api-logs": "^0.223.0", - "@opentelemetry/auto-instrumentations-node": "^0.81.2", - "@opentelemetry/exporter-metrics-otlp-http": "^0.223.0", - "@opentelemetry/resources": "^2.12.0", - "@opentelemetry/sdk-metrics": "^2.12.0", - "@opentelemetry/sdk-node": "^0.223.0", - "@opentelemetry/sdk-trace-node": "^2.12.0", - "@opentelemetry/semantic-conventions": "^1.43.0", + "@opentelemetry/api": "1.9.1", + "@opentelemetry/api-logs": "0.223.0", + "@opentelemetry/auto-instrumentations-node": "0.81.2", + "@opentelemetry/exporter-metrics-otlp-http": "0.223.0", + "@opentelemetry/resources": "2.12.0", + "@opentelemetry/sdk-metrics": "2.12.0", + "@opentelemetry/sdk-node": "0.223.0", + "@opentelemetry/sdk-trace-node": "2.12.0", + "@opentelemetry/semantic-conventions": "1.43.0", "@postgresql-typed/oids": "^0.2.0", "@rocicorp/lock": "^1.0.4", "@rocicorp/logger": "^6.1.0", diff --git a/packages/zqlite/package.json b/packages/zqlite/package.json index 117fd5adfd..4acd99b69d 100644 --- a/packages/zqlite/package.json +++ b/packages/zqlite/package.json @@ -22,7 +22,7 @@ "dependencies": { "@databases/escape-identifier": "^1.0.3", "@databases/sql": "^3.3.0", - "@opentelemetry/api": "^1.9.1", + "@opentelemetry/api": "1.9.1", "@rocicorp/logger": "^6.1.0", "@rocicorp/zero-sqlite3": "^1.1.7", "zql": "workspace:*" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e3e939a1f6..03925b71c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -525,16 +525,16 @@ importers: packages/otel: dependencies: '@opentelemetry/api': - specifier: ^1.9.1 + specifier: 1.9.1 version: 1.9.1 '@opentelemetry/core': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-metrics': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-node': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@rocicorp/logger': specifier: ^6.1.0 @@ -903,31 +903,31 @@ importers: specifier: ^4.0.0 version: 4.0.0 '@opentelemetry/api': - specifier: ^1.9.1 + specifier: 1.9.1 version: 1.9.1 '@opentelemetry/api-logs': - specifier: ^0.223.0 + specifier: 0.223.0 version: 0.223.0 '@opentelemetry/auto-instrumentations-node': - specifier: ^0.81.2 + specifier: 0.81.2 version: 0.81.2(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.12.0(@opentelemetry/api@1.9.1)) '@opentelemetry/exporter-metrics-otlp-http': - specifier: ^0.223.0 + specifier: 0.223.0 version: 0.223.0(@opentelemetry/api@1.9.1) '@opentelemetry/resources': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-metrics': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-node': - specifier: ^0.223.0 + specifier: 0.223.0 version: 0.223.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-node': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': - specifier: ^1.43.0 + specifier: 1.43.0 version: 1.43.0 '@postgresql-typed/oids': specifier: ^0.2.0 @@ -1108,34 +1108,34 @@ importers: specifier: ^4.0.0 version: 4.0.0 '@opentelemetry/api': - specifier: ^1.9.1 + specifier: 1.9.1 version: 1.9.1 '@opentelemetry/api-logs': - specifier: ^0.223.0 + specifier: 0.223.0 version: 0.223.0 '@opentelemetry/auto-instrumentations-node': - specifier: ^0.81.2 + specifier: 0.81.2 version: 0.81.2(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.12.0(@opentelemetry/api@1.9.1)) '@opentelemetry/exporter-metrics-otlp-http': - specifier: ^0.223.0 + specifier: 0.223.0 version: 0.223.0(@opentelemetry/api@1.9.1) '@opentelemetry/otlp-exporter-base': - specifier: ^0.223.0 + specifier: 0.223.0 version: 0.223.0(@opentelemetry/api@1.9.1) '@opentelemetry/resources': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-metrics': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-node': - specifier: ^0.223.0 + specifier: 0.223.0 version: 0.223.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-node': - specifier: ^2.12.0 + specifier: 2.12.0 version: 2.12.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': - specifier: ^1.43.0 + specifier: 1.43.0 version: 1.43.0 '@postgresql-typed/oids': specifier: ^0.2.0 @@ -1774,7 +1774,7 @@ importers: specifier: ^3.3.0 version: 3.3.0 '@opentelemetry/api': - specifier: ^1.9.1 + specifier: 1.9.1 version: 1.9.1 '@rocicorp/logger': specifier: ^6.1.0 From f418f2e6e9f4992bf723ce6f76b2655f7f228543 Mon Sep 17 00:00:00 2001 From: Greg Baker Date: Sat, 24 Oct 2026 05:09:01 +0000 Subject: [PATCH 6/8] chore(deps): bump zod, body-parser, fast-uri and serialize-javascript for audit advisories Mono-Internal-Commit: d26bed4c1668b1eb572890781535dadc9988369f --- apps/zbugs/package.json | 2 +- pnpm-lock.yaml | 75 +++++++++++++++++++---------------------- pnpm-workspace.yaml | 9 ++++- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/apps/zbugs/package.json b/apps/zbugs/package.json index a116e3a62f..5ea8c59e00 100644 --- a/apps/zbugs/package.json +++ b/apps/zbugs/package.json @@ -78,7 +78,7 @@ "use-debounce": "^10.1.1", "usehooks-ts": "^3.1.1", "wouter": "^3.9.0", - "zod": "^4.4.3" + "zod": "^4.6.6" }, "devDependencies": { "@rocicorp/logger": "^6.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 03925b71c1..177a0ab84d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,10 +13,14 @@ overrides: '@xmldom/xmldom@>=0.9.0 <0.9.12': ^0.9.12 ajv@>=7.0.0-alpha.0 <8.18.0: ^8.18.0 basic-ftp@<6.2.1: ^6.2.1 + body-parser@<1.20.9: ^1.20.9 + body-parser@>=2.0.0 <2.4.0: ^2.4.0 browserslist@<4.28.7: ^4.28.7 compression@<1.8.2: ^1.8.2 deepmerge-ts@<8.0.0: ^8.0.0 esbuild: 0.28.2 + fast-uri@>=3.0.0 <3.1.9: ^3.1.9 + fast-uri@>=4.0.0 <4.2.3: ^4.2.3 hono@<4.12.25: ^4.12.25 image-size@>=2.0.0 <2.0.3: ^2.0.3 js-yaml@>=4.0.0 <4.3.2: ^4.3.2 @@ -29,7 +33,7 @@ overrides: postcss-selector-parser@<7.1.6: ^7.1.6 postcss@<8.5.18: ^8.5.18 qs@<6.16.0: ^6.16.0 - serialize-javascript@<=7.0.2: ^7.0.3 + serialize-javascript@<7.1.3: ^7.1.3 shell-quote@<1.8.4: ^1.8.4 source-map-js@<1.2.2: ^1.2.2 tinypool@<2.1.2: ^2.2.0 @@ -37,6 +41,7 @@ overrides: uuid@<11.1.1: ^11.1.1 valibot@<1.4.2: ^1.4.2 webpackbar: ^7.0.0 + zod@<4.6.6: ^4.6.6 '@rocicorp/zero@1.11.0>@opentelemetry/api-logs': ^0.223.0 '@rocicorp/zero@1.11.0>@opentelemetry/auto-instrumentations-node': ^0.81.2 '@rocicorp/zero@1.11.0>@opentelemetry/exporter-metrics-otlp-http': ^0.223.0 @@ -241,8 +246,8 @@ importers: specifier: ^3.9.0 version: 3.9.0(react@19.3.1) zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: ^4.6.6 + version: 4.6.7 devDependencies: '@rocicorp/logger': specifier: ^6.1.0 @@ -335,8 +340,8 @@ importers: specifier: ^8.22.0 version: 8.22.0 zod: - specifier: ^4.4.3 - version: 4.4.3 + specifier: ^4.6.6 + version: 4.6.7 devDependencies: '@types/node': specifier: ^22.19.19 @@ -7443,12 +7448,12 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - body-parser@1.20.8: - resolution: {integrity: sha512-JNcyFQ64OiijEkPzUBTCe+hyPXUD/3LEldGQ6iF5LR1w00mx9o7xtDWHXBY2iItjdCFGoilOLNQbH943ut7pHA==} + body-parser@1.20.9: + resolution: {integrity: sha512-FISIQxV5u91Y9gvuFq3q/tA/qTqLJn3AhRcEvyozyhJTh5OBFFtv827AdHU7Rbyct4r+Ba1/99oFa1Y3yuFsdw==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@2.3.0: - resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + body-parser@2.4.0: + resolution: {integrity: sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==} engines: {node: '>=18'} bonjour-service@1.3.0: @@ -8829,11 +8834,11 @@ packages: fast-querystring@1.1.2: resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - fast-uri@3.1.8: - resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} + fast-uri@3.1.9: + resolution: {integrity: sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==} - fast-uri@4.2.2: - resolution: {integrity: sha512-EwVpUMzLVNOmcWW0zi5G3JJwkopB6XXjnVvNBGfqrMMsVew2hkQWl5e/pe/CfYUeS6jt4cIO2MnamEW7v/7wPw==} + fast-uri@4.2.3: + resolution: {integrity: sha512-I1PXwP5eAhlNlcdpjt9CgB59op2ZvZfxw+BkqGFVIUOgNpCVTcTqp3HhTX7brxj5vsip+nSY4nTvff+eIA76hg==} fast-xml-builder@1.2.0: resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} @@ -12151,8 +12156,8 @@ packages: resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} engines: {node: '>=0.10.0'} - serialize-javascript@7.0.5: - resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} + serialize-javascript@7.1.3: + resolution: {integrity: sha512-kYEnegpAxWFjUw3dSYdSM9zVlTrsxDbsSkq/qd3B7VanqyJ+JdDy6qVyuqVGBhSfuD/rLZQEKuXsO5KZFCrVYQ==} engines: {node: '>=20.0.0'} seroval-plugins@1.6.9: @@ -13455,12 +13460,6 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - zod@4.6.7: resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} @@ -16327,7 +16326,7 @@ snapshots: toqr: 0.1.1 wrap-ansi: 7.0.0 ws: 8.22.0 - zod: 3.25.76 + zod: 4.6.7 optionalDependencies: react-native: 0.88.0(@babel/core@7.29.7)(@types/react@19.3.0)(react@19.3.1) transitivePeerDependencies: @@ -16639,7 +16638,7 @@ snapshots: dependencies: ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) - fast-uri: 3.1.8 + fast-uri: 3.1.9 '@fastify/cookie@10.0.1': dependencies: @@ -20039,14 +20038,14 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.8 + fast-uri: 3.1.9 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.8 + fast-uri: 3.1.9 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -20424,7 +20423,7 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - body-parser@1.20.8: + body-parser@1.20.9: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -20441,7 +20440,7 @@ snapshots: transitivePeerDependencies: - supports-color - body-parser@2.3.0: + body-parser@2.4.0: dependencies: bytes: 3.1.2 content-type: 2.1.0 @@ -20911,7 +20910,7 @@ snapshots: globby: 13.2.2 normalize-path: 3.0.0 schema-utils: 4.3.3 - serialize-javascript: 7.0.5 + serialize-javascript: 7.1.3 webpack: 5.106.2(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.30))(esbuild@0.28.2)(html-minifier-terser@7.2.0)(postcss@8.5.30) core-js-compat@3.49.0: @@ -21018,7 +21017,7 @@ snapshots: jest-worker: 29.7.0 postcss: 8.5.30 schema-utils: 4.3.3 - serialize-javascript: 7.0.5 + serialize-javascript: 7.1.3 webpack: 5.106.2(clean-css@5.3.3)(cssnano@6.1.2(postcss@8.5.30))(esbuild@0.28.2)(html-minifier-terser@7.2.0)(postcss@8.5.30) optionalDependencies: clean-css: 5.3.3 @@ -21771,7 +21770,7 @@ snapshots: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.8 + body-parser: 1.20.9 content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 @@ -21806,7 +21805,7 @@ snapshots: express@5.3.0: dependencies: accepts: 2.0.0 - body-parser: 2.3.0 + body-parser: 2.4.0 content-disposition: 2.0.1 content-type: 2.1.0 cookie: 0.7.2 @@ -21873,7 +21872,7 @@ snapshots: '@fastify/merge-json-schemas': 0.2.1 ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) - fast-uri: 3.1.8 + fast-uri: 3.1.9 json-schema-ref-resolver: 3.0.0 rfdc: 1.4.1 @@ -21882,7 +21881,7 @@ snapshots: '@fastify/merge-json-schemas': 0.2.1 ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) - fast-uri: 4.2.2 + fast-uri: 4.2.3 json-schema-ref-resolver: 3.0.0 rfdc: 1.4.1 @@ -21890,9 +21889,9 @@ snapshots: dependencies: fast-decode-uri-component: 1.0.1 - fast-uri@3.1.8: {} + fast-uri@3.1.9: {} - fast-uri@4.2.2: {} + fast-uri@4.2.3: {} fast-xml-builder@1.2.0: dependencies: @@ -26003,7 +26002,7 @@ snapshots: serialize-error@2.1.0: {} - serialize-javascript@7.0.5: {} + serialize-javascript@7.1.3: {} seroval-plugins@1.6.9(seroval@1.6.9): dependencies: @@ -27495,10 +27494,6 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 - zod@3.25.76: {} - - zod@4.4.3: {} - zod@4.6.7: {} zstd-codec@0.1.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d142b2a866..1017e900fa 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -60,10 +60,14 @@ overrides: '@xmldom/xmldom@>=0.9.0 <0.9.12': ^0.9.12 ajv@>=7.0.0-alpha.0 <8.18.0: ^8.18.0 basic-ftp@<6.2.1: ^6.2.1 + body-parser@<1.20.9: ^1.20.9 + body-parser@>=2.0.0 <2.4.0: ^2.4.0 browserslist@<4.28.7: ^4.28.7 compression@<1.8.2: ^1.8.2 deepmerge-ts@<8.0.0: ^8.0.0 esbuild: '0.28.2' + fast-uri@>=3.0.0 <3.1.9: ^3.1.9 + fast-uri@>=4.0.0 <4.2.3: ^4.2.3 hono@<4.12.25: ^4.12.25 image-size@>=2.0.0 <2.0.3: ^2.0.3 js-yaml@>=4.0.0 <4.3.2: ^4.3.2 @@ -76,7 +80,7 @@ overrides: postcss-selector-parser@<7.1.6: ^7.1.6 postcss@<8.5.18: ^8.5.18 qs@<6.16.0: ^6.16.0 - serialize-javascript@<=7.0.2: ^7.0.3 + serialize-javascript@<7.1.3: ^7.1.3 shell-quote@<1.8.4: ^1.8.4 source-map-js@<1.2.2: ^1.2.2 tinypool@<2.1.2: ^2.2.0 @@ -84,6 +88,9 @@ overrides: uuid@<11.1.1: ^11.1.1 valibot@<1.4.2: ^1.4.2 webpackbar: ^7.0.0 + # @expo/cli still depends on zod 3, which has no patched release. It only + # uses zod APIs that are unchanged in zod 4. + zod@<4.6.6: ^4.6.6 # @rocicorp/zero-previous (npm:@rocicorp/zero@1.11.0) is only used for its # client in zql-integration-tests; align its OpenTelemetry deps with the # workspace so it doesn't drag in old, vulnerable instrumentations. From 945ce619249e63381fb51d46c12f0d9e80024860 Mon Sep 17 00:00:00 2001 From: Greg Baker Date: Sat, 24 Oct 2026 06:14:27 +0000 Subject: [PATCH 7/8] fix(zero-cache): confine a failed push to the socket that sent it Closes rocicorp/mono#6724 Co-authored-by: Paul Warren Mono-Internal-Commit: ab1bb63ce51d7d7e79c40e17465d3d4484cb6d87 --- .../zero-cache/src/services/mutagen/pusher.ts | 96 +++++++++++++------ 1 file changed, 66 insertions(+), 30 deletions(-) diff --git a/packages/zero-cache/src/services/mutagen/pusher.ts b/packages/zero-cache/src/services/mutagen/pusher.ts index 3182ec640a..35e20dce67 100644 --- a/packages/zero-cache/src/services/mutagen/pusher.ts +++ b/packages/zero-cache/src/services/mutagen/pusher.ts @@ -276,6 +276,18 @@ class PushWorker { string, {wsID: string; downstream: Subscription} >; + /** + * For each client, the wsID of its socket whose push most recently failed. + * Pushes queued behind the failed one on that socket are not sent: they + * start past the failed mutation, so the API server could only reject them + * as out of order. The socket is failed (or was already replaced), and the + * client re-sends every unacknowledged mutation on its next socket. + * + * An entry is kept until the socket can no longer queue pushes (it closed or + * the client reconnected) and the queue has been drained since, so it is not + * removed while pushes from the failed socket may still be queued. + */ + readonly #failedSockets = new Map(); readonly #customMutations = getOrCreateCounter( 'mutation', @@ -338,10 +350,24 @@ class PushWorker { async run() { for (;;) { + // Failed sockets that can no longer queue pushes. Everything they queued + // is in the next drain, so they are forgotten once it has been handled. + const closedSockets = [...this.#failedSockets].filter( + ([clientID, wsID]) => + !this.#connContextManager.getConnectionContext({clientID, wsID}), + ); const task = await this.#queue.dequeue(); const rest = this.#queue.drain(); const [pushes, terminate] = combinePushes([task, ...rest]); for (const push of pushes) { + const {clientID, wsID} = push.connCtx; + if (this.#failedSockets.get(clientID) === wsID) { + this.#lc.debug?.( + 'Not sending push queued behind a failed push on the same socket; the client re-sends it on its next socket', + {clientID, wsID, mutations: push.push.mutations.length}, + ); + continue; + } const parentContext = push.push.traceparent ? propagation.extract(ROOT_CONTEXT, { traceparent: push.push.traceparent, @@ -350,7 +376,13 @@ class PushWorker { const response = await context.with(parentContext, () => this.#processPush(push), ); - await this.#fanOutResponses(response); + await this.#fanOutResponses(push.connCtx, response); + } + + for (const [clientID, wsID] of closedSockets) { + if (this.#failedSockets.get(clientID) === wsID) { + this.#failedSockets.delete(clientID); + } } if (terminate) { @@ -360,11 +392,18 @@ class PushWorker { } /** - * 1. If the entire `push` fails, we send the error to relevant clients. + * 1. If the entire `push` fails, we send the error to `origin`, the + * connection the push was sent on. * 2. If the push succeeds, we look for any mutation failure that should cause the connection to terminate - * and terminate the connection for those clients. + * and terminate `origin`. + * + * Only `origin` is failed, even when the push carried other clients' + * mutations (the client group's commit chain includes other tabs' pending + * mutations). A client tracks what it has sent per socket, so the gap a + * failed push leaves is on `origin` alone. Other clients send their own + * mutations on their own sockets, and see any lasting error there. */ - #fanOutResponses(response: MutateResponse) { + #fanOutResponses(origin: ConnectionContext, response: MutateResponse) { const connectionTerminations: (() => void)[] = []; // if the entire push failed, send that to the client. @@ -376,19 +415,8 @@ class PushWorker { 'The server behind ZERO_MUTATE_URL returned a push error.', response, ); - // TODO(0xcadams): Fanout is keyed only by clientID here. If a response arrives - // after reconnect or re-auth, `#clients.get(clientID)` may point at a - // newer wsID/revision and fail the replacement downstream instead. - const groupedMutationIDs = groupBy( - response.mutationIDs ?? [], - m => m.clientID, - ); - for (const [clientID, mutationIDs] of groupedMutationIDs) { - const client = this.#clients.get(clientID); - if (!client) { - continue; - } - + const mutationIDs = response.mutationIDs ?? []; + if (mutationIDs.length > 0) { // We do not resolve mutations on the client if the push fails // as those mutations will be retried. if ('error' in response) { @@ -426,22 +454,15 @@ class PushWorker { : 'An unknown error occurred while pushing to the API server', }; - this.#failDownstream(client.downstream, pushFailedBody); + this.#failOrigin(origin, pushFailedBody); } else { - this.#failDownstream(client.downstream, response); + this.#failOrigin(origin, response); } } } else { // Look for mutations results that should cause us to terminate the connection - // TODO(0xcadams): Same stale-routing issue as above: fatal mutation results are - // still mapped to the current downstream by clientID only. const groupedMutations = groupBy(response.mutations, m => m.id.clientID); - for (const [clientID, mutations] of groupedMutations) { - const client = this.#clients.get(clientID); - if (!client) { - continue; - } - + for (const mutations of groupedMutations.values()) { let failure: PushFailedBody | undefined; let i = 0; for (; i < mutations.length; i++) { @@ -478,9 +499,7 @@ class PushWorker { } if (failure) { - connectionTerminations.push(() => - this.#failDownstream(client.downstream, failure), - ); + connectionTerminations.push(() => this.#failOrigin(origin, failure)); } } } @@ -488,6 +507,23 @@ class PushWorker { connectionTerminations.forEach(cb => cb()); } + /** + * Fails `origin` after a push sent on it failed, and records it in + * `#failedSockets` so the pushes it queued behind that one are not sent. + * + * If the client has reconnected since sending the push, the old socket is + * already gone and the client re-sends its mutations on the new one. Failing + * the new socket would put the client in its error state, rejecting its + * outstanding mutations, for a failure it has already recovered from. + */ + #failOrigin(origin: ConnectionContext, errorBody: PushFailedBody): void { + this.#failedSockets.set(origin.clientID, origin.wsID); + const client = this.#clients.get(origin.clientID); + if (client?.wsID === origin.wsID) { + this.#failDownstream(client.downstream, errorBody); + } + } + async #processPush(entry: PusherEntry): Promise { this.#customMutations.add(entry.push.mutations.length, { clientGroupID: entry.push.clientGroupID, From 4e39eec33c8e8a193f93731d63479a9eb79c1706 Mon Sep 17 00:00:00 2001 From: Amp Date: Mon, 26 Oct 2026 02:37:28 +0000 Subject: [PATCH 8/8] chore: point the fork's zod snapshots at upstream's override Upstream overrides zod@<4.6.6 to ^4.6.6 and dropped zod 4.4.3 from the lockfile, which incur and @modelcontextprotocol/server (zero-swift-cli) still resolved to. Both now take the existing 4.6.7 entry. Amp-Thread-ID: https://ampcode.com/threads/T-c513a037-a257-45e0-b9a9-15c15edfe859 Co-authored-by: tmm --- pnpm-lock.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f31515887..f20bcab629 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17180,7 +17180,7 @@ snapshots: '@modelcontextprotocol/server@2.0.0-alpha.4': dependencies: - zod: 4.4.3 + zod: 4.6.7 '@monaco-editor/loader@1.7.0': dependencies: @@ -22712,7 +22712,7 @@ snapshots: '@toon-format/toon': 2.3.1 tokenx: 1.6.0 yaml: 2.9.1 - zod: 4.4.3 + zod: 4.6.7 indent-string@4.0.0: {}