import type { UnknownError } from '@livestore/common'; import type { CfTypes } from '@livestore/common-cf'; import { Effect, Schema } from '@livestore/utils/effect'; import type { SearchParams } from '../common/mod.ts'; import { SyncMessage } from '../common/mod.ts'; export type Env = {}; /** Headers forwarded from the request to callbacks */ export type ForwardedHeaders = ReadonlyMap; /** * Configuration for forwarding request headers to DO callbacks. * - `string[]`: List of header names to forward (case-insensitive) * - `(request) => Record`: Custom extraction function (sync) */ export type ForwardHeadersOption = readonly string[] | ((request: CfTypes.Request) => Record); /** Context passed to onPush/onPull callbacks */ export type CallbackContext = { storeId: StoreId; payload?: Schema.JsonValue; /** Headers forwarded from the request (only present if `forwardHeaders` is configured) */ headers?: ForwardedHeaders; }; export type MakeDurableObjectClassOptions = { onPush?: (message: SyncMessage.PushRequest, context: CallbackContext) => Effect.SyncOrPromiseOrEffect; onPushRes?: (message: SyncMessage.PushAck | UnknownError) => Effect.SyncOrPromiseOrEffect; onPull?: (message: SyncMessage.PullRequest, context: CallbackContext) => Effect.SyncOrPromiseOrEffect; onPullRes?: (message: SyncMessage.PullResponse | UnknownError) => Effect.SyncOrPromiseOrEffect; /** * Forward request headers to `onPush`/`onPull` callbacks for authentication. * * This enables cookie-based or header-based authentication patterns where * you need access to request headers inside the Durable Object. * * @example Forward specific headers by name (case-insensitive) * ```ts * makeDurableObject({ * forwardHeaders: ['cookie', 'authorization'], * onPush: async (message, { headers }) => { * const cookie = headers?.get('cookie') * const session = await validateSession(cookie) * }, * }) * ``` * * @example Custom extraction function for derived values * ```ts * makeDurableObject({ * forwardHeaders: (request) => ({ * 'x-user-id': request.headers.get('x-user-id') ?? '', * 'x-session': request.headers.get('cookie')?.split('session=')[1]?.split(';')[0] ?? '', * }), * onPush: async (message, { headers }) => { * const userId = headers?.get('x-user-id') * }, * }) * ``` */ forwardHeaders?: ForwardHeadersOption; /** * Storage engine for event persistence. * - Default: `{ _tag: 'do-sqlite' }` (Durable Object SQLite) * - D1: `{ _tag: 'd1', binding: string }` where `binding` is the D1 binding name in wrangler.toml. * * If omitted, the runtime defaults to DO SQLite. For backwards-compatibility, if an env binding named * `DB` exists and looks like a D1Database, D1 will be used. * * Trade-offs: * - DO SQLite: simpler deploy, data co-located with DO, not externally queryable * - D1: centralized DB, inspectable with DB tools, extra network hop and JSON size limits */ storage?: { _tag: 'do-sqlite'; } | { _tag: 'd1'; binding: string; }; /** * Enabled transports for sync backend * - `http`: HTTP JSON-RPC * - `ws`: WebSocket * - `do-rpc`: Durable Object RPC calls (only works in combination with `@livestore/adapter-cf`) * * @default Set(['http', 'ws', 'do-rpc']) */ enabledTransports?: Set<'http' | 'ws' | 'do-rpc'>; /** * Custom HTTP response headers for HTTP transport * These headers will be added to all HTTP RPC responses (Pull, Push, Ping) * * @example * ```ts * { * http: { * responseHeaders: { * 'Access-Control-Allow-Origin': '*', * 'Cache-Control': 'no-cache' * } * } * } * ``` */ http?: { responseHeaders?: Record; }; otel?: { baseUrl?: string; serviceName?: string; }; }; export type StoreId = string; export type DurableObjectId = string; /** * CRITICAL: Increment this version whenever you modify the database schema structure. * * Bump required when: * - Adding/removing/renaming columns in eventlogTable or contextTable (see sqlite.ts) * - Changing column types or constraints * - Modifying primary keys or indexes * * Bump NOT required when: * - Changing query patterns, pagination logic, or streaming behavior * - Adding new tables (as long as existing table schemas remain unchanged) * - Updating implementation details in sync-storage.ts * * Impact: Changing this version triggers a "soft reset" - new table names are created * and old data becomes inaccessible (but remains in storage). */ export declare const PERSISTENCE_FORMAT_VERSION = 7; export declare const encodeOutgoingMessage: (a: { readonly backendId: string; readonly batch: readonly { readonly metadata: import("effect/Option").Option<{ readonly createdAt: string; readonly _tag: "SyncMessage.SyncMetadata"; }>; readonly eventEncoded: { readonly name: string; readonly args: any; readonly seqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">; readonly parentSeqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">; readonly clientId: string; readonly sessionId: string; }; }[]; readonly pageInfo: { readonly _tag: "MoreUnknown"; } | { readonly _tag: "MoreKnown"; readonly remaining: number; } | { readonly _tag: "NoMore"; }; } | {} | { readonly _tag: "SyncMessage.Pong"; } | { readonly _tag: "SyncMessage.AdminResetRoomResponse"; } | { readonly info: { readonly durableObjectId: string; }; readonly _tag: "SyncMessage.AdminInfoResponse"; }, overrideOptions?: import("effect/SchemaAST").ParseOptions) => string; export declare const encodeIncomingMessage: (a: { readonly cursor: import("effect/Option").Option<{ readonly backendId: string; readonly eventSequenceNumber: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">; }>; } | { readonly backendId: import("effect/Option").Option; readonly batch: readonly { readonly name: string; readonly args: any; readonly seqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">; readonly parentSeqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">; readonly clientId: string; readonly sessionId: string; }[]; } | { readonly _tag: "SyncMessage.Ping"; } | { readonly _tag: "SyncMessage.AdminResetRoomRequest"; readonly adminSecret: string; } | { readonly _tag: "SyncMessage.AdminInfoRequest"; readonly adminSecret: string; }, overrideOptions?: import("effect/SchemaAST").ParseOptions) => string; /** * Extracts the LiveStore sync search parameters from a request. Returns * `undefined` when the request does not carry valid sync metadata so callers * can fall back to custom routing. */ export declare const matchSyncRequest: (request: CfTypes.Request) => SearchParams | undefined; export type RpcSubscription = { storeId: StoreId; payload?: Schema.JsonValue; subscribedAt: number; /** Effect RPC request ID */ requestId: string; callerContext: { bindingName: string; durableObjectId: string; }; }; /** * Durable Object interface supporting the DO RPC protocol for DO <> DO syncing. */ export interface SyncBackendRpcInterface { __DURABLE_OBJECT_BRAND: never; rpc(payload: Uint8Array): Promise; } export declare const WebSocketAttachmentSchema: Schema.transform, Schema.Struct<{ storeId: typeof Schema.String; payload: Schema.optional>; pullRequestIds: Schema.Array$; headers: Schema.optional>; }>>; /** Helper to extract headers from a request based on the forwardHeaders option */ export declare const extractForwardedHeaders: (request: CfTypes.Request, forwardHeaders: ForwardHeadersOption | undefined) => Record | undefined; /** Convert a headers record to a ReadonlyMap */ export declare const headersRecordToMap: (headers: Record | undefined) => ForwardedHeaders | undefined; //# sourceMappingURL=shared.d.ts.map