@voidhash/mimic 1.0.0-beta.13 → 1.0.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +27 -27
- package/dist/Primitive.cjs +1 -0
- package/dist/Primitive.d.cts +2 -2
- package/dist/Primitive.d.mts +2 -2
- package/dist/Primitive.mjs +2 -1
- package/dist/client/ClientDocument.cjs +36 -7
- package/dist/client/ClientDocument.d.mts.map +1 -1
- package/dist/client/ClientDocument.mjs +36 -7
- package/dist/client/ClientDocument.mjs.map +1 -1
- package/dist/primitives/Struct.cjs +38 -13
- package/dist/primitives/Struct.d.cts +1 -0
- package/dist/primitives/Struct.d.cts.map +1 -1
- package/dist/primitives/Struct.d.mts +1 -0
- package/dist/primitives/Struct.d.mts.map +1 -1
- package/dist/primitives/Struct.mjs +39 -14
- package/dist/primitives/Struct.mjs.map +1 -1
- package/dist/primitives/shared.cjs +28 -4
- package/dist/primitives/shared.d.cts +6 -1
- package/dist/primitives/shared.d.cts.map +1 -1
- package/dist/primitives/shared.d.mts +6 -1
- package/dist/primitives/shared.d.mts.map +1 -1
- package/dist/primitives/shared.mjs +28 -5
- package/dist/primitives/shared.mjs.map +1 -1
- package/package.json +2 -2
- package/src/client/ClientDocument.ts +40 -3
- package/src/primitives/Struct.ts +52 -18
- package/src/primitives/shared.ts +51 -5
- package/tests/client/ClientDocument.test.ts +99 -0
- package/tests/primitives/Struct.test.ts +141 -4
- package/tests/primitives/Tree.test.ts +143 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientDocument.mjs","names":["_serverState: Primitive.InferState<TSchema> | undefined","_pending: PendingTransaction[]","_serverTransactionHistory: Transaction.Transaction[]","Document.make","_unsubscribe: (() => void) | null","_initState: InitState","_initTimeoutHandle: ReturnType<typeof setTimeout> | null","_initResolver: (() => void) | null","_initRejecter: ((error: Error) => void) | null","_presenceSelfId: string | undefined","_presenceSelfData: unknown","pending: PendingTransaction","Rebase.transformTransactionWithPrimitive","Rebase.rebaseAfterRejectionWithPrimitive","Transaction.isEmpty","Presence.validate","draftState: DraftState","OperationPath.encode","Transaction.make"],"sources":["../../src/client/ClientDocument.ts"],"sourcesContent":["import * as Document from \"../Document\";\nimport * as Transaction from \"../Transaction\";\nimport * as Operation from \"../Operation\";\nimport * as OperationPath from \"../OperationPath\";\nimport * as Presence from \"../Presence\";\nimport type * as Primitive from \"../Primitive\";\nimport type * as Transport from \"./Transport\";\nimport * as Rebase from \"./Rebase\";\nimport {\n TransactionRejectedError,\n NotConnectedError,\n InvalidStateError,\n} from \"./errors\";\n\n// =============================================================================\n// Draft Types\n// =============================================================================\n\n/**\n * Internal state for a single draft.\n */\ninterface DraftState {\n /** Accumulated ops keyed by `pathString:kind` for per-field replace semantics */\n ops: Map<string, Operation.Operation<any, any, any>>;\n}\n\n/**\n * Handle returned by `createDraft()` for managing a draft lifecycle.\n */\nexport interface DraftHandle<TSchema extends Primitive.AnyPrimitive> {\n /** Unique ID for this draft */\n readonly id: string;\n /** Run a mutation for preview. Per-path ops replace previous; different paths accumulate. */\n update(fn: (root: Primitive.InferProxy<TSchema>) => void): void;\n /** Commit draft as a real transaction sent to server. Draft is consumed. */\n commit(): void;\n /** Discard draft, reverting preview state. */\n discard(): void;\n}\n\n// =============================================================================\n// Client Document Types\n// =============================================================================\n\n/**\n * Pending transaction with metadata for tracking.\n */\ninterface PendingTransaction {\n /** The transaction */\n readonly transaction: Transaction.Transaction;\n /** Original transaction before any rebasing */\n readonly original: Transaction.Transaction;\n /** Timestamp when the transaction was sent */\n readonly sentAt: number;\n}\n\n/**\n * Initialization state for the client document.\n * Handles the race condition during startup where transactions\n * may arrive while fetching the initial snapshot.\n */\ntype InitState =\n | { readonly type: \"uninitialized\" }\n | { readonly type: \"initializing\"; readonly bufferedMessages: Transport.ServerMessage[] }\n | { readonly type: \"ready\" };\n\n// =============================================================================\n// Presence Types\n// =============================================================================\n\n/**\n * Listener for presence changes.\n */\nexport interface PresenceListener<_TData> {\n /** Called when any presence changes (self or others) */\n readonly onPresenceChange?: () => void;\n}\n\n/**\n * Presence API exposed on the ClientDocument.\n */\nexport interface ClientPresence<TData> {\n /**\n * Returns this client's connection ID (set after receiving presence_snapshot).\n * Returns undefined before the snapshot is received.\n */\n readonly selfId: () => string | undefined;\n\n /**\n * Returns this client's current presence data.\n * Returns undefined if not set.\n */\n readonly self: () => TData | undefined;\n\n /**\n * Returns a map of other clients' presence data.\n * Keys are connection IDs.\n */\n readonly others: () => ReadonlyMap<string, Presence.PresenceEntry<TData>>;\n\n /**\n * Returns all presence entries including self.\n */\n readonly all: () => ReadonlyMap<string, Presence.PresenceEntry<TData>>;\n\n /**\n * Sets this client's presence data.\n * Validates against the presence schema before sending.\n * @throws ParseError if validation fails\n */\n readonly set: (data: TData) => void;\n\n /**\n * Clears this client's presence data.\n */\n readonly clear: () => void;\n\n /**\n * Subscribes to presence changes.\n * @returns Unsubscribe function\n */\n readonly subscribe: (listener: PresenceListener<TData>) => () => void;\n}\n\n/**\n * Options for creating a ClientDocument.\n */\nexport interface ClientDocumentOptions<\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n> {\n /** The schema defining the document structure */\n readonly schema: TSchema;\n /** Transport for server communication */\n readonly transport: Transport.Transport;\n /** Initial state (optional, will sync from server if not provided) */\n readonly initialState?: Primitive.InferState<TSchema>;\n /** Initial server version (optional) */\n readonly initialVersion?: number;\n /** Called when server rejects a transaction */\n readonly onRejection?: (\n transaction: Transaction.Transaction,\n reason: string\n ) => void;\n /** Called when optimistic state changes */\n readonly onStateChange?: (state: Primitive.InferState<TSchema> | undefined) => void;\n /** Called when connection status changes */\n readonly onConnectionChange?: (connected: boolean) => void;\n /** Called when client is fully initialized and ready */\n readonly onReady?: () => void;\n /** Timeout in ms for pending transactions (default: 30000) */\n readonly transactionTimeout?: number;\n /** Timeout in ms for initialization (default: 10000) */\n readonly initTimeout?: number;\n /** Enable debug logging for all activity (default: false) */\n readonly debug?: boolean;\n /**\n * Optional presence schema for ephemeral per-user data.\n * When provided, enables the presence API on the ClientDocument.\n */\n readonly presence?: TPresence;\n /** Initial presence data, that will be set on the ClientDocument when it is created */\n readonly initialPresence?: TPresence extends Presence.AnyPresence ? Presence.Infer<TPresence> : undefined;\n}\n\n/**\n * Listener callbacks for subscribing to ClientDocument events.\n */\nexport interface ClientDocumentListener<TSchema extends Primitive.AnyPrimitive> {\n /** Called when optimistic state changes */\n readonly onStateChange?: (state: Primitive.InferState<TSchema> | undefined) => void;\n /** Called when connection status changes */\n readonly onConnectionChange?: (connected: boolean) => void;\n /** Called when client is fully initialized and ready */\n readonly onReady?: () => void;\n /** Called when draft state changes (create, update, commit, discard) */\n readonly onDraftChange?: () => void;\n}\n\n/**\n * A ClientDocument provides optimistic updates with server synchronization.\n */\nexport interface ClientDocument<\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n> {\n /** The schema defining this document's structure */\n readonly schema: TSchema;\n\n /** Root proxy for accessing and modifying document data (optimistic) */\n readonly root: Primitive.InferProxy<TSchema>;\n\n /** Returns the current optimistic state (server + pending) */\n get(): Primitive.InferState<TSchema> | undefined;\n\n /** Returns the confirmed server state */\n getServerState(): Primitive.InferState<TSchema> | undefined;\n\n /** Returns the current server version */\n getServerVersion(): number;\n\n /** Returns pending transactions count */\n getPendingCount(): number;\n\n /** Returns whether there are pending transactions */\n hasPendingChanges(): boolean;\n\n /**\n * Runs a function within a transaction.\n * Changes are applied optimistically and sent to the server.\n */\n transaction<R>(fn: (root: Primitive.InferProxy<TSchema>) => R): R;\n\n /**\n * Connects to the server and starts syncing.\n */\n connect(): Promise<void>;\n\n /**\n * Disconnects from the server.\n */\n disconnect(): void;\n\n /**\n * Returns whether currently connected to the server.\n */\n isConnected(): boolean;\n\n /**\n * Forces a full resync from the server.\n */\n resync(): void;\n\n /**\n * Returns whether the client is fully initialized and ready.\n */\n isReady(): boolean;\n\n /**\n * Subscribes to document events (state changes, connection changes, ready).\n * @returns Unsubscribe function\n */\n subscribe(listener: ClientDocumentListener<TSchema>): () => void;\n\n /**\n * Creates a new draft for in-memory preview without sending to server.\n * Draft ops overlay on top of optimistic state.\n */\n createDraft(): DraftHandle<TSchema>;\n\n /**\n * Returns the set of active draft IDs.\n */\n getActiveDraftIds(): ReadonlySet<string>;\n\n /**\n * Presence API for ephemeral per-user data.\n * Only available when presence schema is provided in options.\n */\n readonly presence: TPresence extends Presence.AnyPresence\n ? ClientPresence<Presence.Infer<TPresence>>\n : undefined;\n}\n\n// =============================================================================\n// Client Document Implementation\n// =============================================================================\n\n/**\n * Creates a new ClientDocument for the given schema.\n */\nexport const make = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n>(\n options: ClientDocumentOptions<TSchema, TPresence>\n): ClientDocument<TSchema, TPresence> => {\n const {\n schema,\n transport,\n initialState,\n initialVersion = 0,\n onRejection,\n onStateChange,\n onConnectionChange,\n onReady,\n transactionTimeout = 30000,\n initTimeout = 10000,\n debug = false,\n presence: presenceSchema,\n initialPresence,\n } = options;\n\n // ==========================================================================\n // Internal State\n // ==========================================================================\n\n // Server-confirmed state\n let _serverState: Primitive.InferState<TSchema> | undefined = initialState;\n let _serverVersion = initialVersion;\n\n // Pending transactions queue\n let _pending: PendingTransaction[] = [];\n\n // Server transactions received (for rebase after rejection)\n let _serverTransactionHistory: Transaction.Transaction[] = [];\n const MAX_HISTORY_SIZE = 100;\n\n // The underlying document for optimistic state (use initialState for raw state format)\n let _optimisticDoc = Document.make(schema, { initialState: _serverState });\n\n // Subscription cleanup\n let _unsubscribe: (() => void) | null = null;\n\n // Timeout handles for pending transactions\n const _timeoutHandles = new Map<string, ReturnType<typeof setTimeout>>();\n\n // Initialization state - handles buffering during startup\n let _initState: InitState = initialState !== undefined\n ? { type: \"ready\" }\n : { type: \"uninitialized\" };\n\n // Init timeout handle\n let _initTimeoutHandle: ReturnType<typeof setTimeout> | null = null;\n\n // Promise resolver for connect() to wait for ready state\n let _initResolver: (() => void) | null = null;\n let _initRejecter: ((error: Error) => void) | null = null;\n\n // Subscribers for events (added after creation via subscribe())\n const _subscribers = new Set<ClientDocumentListener<TSchema>>();\n\n // ==========================================================================\n // Presence State (only used when presenceSchema is provided)\n // ==========================================================================\n\n // This client's connection ID (received from presence_snapshot)\n let _presenceSelfId: string | undefined = undefined;\n\n // This client's current presence data\n let _presenceSelfData: unknown = undefined;\n\n // Other clients' presence entries (connectionId -> entry)\n const _presenceOthers = new Map<string, Presence.PresenceEntry<unknown>>();\n\n // Presence change subscribers\n const _presenceSubscribers = new Set<PresenceListener<unknown>>();\n\n // ==========================================================================\n // Draft State\n // ==========================================================================\n\n const _drafts = new Map<string, DraftState>();\n\n // ==========================================================================\n // Debug Logging\n // ==========================================================================\n\n /**\n * Debug logging helper that only logs when debug is enabled.\n */\n const debugLog = (...args: unknown[]): void => {\n if (debug) {\n console.log(\"[ClientDocument]\", ...args);\n }\n };\n\n // ==========================================================================\n // Notification Helpers\n // ==========================================================================\n\n /**\n * Notifies all listeners of a state change.\n */\n const notifyStateChange = (state: Primitive.InferState<TSchema> | undefined): void => {\n debugLog(\"notifyStateChange\", {\n state,\n subscriberCount: _subscribers.size,\n hasOnStateChange: !!onStateChange,\n });\n onStateChange?.(state);\n for (const listener of _subscribers) {\n listener.onStateChange?.(state);\n }\n };\n\n /**\n * Notifies all listeners of a connection change.\n */\n const notifyConnectionChange = (connected: boolean): void => {\n debugLog(\"notifyConnectionChange\", {\n connected,\n subscriberCount: _subscribers.size,\n hasOnConnectionChange: !!onConnectionChange,\n });\n onConnectionChange?.(connected);\n for (const listener of _subscribers) {\n listener.onConnectionChange?.(connected);\n }\n };\n\n /**\n * Notifies all listeners when ready.\n */\n const notifyReady = (): void => {\n debugLog(\"notifyReady\", {\n subscriberCount: _subscribers.size,\n hasOnReady: !!onReady,\n });\n onReady?.();\n for (const listener of _subscribers) {\n listener.onReady?.();\n }\n };\n\n /**\n * Notifies all listeners of a draft change.\n */\n const notifyDraftChange = (): void => {\n debugLog(\"notifyDraftChange\", { draftCount: _drafts.size });\n for (const listener of _subscribers) {\n listener.onDraftChange?.();\n }\n };\n\n /**\n * Notifies all presence listeners of a change.\n */\n const notifyPresenceChange = (): void => {\n debugLog(\"notifyPresenceChange\", {\n subscriberCount: _presenceSubscribers.size,\n });\n for (const listener of _presenceSubscribers) {\n try {\n listener.onPresenceChange?.();\n } catch {\n // Ignore listener errors\n }\n }\n };\n\n // ==========================================================================\n // Presence Handlers\n // ==========================================================================\n\n /**\n * Handles incoming presence snapshot from server.\n */\n const handlePresenceSnapshot = (message: Transport.PresenceSnapshotMessage): void => {\n if (!presenceSchema) return;\n\n debugLog(\"handlePresenceSnapshot\", {\n selfId: message.selfId,\n presenceCount: Object.keys(message.presences).length,\n });\n\n _presenceSelfId = message.selfId;\n _presenceOthers.clear();\n\n // Populate others from snapshot (exclude self)\n for (const [id, entry] of Object.entries(message.presences)) {\n if (id !== message.selfId) {\n _presenceOthers.set(id, entry);\n }\n }\n\n notifyPresenceChange();\n };\n\n /**\n * Handles incoming presence update from server (another user).\n */\n const handlePresenceUpdate = (message: Transport.PresenceUpdateMessage): void => {\n if (!presenceSchema) return;\n\n debugLog(\"handlePresenceUpdate\", {\n id: message.id,\n userId: message.userId,\n });\n\n _presenceOthers.set(message.id, {\n data: message.data,\n userId: message.userId,\n });\n\n notifyPresenceChange();\n };\n\n /**\n * Handles incoming presence remove from server (user disconnected).\n */\n const handlePresenceRemove = (message: Transport.PresenceRemoveMessage): void => {\n if (!presenceSchema) return;\n\n debugLog(\"handlePresenceRemove\", {\n id: message.id,\n });\n\n _presenceOthers.delete(message.id);\n notifyPresenceChange();\n };\n\n /**\n * Clears all presence state (on disconnect).\n */\n const clearPresenceState = (): void => {\n _presenceSelfId = undefined;\n _presenceSelfData = undefined;\n _presenceOthers.clear();\n notifyPresenceChange();\n };\n\n // ==========================================================================\n // Helper Functions\n // ==========================================================================\n\n /**\n * Recomputes the optimistic document from server state + pending transactions.\n */\n const recomputeOptimisticState = (): void => {\n debugLog(\"recomputeOptimisticState\", {\n serverVersion: _serverVersion,\n pendingCount: _pending.length,\n draftCount: _drafts.size,\n serverState: _serverState,\n });\n\n // Create fresh document from server state (use initialState for raw state format)\n _optimisticDoc = Document.make(schema, { initialState: _serverState });\n\n // Apply all pending transactions\n for (const pending of _pending) {\n _optimisticDoc.apply(pending.transaction.ops);\n }\n\n // Apply all draft ops on top\n for (const draft of _drafts.values()) {\n const draftOps = Array.from(draft.ops.values());\n if (draftOps.length > 0) {\n _optimisticDoc.apply(draftOps);\n }\n }\n\n const newState = _optimisticDoc.get();\n debugLog(\"recomputeOptimisticState: new optimistic state\", newState);\n\n // Notify state change\n notifyStateChange(newState);\n };\n\n /**\n * Adds a transaction to pending queue and sends to server.\n * If disconnected, the transport will queue it for later submission.\n */\n const submitTransaction = (tx: Transaction.Transaction): void => {\n debugLog(\"submitTransaction\", {\n txId: tx.id,\n ops: tx.ops,\n pendingCount: _pending.length + 1,\n isConnected: transport.isConnected(),\n });\n\n const pending: PendingTransaction = {\n transaction: tx,\n original: tx,\n sentAt: Date.now(),\n };\n\n _pending.push(pending);\n\n // Only set timeout if connected - otherwise the transport queues it\n // and the timeout will start when the message is actually sent on reconnect\n if (transport.isConnected()) {\n const timeoutHandle = setTimeout(() => {\n handleTransactionTimeout(tx.id);\n }, transactionTimeout);\n _timeoutHandles.set(tx.id, timeoutHandle);\n }\n\n // Send to server (transport queues if disconnected)\n transport.send(tx);\n debugLog(\"submitTransaction: sent to transport\", { txId: tx.id, queued: !transport.isConnected() });\n };\n\n /**\n * Handles a transaction timeout.\n */\n const handleTransactionTimeout = (txId: string): void => {\n debugLog(\"handleTransactionTimeout\", { txId });\n const index = _pending.findIndex((p) => p.transaction.id === txId);\n if (index === -1) {\n debugLog(\"handleTransactionTimeout: transaction not found (already confirmed/rejected)\", { txId });\n return; // Already confirmed or rejected\n }\n\n // Remove from pending\n const [removed] = _pending.splice(index, 1);\n _timeoutHandles.delete(txId);\n\n debugLog(\"handleTransactionTimeout: removed from pending\", {\n txId,\n remainingPending: _pending.length,\n });\n\n // Recompute state\n recomputeOptimisticState();\n\n // Notify as rejection\n onRejection?.(removed!.transaction, \"Transaction timed out\");\n };\n\n /**\n * Handles an incoming server transaction.\n */\n const handleServerTransaction = (\n serverTx: Transaction.Transaction,\n version: number\n ): void => {\n debugLog(\"handleServerTransaction\", {\n txId: serverTx.id,\n version,\n ops: serverTx.ops,\n currentServerVersion: _serverVersion,\n pendingCount: _pending.length,\n });\n\n // Update server version\n _serverVersion = version;\n\n // Check if this is one of our pending transactions (ACK)\n const pendingIndex = _pending.findIndex(\n (p) => p.transaction.id === serverTx.id\n );\n\n if (pendingIndex !== -1) {\n // This is our transaction - confirmed!\n debugLog(\"handleServerTransaction: transaction confirmed (ACK)\", {\n txId: serverTx.id,\n pendingIndex,\n });\n\n const confirmed = _pending[pendingIndex]!;\n\n // Clear timeout\n const timeoutHandle = _timeoutHandles.get(serverTx.id);\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n _timeoutHandles.delete(serverTx.id);\n }\n\n // Remove from pending\n _pending.splice(pendingIndex, 1);\n\n // Apply to server state\n const tempDoc = Document.make(schema, { initialState: _serverState });\n tempDoc.apply(serverTx.ops);\n _serverState = tempDoc.get();\n\n debugLog(\"handleServerTransaction: updated server state\", {\n txId: serverTx.id,\n newServerState: _serverState,\n remainingPending: _pending.length,\n });\n\n // Recompute optimistic state (pending txs already applied, just need to update base)\n recomputeOptimisticState();\n } else {\n // This is someone else's transaction - need to rebase\n debugLog(\"handleServerTransaction: remote transaction, rebasing pending\", {\n txId: serverTx.id,\n pendingCount: _pending.length,\n });\n\n // Apply to server state\n const tempDoc = Document.make(schema, { initialState: _serverState });\n tempDoc.apply(serverTx.ops);\n _serverState = tempDoc.get();\n\n // Add to history for potential rebase after rejection\n _serverTransactionHistory.push(serverTx);\n if (_serverTransactionHistory.length > MAX_HISTORY_SIZE) {\n _serverTransactionHistory.shift();\n }\n\n // Rebase all pending transactions using primitive-based transformation\n const rebasedPending = _pending.map((p) => ({\n ...p,\n transaction: Rebase.transformTransactionWithPrimitive(p.transaction, serverTx, schema),\n }));\n\n debugLog(\"handleServerTransaction: rebased pending transactions\", {\n txId: serverTx.id,\n rebasedCount: rebasedPending.length,\n originalPendingIds: _pending.map((p) => p.transaction.id),\n rebasedPendingIds: rebasedPending.map((p) => p.transaction.id),\n });\n\n _pending = rebasedPending;\n\n // Recompute optimistic state\n recomputeOptimisticState();\n }\n };\n\n /**\n * Handles a transaction rejection from the server.\n */\n const handleRejection = (txId: string, reason: string): void => {\n debugLog(\"handleRejection\", {\n txId,\n reason,\n pendingCount: _pending.length,\n });\n\n const index = _pending.findIndex((p) => p.transaction.id === txId);\n if (index === -1) {\n debugLog(\"handleRejection: transaction not found (already removed)\", { txId });\n return; // Already removed\n }\n\n const rejected = _pending[index]!;\n\n // Clear timeout\n const timeoutHandle = _timeoutHandles.get(txId);\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n _timeoutHandles.delete(txId);\n }\n\n // Remove rejected transaction\n _pending.splice(index, 1);\n\n debugLog(\"handleRejection: removed rejected transaction, rebasing remaining\", {\n txId,\n remainingPending: _pending.length,\n serverHistorySize: _serverTransactionHistory.length,\n });\n\n // Re-transform remaining pending transactions without the rejected one\n // We need to replay from their original state\n const remainingOriginals = _pending.map((p) => p.original);\n const retransformed = Rebase.rebaseAfterRejectionWithPrimitive(\n [...remainingOriginals, rejected.original],\n txId,\n _serverTransactionHistory,\n schema\n );\n\n // Update pending with retransformed versions\n _pending = _pending.map((p, i) => ({\n ...p,\n transaction: retransformed[i] ?? p.transaction,\n }));\n\n debugLog(\"handleRejection: rebased remaining transactions\", {\n txId,\n rebasedCount: _pending.length,\n });\n\n // Recompute optimistic state\n recomputeOptimisticState();\n\n // Notify rejection\n onRejection?.(rejected.original, reason);\n };\n\n /**\n * Handles a snapshot from the server.\n * @param isInitialSnapshot - If true, this is the initial sync snapshot\n */\n const handleSnapshot = (state: unknown, version: number, isInitialSnapshot: boolean = false): void => {\n debugLog(\"handleSnapshot\", {\n isInitialSnapshot,\n version,\n currentServerVersion: _serverVersion,\n pendingCount: _pending.length,\n state,\n });\n\n if (!isInitialSnapshot) {\n debugLog(\"handleSnapshot: non-initial snapshot, clearing pending transactions\", {\n clearedPendingCount: _pending.length,\n });\n\n // For non-initial snapshots, clear all pending (they're now invalid)\n for (const handle of _timeoutHandles.values()) {\n clearTimeout(handle);\n }\n _timeoutHandles.clear();\n\n // Notify rejections for all pending\n for (const pending of _pending) {\n onRejection?.(pending.original, \"State reset due to resync\");\n }\n\n _pending = [];\n }\n\n _serverTransactionHistory = [];\n _serverState = state as Primitive.InferState<TSchema>;\n _serverVersion = version;\n\n debugLog(\"handleSnapshot: updated server state\", {\n newVersion: _serverVersion,\n newState: _serverState,\n });\n\n // Recompute optimistic state (now equals server state)\n recomputeOptimisticState();\n };\n\n /**\n * Processes buffered messages after receiving the initial snapshot.\n * Filters out transactions already included in the snapshot (version <= snapshotVersion)\n * and applies newer transactions in order.\n */\n const processBufferedMessages = (\n bufferedMessages: Transport.ServerMessage[],\n snapshotVersion: number\n ): void => {\n debugLog(\"processBufferedMessages\", {\n bufferedCount: bufferedMessages.length,\n snapshotVersion,\n });\n\n // Sort transactions by version to ensure correct order\n const sortedMessages = [...bufferedMessages].sort((a, b) => {\n if (a.type === \"transaction\" && b.type === \"transaction\") {\n return a.version - b.version;\n }\n return 0;\n });\n\n // Process each buffered message\n for (const message of sortedMessages) {\n switch (message.type) {\n case \"transaction\":\n // Only apply transactions with version > snapshot version\n if (message.version > snapshotVersion) {\n debugLog(\"processBufferedMessages: applying buffered transaction\", {\n txId: message.transaction.id,\n version: message.version,\n snapshotVersion,\n });\n handleServerTransaction(message.transaction, message.version);\n } else {\n debugLog(\"processBufferedMessages: skipping buffered transaction (already in snapshot)\", {\n txId: message.transaction.id,\n version: message.version,\n snapshotVersion,\n });\n }\n break;\n case \"error\":\n // Errors are still relevant - pass through\n debugLog(\"processBufferedMessages: processing buffered error\", {\n txId: message.transactionId,\n reason: message.reason,\n });\n handleRejection(message.transactionId, message.reason);\n break;\n // Ignore additional snapshots in buffer - we already have one\n }\n }\n };\n\n /**\n * Completes initialization and transitions to ready state.\n */\n const completeInitialization = (): void => {\n debugLog(\"completeInitialization\");\n\n // Clear init timeout\n if (_initTimeoutHandle !== null) {\n clearTimeout(_initTimeoutHandle);\n _initTimeoutHandle = null;\n }\n\n _initState = { type: \"ready\" };\n\n // Resolve the connect promise\n if (_initResolver) {\n _initResolver();\n _initResolver = null;\n _initRejecter = null;\n }\n\n debugLog(\"completeInitialization: ready\", {\n serverVersion: _serverVersion,\n serverState: _serverState,\n });\n\n // Notify ready\n notifyReady();\n };\n\n /**\n * Handles initialization timeout.\n */\n const handleInitTimeout = (): void => {\n debugLog(\"handleInitTimeout: initialization timed out\");\n _initTimeoutHandle = null;\n\n // Reject the connect promise\n if (_initRejecter) {\n const error = new Error(\"Initialization timed out waiting for snapshot\");\n _initRejecter(error);\n _initResolver = null;\n _initRejecter = null;\n }\n\n // Reset to uninitialized state\n _initState = { type: \"uninitialized\" };\n };\n\n /**\n * Handles incoming server messages.\n * During initialization, messages are buffered until the snapshot arrives.\n * Presence messages are always processed immediately (not buffered).\n */\n const handleServerMessage = (message: Transport.ServerMessage): void => {\n debugLog(\"handleServerMessage\", {\n messageType: message.type,\n initState: _initState.type,\n });\n\n // Presence messages are always handled immediately (not buffered)\n // This allows presence to work even during document initialization\n if (message.type === \"presence_snapshot\") {\n handlePresenceSnapshot(message);\n return;\n }\n if (message.type === \"presence_update\") {\n handlePresenceUpdate(message);\n return;\n }\n if (message.type === \"presence_remove\") {\n handlePresenceRemove(message);\n return;\n }\n\n // Handle based on initialization state\n if (_initState.type === \"initializing\") {\n if (message.type === \"snapshot\") {\n debugLog(\"handleServerMessage: received snapshot during initialization\", {\n version: message.version,\n bufferedCount: _initState.bufferedMessages.length,\n });\n // Snapshot received - apply it and process buffered messages\n const buffered = _initState.bufferedMessages;\n handleSnapshot(message.state, message.version, true);\n processBufferedMessages(buffered, message.version);\n completeInitialization();\n } else {\n debugLog(\"handleServerMessage: buffering message during initialization\", {\n messageType: message.type,\n bufferedCount: _initState.bufferedMessages.length + 1,\n });\n // Buffer other messages during initialization\n _initState.bufferedMessages.push(message);\n }\n return;\n }\n\n // Normal message handling when ready (or uninitialized with initial state)\n switch (message.type) {\n case \"transaction\":\n handleServerTransaction(message.transaction, message.version);\n break;\n case \"snapshot\":\n handleSnapshot(message.state, message.version, false);\n break;\n case \"error\":\n handleRejection(message.transactionId, message.reason);\n break;\n }\n };\n\n // ==========================================================================\n // Public API\n // ==========================================================================\n\n const clientDocument = {\n schema,\n\n get root() {\n return _optimisticDoc.root;\n },\n\n get: () => _optimisticDoc.get(),\n\n getServerState: () => _serverState,\n\n getServerVersion: () => _serverVersion,\n\n getPendingCount: () => _pending.length,\n\n hasPendingChanges: () => _pending.length > 0,\n\n transaction: <R,>(fn: (root: Primitive.InferProxy<TSchema>) => R): R => {\n debugLog(\"transaction: starting\", {\n isConnected: transport.isConnected(),\n isReady: _initState.type === \"ready\",\n pendingCount: _pending.length,\n });\n\n // Allow transactions even when disconnected - they will be queued\n // Only require that we have been initialized at least once (have server state)\n if (_initState.type !== \"ready\") {\n throw new InvalidStateError(\"Client is not ready. Wait for initialization to complete.\");\n }\n\n // Run the transaction on the optimistic document\n const result = _optimisticDoc.transaction(fn);\n\n // Flush and get the transaction\n const tx = _optimisticDoc.flush();\n\n // If there are operations, submit to server\n if (!Transaction.isEmpty(tx)) {\n debugLog(\"transaction: flushed, submitting\", {\n txId: tx.id,\n opsCount: tx.ops.length,\n });\n submitTransaction(tx);\n } else {\n debugLog(\"transaction: flushed, empty transaction (no ops)\");\n }\n\n // Notify state change\n notifyStateChange(_optimisticDoc.get());\n\n return result;\n },\n\n connect: async (): Promise<void> => {\n debugLog(\"connect: starting\");\n // Subscribe to server messages\n _unsubscribe = transport.subscribe(handleServerMessage);\n\n // Connect transport\n await transport.connect();\n debugLog(\"connect: transport connected\");\n\n notifyConnectionChange(true);\n\n // Set initial presence if provided\n if (presenceSchema && initialPresence !== undefined) {\n debugLog(\"connect: setting initial presence\", { initialPresence });\n const validated = Presence.validate(presenceSchema, initialPresence);\n _presenceSelfData = validated;\n transport.sendPresenceSet(validated);\n notifyPresenceChange();\n }\n\n // If we already have initial state, we're ready immediately\n if (_initState.type === \"ready\") {\n debugLog(\"connect: already ready (has initial state)\");\n notifyReady();\n return;\n }\n\n // Enter initializing state - buffer messages until snapshot arrives\n _initState = { type: \"initializing\", bufferedMessages: [] };\n debugLog(\"connect: entering initializing state\", {\n initTimeout,\n });\n\n // Set up initialization timeout\n _initTimeoutHandle = setTimeout(handleInitTimeout, initTimeout);\n\n // Create a promise that resolves when we're ready\n const readyPromise = new Promise<void>((resolve, reject) => {\n _initResolver = resolve;\n _initRejecter = reject;\n });\n\n // Request initial snapshot\n debugLog(\"connect: requesting initial snapshot\");\n \n transport.requestSnapshot();\n\n\n // Wait for initialization to complete\n await readyPromise;\n debugLog(\"connect: completed\");\n },\n\n disconnect: (): void => {\n debugLog(\"disconnect: starting\", {\n pendingCount: _pending.length,\n initState: _initState.type,\n });\n\n // Clear all timeouts\n for (const handle of _timeoutHandles.values()) {\n clearTimeout(handle);\n }\n _timeoutHandles.clear();\n\n // Clear init timeout\n if (_initTimeoutHandle !== null) {\n clearTimeout(_initTimeoutHandle);\n _initTimeoutHandle = null;\n }\n\n // Reject any pending init promise\n if (_initRejecter) {\n _initRejecter(new Error(\"Disconnected during initialization\"));\n _initResolver = null;\n _initRejecter = null;\n }\n\n // Reset init state\n if (_initState.type === \"initializing\") {\n _initState = { type: \"uninitialized\" };\n }\n\n // Clear presence state\n clearPresenceState();\n\n // Unsubscribe\n if (_unsubscribe) {\n _unsubscribe();\n _unsubscribe = null;\n }\n\n // Disconnect transport\n transport.disconnect();\n\n notifyConnectionChange(false);\n debugLog(\"disconnect: completed\");\n },\n\n isConnected: () => transport.isConnected(),\n\n isReady: () => _initState.type === \"ready\",\n\n resync: (): void => {\n debugLog(\"resync: requesting snapshot\", {\n currentVersion: _serverVersion,\n pendingCount: _pending.length,\n });\n if (!transport.isConnected()) {\n throw new NotConnectedError();\n }\n transport.requestSnapshot();\n },\n\n subscribe: (listener: ClientDocumentListener<TSchema>): (() => void) => {\n _subscribers.add(listener);\n return () => {\n _subscribers.delete(listener);\n };\n },\n\n // =========================================================================\n // Draft API\n // =========================================================================\n\n createDraft: (): DraftHandle<TSchema> => {\n if (_initState.type !== \"ready\") {\n throw new InvalidStateError(\"Client is not ready. Wait for initialization to complete.\");\n }\n\n const draftId = crypto.randomUUID();\n const draftState: DraftState = { ops: new Map() };\n _drafts.set(draftId, draftState);\n\n debugLog(\"createDraft\", { draftId });\n notifyDraftChange();\n\n let consumed = false;\n\n const handle: DraftHandle<TSchema> = {\n id: draftId,\n\n update: (fn: (root: Primitive.InferProxy<TSchema>) => void): void => {\n if (consumed) {\n throw new InvalidStateError(\"Draft has already been committed or discarded.\");\n }\n\n // Create a scratch document from current optimistic state (without this draft's ops)\n // First compute base = server + pending + other drafts\n const baseDoc = Document.make(schema, { initialState: _serverState });\n for (const pending of _pending) {\n baseDoc.apply(pending.transaction.ops);\n }\n for (const [id, d] of _drafts) {\n if (id !== draftId) {\n const ops = Array.from(d.ops.values());\n if (ops.length > 0) baseDoc.apply(ops);\n }\n }\n // Also apply current draft ops so the scratch doc has full state\n const currentDraftOps = Array.from(draftState.ops.values());\n if (currentDraftOps.length > 0) baseDoc.apply(currentDraftOps);\n\n // Run transaction on scratch doc\n baseDoc.transaction(fn);\n const tx = baseDoc.flush();\n\n // Merge new ops into draft's op map\n for (const op of tx.ops) {\n const pathStr = OperationPath.encode(op.path);\n const key = `${pathStr}:${String(op.kind)}`;\n if (op.deduplicable) {\n draftState.ops.set(key, op);\n } else {\n // Use a unique key to avoid overwriting non-deduplicable ops\n const uniqueKey = `${key}:${crypto.randomUUID()}`;\n draftState.ops.set(uniqueKey, op);\n }\n }\n\n debugLog(\"draft.update\", { draftId, newOpsCount: tx.ops.length, totalOps: draftState.ops.size });\n\n // Recompute optimistic state to reflect draft changes\n recomputeOptimisticState();\n notifyDraftChange();\n },\n\n commit: (): void => {\n if (consumed) {\n throw new InvalidStateError(\"Draft has already been committed or discarded.\");\n }\n consumed = true;\n\n const ops = Array.from(draftState.ops.values());\n _drafts.delete(draftId);\n\n debugLog(\"draft.commit\", { draftId, opsCount: ops.length });\n\n if (ops.length > 0) {\n const tx = Transaction.make(ops);\n submitTransaction(tx);\n }\n\n // Recompute: draft is removed, but committed ops are now in pending\n recomputeOptimisticState();\n\n notifyDraftChange();\n },\n\n discard: (): void => {\n if (consumed) {\n throw new InvalidStateError(\"Draft has already been committed or discarded.\");\n }\n consumed = true;\n\n _drafts.delete(draftId);\n\n debugLog(\"draft.discard\", { draftId });\n\n recomputeOptimisticState();\n notifyDraftChange();\n },\n };\n\n return handle;\n },\n\n getActiveDraftIds: (): ReadonlySet<string> => {\n return new Set(_drafts.keys());\n },\n\n // =========================================================================\n // Presence API\n // =========================================================================\n\n presence: (presenceSchema\n ? {\n selfId: () => _presenceSelfId,\n\n self: () => _presenceSelfData as Presence.Infer<NonNullable<TPresence>> | undefined,\n\n others: () => _presenceOthers as ReadonlyMap<string, Presence.PresenceEntry<Presence.Infer<NonNullable<TPresence>>>>,\n\n all: () => {\n const all = new Map<string, Presence.PresenceEntry<unknown>>();\n // Add others\n for (const [id, entry] of _presenceOthers) {\n all.set(id, entry);\n }\n // Add self if we have data\n if (_presenceSelfId !== undefined && _presenceSelfData !== undefined) {\n all.set(_presenceSelfId, { data: _presenceSelfData });\n }\n return all as ReadonlyMap<string, Presence.PresenceEntry<Presence.Infer<NonNullable<TPresence>>>>;\n },\n\n set: (data: Presence.Infer<NonNullable<TPresence>>) => {\n if (!presenceSchema) return;\n\n // Validate against schema (throws if invalid)\n const validated = Presence.validate(presenceSchema, data);\n\n debugLog(\"presence.set\", { data: validated });\n\n // Update local state\n _presenceSelfData = validated;\n\n // Send to server\n transport.sendPresenceSet(validated);\n\n // Notify listeners\n notifyPresenceChange();\n },\n\n clear: () => {\n if (!presenceSchema) return;\n\n debugLog(\"presence.clear\");\n\n // Clear local state\n _presenceSelfData = undefined;\n\n // Send to server\n transport.sendPresenceClear();\n\n // Notify listeners\n notifyPresenceChange();\n },\n\n subscribe: (listener: PresenceListener<Presence.Infer<NonNullable<TPresence>>>) => {\n _presenceSubscribers.add(listener as PresenceListener<unknown>);\n return () => {\n _presenceSubscribers.delete(listener as PresenceListener<unknown>);\n };\n },\n }\n : undefined) as TPresence extends Presence.AnyPresence\n ? ClientPresence<Presence.Infer<TPresence>>\n : undefined,\n } as ClientDocument<TSchema, TPresence>;\n\n return clientDocument;\n};\n"],"mappings":";;;;;;;;;;;;;;AA+QA,MAAa,QAIX,YACuC;CACvC,MAAM,EACJ,QACA,WACA,cACA,iBAAiB,GACjB,aACA,eACA,oBACA,SACA,qBAAqB,KACrB,cAAc,KACd,QAAQ,OACR,UAAU,gBACV,oBACE;CAOJ,IAAIA,eAA0D;CAC9D,IAAI,iBAAiB;CAGrB,IAAIC,WAAiC,EAAE;CAGvC,IAAIC,4BAAuD,EAAE;CAC7D,MAAM,mBAAmB;CAGzB,IAAI,iBAAiBC,OAAc,QAAQ,EAAE,cAAc,cAAc,CAAC;CAG1E,IAAIC,eAAoC;CAGxC,MAAM,kCAAkB,IAAI,KAA4C;CAGxE,IAAIC,aAAwB,iBAAiB,SACzC,EAAE,MAAM,SAAS,GACjB,EAAE,MAAM,iBAAiB;CAG7B,IAAIC,qBAA2D;CAG/D,IAAIC,gBAAqC;CACzC,IAAIC,gBAAiD;CAGrD,MAAM,+BAAe,IAAI,KAAsC;CAO/D,IAAIC,kBAAsC;CAG1C,IAAIC,oBAA6B;CAGjC,MAAM,kCAAkB,IAAI,KAA8C;CAG1E,MAAM,uCAAuB,IAAI,KAAgC;CAMjE,MAAM,0BAAU,IAAI,KAAyB;;;;CAS7C,MAAM,YAAY,GAAG,SAA0B;AAC7C,MAAI,MACF,SAAQ,IAAI,oBAAoB,GAAG,KAAK;;;;;CAW5C,MAAM,qBAAqB,UAA2D;AACpF,WAAS,qBAAqB;GAC5B;GACA,iBAAiB,aAAa;GAC9B,kBAAkB,CAAC,CAAC;GACrB,CAAC;AACF,sEAAgB,MAAM;AACtB,OAAK,MAAM,YAAY,cAAc;;AACnC,qCAAS,oGAAgB,MAAM;;;;;;CAOnC,MAAM,0BAA0B,cAA6B;AAC3D,WAAS,0BAA0B;GACjC;GACA,iBAAiB,aAAa;GAC9B,uBAAuB,CAAC,CAAC;GAC1B,CAAC;AACF,qFAAqB,UAAU;AAC/B,OAAK,MAAM,YAAY,cAAc;;AACnC,qCAAS,yGAAqB,UAAU;;;;;;CAO5C,MAAM,oBAA0B;AAC9B,WAAS,eAAe;GACtB,iBAAiB,aAAa;GAC9B,YAAY,CAAC,CAAC;GACf,CAAC;AACF,qDAAW;AACX,OAAK,MAAM,YAAY,cAAc;;AACnC,iCAAS,qFAAW;;;;;;CAOxB,MAAM,0BAAgC;AACpC,WAAS,qBAAqB,EAAE,YAAY,QAAQ,MAAM,CAAC;AAC3D,OAAK,MAAM,YAAY,cAAc;;AACnC,qCAAS,mGAAiB;;;;;;CAO9B,MAAM,6BAAmC;AACvC,WAAS,wBAAwB,EAC/B,iBAAiB,qBAAqB,MACvC,CAAC;AACF,OAAK,MAAM,YAAY,qBACrB,KAAI;;AACF,qCAAS,sGAAoB;oBACvB;;;;;CAaZ,MAAM,0BAA0B,YAAqD;AACnF,MAAI,CAAC,eAAgB;AAErB,WAAS,0BAA0B;GACjC,QAAQ,QAAQ;GAChB,eAAe,OAAO,KAAK,QAAQ,UAAU,CAAC;GAC/C,CAAC;AAEF,oBAAkB,QAAQ;AAC1B,kBAAgB,OAAO;AAGvB,OAAK,MAAM,CAAC,IAAI,UAAU,OAAO,QAAQ,QAAQ,UAAU,CACzD,KAAI,OAAO,QAAQ,OACjB,iBAAgB,IAAI,IAAI,MAAM;AAIlC,wBAAsB;;;;;CAMxB,MAAM,wBAAwB,YAAmD;AAC/E,MAAI,CAAC,eAAgB;AAErB,WAAS,wBAAwB;GAC/B,IAAI,QAAQ;GACZ,QAAQ,QAAQ;GACjB,CAAC;AAEF,kBAAgB,IAAI,QAAQ,IAAI;GAC9B,MAAM,QAAQ;GACd,QAAQ,QAAQ;GACjB,CAAC;AAEF,wBAAsB;;;;;CAMxB,MAAM,wBAAwB,YAAmD;AAC/E,MAAI,CAAC,eAAgB;AAErB,WAAS,wBAAwB,EAC/B,IAAI,QAAQ,IACb,CAAC;AAEF,kBAAgB,OAAO,QAAQ,GAAG;AAClC,wBAAsB;;;;;CAMxB,MAAM,2BAAiC;AACrC,oBAAkB;AAClB,sBAAoB;AACpB,kBAAgB,OAAO;AACvB,wBAAsB;;;;;CAUxB,MAAM,iCAAuC;AAC3C,WAAS,4BAA4B;GACnC,eAAe;GACf,cAAc,SAAS;GACvB,YAAY,QAAQ;GACpB,aAAa;GACd,CAAC;AAGF,mBAAiBP,OAAc,QAAQ,EAAE,cAAc,cAAc,CAAC;AAGtE,OAAK,MAAM,WAAW,SACpB,gBAAe,MAAM,QAAQ,YAAY,IAAI;AAI/C,OAAK,MAAM,SAAS,QAAQ,QAAQ,EAAE;GACpC,MAAM,WAAW,MAAM,KAAK,MAAM,IAAI,QAAQ,CAAC;AAC/C,OAAI,SAAS,SAAS,EACpB,gBAAe,MAAM,SAAS;;EAIlC,MAAM,WAAW,eAAe,KAAK;AACrC,WAAS,kDAAkD,SAAS;AAGpE,oBAAkB,SAAS;;;;;;CAO7B,MAAM,qBAAqB,OAAsC;AAC/D,WAAS,qBAAqB;GAC5B,MAAM,GAAG;GACT,KAAK,GAAG;GACR,cAAc,SAAS,SAAS;GAChC,aAAa,UAAU,aAAa;GACrC,CAAC;EAEF,MAAMQ,UAA8B;GAClC,aAAa;GACb,UAAU;GACV,QAAQ,KAAK,KAAK;GACnB;AAED,WAAS,KAAK,QAAQ;AAItB,MAAI,UAAU,aAAa,EAAE;GAC3B,MAAM,gBAAgB,iBAAiB;AACrC,6BAAyB,GAAG,GAAG;MAC9B,mBAAmB;AACtB,mBAAgB,IAAI,GAAG,IAAI,cAAc;;AAI3C,YAAU,KAAK,GAAG;AAClB,WAAS,wCAAwC;GAAE,MAAM,GAAG;GAAI,QAAQ,CAAC,UAAU,aAAa;GAAE,CAAC;;;;;CAMrG,MAAM,4BAA4B,SAAuB;AACvD,WAAS,4BAA4B,EAAE,MAAM,CAAC;EAC9C,MAAM,QAAQ,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,KAAK;AAClE,MAAI,UAAU,IAAI;AAChB,YAAS,gFAAgF,EAAE,MAAM,CAAC;AAClG;;EAIF,MAAM,CAAC,WAAW,SAAS,OAAO,OAAO,EAAE;AAC3C,kBAAgB,OAAO,KAAK;AAE5B,WAAS,kDAAkD;GACzD;GACA,kBAAkB,SAAS;GAC5B,CAAC;AAGF,4BAA0B;AAG1B,gEAAc,QAAS,aAAa,wBAAwB;;;;;CAM9D,MAAM,2BACJ,UACA,YACS;AACT,WAAS,2BAA2B;GAClC,MAAM,SAAS;GACf;GACA,KAAK,SAAS;GACd,sBAAsB;GACtB,cAAc,SAAS;GACxB,CAAC;AAGF,mBAAiB;EAGjB,MAAM,eAAe,SAAS,WAC3B,MAAM,EAAE,YAAY,OAAO,SAAS,GACtC;AAED,MAAI,iBAAiB,IAAI;AAEvB,YAAS,wDAAwD;IAC/D,MAAM,SAAS;IACf;IACD,CAAC;AAEgB,YAAS;GAG3B,MAAM,gBAAgB,gBAAgB,IAAI,SAAS,GAAG;AACtD,OAAI,eAAe;AACjB,iBAAa,cAAc;AAC3B,oBAAgB,OAAO,SAAS,GAAG;;AAIrC,YAAS,OAAO,cAAc,EAAE;GAGhC,MAAM,UAAUR,OAAc,QAAQ,EAAE,cAAc,cAAc,CAAC;AACrE,WAAQ,MAAM,SAAS,IAAI;AAC3B,kBAAe,QAAQ,KAAK;AAE5B,YAAS,iDAAiD;IACxD,MAAM,SAAS;IACf,gBAAgB;IAChB,kBAAkB,SAAS;IAC5B,CAAC;AAGF,6BAA0B;SACrB;AAEL,YAAS,iEAAiE;IACxE,MAAM,SAAS;IACf,cAAc,SAAS;IACxB,CAAC;GAGF,MAAM,UAAUA,OAAc,QAAQ,EAAE,cAAc,cAAc,CAAC;AACrE,WAAQ,MAAM,SAAS,IAAI;AAC3B,kBAAe,QAAQ,KAAK;AAG5B,6BAA0B,KAAK,SAAS;AACxC,OAAI,0BAA0B,SAAS,iBACrC,2BAA0B,OAAO;GAInC,MAAM,iBAAiB,SAAS,KAAK,wCAChC,UACH,aAAaS,kCAAyC,EAAE,aAAa,UAAU,OAAO,IACrF;AAEH,YAAS,yDAAyD;IAChE,MAAM,SAAS;IACf,cAAc,eAAe;IAC7B,oBAAoB,SAAS,KAAK,MAAM,EAAE,YAAY,GAAG;IACzD,mBAAmB,eAAe,KAAK,MAAM,EAAE,YAAY,GAAG;IAC/D,CAAC;AAEF,cAAW;AAGX,6BAA0B;;;;;;CAO9B,MAAM,mBAAmB,MAAc,WAAyB;AAC9D,WAAS,mBAAmB;GAC1B;GACA;GACA,cAAc,SAAS;GACxB,CAAC;EAEF,MAAM,QAAQ,SAAS,WAAW,MAAM,EAAE,YAAY,OAAO,KAAK;AAClE,MAAI,UAAU,IAAI;AAChB,YAAS,4DAA4D,EAAE,MAAM,CAAC;AAC9E;;EAGF,MAAM,WAAW,SAAS;EAG1B,MAAM,gBAAgB,gBAAgB,IAAI,KAAK;AAC/C,MAAI,eAAe;AACjB,gBAAa,cAAc;AAC3B,mBAAgB,OAAO,KAAK;;AAI9B,WAAS,OAAO,OAAO,EAAE;AAEzB,WAAS,qEAAqE;GAC5E;GACA,kBAAkB,SAAS;GAC3B,mBAAmB,0BAA0B;GAC9C,CAAC;EAIF,MAAM,qBAAqB,SAAS,KAAK,MAAM,EAAE,SAAS;EAC1D,MAAM,gBAAgBC,kCACpB,CAAC,GAAG,oBAAoB,SAAS,SAAS,EAC1C,MACA,2BACA,OACD;AAGD,aAAW,SAAS,KAAK,GAAG,MAAM;;4CAC7B,UACH,iCAAa,cAAc,iEAAM,EAAE;IAClC;AAEH,WAAS,mDAAmD;GAC1D;GACA,cAAc,SAAS;GACxB,CAAC;AAGF,4BAA0B;AAG1B,gEAAc,SAAS,UAAU,OAAO;;;;;;CAO1C,MAAM,kBAAkB,OAAgB,SAAiB,oBAA6B,UAAgB;AACpG,WAAS,kBAAkB;GACzB;GACA;GACA,sBAAsB;GACtB,cAAc,SAAS;GACvB;GACD,CAAC;AAEF,MAAI,CAAC,mBAAmB;AACtB,YAAS,uEAAuE,EAC9E,qBAAqB,SAAS,QAC/B,CAAC;AAGF,QAAK,MAAM,UAAU,gBAAgB,QAAQ,CAC3C,cAAa,OAAO;AAEtB,mBAAgB,OAAO;AAGvB,QAAK,MAAM,WAAW,SACpB,+DAAc,QAAQ,UAAU,4BAA4B;AAG9D,cAAW,EAAE;;AAGf,8BAA4B,EAAE;AAC9B,iBAAe;AACf,mBAAiB;AAEjB,WAAS,wCAAwC;GAC/C,YAAY;GACZ,UAAU;GACX,CAAC;AAGF,4BAA0B;;;;;;;CAQ5B,MAAM,2BACJ,kBACA,oBACS;AACT,WAAS,2BAA2B;GAClC,eAAe,iBAAiB;GAChC;GACD,CAAC;EAGF,MAAM,iBAAiB,CAAC,GAAG,iBAAiB,CAAC,MAAM,GAAG,MAAM;AAC1D,OAAI,EAAE,SAAS,iBAAiB,EAAE,SAAS,cACzC,QAAO,EAAE,UAAU,EAAE;AAEvB,UAAO;IACP;AAGF,OAAK,MAAM,WAAW,eACpB,SAAQ,QAAQ,MAAhB;GACE,KAAK;AAEH,QAAI,QAAQ,UAAU,iBAAiB;AACrC,cAAS,0DAA0D;MACjE,MAAM,QAAQ,YAAY;MAC1B,SAAS,QAAQ;MACjB;MACD,CAAC;AACF,6BAAwB,QAAQ,aAAa,QAAQ,QAAQ;UAE7D,UAAS,gFAAgF;KACvF,MAAM,QAAQ,YAAY;KAC1B,SAAS,QAAQ;KACjB;KACD,CAAC;AAEJ;GACF,KAAK;AAEH,aAAS,sDAAsD;KAC7D,MAAM,QAAQ;KACd,QAAQ,QAAQ;KACjB,CAAC;AACF,oBAAgB,QAAQ,eAAe,QAAQ,OAAO;AACtD;;;;;;CASR,MAAM,+BAAqC;AACzC,WAAS,yBAAyB;AAGlC,MAAI,uBAAuB,MAAM;AAC/B,gBAAa,mBAAmB;AAChC,wBAAqB;;AAGvB,eAAa,EAAE,MAAM,SAAS;AAG9B,MAAI,eAAe;AACjB,kBAAe;AACf,mBAAgB;AAChB,mBAAgB;;AAGlB,WAAS,iCAAiC;GACxC,eAAe;GACf,aAAa;GACd,CAAC;AAGF,eAAa;;;;;CAMf,MAAM,0BAAgC;AACpC,WAAS,8CAA8C;AACvD,uBAAqB;AAGrB,MAAI,eAAe;AAEjB,iCADc,IAAI,MAAM,gDAAgD,CACpD;AACpB,mBAAgB;AAChB,mBAAgB;;AAIlB,eAAa,EAAE,MAAM,iBAAiB;;;;;;;CAQxC,MAAM,uBAAuB,YAA2C;AACtE,WAAS,uBAAuB;GAC9B,aAAa,QAAQ;GACrB,WAAW,WAAW;GACvB,CAAC;AAIF,MAAI,QAAQ,SAAS,qBAAqB;AACxC,0BAAuB,QAAQ;AAC/B;;AAEF,MAAI,QAAQ,SAAS,mBAAmB;AACtC,wBAAqB,QAAQ;AAC7B;;AAEF,MAAI,QAAQ,SAAS,mBAAmB;AACtC,wBAAqB,QAAQ;AAC7B;;AAIF,MAAI,WAAW,SAAS,gBAAgB;AACtC,OAAI,QAAQ,SAAS,YAAY;AAC/B,aAAS,gEAAgE;KACvE,SAAS,QAAQ;KACjB,eAAe,WAAW,iBAAiB;KAC5C,CAAC;IAEF,MAAM,WAAW,WAAW;AAC5B,mBAAe,QAAQ,OAAO,QAAQ,SAAS,KAAK;AACpD,4BAAwB,UAAU,QAAQ,QAAQ;AAClD,4BAAwB;UACnB;AACL,aAAS,gEAAgE;KACvE,aAAa,QAAQ;KACrB,eAAe,WAAW,iBAAiB,SAAS;KACrD,CAAC;AAEF,eAAW,iBAAiB,KAAK,QAAQ;;AAE3C;;AAIF,UAAQ,QAAQ,MAAhB;GACE,KAAK;AACH,4BAAwB,QAAQ,aAAa,QAAQ,QAAQ;AAC7D;GACF,KAAK;AACH,mBAAe,QAAQ,OAAO,QAAQ,SAAS,MAAM;AACrD;GACF,KAAK;AACH,oBAAgB,QAAQ,eAAe,QAAQ,OAAO;AACtD;;;AA0WN,QAlWuB;EACrB;EAEA,IAAI,OAAO;AACT,UAAO,eAAe;;EAGxB,WAAW,eAAe,KAAK;EAE/B,sBAAsB;EAEtB,wBAAwB;EAExB,uBAAuB,SAAS;EAEhC,yBAAyB,SAAS,SAAS;EAE3C,cAAkB,OAAsD;AACtE,YAAS,yBAAyB;IAChC,aAAa,UAAU,aAAa;IACpC,SAAS,WAAW,SAAS;IAC7B,cAAc,SAAS;IACxB,CAAC;AAIF,OAAI,WAAW,SAAS,QACtB,OAAM,IAAI,kBAAkB,4DAA4D;GAI1F,MAAM,SAAS,eAAe,YAAY,GAAG;GAG7C,MAAM,KAAK,eAAe,OAAO;AAGjC,OAAI,CAACC,QAAoB,GAAG,EAAE;AAC5B,aAAS,oCAAoC;KAC3C,MAAM,GAAG;KACT,UAAU,GAAG,IAAI;KAClB,CAAC;AACF,sBAAkB,GAAG;SAErB,UAAS,mDAAmD;AAI9D,qBAAkB,eAAe,KAAK,CAAC;AAEvC,UAAO;;EAGT,SAAS,YAA2B;AAClC,YAAS,oBAAoB;AAE7B,kBAAe,UAAU,UAAU,oBAAoB;AAGvD,SAAM,UAAU,SAAS;AACzB,YAAS,+BAA+B;AAExC,0BAAuB,KAAK;AAG5B,OAAI,kBAAkB,oBAAoB,QAAW;AACnD,aAAS,qCAAqC,EAAE,iBAAiB,CAAC;IAClE,MAAM,YAAYC,SAAkB,gBAAgB,gBAAgB;AACpE,wBAAoB;AACpB,cAAU,gBAAgB,UAAU;AACpC,0BAAsB;;AAIxB,OAAI,WAAW,SAAS,SAAS;AAC/B,aAAS,6CAA6C;AACtD,iBAAa;AACb;;AAIF,gBAAa;IAAE,MAAM;IAAgB,kBAAkB,EAAE;IAAE;AAC3D,YAAS,wCAAwC,EAC/C,aACD,CAAC;AAGF,wBAAqB,WAAW,mBAAmB,YAAY;GAG/D,MAAM,eAAe,IAAI,SAAe,SAAS,WAAW;AAC1D,oBAAgB;AAChB,oBAAgB;KAChB;AAGF,YAAS,uCAAuC;AAEhD,aAAU,iBAAiB;AAI3B,SAAM;AACN,YAAS,qBAAqB;;EAGhC,kBAAwB;AACtB,YAAS,wBAAwB;IAC/B,cAAc,SAAS;IACvB,WAAW,WAAW;IACvB,CAAC;AAGF,QAAK,MAAM,UAAU,gBAAgB,QAAQ,CAC3C,cAAa,OAAO;AAEtB,mBAAgB,OAAO;AAGvB,OAAI,uBAAuB,MAAM;AAC/B,iBAAa,mBAAmB;AAChC,yBAAqB;;AAIvB,OAAI,eAAe;AACjB,kCAAc,IAAI,MAAM,qCAAqC,CAAC;AAC9D,oBAAgB;AAChB,oBAAgB;;AAIlB,OAAI,WAAW,SAAS,eACtB,cAAa,EAAE,MAAM,iBAAiB;AAIxC,uBAAoB;AAGpB,OAAI,cAAc;AAChB,kBAAc;AACd,mBAAe;;AAIjB,aAAU,YAAY;AAEtB,0BAAuB,MAAM;AAC7B,YAAS,wBAAwB;;EAGnC,mBAAmB,UAAU,aAAa;EAE1C,eAAe,WAAW,SAAS;EAEnC,cAAoB;AAClB,YAAS,+BAA+B;IACtC,gBAAgB;IAChB,cAAc,SAAS;IACxB,CAAC;AACF,OAAI,CAAC,UAAU,aAAa,CAC1B,OAAM,IAAI,mBAAmB;AAE/B,aAAU,iBAAiB;;EAG7B,YAAY,aAA4D;AACtE,gBAAa,IAAI,SAAS;AAC1B,gBAAa;AACX,iBAAa,OAAO,SAAS;;;EAQjC,mBAAyC;AACvC,OAAI,WAAW,SAAS,QACtB,OAAM,IAAI,kBAAkB,4DAA4D;GAG1F,MAAM,UAAU,OAAO,YAAY;GACnC,MAAMC,aAAyB,EAAE,qBAAK,IAAI,KAAK,EAAE;AACjD,WAAQ,IAAI,SAAS,WAAW;AAEhC,YAAS,eAAe,EAAE,SAAS,CAAC;AACpC,sBAAmB;GAEnB,IAAI,WAAW;AAuFf,UArFqC;IACnC,IAAI;IAEJ,SAAS,OAA4D;AACnE,SAAI,SACF,OAAM,IAAI,kBAAkB,iDAAiD;KAK/E,MAAM,UAAUb,OAAc,QAAQ,EAAE,cAAc,cAAc,CAAC;AACrE,UAAK,MAAM,WAAW,SACpB,SAAQ,MAAM,QAAQ,YAAY,IAAI;AAExC,UAAK,MAAM,CAAC,IAAI,MAAM,QACpB,KAAI,OAAO,SAAS;MAClB,MAAM,MAAM,MAAM,KAAK,EAAE,IAAI,QAAQ,CAAC;AACtC,UAAI,IAAI,SAAS,EAAG,SAAQ,MAAM,IAAI;;KAI1C,MAAM,kBAAkB,MAAM,KAAK,WAAW,IAAI,QAAQ,CAAC;AAC3D,SAAI,gBAAgB,SAAS,EAAG,SAAQ,MAAM,gBAAgB;AAG9D,aAAQ,YAAY,GAAG;KACvB,MAAM,KAAK,QAAQ,OAAO;AAG1B,UAAK,MAAM,MAAM,GAAG,KAAK;MAEvB,MAAM,MAAM,GADIc,OAAqB,GAAG,KAAK,CACtB,GAAG,OAAO,GAAG,KAAK;AACzC,UAAI,GAAG,aACL,YAAW,IAAI,IAAI,KAAK,GAAG;WACtB;OAEL,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,YAAY;AAC/C,kBAAW,IAAI,IAAI,WAAW,GAAG;;;AAIrC,cAAS,gBAAgB;MAAE;MAAS,aAAa,GAAG,IAAI;MAAQ,UAAU,WAAW,IAAI;MAAM,CAAC;AAGhG,+BAA0B;AAC1B,wBAAmB;;IAGrB,cAAoB;AAClB,SAAI,SACF,OAAM,IAAI,kBAAkB,iDAAiD;AAE/E,gBAAW;KAEX,MAAM,MAAM,MAAM,KAAK,WAAW,IAAI,QAAQ,CAAC;AAC/C,aAAQ,OAAO,QAAQ;AAEvB,cAAS,gBAAgB;MAAE;MAAS,UAAU,IAAI;MAAQ,CAAC;AAE3D,SAAI,IAAI,SAAS,EAEf,mBADWC,OAAiB,IAAI,CACX;AAIvB,+BAA0B;AAE1B,wBAAmB;;IAGrB,eAAqB;AACnB,SAAI,SACF,OAAM,IAAI,kBAAkB,iDAAiD;AAE/E,gBAAW;AAEX,aAAQ,OAAO,QAAQ;AAEvB,cAAS,iBAAiB,EAAE,SAAS,CAAC;AAEtC,+BAA0B;AAC1B,wBAAmB;;IAEtB;;EAKH,yBAA8C;AAC5C,UAAO,IAAI,IAAI,QAAQ,MAAM,CAAC;;EAOhC,UAAW,iBACP;GACE,cAAc;GAEd,YAAY;GAEZ,cAAc;GAEd,WAAW;IACT,MAAM,sBAAM,IAAI,KAA8C;AAE9D,SAAK,MAAM,CAAC,IAAI,UAAU,gBACxB,KAAI,IAAI,IAAI,MAAM;AAGpB,QAAI,oBAAoB,UAAa,sBAAsB,OACzD,KAAI,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,WAAO;;GAGT,MAAM,SAAiD;AACrD,QAAI,CAAC,eAAgB;IAGrB,MAAM,YAAYH,SAAkB,gBAAgB,KAAK;AAEzD,aAAS,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG7C,wBAAoB;AAGpB,cAAU,gBAAgB,UAAU;AAGpC,0BAAsB;;GAGxB,aAAa;AACX,QAAI,CAAC,eAAgB;AAErB,aAAS,iBAAiB;AAG1B,wBAAoB;AAGpB,cAAU,mBAAmB;AAG7B,0BAAsB;;GAGxB,YAAY,aAAuE;AACjF,yBAAqB,IAAI,SAAsC;AAC/D,iBAAa;AACX,0BAAqB,OAAO,SAAsC;;;GAGvE,GACD;EAGL"}
|
|
1
|
+
{"version":3,"file":"ClientDocument.mjs","names":["_serverState: Primitive.InferState<TSchema> | undefined","_pending: PendingTransaction[]","_serverTransactionHistory: Transaction.Transaction[]","Document.make","_unsubscribe: (() => void) | null","_initState: InitState","_initTimeoutHandle: ReturnType<typeof setTimeout> | null","_initResolver: (() => void) | null","_initRejecter: ((error: Error) => void) | null","_presenceSelfId: string | undefined","_presenceSelfData: unknown","pending: PendingTransaction","Rebase.transformTransactionWithPrimitive","Rebase.rebaseAfterRejectionWithPrimitive","Transaction.isEmpty","Presence.validate","draftState: DraftState","OperationPath.encode","Transaction.make"],"sources":["../../src/client/ClientDocument.ts"],"sourcesContent":["import * as Document from \"../Document\";\nimport * as Transaction from \"../Transaction\";\nimport * as Operation from \"../Operation\";\nimport * as OperationPath from \"../OperationPath\";\nimport * as Presence from \"../Presence\";\nimport type * as Primitive from \"../Primitive\";\nimport type * as Transport from \"./Transport\";\nimport * as Rebase from \"./Rebase\";\nimport {\n TransactionRejectedError,\n NotConnectedError,\n InvalidStateError,\n} from \"./errors\";\n\n// =============================================================================\n// Draft Types\n// =============================================================================\n\n/**\n * Internal state for a single draft.\n */\ninterface DraftState {\n /** Accumulated ops keyed by `pathString:kind` for per-field replace semantics */\n ops: Map<string, Operation.Operation<any, any, any>>;\n}\n\n/**\n * Handle returned by `createDraft()` for managing a draft lifecycle.\n */\nexport interface DraftHandle<TSchema extends Primitive.AnyPrimitive> {\n /** Unique ID for this draft */\n readonly id: string;\n /** Run a mutation for preview. Per-path ops replace previous; different paths accumulate. */\n update(fn: (root: Primitive.InferProxy<TSchema>) => void): void;\n /** Commit draft as a real transaction sent to server. Draft is consumed. */\n commit(): void;\n /** Discard draft, reverting preview state. */\n discard(): void;\n}\n\n// =============================================================================\n// Client Document Types\n// =============================================================================\n\n/**\n * Pending transaction with metadata for tracking.\n */\ninterface PendingTransaction {\n /** The transaction */\n readonly transaction: Transaction.Transaction;\n /** Original transaction before any rebasing */\n readonly original: Transaction.Transaction;\n /** Timestamp when the transaction was sent */\n readonly sentAt: number;\n}\n\n/**\n * Initialization state for the client document.\n * Handles the race condition during startup where transactions\n * may arrive while fetching the initial snapshot.\n */\ntype InitState =\n | { readonly type: \"uninitialized\" }\n | { readonly type: \"initializing\"; readonly bufferedMessages: Transport.ServerMessage[] }\n | { readonly type: \"ready\" };\n\n// =============================================================================\n// Presence Types\n// =============================================================================\n\n/**\n * Listener for presence changes.\n */\nexport interface PresenceListener<_TData> {\n /** Called when any presence changes (self or others) */\n readonly onPresenceChange?: () => void;\n}\n\n/**\n * Presence API exposed on the ClientDocument.\n */\nexport interface ClientPresence<TData> {\n /**\n * Returns this client's connection ID (set after receiving presence_snapshot).\n * Returns undefined before the snapshot is received.\n */\n readonly selfId: () => string | undefined;\n\n /**\n * Returns this client's current presence data.\n * Returns undefined if not set.\n */\n readonly self: () => TData | undefined;\n\n /**\n * Returns a map of other clients' presence data.\n * Keys are connection IDs.\n */\n readonly others: () => ReadonlyMap<string, Presence.PresenceEntry<TData>>;\n\n /**\n * Returns all presence entries including self.\n */\n readonly all: () => ReadonlyMap<string, Presence.PresenceEntry<TData>>;\n\n /**\n * Sets this client's presence data.\n * Validates against the presence schema before sending.\n * @throws ParseError if validation fails\n */\n readonly set: (data: TData) => void;\n\n /**\n * Clears this client's presence data.\n */\n readonly clear: () => void;\n\n /**\n * Subscribes to presence changes.\n * @returns Unsubscribe function\n */\n readonly subscribe: (listener: PresenceListener<TData>) => () => void;\n}\n\n/**\n * Options for creating a ClientDocument.\n */\nexport interface ClientDocumentOptions<\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n> {\n /** The schema defining the document structure */\n readonly schema: TSchema;\n /** Transport for server communication */\n readonly transport: Transport.Transport;\n /** Initial state (optional, will sync from server if not provided) */\n readonly initialState?: Primitive.InferState<TSchema>;\n /** Initial server version (optional) */\n readonly initialVersion?: number;\n /** Called when server rejects a transaction */\n readonly onRejection?: (\n transaction: Transaction.Transaction,\n reason: string\n ) => void;\n /** Called when optimistic state changes */\n readonly onStateChange?: (state: Primitive.InferState<TSchema> | undefined) => void;\n /** Called when connection status changes */\n readonly onConnectionChange?: (connected: boolean) => void;\n /** Called when client is fully initialized and ready */\n readonly onReady?: () => void;\n /** Timeout in ms for pending transactions (default: 30000) */\n readonly transactionTimeout?: number;\n /** Timeout in ms for initialization (default: 10000) */\n readonly initTimeout?: number;\n /** Enable debug logging for all activity (default: false) */\n readonly debug?: boolean;\n /**\n * Optional presence schema for ephemeral per-user data.\n * When provided, enables the presence API on the ClientDocument.\n */\n readonly presence?: TPresence;\n /** Initial presence data, that will be set on the ClientDocument when it is created */\n readonly initialPresence?: TPresence extends Presence.AnyPresence ? Presence.Infer<TPresence> : undefined;\n}\n\n/**\n * Listener callbacks for subscribing to ClientDocument events.\n */\nexport interface ClientDocumentListener<TSchema extends Primitive.AnyPrimitive> {\n /** Called when optimistic state changes */\n readonly onStateChange?: (state: Primitive.InferState<TSchema> | undefined) => void;\n /** Called when connection status changes */\n readonly onConnectionChange?: (connected: boolean) => void;\n /** Called when client is fully initialized and ready */\n readonly onReady?: () => void;\n /** Called when draft state changes (create, update, commit, discard) */\n readonly onDraftChange?: () => void;\n}\n\n/**\n * A ClientDocument provides optimistic updates with server synchronization.\n */\nexport interface ClientDocument<\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n> {\n /** The schema defining this document's structure */\n readonly schema: TSchema;\n\n /** Root proxy for accessing and modifying document data (optimistic) */\n readonly root: Primitive.InferProxy<TSchema>;\n\n /** Returns the current optimistic state (server + pending) */\n get(): Primitive.InferState<TSchema> | undefined;\n\n /** Returns the confirmed server state */\n getServerState(): Primitive.InferState<TSchema> | undefined;\n\n /** Returns the current server version */\n getServerVersion(): number;\n\n /** Returns pending transactions count */\n getPendingCount(): number;\n\n /** Returns whether there are pending transactions */\n hasPendingChanges(): boolean;\n\n /**\n * Runs a function within a transaction.\n * Changes are applied optimistically and sent to the server.\n */\n transaction<R>(fn: (root: Primitive.InferProxy<TSchema>) => R): R;\n\n /**\n * Connects to the server and starts syncing.\n */\n connect(): Promise<void>;\n\n /**\n * Disconnects from the server.\n */\n disconnect(): void;\n\n /**\n * Returns whether currently connected to the server.\n */\n isConnected(): boolean;\n\n /**\n * Forces a full resync from the server.\n */\n resync(): void;\n\n /**\n * Returns whether the client is fully initialized and ready.\n */\n isReady(): boolean;\n\n /**\n * Subscribes to document events (state changes, connection changes, ready).\n * @returns Unsubscribe function\n */\n subscribe(listener: ClientDocumentListener<TSchema>): () => void;\n\n /**\n * Creates a new draft for in-memory preview without sending to server.\n * Draft ops overlay on top of optimistic state.\n */\n createDraft(): DraftHandle<TSchema>;\n\n /**\n * Returns the set of active draft IDs.\n */\n getActiveDraftIds(): ReadonlySet<string>;\n\n /**\n * Presence API for ephemeral per-user data.\n * Only available when presence schema is provided in options.\n */\n readonly presence: TPresence extends Presence.AnyPresence\n ? ClientPresence<Presence.Infer<TPresence>>\n : undefined;\n}\n\n// =============================================================================\n// Client Document Implementation\n// =============================================================================\n\n/**\n * Creates a new ClientDocument for the given schema.\n */\nexport const make = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n>(\n options: ClientDocumentOptions<TSchema, TPresence>\n): ClientDocument<TSchema, TPresence> => {\n const {\n schema,\n transport,\n initialState,\n initialVersion = 0,\n onRejection,\n onStateChange,\n onConnectionChange,\n onReady,\n transactionTimeout = 30000,\n initTimeout = 10000,\n debug = false,\n presence: presenceSchema,\n initialPresence,\n } = options;\n\n // ==========================================================================\n // Internal State\n // ==========================================================================\n\n // Server-confirmed state\n let _serverState: Primitive.InferState<TSchema> | undefined = initialState;\n let _serverVersion = initialVersion;\n\n // Pending transactions queue\n let _pending: PendingTransaction[] = [];\n\n // Server transactions received (for rebase after rejection)\n let _serverTransactionHistory: Transaction.Transaction[] = [];\n const MAX_HISTORY_SIZE = 100;\n\n // The underlying document for optimistic state (use initialState for raw state format)\n let _optimisticDoc = Document.make(schema, { initialState: _serverState });\n\n // Subscription cleanup\n let _unsubscribe: (() => void) | null = null;\n\n // Timeout handles for pending transactions\n const _timeoutHandles = new Map<string, ReturnType<typeof setTimeout>>();\n\n // Initialization state - handles buffering during startup\n let _initState: InitState = initialState !== undefined\n ? { type: \"ready\" }\n : { type: \"uninitialized\" };\n\n // Init timeout handle\n let _initTimeoutHandle: ReturnType<typeof setTimeout> | null = null;\n\n // Promise resolver for connect() to wait for ready state\n let _initResolver: (() => void) | null = null;\n let _initRejecter: ((error: Error) => void) | null = null;\n\n // Subscribers for events (added after creation via subscribe())\n const _subscribers = new Set<ClientDocumentListener<TSchema>>();\n\n // ==========================================================================\n // Presence State (only used when presenceSchema is provided)\n // ==========================================================================\n\n // This client's connection ID (received from presence_snapshot)\n let _presenceSelfId: string | undefined = undefined;\n\n // This client's current presence data\n let _presenceSelfData: unknown = undefined;\n\n // Other clients' presence entries (connectionId -> entry)\n const _presenceOthers = new Map<string, Presence.PresenceEntry<unknown>>();\n\n // Presence change subscribers\n const _presenceSubscribers = new Set<PresenceListener<unknown>>();\n\n // ==========================================================================\n // Draft State\n // ==========================================================================\n\n const _drafts = new Map<string, DraftState>();\n\n // ==========================================================================\n // Debug Logging\n // ==========================================================================\n\n /**\n * Debug logging helper that only logs when debug is enabled.\n */\n const debugLog = (...args: unknown[]): void => {\n if (debug) {\n console.log(\"[ClientDocument]\", ...args);\n }\n };\n\n // ==========================================================================\n // Notification Helpers\n // ==========================================================================\n\n /**\n * Notifies all listeners of a state change.\n */\n const notifyStateChange = (state: Primitive.InferState<TSchema> | undefined): void => {\n debugLog(\"notifyStateChange\", {\n state,\n subscriberCount: _subscribers.size,\n hasOnStateChange: !!onStateChange,\n });\n onStateChange?.(state);\n for (const listener of _subscribers) {\n listener.onStateChange?.(state);\n }\n };\n\n /**\n * Notifies all listeners of a connection change.\n */\n const notifyConnectionChange = (connected: boolean): void => {\n debugLog(\"notifyConnectionChange\", {\n connected,\n subscriberCount: _subscribers.size,\n hasOnConnectionChange: !!onConnectionChange,\n });\n onConnectionChange?.(connected);\n for (const listener of _subscribers) {\n listener.onConnectionChange?.(connected);\n }\n };\n\n /**\n * Notifies all listeners when ready.\n */\n const notifyReady = (): void => {\n debugLog(\"notifyReady\", {\n subscriberCount: _subscribers.size,\n hasOnReady: !!onReady,\n });\n onReady?.();\n for (const listener of _subscribers) {\n listener.onReady?.();\n }\n };\n\n /**\n * Notifies all listeners of a draft change.\n */\n const notifyDraftChange = (): void => {\n debugLog(\"notifyDraftChange\", { draftCount: _drafts.size });\n for (const listener of _subscribers) {\n listener.onDraftChange?.();\n }\n };\n\n /**\n * Notifies all presence listeners of a change.\n */\n const notifyPresenceChange = (): void => {\n debugLog(\"notifyPresenceChange\", {\n subscriberCount: _presenceSubscribers.size,\n });\n for (const listener of _presenceSubscribers) {\n try {\n listener.onPresenceChange?.();\n } catch {\n // Ignore listener errors\n }\n }\n };\n\n // ==========================================================================\n // Presence Handlers\n // ==========================================================================\n\n /**\n * Handles incoming presence snapshot from server.\n */\n const handlePresenceSnapshot = (message: Transport.PresenceSnapshotMessage): void => {\n if (!presenceSchema) return;\n\n debugLog(\"handlePresenceSnapshot\", {\n selfId: message.selfId,\n presenceCount: Object.keys(message.presences).length,\n });\n\n _presenceSelfId = message.selfId;\n _presenceOthers.clear();\n\n // Populate others from snapshot (exclude self)\n for (const [id, entry] of Object.entries(message.presences)) {\n if (id !== message.selfId) {\n _presenceOthers.set(id, entry);\n }\n }\n\n notifyPresenceChange();\n };\n\n /**\n * Handles incoming presence update from server (another user).\n */\n const handlePresenceUpdate = (message: Transport.PresenceUpdateMessage): void => {\n if (!presenceSchema) return;\n\n debugLog(\"handlePresenceUpdate\", {\n id: message.id,\n userId: message.userId,\n });\n\n _presenceOthers.set(message.id, {\n data: message.data,\n userId: message.userId,\n });\n\n notifyPresenceChange();\n };\n\n /**\n * Handles incoming presence remove from server (user disconnected).\n */\n const handlePresenceRemove = (message: Transport.PresenceRemoveMessage): void => {\n if (!presenceSchema) return;\n\n debugLog(\"handlePresenceRemove\", {\n id: message.id,\n });\n\n _presenceOthers.delete(message.id);\n notifyPresenceChange();\n };\n\n /**\n * Clears all presence state (on disconnect).\n */\n const clearPresenceState = (): void => {\n _presenceSelfId = undefined;\n _presenceSelfData = undefined;\n _presenceOthers.clear();\n notifyPresenceChange();\n };\n\n // ==========================================================================\n // Helper Functions\n // ==========================================================================\n\n /**\n * Recomputes the optimistic document from server state + pending transactions.\n */\n const recomputeOptimisticState = (): void => {\n debugLog(\"recomputeOptimisticState\", {\n serverVersion: _serverVersion,\n pendingCount: _pending.length,\n draftCount: _drafts.size,\n serverState: _serverState,\n });\n\n // Create fresh document from server state (use initialState for raw state format)\n _optimisticDoc = Document.make(schema, { initialState: _serverState });\n\n // Apply all pending transactions\n for (const pending of _pending) {\n _optimisticDoc.apply(pending.transaction.ops);\n }\n\n // Apply all draft ops on top\n for (const draft of _drafts.values()) {\n const draftOps = Array.from(draft.ops.values());\n if (draftOps.length > 0) {\n _optimisticDoc.apply(draftOps);\n }\n }\n\n const newState = _optimisticDoc.get();\n debugLog(\"recomputeOptimisticState: new optimistic state\", newState);\n\n // Notify state change\n notifyStateChange(newState);\n };\n\n /**\n * Adds a transaction to pending queue and sends to server.\n * If disconnected, the transport will queue it for later submission.\n */\n const submitTransaction = (tx: Transaction.Transaction): void => {\n debugLog(\"submitTransaction\", {\n txId: tx.id,\n ops: tx.ops,\n pendingCount: _pending.length + 1,\n isConnected: transport.isConnected(),\n activeDraftCount: _drafts.size,\n activeDraftIds: Array.from(_drafts.keys()),\n callStack: new Error().stack?.split(\"\\n\").slice(1, 6).join(\"\\n\"),\n });\n\n const pending: PendingTransaction = {\n transaction: tx,\n original: tx,\n sentAt: Date.now(),\n };\n\n _pending.push(pending);\n\n // Only set timeout if connected - otherwise the transport queues it\n // and the timeout will start when the message is actually sent on reconnect\n if (transport.isConnected()) {\n const timeoutHandle = setTimeout(() => {\n handleTransactionTimeout(tx.id);\n }, transactionTimeout);\n _timeoutHandles.set(tx.id, timeoutHandle);\n }\n\n // Send to server (transport queues if disconnected)\n transport.send(tx);\n debugLog(\"submitTransaction: sent to transport\", { txId: tx.id, queued: !transport.isConnected() });\n };\n\n /**\n * Handles a transaction timeout.\n */\n const handleTransactionTimeout = (txId: string): void => {\n debugLog(\"handleTransactionTimeout\", { txId });\n const index = _pending.findIndex((p) => p.transaction.id === txId);\n if (index === -1) {\n debugLog(\"handleTransactionTimeout: transaction not found (already confirmed/rejected)\", { txId });\n return; // Already confirmed or rejected\n }\n\n // Remove from pending\n const [removed] = _pending.splice(index, 1);\n _timeoutHandles.delete(txId);\n\n debugLog(\"handleTransactionTimeout: removed from pending\", {\n txId,\n remainingPending: _pending.length,\n });\n\n // Recompute state\n recomputeOptimisticState();\n\n // Notify as rejection\n onRejection?.(removed!.transaction, \"Transaction timed out\");\n };\n\n /**\n * Handles an incoming server transaction.\n */\n const handleServerTransaction = (\n serverTx: Transaction.Transaction,\n version: number\n ): void => {\n debugLog(\"handleServerTransaction\", {\n txId: serverTx.id,\n version,\n ops: serverTx.ops,\n currentServerVersion: _serverVersion,\n pendingCount: _pending.length,\n });\n\n // Update server version\n _serverVersion = version;\n\n // Check if this is one of our pending transactions (ACK)\n const pendingIndex = _pending.findIndex(\n (p) => p.transaction.id === serverTx.id\n );\n\n if (pendingIndex !== -1) {\n // This is our transaction - confirmed!\n debugLog(\"handleServerTransaction: transaction confirmed (ACK)\", {\n txId: serverTx.id,\n pendingIndex,\n });\n\n const confirmed = _pending[pendingIndex]!;\n\n // Clear timeout\n const timeoutHandle = _timeoutHandles.get(serverTx.id);\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n _timeoutHandles.delete(serverTx.id);\n }\n\n // Remove from pending\n _pending.splice(pendingIndex, 1);\n\n // Apply to server state\n const tempDoc = Document.make(schema, { initialState: _serverState });\n tempDoc.apply(serverTx.ops);\n _serverState = tempDoc.get();\n\n debugLog(\"handleServerTransaction: updated server state\", {\n txId: serverTx.id,\n newServerState: _serverState,\n remainingPending: _pending.length,\n });\n\n // Recompute optimistic state (pending txs already applied, just need to update base)\n recomputeOptimisticState();\n } else {\n // This is someone else's transaction - need to rebase\n debugLog(\"handleServerTransaction: remote transaction, rebasing pending\", {\n txId: serverTx.id,\n pendingCount: _pending.length,\n });\n\n // Apply to server state\n const tempDoc = Document.make(schema, { initialState: _serverState });\n tempDoc.apply(serverTx.ops);\n _serverState = tempDoc.get();\n\n // Add to history for potential rebase after rejection\n _serverTransactionHistory.push(serverTx);\n if (_serverTransactionHistory.length > MAX_HISTORY_SIZE) {\n _serverTransactionHistory.shift();\n }\n\n // Rebase all pending transactions using primitive-based transformation\n const rebasedPending = _pending.map((p) => ({\n ...p,\n transaction: Rebase.transformTransactionWithPrimitive(p.transaction, serverTx, schema),\n }));\n\n debugLog(\"handleServerTransaction: rebased pending transactions\", {\n txId: serverTx.id,\n rebasedCount: rebasedPending.length,\n originalPendingIds: _pending.map((p) => p.transaction.id),\n rebasedPendingIds: rebasedPending.map((p) => p.transaction.id),\n });\n\n _pending = rebasedPending;\n\n // Recompute optimistic state\n recomputeOptimisticState();\n }\n };\n\n /**\n * Handles a transaction rejection from the server.\n */\n const handleRejection = (txId: string, reason: string): void => {\n debugLog(\"handleRejection\", {\n txId,\n reason,\n pendingCount: _pending.length,\n });\n\n const index = _pending.findIndex((p) => p.transaction.id === txId);\n if (index === -1) {\n debugLog(\"handleRejection: transaction not found (already removed)\", { txId });\n return; // Already removed\n }\n\n const rejected = _pending[index]!;\n\n // Clear timeout\n const timeoutHandle = _timeoutHandles.get(txId);\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n _timeoutHandles.delete(txId);\n }\n\n // Remove rejected transaction\n _pending.splice(index, 1);\n\n debugLog(\"handleRejection: removed rejected transaction, rebasing remaining\", {\n txId,\n remainingPending: _pending.length,\n serverHistorySize: _serverTransactionHistory.length,\n });\n\n // Re-transform remaining pending transactions without the rejected one\n // We need to replay from their original state\n const remainingOriginals = _pending.map((p) => p.original);\n const retransformed = Rebase.rebaseAfterRejectionWithPrimitive(\n [...remainingOriginals, rejected.original],\n txId,\n _serverTransactionHistory,\n schema\n );\n\n // Update pending with retransformed versions\n _pending = _pending.map((p, i) => ({\n ...p,\n transaction: retransformed[i] ?? p.transaction,\n }));\n\n debugLog(\"handleRejection: rebased remaining transactions\", {\n txId,\n rebasedCount: _pending.length,\n });\n\n // Recompute optimistic state\n recomputeOptimisticState();\n\n // Notify rejection\n onRejection?.(rejected.original, reason);\n };\n\n /**\n * Handles a snapshot from the server.\n * @param isInitialSnapshot - If true, this is the initial sync snapshot\n */\n const handleSnapshot = (state: unknown, version: number, isInitialSnapshot: boolean = false): void => {\n debugLog(\"handleSnapshot\", {\n isInitialSnapshot,\n version,\n currentServerVersion: _serverVersion,\n pendingCount: _pending.length,\n state,\n });\n\n if (!isInitialSnapshot) {\n debugLog(\"handleSnapshot: non-initial snapshot, clearing pending transactions\", {\n clearedPendingCount: _pending.length,\n });\n\n // For non-initial snapshots, clear all pending (they're now invalid)\n for (const handle of _timeoutHandles.values()) {\n clearTimeout(handle);\n }\n _timeoutHandles.clear();\n\n // Notify rejections for all pending\n for (const pending of _pending) {\n onRejection?.(pending.original, \"State reset due to resync\");\n }\n\n _pending = [];\n }\n\n _serverTransactionHistory = [];\n _serverState = state as Primitive.InferState<TSchema>;\n _serverVersion = version;\n\n debugLog(\"handleSnapshot: updated server state\", {\n newVersion: _serverVersion,\n newState: _serverState,\n });\n\n // Recompute optimistic state (now equals server state)\n recomputeOptimisticState();\n };\n\n /**\n * Processes buffered messages after receiving the initial snapshot.\n * Filters out transactions already included in the snapshot (version <= snapshotVersion)\n * and applies newer transactions in order.\n */\n const processBufferedMessages = (\n bufferedMessages: Transport.ServerMessage[],\n snapshotVersion: number\n ): void => {\n debugLog(\"processBufferedMessages\", {\n bufferedCount: bufferedMessages.length,\n snapshotVersion,\n });\n\n // Sort transactions by version to ensure correct order\n const sortedMessages = [...bufferedMessages].sort((a, b) => {\n if (a.type === \"transaction\" && b.type === \"transaction\") {\n return a.version - b.version;\n }\n return 0;\n });\n\n // Process each buffered message\n for (const message of sortedMessages) {\n switch (message.type) {\n case \"transaction\":\n // Only apply transactions with version > snapshot version\n if (message.version > snapshotVersion) {\n debugLog(\"processBufferedMessages: applying buffered transaction\", {\n txId: message.transaction.id,\n version: message.version,\n snapshotVersion,\n });\n handleServerTransaction(message.transaction, message.version);\n } else {\n debugLog(\"processBufferedMessages: skipping buffered transaction (already in snapshot)\", {\n txId: message.transaction.id,\n version: message.version,\n snapshotVersion,\n });\n }\n break;\n case \"error\":\n // Errors are still relevant - pass through\n debugLog(\"processBufferedMessages: processing buffered error\", {\n txId: message.transactionId,\n reason: message.reason,\n });\n handleRejection(message.transactionId, message.reason);\n break;\n // Ignore additional snapshots in buffer - we already have one\n }\n }\n };\n\n /**\n * Completes initialization and transitions to ready state.\n */\n const completeInitialization = (): void => {\n debugLog(\"completeInitialization\");\n\n // Clear init timeout\n if (_initTimeoutHandle !== null) {\n clearTimeout(_initTimeoutHandle);\n _initTimeoutHandle = null;\n }\n\n _initState = { type: \"ready\" };\n\n // Resolve the connect promise\n if (_initResolver) {\n _initResolver();\n _initResolver = null;\n _initRejecter = null;\n }\n\n debugLog(\"completeInitialization: ready\", {\n serverVersion: _serverVersion,\n serverState: _serverState,\n });\n\n // Notify ready\n notifyReady();\n };\n\n /**\n * Handles initialization timeout.\n */\n const handleInitTimeout = (): void => {\n debugLog(\"handleInitTimeout: initialization timed out\");\n _initTimeoutHandle = null;\n\n // Reject the connect promise\n if (_initRejecter) {\n const error = new Error(\"Initialization timed out waiting for snapshot\");\n _initRejecter(error);\n _initResolver = null;\n _initRejecter = null;\n }\n\n // Reset to uninitialized state\n _initState = { type: \"uninitialized\" };\n };\n\n /**\n * Handles incoming server messages.\n * During initialization, messages are buffered until the snapshot arrives.\n * Presence messages are always processed immediately (not buffered).\n */\n const handleServerMessage = (message: Transport.ServerMessage): void => {\n debugLog(\"handleServerMessage\", {\n messageType: message.type,\n initState: _initState.type,\n });\n\n // Presence messages are always handled immediately (not buffered)\n // This allows presence to work even during document initialization\n if (message.type === \"presence_snapshot\") {\n handlePresenceSnapshot(message);\n return;\n }\n if (message.type === \"presence_update\") {\n handlePresenceUpdate(message);\n return;\n }\n if (message.type === \"presence_remove\") {\n handlePresenceRemove(message);\n return;\n }\n\n // Handle based on initialization state\n if (_initState.type === \"initializing\") {\n if (message.type === \"snapshot\") {\n debugLog(\"handleServerMessage: received snapshot during initialization\", {\n version: message.version,\n bufferedCount: _initState.bufferedMessages.length,\n });\n // Snapshot received - apply it and process buffered messages\n const buffered = _initState.bufferedMessages;\n handleSnapshot(message.state, message.version, true);\n processBufferedMessages(buffered, message.version);\n completeInitialization();\n } else {\n debugLog(\"handleServerMessage: buffering message during initialization\", {\n messageType: message.type,\n bufferedCount: _initState.bufferedMessages.length + 1,\n });\n // Buffer other messages during initialization\n _initState.bufferedMessages.push(message);\n }\n return;\n }\n\n // Normal message handling when ready (or uninitialized with initial state)\n switch (message.type) {\n case \"transaction\":\n handleServerTransaction(message.transaction, message.version);\n break;\n case \"snapshot\":\n handleSnapshot(message.state, message.version, false);\n break;\n case \"error\":\n handleRejection(message.transactionId, message.reason);\n break;\n }\n };\n\n // ==========================================================================\n // Public API\n // ==========================================================================\n\n const clientDocument = {\n schema,\n\n get root() {\n return _optimisticDoc.root;\n },\n\n get: () => _optimisticDoc.get(),\n\n getServerState: () => _serverState,\n\n getServerVersion: () => _serverVersion,\n\n getPendingCount: () => _pending.length,\n\n hasPendingChanges: () => _pending.length > 0,\n\n transaction: <R,>(fn: (root: Primitive.InferProxy<TSchema>) => R): R => {\n debugLog(\"transaction: starting\", {\n isConnected: transport.isConnected(),\n isReady: _initState.type === \"ready\",\n pendingCount: _pending.length,\n activeDraftCount: _drafts.size,\n activeDraftIds: Array.from(_drafts.keys()),\n callStack: new Error().stack?.split(\"\\n\").slice(1, 6).join(\"\\n\"),\n });\n\n // Allow transactions even when disconnected - they will be queued\n // Only require that we have been initialized at least once (have server state)\n if (_initState.type !== \"ready\") {\n throw new InvalidStateError(\"Client is not ready. Wait for initialization to complete.\");\n }\n\n // Run the transaction on the optimistic document\n const result = _optimisticDoc.transaction(fn);\n\n // Flush and get the transaction\n const tx = _optimisticDoc.flush();\n\n // If there are operations, submit to server\n if (!Transaction.isEmpty(tx)) {\n debugLog(\"transaction: flushed, submitting\", {\n txId: tx.id,\n opsCount: tx.ops.length,\n });\n submitTransaction(tx);\n } else {\n debugLog(\"transaction: flushed, empty transaction (no ops)\");\n }\n\n // Notify state change\n notifyStateChange(_optimisticDoc.get());\n\n return result;\n },\n\n connect: async (): Promise<void> => {\n debugLog(\"connect: starting\");\n // Subscribe to server messages\n _unsubscribe = transport.subscribe(handleServerMessage);\n\n // Connect transport\n await transport.connect();\n debugLog(\"connect: transport connected\");\n\n notifyConnectionChange(true);\n\n // Set initial presence if provided\n if (presenceSchema && initialPresence !== undefined) {\n debugLog(\"connect: setting initial presence\", { initialPresence });\n const validated = Presence.validate(presenceSchema, initialPresence);\n _presenceSelfData = validated;\n transport.sendPresenceSet(validated);\n notifyPresenceChange();\n }\n\n // If we already have initial state, we're ready immediately\n if (_initState.type === \"ready\") {\n debugLog(\"connect: already ready (has initial state)\");\n notifyReady();\n return;\n }\n\n // Enter initializing state - buffer messages until snapshot arrives\n _initState = { type: \"initializing\", bufferedMessages: [] };\n debugLog(\"connect: entering initializing state\", {\n initTimeout,\n });\n\n // Set up initialization timeout\n _initTimeoutHandle = setTimeout(handleInitTimeout, initTimeout);\n\n // Create a promise that resolves when we're ready\n const readyPromise = new Promise<void>((resolve, reject) => {\n _initResolver = resolve;\n _initRejecter = reject;\n });\n\n // Request initial snapshot\n debugLog(\"connect: requesting initial snapshot\");\n \n transport.requestSnapshot();\n\n\n // Wait for initialization to complete\n await readyPromise;\n debugLog(\"connect: completed\");\n },\n\n disconnect: (): void => {\n debugLog(\"disconnect: starting\", {\n pendingCount: _pending.length,\n initState: _initState.type,\n });\n\n // Clear all timeouts\n for (const handle of _timeoutHandles.values()) {\n clearTimeout(handle);\n }\n _timeoutHandles.clear();\n\n // Clear init timeout\n if (_initTimeoutHandle !== null) {\n clearTimeout(_initTimeoutHandle);\n _initTimeoutHandle = null;\n }\n\n // Reject any pending init promise\n if (_initRejecter) {\n _initRejecter(new Error(\"Disconnected during initialization\"));\n _initResolver = null;\n _initRejecter = null;\n }\n\n // Reset init state\n if (_initState.type === \"initializing\") {\n _initState = { type: \"uninitialized\" };\n }\n\n // Clear presence state\n clearPresenceState();\n\n // Unsubscribe\n if (_unsubscribe) {\n _unsubscribe();\n _unsubscribe = null;\n }\n\n // Disconnect transport\n transport.disconnect();\n\n notifyConnectionChange(false);\n debugLog(\"disconnect: completed\");\n },\n\n isConnected: () => transport.isConnected(),\n\n isReady: () => _initState.type === \"ready\",\n\n resync: (): void => {\n debugLog(\"resync: requesting snapshot\", {\n currentVersion: _serverVersion,\n pendingCount: _pending.length,\n });\n if (!transport.isConnected()) {\n throw new NotConnectedError();\n }\n transport.requestSnapshot();\n },\n\n subscribe: (listener: ClientDocumentListener<TSchema>): (() => void) => {\n _subscribers.add(listener);\n return () => {\n _subscribers.delete(listener);\n };\n },\n\n // =========================================================================\n // Draft API\n // =========================================================================\n\n createDraft: (): DraftHandle<TSchema> => {\n if (_initState.type !== \"ready\") {\n throw new InvalidStateError(\"Client is not ready. Wait for initialization to complete.\");\n }\n\n const draftId = crypto.randomUUID();\n const draftState: DraftState = { ops: new Map() };\n _drafts.set(draftId, draftState);\n\n debugLog(\"createDraft\", { draftId });\n notifyDraftChange();\n\n let consumed = false;\n\n const handle: DraftHandle<TSchema> = {\n id: draftId,\n\n update: (fn: (root: Primitive.InferProxy<TSchema>) => void): void => {\n debugLog(\"draft.update: starting\", {\n draftId,\n consumed,\n currentOpsCount: draftState.ops.size,\n pendingCount: _pending.length,\n });\n\n if (consumed) {\n throw new InvalidStateError(\"Draft has already been committed or discarded.\");\n }\n\n // Create a scratch document from current optimistic state (without this draft's ops)\n // First compute base = server + pending + other drafts\n const baseDoc = Document.make(schema, { initialState: _serverState });\n for (const pending of _pending) {\n baseDoc.apply(pending.transaction.ops);\n }\n for (const [id, d] of _drafts) {\n if (id !== draftId) {\n const ops = Array.from(d.ops.values());\n if (ops.length > 0) baseDoc.apply(ops);\n }\n }\n // Also apply current draft ops so the scratch doc has full state\n const currentDraftOps = Array.from(draftState.ops.values());\n if (currentDraftOps.length > 0) baseDoc.apply(currentDraftOps);\n\n // Run transaction on scratch doc\n baseDoc.transaction(fn);\n const tx = baseDoc.flush();\n\n // Merge new ops into draft's op map\n for (const op of tx.ops) {\n const pathStr = OperationPath.encode(op.path);\n const key = `${pathStr}:${String(op.kind)}`;\n if (op.deduplicable) {\n draftState.ops.set(key, op);\n } else {\n // Use a unique key to avoid overwriting non-deduplicable ops\n const uniqueKey = `${key}:${crypto.randomUUID()}`;\n draftState.ops.set(uniqueKey, op);\n }\n }\n\n debugLog(\"draft.update: complete\", {\n draftId,\n newOpsCount: tx.ops.length,\n totalOps: draftState.ops.size,\n note: \"Ops stored in draft - NOT sent to server\",\n });\n\n // Recompute optimistic state to reflect draft changes\n recomputeOptimisticState();\n notifyDraftChange();\n },\n\n commit: (): void => {\n debugLog(\"draft.commit: starting\", {\n draftId,\n consumed,\n opsCount: draftState.ops.size,\n });\n\n if (consumed) {\n throw new InvalidStateError(\"Draft has already been committed or discarded.\");\n }\n consumed = true;\n\n const ops = Array.from(draftState.ops.values());\n _drafts.delete(draftId);\n\n debugLog(\"draft.commit: submitting\", {\n draftId,\n opsCount: ops.length,\n note: ops.length > 0 ? \"Will call submitTransaction\" : \"Empty draft - no transaction\",\n });\n\n if (ops.length > 0) {\n const tx = Transaction.make(ops);\n submitTransaction(tx);\n }\n\n // Recompute: draft is removed, but committed ops are now in pending\n recomputeOptimisticState();\n\n notifyDraftChange();\n },\n\n discard: (): void => {\n debugLog(\"draft.discard: starting\", {\n draftId,\n consumed,\n opsCount: draftState.ops.size,\n });\n\n if (consumed) {\n throw new InvalidStateError(\"Draft has already been committed or discarded.\");\n }\n consumed = true;\n\n _drafts.delete(draftId);\n\n debugLog(\"draft.discard: complete\", {\n draftId,\n note: \"Draft discarded - no transaction sent to server\",\n });\n\n recomputeOptimisticState();\n notifyDraftChange();\n },\n };\n\n return handle;\n },\n\n getActiveDraftIds: (): ReadonlySet<string> => {\n return new Set(_drafts.keys());\n },\n\n // =========================================================================\n // Presence API\n // =========================================================================\n\n presence: (presenceSchema\n ? {\n selfId: () => _presenceSelfId,\n\n self: () => _presenceSelfData as Presence.Infer<NonNullable<TPresence>> | undefined,\n\n others: () => _presenceOthers as ReadonlyMap<string, Presence.PresenceEntry<Presence.Infer<NonNullable<TPresence>>>>,\n\n all: () => {\n const all = new Map<string, Presence.PresenceEntry<unknown>>();\n // Add others\n for (const [id, entry] of _presenceOthers) {\n all.set(id, entry);\n }\n // Add self if we have data\n if (_presenceSelfId !== undefined && _presenceSelfData !== undefined) {\n all.set(_presenceSelfId, { data: _presenceSelfData });\n }\n return all as ReadonlyMap<string, Presence.PresenceEntry<Presence.Infer<NonNullable<TPresence>>>>;\n },\n\n set: (data: Presence.Infer<NonNullable<TPresence>>) => {\n if (!presenceSchema) return;\n\n // Validate against schema (throws if invalid)\n const validated = Presence.validate(presenceSchema, data);\n\n debugLog(\"presence.set\", { data: validated });\n\n // Update local state\n _presenceSelfData = validated;\n\n // Send to server\n transport.sendPresenceSet(validated);\n\n // Notify listeners\n notifyPresenceChange();\n },\n\n clear: () => {\n if (!presenceSchema) return;\n\n debugLog(\"presence.clear\");\n\n // Clear local state\n _presenceSelfData = undefined;\n\n // Send to server\n transport.sendPresenceClear();\n\n // Notify listeners\n notifyPresenceChange();\n },\n\n subscribe: (listener: PresenceListener<Presence.Infer<NonNullable<TPresence>>>) => {\n _presenceSubscribers.add(listener as PresenceListener<unknown>);\n return () => {\n _presenceSubscribers.delete(listener as PresenceListener<unknown>);\n };\n },\n }\n : undefined) as TPresence extends Presence.AnyPresence\n ? ClientPresence<Presence.Infer<TPresence>>\n : undefined,\n } as ClientDocument<TSchema, TPresence>;\n\n return clientDocument;\n};\n"],"mappings":"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"}
|
|
@@ -19,13 +19,22 @@ var StructPrimitive = class StructPrimitive {
|
|
|
19
19
|
require_defineProperty._defineProperty(this, "TSetInput", void 0);
|
|
20
20
|
require_defineProperty._defineProperty(this, "TUpdateInput", void 0);
|
|
21
21
|
require_defineProperty._defineProperty(this, "_schema", void 0);
|
|
22
|
-
require_defineProperty._defineProperty(this, "_opDefinitions", {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
require_defineProperty._defineProperty(this, "_opDefinitions", {
|
|
23
|
+
set: require_OperationDefinition.make({
|
|
24
|
+
kind: "struct.set",
|
|
25
|
+
payload: effect.Schema.Unknown,
|
|
26
|
+
target: effect.Schema.Unknown,
|
|
27
|
+
apply: (payload) => payload,
|
|
28
|
+
deduplicable: true
|
|
29
|
+
}),
|
|
30
|
+
unset: require_OperationDefinition.make({
|
|
31
|
+
kind: "struct.unset",
|
|
32
|
+
payload: effect.Schema.Unknown,
|
|
33
|
+
target: effect.Schema.Unknown,
|
|
34
|
+
apply: (payload) => payload,
|
|
35
|
+
deduplicable: true
|
|
36
|
+
})
|
|
37
|
+
});
|
|
29
38
|
require_defineProperty._defineProperty(this, "_internal", {
|
|
30
39
|
createProxy: (env, operationPath) => {
|
|
31
40
|
const fields = this._schema.fields;
|
|
@@ -56,10 +65,14 @@ var StructPrimitive = class StructPrimitive {
|
|
|
56
65
|
update: (value) => {
|
|
57
66
|
for (const key in value) if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
58
67
|
const fieldValue = value[key];
|
|
59
|
-
if (fieldValue === void 0) continue;
|
|
60
68
|
const fieldPrimitive = fields[key];
|
|
61
69
|
if (!fieldPrimitive) continue;
|
|
62
70
|
const fieldPath = operationPath.append(key);
|
|
71
|
+
if (fieldValue === void 0 || fieldValue === null && !require_shared.primitiveAllowsNullValue(fieldPrimitive)) {
|
|
72
|
+
if (this._isRequiredWithoutDefault(fieldPrimitive)) throw new require_shared.ValidationError(`Field "${key}" is required and cannot be null or undefined`);
|
|
73
|
+
env.addOperation(require_Operation.fromDefinition(fieldPath, this._opDefinitions.unset, null));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
63
76
|
const fieldProxy = fieldPrimitive._internal.createProxy(env, fieldPath);
|
|
64
77
|
if (fieldPrimitive._tag === "StructPrimitive" && typeof fieldValue === "object" && fieldValue !== null && !Array.isArray(fieldValue)) fieldProxy.update(fieldValue);
|
|
65
78
|
else fieldProxy.set(fieldValue);
|
|
@@ -101,12 +114,19 @@ var StructPrimitive = class StructPrimitive {
|
|
|
101
114
|
const fieldName = tokens[0];
|
|
102
115
|
if (!(fieldName in this._schema.fields)) throw new require_shared.ValidationError(`Unknown field: ${globalThis.String(fieldName)}`);
|
|
103
116
|
const fieldPrimitive = this._schema.fields[fieldName];
|
|
104
|
-
const remainingPath = path.shift();
|
|
105
|
-
const fieldOperation = require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, operation), {}, { path: remainingPath });
|
|
106
117
|
const currentState = state !== null && state !== void 0 ? state : {};
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
if (operation.kind === "struct.unset" && tokens.length === 1) {
|
|
119
|
+
if (this._isRequiredWithoutDefault(fieldPrimitive)) throw new require_shared.ValidationError(`Field "${globalThis.String(fieldName)}" is required and cannot be removed`);
|
|
120
|
+
const mutableState = require_objectSpread2._objectSpread2({}, currentState);
|
|
121
|
+
delete mutableState[globalThis.String(fieldName)];
|
|
122
|
+
newState = mutableState;
|
|
123
|
+
} else {
|
|
124
|
+
const remainingPath = path.shift();
|
|
125
|
+
const fieldOperation = require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, operation), {}, { path: remainingPath });
|
|
126
|
+
const currentFieldState = currentState[fieldName];
|
|
127
|
+
const newFieldState = fieldPrimitive._internal.applyOperation(currentFieldState, fieldOperation);
|
|
128
|
+
newState = require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, currentState), {}, { [fieldName]: newFieldState });
|
|
129
|
+
}
|
|
110
130
|
}
|
|
111
131
|
require_shared.runValidators(newState, this._schema.validators);
|
|
112
132
|
return newState;
|
|
@@ -225,6 +245,11 @@ var StructPrimitive = class StructPrimitive {
|
|
|
225
245
|
}
|
|
226
246
|
return field;
|
|
227
247
|
}
|
|
248
|
+
_isRequiredWithoutDefault(field) {
|
|
249
|
+
var _schema;
|
|
250
|
+
const fieldDefault = field._internal.getInitialState();
|
|
251
|
+
return ((_schema = field._schema) === null || _schema === void 0 ? void 0 : _schema.required) === true && fieldDefault === void 0;
|
|
252
|
+
}
|
|
228
253
|
};
|
|
229
254
|
/** Creates a new StructPrimitive with the given fields */
|
|
230
255
|
const Struct = (fields) => new StructPrimitive({
|
|
@@ -102,6 +102,7 @@ declare class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TReq
|
|
|
102
102
|
/** Make all properties of this struct optional (TRequired = false for all fields) */
|
|
103
103
|
partial(): StructPrimitive<PartialFields<TFields>, TRequired, THasDefault>;
|
|
104
104
|
private _makeFieldOptional;
|
|
105
|
+
private _isRequiredWithoutDefault;
|
|
105
106
|
readonly _internal: PrimitiveInternal<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>>;
|
|
106
107
|
}
|
|
107
108
|
/** Creates a new StructPrimitive with the given fields */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Struct.d.cts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Struct.d.cts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -103,6 +103,7 @@ declare class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TReq
|
|
|
103
103
|
/** Make all properties of this struct optional (TRequired = false for all fields) */
|
|
104
104
|
partial(): StructPrimitive<PartialFields<TFields>, TRequired, THasDefault>;
|
|
105
105
|
private _makeFieldOptional;
|
|
106
|
+
private _isRequiredWithoutDefault;
|
|
106
107
|
readonly _internal: PrimitiveInternal<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>>;
|
|
107
108
|
}
|
|
108
109
|
/** Creates a new StructPrimitive with the given fields */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Struct.d.mts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Struct.d.mts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _defineProperty } from "../_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.mjs";
|
|
2
2
|
import { _objectSpread2 } from "../_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.mjs";
|
|
3
|
-
import { ValidationError, applyDefaults, runValidators } from "./shared.mjs";
|
|
3
|
+
import { ValidationError, applyDefaults, primitiveAllowsNullValue, runValidators } from "./shared.mjs";
|
|
4
4
|
import { make } from "../OperationDefinition.mjs";
|
|
5
5
|
import { pathsOverlap } from "../OperationPath.mjs";
|
|
6
6
|
import { fromDefinition } from "../Operation.mjs";
|
|
@@ -18,13 +18,22 @@ var StructPrimitive = class StructPrimitive {
|
|
|
18
18
|
_defineProperty(this, "TSetInput", void 0);
|
|
19
19
|
_defineProperty(this, "TUpdateInput", void 0);
|
|
20
20
|
_defineProperty(this, "_schema", void 0);
|
|
21
|
-
_defineProperty(this, "_opDefinitions", {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
_defineProperty(this, "_opDefinitions", {
|
|
22
|
+
set: make({
|
|
23
|
+
kind: "struct.set",
|
|
24
|
+
payload: Schema.Unknown,
|
|
25
|
+
target: Schema.Unknown,
|
|
26
|
+
apply: (payload) => payload,
|
|
27
|
+
deduplicable: true
|
|
28
|
+
}),
|
|
29
|
+
unset: make({
|
|
30
|
+
kind: "struct.unset",
|
|
31
|
+
payload: Schema.Unknown,
|
|
32
|
+
target: Schema.Unknown,
|
|
33
|
+
apply: (payload) => payload,
|
|
34
|
+
deduplicable: true
|
|
35
|
+
})
|
|
36
|
+
});
|
|
28
37
|
_defineProperty(this, "_internal", {
|
|
29
38
|
createProxy: (env, operationPath) => {
|
|
30
39
|
const fields = this._schema.fields;
|
|
@@ -55,10 +64,14 @@ var StructPrimitive = class StructPrimitive {
|
|
|
55
64
|
update: (value) => {
|
|
56
65
|
for (const key in value) if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
57
66
|
const fieldValue = value[key];
|
|
58
|
-
if (fieldValue === void 0) continue;
|
|
59
67
|
const fieldPrimitive = fields[key];
|
|
60
68
|
if (!fieldPrimitive) continue;
|
|
61
69
|
const fieldPath = operationPath.append(key);
|
|
70
|
+
if (fieldValue === void 0 || fieldValue === null && !primitiveAllowsNullValue(fieldPrimitive)) {
|
|
71
|
+
if (this._isRequiredWithoutDefault(fieldPrimitive)) throw new ValidationError(`Field "${key}" is required and cannot be null or undefined`);
|
|
72
|
+
env.addOperation(fromDefinition(fieldPath, this._opDefinitions.unset, null));
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
62
75
|
const fieldProxy = fieldPrimitive._internal.createProxy(env, fieldPath);
|
|
63
76
|
if (fieldPrimitive._tag === "StructPrimitive" && typeof fieldValue === "object" && fieldValue !== null && !Array.isArray(fieldValue)) fieldProxy.update(fieldValue);
|
|
64
77
|
else fieldProxy.set(fieldValue);
|
|
@@ -100,12 +113,19 @@ var StructPrimitive = class StructPrimitive {
|
|
|
100
113
|
const fieldName = tokens[0];
|
|
101
114
|
if (!(fieldName in this._schema.fields)) throw new ValidationError(`Unknown field: ${globalThis.String(fieldName)}`);
|
|
102
115
|
const fieldPrimitive = this._schema.fields[fieldName];
|
|
103
|
-
const remainingPath = path.shift();
|
|
104
|
-
const fieldOperation = _objectSpread2(_objectSpread2({}, operation), {}, { path: remainingPath });
|
|
105
116
|
const currentState = state !== null && state !== void 0 ? state : {};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
117
|
+
if (operation.kind === "struct.unset" && tokens.length === 1) {
|
|
118
|
+
if (this._isRequiredWithoutDefault(fieldPrimitive)) throw new ValidationError(`Field "${globalThis.String(fieldName)}" is required and cannot be removed`);
|
|
119
|
+
const mutableState = _objectSpread2({}, currentState);
|
|
120
|
+
delete mutableState[globalThis.String(fieldName)];
|
|
121
|
+
newState = mutableState;
|
|
122
|
+
} else {
|
|
123
|
+
const remainingPath = path.shift();
|
|
124
|
+
const fieldOperation = _objectSpread2(_objectSpread2({}, operation), {}, { path: remainingPath });
|
|
125
|
+
const currentFieldState = currentState[fieldName];
|
|
126
|
+
const newFieldState = fieldPrimitive._internal.applyOperation(currentFieldState, fieldOperation);
|
|
127
|
+
newState = _objectSpread2(_objectSpread2({}, currentState), {}, { [fieldName]: newFieldState });
|
|
128
|
+
}
|
|
109
129
|
}
|
|
110
130
|
runValidators(newState, this._schema.validators);
|
|
111
131
|
return newState;
|
|
@@ -224,6 +244,11 @@ var StructPrimitive = class StructPrimitive {
|
|
|
224
244
|
}
|
|
225
245
|
return field;
|
|
226
246
|
}
|
|
247
|
+
_isRequiredWithoutDefault(field) {
|
|
248
|
+
var _schema;
|
|
249
|
+
const fieldDefault = field._internal.getInitialState();
|
|
250
|
+
return ((_schema = field._schema) === null || _schema === void 0 ? void 0 : _schema.required) === true && fieldDefault === void 0;
|
|
251
|
+
}
|
|
227
252
|
};
|
|
228
253
|
/** Creates a new StructPrimitive with the given fields */
|
|
229
254
|
const Struct = (fields) => new StructPrimitive({
|