Skip to content

Conversation

maxstevens-nl
Copy link
Collaborator

This PR adds support for Synced Queries in a backwards compatible way. In order to achieve this, we had to find a way to give the useQuery composable access to the zero instance. We do this using provide/inject wrapped in a plugin, createZero. The plugin takes either an initialized Zero instance or a ZeroOptions object.

We also add a createUseZero factory, the output of which is just a wrapper around the inject call. By having this as a factory, we allow users to specify the types of the returned Zero instance (which is also how the Solid lib is implemented).

I'm still on the fence about whether we should also provide a useZero composable. It will allow users to get up and running more quickly, but I am not sure if many people are going to want to use this without types. Not including it means IntelliSense will provide you with only the import from your own project, instead of also the version we provide, which improves DX. Or are we able to get calls to useZero typed based on the plugin registration?

@maxstevens-nl maxstevens-nl self-assigned this Sep 9, 2025
Copy link

socket-security bot commented Sep 9, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedhappy-dom@​18.0.1991008887100

View full report

Copy link
Collaborator

@arv arv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@maxstevens-nl
Copy link
Collaborator Author

@danielroe good to merge?

@danielroe
Copy link
Owner

apologies for the delay. I want to review with an eye to how we would implement in nuxt (where provide/inject is often not the best pattern).

ideally something that would support lazy creation of the stateful singleton (ie on first access)

@Gerbuuun
Copy link
Contributor

I'm doing this. A global variable and checking if it exist on each access. I watch the user session but most of the time changing the value comes with navigation/reload so not sure how necessary it is.

import { Zero } from "@rocicorp/zero";
import { schema, clientMutators } from "~~/zero";
import type { AuthData } from "~~/zero";
import { decodeJwt } from "jose";

let client: Zero<typeof schema, ReturnType<typeof clientMutators>>;

export function useZero() {
  const { session } = useUserSession();
  const config = useRuntimeConfig().public.zero;
  const decodedJWT = computed<AuthData | undefined>(() => session.value?.token ? decodeJwt<AuthData>(session.value.token) : undefined);
  const userID = computed(() => decodedJWT.value?.sub ?? 'anon');

  watch([userID], () => {
    if (client && client.userID === userID.value)
      return;
      
    if (client && !client.closed) {
      client.close();
    }

    client = new Zero({
      userID: userID.value,
      auth: () => session.value?.token,
      mutators: clientMutators(decodedJWT.value),
      server: import.meta.client ? config.server : undefined,
      schema,
    });
  }, { immediate: true });

  return client;
}

@maxstevens-nl
Copy link
Collaborator Author

@danielroe would doing something along the lines of what Pinia does:

export let activeZero: Zero<any, any> | undefined

export function setActiveZero(zero: Zero<any, any>) {
  activeZero = zero
}

export function useZero() {
  return ((hasInjectionContext() && inject(zeroSymbol)) || shallowRef(activeZero))
}

in combination with the plugin proposed in this PR and a to-be-created Nuxt module be a step in the right direction?

While not lazy-creation, it would make sure that Zero is available during SSR. You also keep the benefit of useZero returning a shallowRef (in an injection context).

Although I need to add that I don't have a lot of experience with Nuxt, so if you know of any libraries that have a more 'nuxt-native' implementation that would be very welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants