{"version":3,"sources":["../../src/sync/sync-client.ts","../../src/tanstack/collection-options.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * SyncClient - WebSocket sync client for real-time updates\n *\n * Wire Protocol Reference:\n *\n * Client -> Server:\n *   { type: 'subscribe', collection: 'Task', branch?: string }\n *   { type: 'unsubscribe', collection: 'Task' }\n *\n * Server -> Client:\n *   { type: 'initial', collection: 'Task', data: T[], txid: number }\n *   { type: 'insert', collection: 'Task', key: string, data: T, txid: number }\n *   { type: 'update', collection: 'Task', key: string, data: T, txid: number }\n *   { type: 'delete', collection: 'Task', key: string, txid: number }\n *\n * @module @dotdo/react/sync\n */\n\n/** Base delay for reconnection in milliseconds */\nconst RECONNECT_BASE_DELAY_MS = 1000\n\n/** Maximum delay for reconnection in milliseconds */\nconst RECONNECT_MAX_DELAY_MS = 30000\n\n/**\n * Configuration for SyncClient\n */\nexport interface SyncClientConfig {\n  /** WebSocket URL for the Durable Object (will append /sync) */\n  doUrl: string\n  /** Collection name (Noun type) */\n  collection: string\n  /** Optional branch for branched data */\n  branch?: string\n}\n\n/**\n * Connection state for the sync client\n */\nexport type SyncConnectionState = 'connecting' | 'connected' | 'reconnecting' | 'disconnected'\n\n/**\n * Callbacks for sync events\n */\nexport interface SyncCallbacks<T> {\n  /**\n   * Called when initial data is received after subscribing\n   * @param items - Array of items in the collection\n   * @param txid - Transaction ID for the initial state\n   */\n  onInitial?: (items: T[], txid: number) => void\n\n  /**\n   * Called when a change is received (insert, update, or delete)\n   * @param op - The operation type: 'insert', 'update', or 'delete'\n   * @param item - The item that was changed (for delete, may contain key info)\n   * @param txid - Transaction ID for the change\n   */\n  onChange?: (op: 'insert' | 'update' | 'delete', item: T, txid: number) => void\n\n  /**\n   * Called when the WebSocket connection is closed\n   */\n  onDisconnect?: () => void\n\n  /**\n   * Called when connection state changes\n   */\n  onStateChange?: (state: SyncConnectionState) => void\n\n  /**\n   * Called when a WebSocket error occurs\n   * @param error - The error that occurred\n   */\n  onError?: (error: Error) => void\n}\n\n/**\n * WebSocket sync client for real-time updates\n *\n * Handles:\n * - WebSocket connection to DO /sync endpoint\n * - Subscribe/unsubscribe protocol messages\n * - Initial data and change stream handling\n * - Automatic reconnection with exponential backoff\n * - Error reporting via callbacks\n *\n * @example\n * ```typescript\n * const client = new SyncClient<Task>({\n *   doUrl: 'wss://example.com.ai/do/123',\n *   collection: 'Task',\n * })\n *\n * client.onInitial = (items, txid) => {\n *   console.log('Initial data:', items, 'at txid:', txid)\n * }\n *\n * client.onChange = (op, item, txid) => {\n *   console.log('Change:', op, item, 'at txid:', txid)\n * }\n *\n * client.onDisconnect = () => {\n *   console.log('Disconnected')\n * }\n *\n * client.connect()\n * ```\n */\nexport class SyncClient<T> {\n  private config: SyncClientConfig\n  private ws: WebSocket | null = null\n  private reconnectAttempts = 0\n  private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n  private intentionalDisconnect = false\n  private _connectionState: SyncConnectionState = 'disconnected'\n\n  /**\n   * Called when initial data is received after subscribing\n   * @param items - Array of items in the collection\n   * @param txid - Transaction ID for the initial state\n   */\n  onInitial: (items: T[], txid: number) => void = () => {}\n\n  /**\n   * Called when a change is received (insert, update, or delete)\n   * @param op - The operation type: 'insert', 'update', or 'delete'\n   * @param item - The item that was changed (for delete, may contain key info)\n   * @param txid - Transaction ID for the change\n   */\n  onChange: (op: 'insert' | 'update' | 'delete', item: T, txid: number) => void = () => {}\n\n  /**\n   * Called when the WebSocket connection is closed\n   */\n  onDisconnect: () => void = () => {}\n\n  /**\n   * Called when connection state changes\n   */\n  onStateChange: (state: SyncConnectionState) => void = () => {}\n\n  /**\n   * Called when a WebSocket error occurs\n   */\n  onError: (error: Error) => void = () => {}\n\n  /**\n   * Create a new SyncClient instance\n   * @param config - Configuration for the sync client\n   */\n  constructor(config: SyncClientConfig) {\n    this.config = config\n  }\n\n  /**\n   * Get the current connection state\n   */\n  get connectionState(): SyncConnectionState {\n    return this._connectionState\n  }\n\n  /**\n   * Check if the client is currently connected\n   */\n  get isConnected(): boolean {\n    return this._connectionState === 'connected'\n  }\n\n  /**\n   * Connect to the WebSocket server\n   *\n   * Opens a WebSocket connection to `${doUrl}/sync` and sends a subscribe\n   * message for the configured collection. Automatically reconnects with\n   * exponential backoff on connection loss.\n   */\n  connect(): void {\n    this.intentionalDisconnect = false\n    this.setConnectionState('connecting')\n\n    const wsUrl = `${this.config.doUrl}/sync`\n\n    try {\n      this.ws = new WebSocket(wsUrl)\n    } catch (error) {\n      this.onError(error instanceof Error ? error : new Error('Failed to create WebSocket'))\n      this.setConnectionState('disconnected')\n      return\n    }\n\n    const ws = this.ws\n    ws.addEventListener('open', () => {\n      this.reconnectAttempts = 0\n      this.setConnectionState('connected')\n\n      const subscribeMsg: Record<string, string> = {\n        type: 'subscribe',\n        collection: this.config.collection,\n      }\n\n      if (this.config.branch) {\n        subscribeMsg.branch = this.config.branch\n      }\n\n      // Check ws is still valid before sending\n      if (ws.readyState === WebSocket.OPEN) {\n        ws.send(JSON.stringify(subscribeMsg))\n      }\n    })\n\n    this.ws.addEventListener('message', (event: MessageEvent) => {\n      try {\n        const msg = JSON.parse(event.data)\n\n        if (msg.type === 'initial') {\n          this.onInitial(msg.data, msg.txid)\n        } else if (msg.type === 'insert' || msg.type === 'update') {\n          this.onChange(msg.type, msg.data, msg.txid)\n        } else if (msg.type === 'delete') {\n          const item = msg.data || { key: msg.key }\n          this.onChange('delete', item as T, msg.txid)\n        }\n        // Unknown message types are silently ignored\n      } catch {\n        // Malformed JSON - silently ignore\n      }\n    })\n\n    this.ws.addEventListener('close', () => {\n      this.onDisconnect()\n\n      if (!this.intentionalDisconnect) {\n        this.setConnectionState('reconnecting')\n        this.scheduleReconnect()\n      } else {\n        this.setConnectionState('disconnected')\n      }\n    })\n\n    this.ws.addEventListener('error', () => {\n      this.onError(new Error('WebSocket connection error'))\n      // The onclose handler will fire after this and handle reconnection\n    })\n  }\n\n  /**\n   * Disconnect from the WebSocket server\n   *\n   * Sends an unsubscribe message and closes the WebSocket connection.\n   * Cancels any pending reconnection attempts.\n   */\n  disconnect(): void {\n    this.intentionalDisconnect = true\n\n    if (this.reconnectTimer) {\n      clearTimeout(this.reconnectTimer)\n      this.reconnectTimer = null\n    }\n\n    if (this.ws) {\n      if (this.ws.readyState === WebSocket.OPEN) {\n        this.ws.send(JSON.stringify({\n          type: 'unsubscribe',\n          collection: this.config.collection,\n        }))\n      }\n\n      this.ws.close()\n      this.ws = null\n    }\n\n    this.setConnectionState('disconnected')\n  }\n\n  /**\n   * Set connection state and notify listeners\n   */\n  private setConnectionState(state: SyncConnectionState): void {\n    if (this._connectionState !== state) {\n      this._connectionState = state\n      this.onStateChange(state)\n    }\n  }\n\n  /**\n   * Schedule a reconnection attempt with exponential backoff\n   */\n  private scheduleReconnect(): void {\n    const delay = Math.min(\n      RECONNECT_BASE_DELAY_MS * Math.pow(2, this.reconnectAttempts),\n      RECONNECT_MAX_DELAY_MS\n    )\n    this.reconnectAttempts++\n\n    this.reconnectTimer = setTimeout(() => {\n      this.reconnectTimer = null\n      this.connect()\n    }, delay)\n  }\n}\n","/**\n * TanStack DB Collection Options for dotdo\n *\n * Provides CollectionOptions factory for creating TanStack DB collections\n * that sync with dotdo backends via WebSocket.\n *\n * @example\n * ```tsx\n * import { CollectionOptions } from '@dotdo/react/tanstack'\n * import { useCollection } from '@tanstack/db'\n *\n * const taskOptions = CollectionOptions({\n *   doUrl: 'wss://my-do.workers.dev/do/123',\n *   collection: 'Task',\n *   schema: TaskSchema,\n * })\n *\n * function TaskList() {\n *   const collection = useCollection(taskOptions)\n *   // ...\n * }\n * ```\n *\n * @module @dotdo/react/tanstack\n */\n\nimport type { z } from 'zod'\nimport { SyncClient } from '../sync/sync-client'\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Callbacks used by TanStack DB collection for sync operations\n */\nexport interface CollectionCallbacks<T = unknown> {\n  /** Called at the start of a transaction */\n  begin: () => void\n  /** Called with initial or batch data */\n  onData: (items: T[]) => void\n  /** Called when a new item is inserted */\n  onInsert: (item: T) => void\n  /** Called when an item is updated */\n  onUpdate: (item: T) => void\n  /** Called when an item is deleted */\n  onDelete: (item: { id: string }) => void\n  /** Called to commit a transaction */\n  commit: (info: { txid: number }) => void\n  /** Called when a sync error occurs (optional) */\n  onError?: (error: Error) => void\n}\n\n/**\n * Configuration for dotdo collection\n */\nexport interface DotdoCollectionConfig<T> {\n  /** WebSocket URL for the Durable Object (will append /sync) */\n  doUrl: string\n  /** Collection name (Noun type) */\n  collection: string\n  /** Optional branch for branched data */\n  branch?: string\n  /** Zod schema for validating items */\n  schema: z.ZodSchema<T>\n  /** Optional fetch options for RPC calls */\n  fetchOptions?: RequestInit\n  /** Optional transaction timeout in ms (default: 30000) */\n  transactionTimeout?: number\n}\n\n/**\n * Mutation from TanStack DB transaction\n */\nexport interface Mutation<T> {\n  /** Unique key for the item */\n  key: string\n  /** Modified item data (for insert) */\n  modified?: T\n  /** Original item data (for update/delete) */\n  original?: T\n  /** Changed fields (for update) */\n  changes?: Partial<T>\n}\n\n/**\n * Mutation context from TanStack DB\n */\nexport interface MutationContext<T> {\n  /** Transaction containing mutations */\n  transaction: {\n    /** Array of mutations in this transaction */\n    mutations: Array<Mutation<T>>\n  }\n  /** Collection reference */\n  collection: unknown\n}\n\n/**\n * Options returned by CollectionOptions for TanStack DB\n */\nexport interface DotdoCollectionOptionsResult<T> {\n  /** Unique identifier for this collection */\n  id: string\n  /** Zod schema for validation */\n  schema: z.ZodSchema<T>\n  /** Function to extract key from item */\n  getKey: (item: T) => string\n  /** Subscribe to collection changes */\n  subscribe: (callbacks: CollectionCallbacks<T>) => () => void\n  /** Handle insert mutations */\n  onInsert: (ctx: MutationContext<T>) => Promise<{ txid: number }>\n  /** Handle update mutations */\n  onUpdate: (ctx: MutationContext<T>) => Promise<{ txid: number }>\n  /** Handle delete mutations */\n  onDelete: (ctx: MutationContext<T>) => Promise<{ txid: number }>\n}\n\n// =============================================================================\n// Cap'n Web Protocol Types\n// =============================================================================\n\ninterface CapnWebRequest {\n  id: string\n  type: 'call' | 'batch'\n  calls: Array<{\n    promiseId: string\n    target: { type: 'root' }\n    method: string\n    args: Array<{ type: 'value'; value: unknown }>\n  }>\n}\n\ninterface CapnWebResponse {\n  id: string\n  type: 'result' | 'error' | 'batch'\n  results?: Array<{\n    promiseId: string\n    type: 'value' | 'promise' | 'error'\n    value?: unknown\n    error?: { code: string; message: string }\n  }>\n  error?: { code: string; message: string }\n}\n\n// =============================================================================\n// Validation Helpers\n// =============================================================================\n\n/**\n * Validate that the doUrl is a valid URL\n * @throws Error if URL is invalid\n */\nfunction validateDoUrl(doUrl: string): void {\n  try {\n    new URL(doUrl)\n  } catch {\n    throw new Error(`Invalid doUrl: ${doUrl}`)\n  }\n}\n\n/**\n * Validate that the collection name is not empty\n * @throws Error if collection name is empty\n */\nfunction validateCollection(collection: string): void {\n  if (!collection || collection.trim() === '') {\n    throw new Error('Collection name cannot be empty')\n  }\n}\n\n/**\n * Convert WebSocket URL to HTTP URL for RPC\n */\nfunction deriveRpcUrl(doUrl: string): string {\n  let rpcUrl = doUrl.replace(/^wss:/, 'https:').replace(/^ws:/, 'http:')\n  rpcUrl = rpcUrl.replace(/\\/sync$/, '')\n  return `${rpcUrl}/rpc`\n}\n\n// =============================================================================\n// RPC Execution\n// =============================================================================\n\n/**\n * Execute mutations via Cap'n Web RPC\n */\nasync function executeMutations(\n  rpcUrl: string,\n  collection: string,\n  mutations: Array<{\n    type: 'create' | 'insert' | 'update' | 'delete'\n    key: string\n    data?: unknown\n  }>,\n  fetchOptions?: RequestInit\n): Promise<Array<{ success: boolean; rowid: number }>> {\n  const requestId = crypto.randomUUID()\n  const calls = mutations.map((mutation, index) => {\n    const method = `${collection}.${mutation.type}`\n    return {\n      promiseId: `p-${index + 1}`,\n      target: { type: 'root' as const },\n      method,\n      args: [{ type: 'value' as const, value: mutation.data || { key: mutation.key } }],\n    }\n  })\n\n  const request: CapnWebRequest = {\n    id: requestId,\n    type: mutations.length > 1 ? 'batch' : 'call',\n    calls,\n  }\n\n  const headers: Record<string, string> = {\n    'Content-Type': 'application/json',\n    ...(fetchOptions?.headers as Record<string, string> ?? {}),\n  }\n\n  const response = await fetch(rpcUrl, {\n    ...fetchOptions,\n    method: 'POST',\n    headers,\n    body: JSON.stringify(request),\n  })\n\n  if (!response.ok) {\n    throw new Error(`HTTP error: ${response.status}`)\n  }\n\n  const result = await response.json() as CapnWebResponse\n\n  if (result.type === 'error' && result.error) {\n    throw new Error(result.error.message)\n  }\n\n  if (!result.results || result.results.length === 0) {\n    throw new Error('No results in response')\n  }\n\n  return result.results.map((r) => {\n    if (r.type === 'error' && r.error) {\n      throw new Error(r.error.message)\n    }\n    return r.value as { success: boolean; rowid: number }\n  })\n}\n\n// =============================================================================\n// CollectionOptions Factory\n// =============================================================================\n\n/**\n * Create collection options for TanStack DB with dotdo sync.\n *\n * Provides full integration with dotdo backends:\n * - WebSocket sync for real-time updates via SyncClient\n * - Cap'n Web RPC for mutations with optimistic updates\n * - Automatic reconnection and error handling\n *\n * @param config - Configuration for the collection\n * @returns Collection options compatible with TanStack DB\n *\n * @example\n * ```tsx\n * import { CollectionOptions } from '@dotdo/react/tanstack'\n * import { z } from 'zod'\n *\n * const TaskSchema = z.object({\n *   $id: z.string(),\n *   title: z.string(),\n *   status: z.enum(['todo', 'done']),\n * })\n *\n * const taskOptions = CollectionOptions({\n *   doUrl: 'wss://api.example.com.ai/do/workspace',\n *   collection: 'Task',\n *   schema: TaskSchema,\n * })\n * ```\n */\nexport function CollectionOptions<T extends { $id: string }>(\n  config: DotdoCollectionConfig<T>\n): DotdoCollectionOptionsResult<T> {\n  validateCollection(config.collection)\n  validateDoUrl(config.doUrl)\n\n  const rpcUrl = deriveRpcUrl(config.doUrl)\n\n  const id = config.branch\n    ? `dotdo:${config.collection}:${config.branch}`\n    : `dotdo:${config.collection}`\n\n  return {\n    id,\n    schema: config.schema,\n    getKey: (item: T) => item.$id,\n\n    subscribe: (callbacks: CollectionCallbacks<T>) => {\n      const client = new SyncClient<T>({\n        doUrl: config.doUrl,\n        collection: config.collection,\n        branch: config.branch,\n      })\n\n      callbacks.begin()\n\n      client.onInitial = (items, txid) => {\n        callbacks.begin()\n        callbacks.onData(items)\n        callbacks.commit({ txid })\n      }\n\n      client.onChange = (op, item, txid) => {\n        callbacks.begin()\n        if (op === 'insert') {\n          callbacks.onInsert(item)\n        } else if (op === 'update') {\n          callbacks.onUpdate(item)\n        } else if (op === 'delete') {\n          const itemId = (item as T).$id || ((item as unknown as { key: string }).key)\n          callbacks.onDelete({ id: itemId })\n        }\n        callbacks.commit({ txid })\n      }\n\n      // Forward errors to callback if provided\n      client.onError = (error) => {\n        callbacks.onError?.(error)\n      }\n\n      client.connect()\n\n      return () => {\n        client.disconnect()\n      }\n    },\n\n    onInsert: async (ctx: MutationContext<T> | { transaction: { changes: T } }): Promise<{ txid: number }> => {\n      const transaction = ctx.transaction as { mutations?: Array<Mutation<T>>; changes?: T }\n      const mutations = transaction.mutations ?? (transaction.changes ? [{ key: (transaction.changes as T).$id, modified: transaction.changes }] : [])\n\n      const ops = mutations.map((mutation) => ({\n        type: 'create' as const,\n        key: mutation.key,\n        data: mutation.modified,\n      }))\n\n      const results = await executeMutations(rpcUrl, config.collection, ops, config.fetchOptions)\n      const lastResult = results[results.length - 1]\n      return { txid: lastResult.rowid }\n    },\n\n    onUpdate: async (ctx: MutationContext<T>): Promise<{ txid: number }> => {\n      const { mutations } = ctx.transaction\n\n      const ops = mutations.map((mutation) => ({\n        type: 'update' as const,\n        key: mutation.key,\n        data: { key: mutation.key, ...mutation.changes },\n      }))\n\n      const results = await executeMutations(rpcUrl, config.collection, ops, config.fetchOptions)\n      const lastResult = results[results.length - 1]\n      return { txid: lastResult.rowid }\n    },\n\n    onDelete: async (ctx: MutationContext<T>): Promise<{ txid: number }> => {\n      const { mutations } = ctx.transaction\n\n      const ops = mutations.map((mutation) => ({\n        type: 'delete' as const,\n        key: mutation.key,\n      }))\n\n      const results = await executeMutations(rpcUrl, config.collection, ops, config.fetchOptions)\n      const lastResult = results[results.length - 1]\n      return { txid: lastResult.rowid }\n    },\n  }\n}\n"]}