From 31012c613048d78cffa64bfdcfcd92a1d2d5c0ab Mon Sep 17 00:00:00 2001 From: Gerben Mulder Date: Mon, 1 Dec 2025 21:14:24 +0100 Subject: [PATCH 1/6] fix: make zero a peer dependency --- package.json | 5 ++-- pnpm-lock.yaml | 78 +++++++------------------------------------------- 2 files changed, 13 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 505b5eb..3952dc1 100644 --- a/package.json +++ b/package.json @@ -32,14 +32,13 @@ "test:types": "tsc --noEmit && pnpm -r test:types" }, "peerDependencies": { + "@rocicorp/zero": "^0.24.3000000000", "vue": "^3.5.13" }, - "dependencies": { - "@rocicorp/zero": "^0.24.3000000000" - }, "devDependencies": { "@antfu/eslint-config": "latest", "@rocicorp/resolver": "1.0.2", + "@rocicorp/zero": "0.24.3000000000", "@vitest/coverage-v8": "latest", "bumpp": "latest", "changelogithub": "14.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ca7034..960d7eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,6 @@ overrides: importers: .: - dependencies: - '@rocicorp/zero': - specifier: ^0.24.3000000000 - version: 0.24.3000000000(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)) devDependencies: '@antfu/eslint-config': specifier: latest @@ -21,6 +17,9 @@ importers: '@rocicorp/resolver': specifier: 1.0.2 version: 1.0.2 + '@rocicorp/zero': + specifier: 0.24.3000000000 + version: 0.24.3000000000(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)) '@vitest/coverage-v8': specifier: latest version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -38,7 +37,7 @@ importers: version: 9.3.0 knip: specifier: latest - version: 5.70.2(@types/node@24.10.1)(typescript@5.9.3) + version: 5.71.0(@types/node@24.10.1)(typescript@5.9.3) lint-staged: specifier: latest version: 16.2.7 @@ -3225,8 +3224,8 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - knip@5.70.2: - resolution: {integrity: sha512-LI7DbeVnk7h9+FAet5KzzHNdDwJyqDa2+cn4uQfZYTfpuVjEqtGmYD9r5b9JEuOs4eVkf/7sskNhWXxELm3C/Q==} + knip@5.71.0: + resolution: {integrity: sha512-hwgdqEJ+7DNJ5jE8BCPu7b57TY7vUwP6MzWYgCgPpg6iPCee/jKPShDNIlFER2koti4oz5xF88VJbKCb4Wl71g==} engines: {node: '>=18.18.0'} hasBin: true peerDependencies: @@ -4552,46 +4551,6 @@ packages: resolution: {integrity: sha512-JwPr6erhX53EWH/HCSzfy1tTFrtPXUe927wdM1jqBBeYp1OM+qPHjWbsvv6pIBduqdgxxS+ScfG7S28pzyr2DQ==} engines: {node: '>=0.10.48'} - vite@7.2.4: - resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - vite@7.2.6: resolution: {integrity: sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -6522,13 +6481,13 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.14(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.14(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.14 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.2.6(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@4.0.14': dependencies: @@ -8159,7 +8118,7 @@ snapshots: dependencies: json-buffer: 3.0.1 - knip@5.70.2(@types/node@24.10.1)(typescript@5.9.3): + knip@5.71.0(@types/node@24.10.1)(typescript@5.9.3): dependencies: '@nodelib/fs.walk': 1.2.8 '@types/node': 24.10.1 @@ -9696,21 +9655,6 @@ snapshots: version-guard@1.1.3: {} - vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.3 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.10.1 - fsevents: 2.3.3 - jiti: 2.6.1 - tsx: 4.21.0 - yaml: 2.8.2 - vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.25.12 @@ -9729,7 +9673,7 @@ snapshots: vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.14 - '@vitest/mocker': 4.0.14(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.0.14(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.14 '@vitest/runner': 4.0.14 '@vitest/snapshot': 4.0.14 @@ -9746,7 +9690,7 @@ snapshots: tinyexec: 0.3.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.2.6(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 From eb4270a9e485bba6f534c02b636035d908a1b9a0 Mon Sep 17 00:00:00 2001 From: Gerben Mulder Date: Mon, 1 Dec 2025 21:14:54 +0100 Subject: [PATCH 2/6] chore: remove support for older zero versions --- src/create-zero-composables.ts | 13 +++++-- src/index.ts | 2 +- src/query.test.ts | 69 ++++------------------------------ src/query.ts | 46 +++-------------------- src/view.ts | 11 +----- 5 files changed, 25 insertions(+), 116 deletions(-) diff --git a/src/create-zero-composables.ts b/src/create-zero-composables.ts index f60842d..283fa6f 100644 --- a/src/create-zero-composables.ts +++ b/src/create-zero-composables.ts @@ -3,9 +3,14 @@ import type { MaybeRefOrGetter, ShallowRef } from 'vue' import type { QueryResult, UseQueryOptions } from './query' import { Zero } from '@rocicorp/zero' import { shallowRef, toValue, watch } from 'vue' -import { useQueryWithZero } from './query' - -export function createZeroComposables(optsOrZero: MaybeRefOrGetter | { zero: Zero }>) { +import { useQuery as _useQuery } from './query' + +export function createZeroComposables< + S extends Schema = Schema, + MD extends CustomMutatorDefs | undefined = undefined, +>( + optsOrZero: MaybeRefOrGetter | { zero: Zero }>, +) { let z: ShallowRef> function useZero(): ShallowRef> { @@ -36,7 +41,7 @@ export function createZeroComposables, ): QueryResult { const z = useZero() - return useQueryWithZero(z, query, options) + return _useQuery(z, query, options) } return { diff --git a/src/index.ts b/src/index.ts index 696b550..b8879bb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ export { createZeroComposables } from './create-zero-composables' export type { QueryResult, UseQueryOptions } from './query' -export { useQuery, useQueryWithZero } from './query' +export { useQuery } from './query' diff --git a/src/query.test.ts b/src/query.test.ts index cfaf7fb..8db464a 100644 --- a/src/query.test.ts +++ b/src/query.test.ts @@ -1,5 +1,4 @@ import type { TTL } from '@rocicorp/zero' -import type { MockInstance } from 'vitest' import { createBuilder, createSchema, number, string, syncedQuery, table, Zero } from '@rocicorp/zero' import { describe, expect, it, vi } from 'vitest' import { nextTick, ref, watchEffect } from 'vue' @@ -98,77 +97,23 @@ describe('useQuery', () => { z.value.close() }) - it('useQuery with ttl (zero@0.18)', async () => { + it('useQuery with ttl', async () => { const { z, tableQuery, useQuery } = await setupTestEnvironment() - if (!('updateTTL' in tableQuery)) { - // 0.19 removed updateTTL from the query - return - } const ttl = ref('1m') - const materializeSpy = vi.spyOn(tableQuery, 'materialize') - // @ts-expect-error missing from v0.19+ - const updateTTLSpy = vi.spyOn(tableQuery, 'updateTTL') + const materializeSpy = vi.spyOn(z.value, 'materialize') const queryGetter = vi.fn(() => tableQuery) useQuery(queryGetter, () => ({ ttl: ttl.value })) - expect(queryGetter).toHaveBeenCalledTimes(1) - expect(updateTTLSpy).toHaveBeenCalledTimes(0) + + expect(materializeSpy).toHaveLastReturnedWith(expect.any(VueView)) expect(materializeSpy).toHaveBeenCalledExactlyOnceWith( + tableQuery, vueViewFactory, - '1m', + { ttl: '1m' }, ) - materializeSpy.mockClear() - - ttl.value = '10m' - await nextTick() - - expect(materializeSpy).toHaveBeenCalledTimes(0) - expect(updateTTLSpy).toHaveBeenCalledExactlyOnceWith('10m') - - z.value.close() - }) - - it('useQuery with ttl (zero@0.19)', async () => { - const { z, tableQuery, useQuery } = await setupTestEnvironment() - if ('updateTTL' in tableQuery) { - // 0.19 removed updateTTL from the query - return - } - - const ttl = ref('1m') - - let materializeSpy: MockInstance - // @ts-expect-error only present in v0.23+ - if (z.value.materialize) { - materializeSpy = vi.spyOn(z.value, 'materialize') - } - else { - materializeSpy = vi.spyOn(tableQuery, 'materialize') - } - - const queryGetter = vi.fn(() => tableQuery) - - useQuery(queryGetter, () => ({ ttl: ttl.value })) - expect(queryGetter).toHaveBeenCalledTimes(1) - - expect(materializeSpy).toHaveLastReturnedWith(expect.any(VueView)) - // @ts-expect-error only present in v0.23+ - if (z.value.materialize) { - expect(materializeSpy).toHaveBeenCalledExactlyOnceWith( - tableQuery, - vueViewFactory, - { ttl: '1m' }, - ) - } - else { - expect(materializeSpy).toHaveBeenCalledExactlyOnceWith( - vueViewFactory, - '1m', - ) - } const view: VueView = materializeSpy.mock.results[0]!.value const updateTTLSpy = vi.spyOn(view, 'updateTTL') @@ -329,7 +274,7 @@ describe('useQuery', () => { await z.mutate.table.insert({ a: 1, b: 'a' }) await z.mutate.table.insert({ a: 2, b: 'b' }) - const { data: rows, status } = useQuery(() => z.query.table) + const { data: rows, status } = useQuery(z, () => z.query.table) expect(rows.value).toMatchInlineSnapshot(`[ { "a": 1, diff --git a/src/query.ts b/src/query.ts index 536ceab..20d086a 100644 --- a/src/query.ts +++ b/src/query.ts @@ -26,40 +26,17 @@ export interface QueryResult { error: ComputedRef void } | undefined> } -/** - * @deprecated - * - * Use `useQuery` returned from `createZero` instead. This function doesn't - * support Synced Queries, and will be removed in a future version. - * - * @param query The query to execute. - * @param options Options for the query. - * @returns The result of the query. - */ export function useQuery< TSchema extends Schema, TTable extends keyof TSchema['tables'] & string, TReturn, ->( - query: MaybeRefOrGetter>, - options?: MaybeRefOrGetter, -): QueryResult { - return useQueryWithZero(undefined as unknown as Zero, query, options) -} - -export function useQueryWithZero< - TSchema extends Schema, - TTable extends keyof TSchema['tables'] & string, - TReturn, MD extends CustomMutatorDefs | undefined = undefined, >( z: MaybeRefOrGetter>, query: MaybeRefOrGetter>, options?: MaybeRefOrGetter, ): QueryResult { - const ttl = computed(() => { - return toValue(options)?.ttl ?? DEFAULT_TTL_MS - }) + const ttl = computed(() => toValue(options)?.ttl ?? DEFAULT_TTL_MS) const view = shallowRef> | null>(null) const refetchKey = shallowRef(0) @@ -71,18 +48,7 @@ export function useQueryWithZero< ], ([q, z]) => { view.value?.destroy() - - // Only present in v0.23+ - if (z?.materialize) { - view.value = z.materialize(q, vueViewFactory, { ttl: ttl.value }) - return - } - - // For synced queries (customQueryID), we need the Zero instance (e.g. during SSR it will be undefined) - if (q.customQueryID) - return - - view.value = q.materialize(vueViewFactory, ttl.value) + view.value = z.materialize(q, vueViewFactory, { ttl: toValue(ttl) }) }, { immediate: true }, ) @@ -96,12 +62,12 @@ export function useQueryWithZero< } return { - data: computed(() => view.value!.data), - status: computed(() => view.value!.status), - error: computed(() => view.value!.error + data: computed(() => view.value?.data as HumanReadable), + status: computed(() => view.value?.status ?? 'unknown'), + error: computed(() => view.value?.error ? { retry: () => { refetchKey.value++ }, - ...view.value!.error, + ...view.value.error, } : undefined, ), diff --git a/src/view.ts b/src/view.ts index 64a908b..3bb6bcd 100644 --- a/src/view.ts +++ b/src/view.ts @@ -162,22 +162,15 @@ export function vueViewFactory< onDestroy: () => void, onTransactionCommit: (cb: () => void) => void, queryComplete: true | ErroredQuery | Promise, - updateTTL?: (ttl: TTL) => void, + updateTTL: (ttl: TTL) => void, ) { - interface UpdateTTL { - updateTTL: (ttl: TTL) => void - } return new VueView>( input, onTransactionCommit, format, onDestroy, queryComplete, - // In zero@0.19 updateTTL is passed in to the view factory. - // In zero@0.18 it was a property on the query. - updateTTL ?? (ttl => - (query as unknown as UpdateTTL).updateTTL(ttl) - ), + updateTTL, ) } From e0d94fed0482935717a4aa1fb67e84b07493efb8 Mon Sep 17 00:00:00 2001 From: Gerben Mulder Date: Mon, 1 Dec 2025 21:21:00 +0100 Subject: [PATCH 3/6] fix: test --- src/view.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/view.test.ts b/src/view.test.ts index 68a293f..3616c3b 100644 --- a/src/view.test.ts +++ b/src/view.test.ts @@ -1306,6 +1306,7 @@ describe('vueViewFactory', () => { onDestroy, onTransactionCommit, true, + () => {}, ) }) From 067a5e4f97438f744908dbb961582581478a5710 Mon Sep 17 00:00:00 2001 From: Gerben Mulder Date: Mon, 1 Dec 2025 21:56:13 +0100 Subject: [PATCH 4/6] fix: revert zero dependency change --- package.json | 5 +++-- pnpm-lock.yaml | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3952dc1..1cabadd 100644 --- a/package.json +++ b/package.json @@ -32,13 +32,14 @@ "test:types": "tsc --noEmit && pnpm -r test:types" }, "peerDependencies": { - "@rocicorp/zero": "^0.24.3000000000", "vue": "^3.5.13" }, + "dependencies": { + "@rocicorp/zero": "0.24.3000000000" + }, "devDependencies": { "@antfu/eslint-config": "latest", "@rocicorp/resolver": "1.0.2", - "@rocicorp/zero": "0.24.3000000000", "@vitest/coverage-v8": "latest", "bumpp": "latest", "changelogithub": "14.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 960d7eb..ed894e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,10 @@ overrides: importers: .: + dependencies: + '@rocicorp/zero': + specifier: 0.24.3000000000 + version: 0.24.3000000000(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)) devDependencies: '@antfu/eslint-config': specifier: latest @@ -17,9 +21,6 @@ importers: '@rocicorp/resolver': specifier: 1.0.2 version: 1.0.2 - '@rocicorp/zero': - specifier: 0.24.3000000000 - version: 0.24.3000000000(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)) '@vitest/coverage-v8': specifier: latest version: 4.0.14(vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) From e54ba5b02b2134593e9ced562fb64fb0f8989984 Mon Sep 17 00:00:00 2001 From: Gerben Mulder Date: Mon, 1 Dec 2025 21:57:08 +0100 Subject: [PATCH 5/6] fix: zero version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1cabadd..505b5eb 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "vue": "^3.5.13" }, "dependencies": { - "@rocicorp/zero": "0.24.3000000000" + "@rocicorp/zero": "^0.24.3000000000" }, "devDependencies": { "@antfu/eslint-config": "latest", From 74e37f9ec04de00d9a96d9a08a9087713b306a74 Mon Sep 17 00:00:00 2001 From: Gerben Mulder Date: Mon, 1 Dec 2025 21:58:22 +0100 Subject: [PATCH 6/6] fix: lock-file .... --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed894e6..47e4c91 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,7 +12,7 @@ importers: .: dependencies: '@rocicorp/zero': - specifier: 0.24.3000000000 + specifier: ^0.24.3000000000 version: 0.24.3000000000(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)) devDependencies: '@antfu/eslint-config':