import type { LogLevel } from '@rocicorp/logger'; import type { StoreProvider } from '../../../replicache/src/kv/store.ts'; import type { MaybePromise } from '../../../shared/src/types.ts'; import * as v from '../../../shared/src/valita.ts'; import type { Schema } from '../../../zero-schema/src/builder/schema-builder.ts'; import type { CustomMutatorDefs } from './custom.ts'; import type { OnError } from './on-error.ts'; import { UpdateNeededReasonType } from './update-needed-reason-type.ts'; /** * Configuration for {@linkcode Zero}. */ export interface ZeroOptions { /** * URL to the zero-cache. This can be a simple hostname, e.g. * - "https://myapp-myteam.zero.ms" * or a prefix with a single path component, e.g. * - "https://myapp-myteam.zero.ms/zero" * - "https://myapp-myteam.zero.ms/db" * * The latter is useful for configuring routing rules (e.g. "/zero/\*") when * the zero-cache is hosted on the same domain as the application. **Note that * only a single path segment is allowed (e.g. it cannot be "/proxy/zero/\*")**. */ server?: string | null | undefined; /** * A JWT to identify and authenticate the user. Can be provided as either: * - A string containing the JWT token * - A function that returns a JWT token * - `undefined` if there is no logged in user * * Token validation behavior: * 1. **For function providers:** * When zero-cache reports that a token is invalid (expired, malformed, * or has an invalid signature), Zero will call the function again with * `error='invalid-token'` to obtain a new token. * * 2. **For string tokens:** * Zero will continue to use the provided token even if zero-cache initially * reports it as invalid. This is because zero-cache may be able to validate * the token after fetching new public keys from its configured JWKS URL * (if `ZERO_AUTH_JWKS_URL` is set). */ auth?: string | ((error?: 'invalid-token') => MaybePromise) | undefined; /** * A unique identifier for the user. Must be non-empty. * * Each userID gets its own client-side storage so that the app can switch * between users without losing state. * * This must match the `sub` claim of the `auth` token if * `auth` is provided. */ userID: string; /** * Distinguishes the storage used by this Zero instance from that of other * instances with the same userID. Useful in the case where the app wants to * have multiple Zero instances for the same user for different parts of the * app. */ storageKey?: string | undefined; /** * How long an inactive client's persisted state is retained before * ClientGC collects it. Defaults to 24h * (`CLIENT_MAX_INACTIVE_TIME`). * * Every page load creates a client, and each client roots a snapshot of * the dag b-tree, so this value is effectively "how many boots' worth of * superseded b-tree nodes stay on disk". An app that loads often can end * up reading back an order of magnitude more than its live row set at * boot; lowering this lets the existing refcount GC reclaim it. * * Only lower it if the app does not rely on mutation recovery from * abandoned clients — a collected client's un-pushed mutations are gone. * * Must be larger than `max(GC_INTERVAL, HEARTBEAT_INTERVAL)`; smaller * values throw from `validateOptions`. */ clientMaxAgeMs?: number | undefined; /** * Determines the level of detail at which Zero logs messages about * its operation. Messages are logged to the `console`. * * When this is set to `'debug'`, `'info'` and `'error'` messages are also * logged. When set to `'info'`, `'info'` and `'error'` but not * `'debug'` messages are logged. When set to `'error'` only `'error'` * messages are logged. * * Default is `'error'`. */ logLevel?: LogLevel | undefined; /** * This defines the schema of the tables used in Zero and their relationships * to one another. */ schema: S; /** * `mutators` is a map of custom mutator definitions. The keys are * namespaces or names of the mutators. The values are the mutator * implementations. Client side mutators must be idempotent as a * mutation can be rebased multiple times when folding in authoritative * changes from the server to the client. */ mutators?: MD | undefined; /** * Custom URL for mutation requests sent to your API server. * If not provided, uses the default configured in zero-cache. */ mutateURL?: string | undefined; /** * Custom URL for query requests sent to your API server. * If not provided, uses the default configured in zero-cache. */ getQueriesURL?: string | undefined; /** * `onOnlineChange` is called when the Zero instance's online status changes. * * @deprecated Use `onOnline` on the Zero instance instead. e.g. * ```ts * const zero = new Zero({...}); * zero.onOnline((online) => { ... }); * ``` */ onOnlineChange?: ((online: boolean) => void) | undefined; /** * `onUpdateNeeded` is called when a client code update is needed. * * See {@link UpdateNeededReason} for why updates can be needed. * * The default behavior is to reload the page (using `location.reload()`). * Provide your own function to prevent the page from * reloading automatically. You may want to display a toast to inform the end * user there is a new version of your app available and prompt them to * refresh. */ onUpdateNeeded?: ((reason: UpdateNeededReason) => void) | undefined; /** * `onClientStateNotFound` is called when this client is no longer able * to sync with the zero-cache due to missing synchronization state. This * can be because: * - the local persistent synchronization state has been garbage collected. * This can happen if the client has no pending mutations and has not been * used for a while (e.g. the client's tab has been hidden for a long time). * - the zero-cache fails to find the server side synchronization state for * this client. * * The default behavior is to reload the page (using `location.reload()`). * Provide your own function to prevent the page from reloading automatically. */ onClientStateNotFound?: (() => void) | undefined; /** * The number of milliseconds to wait before disconnecting a Zero * instance whose tab has become hidden. * * Instances in hidden tabs are disconnected to save resources. * * Default is 5_000. */ hiddenTabDisconnectDelay?: number | undefined; /** * This gets called when the Zero instance encounters an error. The default * behavior is to log the error to the console. Provide your own function to * prevent the default behavior. */ onError?: OnError | undefined; /** * Determines what kind of storage implementation to use on the client. * * Defaults to `'idb'` which means that Zero uses an IndexedDB storage * implementation. This allows the data to be persisted on the client and * enables faster syncs between application restarts. * * By setting this to `'mem'`, Zero uses an in memory storage and * the data is not persisted on the client. * * You can also set this to a function that is used to create new KV stores, * allowing a custom implementation of the underlying storage layer. */ kvStore?: 'mem' | 'idb' | StoreProvider | undefined; /** * The maximum number of bytes to allow in a single header. * * Zero adds some extra information to headers on initialization if possible. * This speeds up data synchronization. This number should be kept less than * or equal to the maximum header size allowed by the zero-cache and any load * balancers. * * Default value: 8kb. */ maxHeaderLength?: number | undefined; /** * The maximum amount of milliseconds to wait for a materialization to * complete (including network/server time) before printing a warning to the * console. * * Default value: 5_000. */ slowMaterializeThreshold?: number | undefined; /** * UI rendering libraries will often provide a utility for batching multiple * state updates into a single render. Some examples are React's * `unstable_batchedUpdates`, and solid-js's `batch`. * * This option enables integrating these batch utilities with Zero. * * When `batchViewUpdates` is provided, Zero will call it whenever * it updates query view state with an `applyViewUpdates` function * that performs the actual state updates. * * Zero updates query view state when: * 1. creating a new view * 2. updating all existing queries' views to a new consistent state * * When creating a new view, that single view's creation will be wrapped * in a `batchViewUpdates` call. * * When updating existing queries, all queries will be updated in a single * `batchViewUpdates` call, so that the transition to the new consistent * state can be done in a single render. * * Implementations must always call `applyViewUpdates` synchronously. */ batchViewUpdates?: ((applyViewUpdates: () => void) => void) | undefined; /** * The maximum number of recent queries, no longer subscribed to by a preload * or view, to continue syncing. * * Defaults is 0. * * @deprecated Use ttl instead */ maxRecentQueries?: number | undefined; /** * Changes to queries are sent to server in batches. This option controls * the number of milliseconds to wait before sending the next batch. * * Defaults is 10. */ queryChangeThrottleMs?: number | undefined; /** * A shared secret used for connection challenge authentication. * When set, the client will generate a challenge token using HMAC-SHA256 * to prove it has access to the secret before establishing a WebSocket connection. * * This prevents direct WebSocket connections from tools like Postman, even with * a valid JWT, as the attacker would need to know this secret to generate * a valid challenge token. * * The same secret must be configured on the server via ZERO_AUTH_CONNECTION_SECRET. * Should be a cryptographically random string of at least 32 characters. */ connectionSecret?: string | undefined; } /** * @deprecated Use {@link ZeroOptions} instead. */ export interface ZeroAdvancedOptions extends ZeroOptions { } type UpdateNeededReasonBase = { message?: string; }; export type UpdateNeededReason = ({ type: UpdateNeededReasonType.NewClientGroup; } & UpdateNeededReasonBase) | ({ type: UpdateNeededReasonType.VersionNotSupported; } & UpdateNeededReasonBase) | ({ type: UpdateNeededReasonType.SchemaVersionNotSupported; } & UpdateNeededReasonBase); export declare const updateNeededReasonTypeSchema: v.Type; export {}; //# sourceMappingURL=options.d.ts.map