@raisindb/client 0.4.4 → 0.4.5

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/connection.ts","../src/utils/reconnect.ts","../src/logger.ts","../src/utils/request-tracker.ts","../src/auth.ts","../src/protocol.ts","../src/events.ts","../src/nodes.ts","../src/transactions.ts","../src/upload/file-source.ts","../src/workspace.ts","../src/sql.ts","../src/node-types.ts","../src/archetypes.ts","../src/element-types.ts","../src/branches.ts","../src/scheduler.ts","../src/tags.ts","../src/flows.ts","../src/functions-api.ts","../src/errors.ts","../src/streaming/sse-client.ts","../src/utils/chat-events.ts","../src/utils/home-path.ts","../src/conversations.ts","../src/flow-client.ts","../src/inbox.ts","../src/database.ts","../src/http-client.ts","../src/upload/types.ts","../src/upload/retry.ts","../src/upload/batch.ts","../src/upload/uploader.ts","../src/http-schema.ts","../src/mcp.ts","../src/identity-auth.ts","../src/node-builder.ts","../src/constants.ts","../src/integrations/react-router.ts","../src/types/flow.ts","../src/types/flow-definition.ts","../src/utils/plan-projection.ts","../src/stores/conversation-store.ts","../src/stores/conversation-list-store.ts","../src/integrations/react-conversation.ts","../src/integrations/svelte-conversation.ts","../src/integrations/svelte/svelte-auth.ts","../src/integrations/svelte/svelte-connection.ts","../src/integrations/svelte/svelte-sql.ts","../src/integrations/svelte/svelte-subscription.ts","../src/integrations/svelte/svelte-flow.ts","../src/integrations/svelte/svelte-context.ts","../src/integrations/react-flow.ts","../src/integrations/react/use-auth.ts","../src/integrations/react/use-connection.ts","../src/integrations/react/use-sql.ts","../src/integrations/react/use-subscription.ts","../src/integrations/react/index.ts","../src/integrations/vue/vue-auth.ts","../src/integrations/vue/vue-connection.ts","../src/integrations/vue/vue-sql.ts","../src/integrations/vue/vue-subscription.ts","../src/integrations/vue/vue-conversation.ts","../src/integrations/vue/index.ts"],"sourcesContent":["/**\n * RaisinDB JavaScript/TypeScript Client SDK\n *\n * A universal WebSocket client for RaisinDB that works in browser, Node.js, and serverless environments.\n *\n * @example\n * ```typescript\n * import { RaisinClient } from '@raisindb/client';\n *\n * const client = new RaisinClient('raisin://localhost:8080/sys/default');\n * await client.connect();\n * await client.authenticate({ username: 'admin', password: 'password' });\n *\n * const db = client.database('my_repo');\n * const ws = db.workspace('content');\n *\n * const node = await ws.nodes().create({\n * type: 'Page',\n * path: '/home',\n * properties: { title: 'Home Page' }\n * });\n * ```\n */\n\n// Main client\nexport { RaisinClient } from './client';\nexport type {\n ClientOptions,\n ClientMode,\n CurrentUser,\n UserNode,\n // Auth state change types (Firebase/Supabase-compatible)\n AuthEvent,\n AuthStateChange,\n AuthStateChangeCallback,\n UserChangeEvent,\n UserChangeCallback,\n} from './client';\n\n// HTTP client for SSR\nexport { RaisinHttpClient, HttpDatabase, HttpWorkspaceClient } from './http-client';\nexport type {\n HttpClientOptions,\n CurrentUser as HttpCurrentUser,\n UserNode as HttpUserNode,\n SignAssetOptions,\n SignedAssetUrl,\n} from './http-client';\n\n// Database and workspace\nexport { Database } from './database';\nexport type { DatabaseHttpOptions } from './database';\nexport { WorkspaceClient, WorkspaceManager } from './workspace';\nexport type { WorkspaceCreateOptions, WorkspaceUpdateOptions } from './workspace';\n\n// Node operations\nexport { NodeOperations } from './nodes';\nexport type {\n NodeCreateOptions,\n NodeCreateDeepOptions,\n NodeUpdateOptions,\n NodeQueryOptions,\n} from './nodes';\n\n// Transactions\nexport { Transaction } from './transactions';\nexport type { TransactionOptions } from './transactions';\n\n// Node builder and helpers\nexport { NodeBuilder, NodeHelpers } from './node-builder';\n\n// Management operations\nexport { NodeTypes } from './node-types';\nexport { Archetypes } from './archetypes';\nexport { ElementTypes } from './element-types';\nexport { Branches } from './branches';\nexport type {\n BranchDiff,\n BranchDivergence,\n CrossBranchCopySummary,\n CrossBranchNodeChange,\n NodeDiffInfo\n} from './branches';\nexport { Tags } from './tags';\nexport { SchedulerApi } from './scheduler';\nexport type {\n ListInvocationsFilter,\n ScheduleInvocationOptions,\n ScheduledInvocation,\n ScheduledInvocationRef,\n ScheduledInvocationTargetKind\n} from './scheduler';\n\n// HTTP (SSR) schema management\nexport { HttpNodeTypes, HttpArchetypes, HttpElementTypes } from './http-schema';\nexport type { SchemaCommit } from './http-schema';\n\n// SQL queries\nexport { SqlQuery, createSqlHandler } from './sql';\n\n// Events\nexport { EventHandler, EventSubscriptions } from './events';\nexport type { EventCallback, Subscription } from './events';\n\n// Event type constants\nexport { NodeEventType, AllNodeEventTypes } from './constants';\nexport type { NodeEventTypeValue } from './constants';\n\n// Connection\nexport { Connection, ConnectionState } from './connection';\nexport type { ConnectionOptions } from './connection';\n\n// Authentication\nexport { AuthManager, MemoryTokenStorage, LocalStorageTokenStorage } from './auth';\nexport type {\n Credentials,\n TokenStorage,\n IdentityUser,\n IdentityAuthResponse,\n IdentityAuthError,\n} from './auth';\n\n// Protocol types\nexport type {\n RequestEnvelope,\n ResponseEnvelope,\n EventMessage,\n NodeEventPayload,\n RequestContext,\n ErrorInfo,\n ResponseMetadata,\n Node,\n RelationRef,\n IncomingRelation,\n NodeRelationships,\n PropertyValue,\n NodeCreatePayload,\n NodeCreateDeepPayload,\n NodeUpdatePayload,\n NodeDeletePayload,\n NodeGetPayload,\n NodeHistoryPayload,\n RevisionEntry,\n AuditQueryPayload,\n AuditLogEntry,\n NodeQueryPayload,\n RelationAddPayload,\n RelationRemovePayload,\n RelationsGetPayload,\n SqlQueryPayload,\n SqlResult,\n Workspace,\n WorkspaceCreatePayload,\n WorkspaceGetPayload,\n WorkspaceDeletePayload,\n WorkspaceUpdatePayload,\n SubscribePayload,\n SubscriptionFilters,\n UnsubscribePayload,\n SubscriptionResponse,\n AuthenticatePayload,\n AuthenticateResponse,\n RefreshTokenPayload,\n TransactionBeginPayload,\n TransactionBeginResponse,\n TransactionCommitPayload,\n TransactionCommitResponse,\n TransactionRollbackPayload,\n} from './protocol';\n\nexport {\n RequestType,\n ResponseStatus,\n encodeMessage,\n decodeMessage,\n isEventMessage,\n isResponseEnvelope,\n} from './protocol';\n\n// Utilities\nexport { RequestTracker } from './utils/request-tracker';\nexport type { RequestTrackerOptions } from './utils/request-tracker';\nexport { ReconnectManager } from './utils/reconnect';\nexport type { ReconnectOptions } from './utils/reconnect';\nexport { normalizeHomePath } from './utils/home-path';\n\n// Logger\nexport { LogLevel, logger, configureLogger, setLogLevel, getLogLevel, getLoggerConfig } from './logger';\nexport type { LoggerConfig } from './logger';\n\n// React Router 7 integration\nexport {\n createSSRClient,\n createLoader,\n createRequestScopedClient,\n rowsToObjects,\n getErrorMessage,\n isHttpClient,\n isWebSocketClient,\n} from './integrations/react-router';\nexport type {\n SSRClientConfig,\n HybridClient,\n} from './integrations/react-router';\n\n// Upload module\nexport type {\n UploadStatus,\n UploadOptions,\n UploadProgress,\n UploadResult,\n Upload,\n CreateUploadRequest,\n CreateUploadResponse,\n ChunkUploadResponse,\n UploadStatusResponse,\n CompleteUploadRequest,\n CompleteUploadResponse,\n RetryOptions,\n FileSource,\n RetryContext,\n RetryCallback,\n UploaderConfig,\n // Batch upload types\n BatchFileProgress,\n BatchProgress,\n BatchUploadResult,\n BatchUploadOptions,\n BatchUpload,\n} from './upload';\nexport {\n UploadError,\n UploadErrorCode,\n DEFAULT_CHUNK_SIZE,\n DEFAULT_MAX_RETRIES,\n DEFAULT_RETRY_BASE_DELAY,\n DEFAULT_RETRY_MAX_DELAY,\n DEFAULT_NODE_TYPE,\n DEFAULT_BRANCH,\n DEFAULT_BATCH_CONCURRENCY,\n BrowserFileSource,\n NodeFileSource,\n createFileSource,\n getContentType,\n calculateChunkCount,\n getChunkRange,\n DEFAULT_RETRY_OPTIONS,\n calculateDelay,\n sleep,\n isRetryableError,\n withRetry,\n RetryBuilder,\n classifyError,\n Uploader,\n UploadManager,\n BatchUploader,\n} from './upload';\n\n// Errors\nexport {\n RaisinError,\n RaisinConnectionError,\n RaisinAuthError,\n RaisinFlowError,\n RaisinTimeoutError,\n RaisinAbortError,\n} from './errors';\nexport type {\n RaisinErrorCode,\n ConnectionErrorCode,\n AuthErrorCode,\n FlowErrorCode,\n TimeoutErrorCode,\n AbortErrorCode,\n} from './errors';\n\n// Flow execution\nexport { FlowClient } from './flow-client';\nexport type { FlowClientOptions, FlowRunResult, FlowCollectResult } from './flow-client';\n\n// Function invocation\nexport { FunctionsApi, HttpFunctionsApi } from './functions-api';\nexport { IdentityAuthApi, readTokensFromFragment } from './identity-auth';\nexport type {\n IdentityAuthResult,\n IdentityAuthTransport,\n IdentityInfo,\n IdentityMe,\n MagicLinkSent,\n MagicLinkOptions,\n AuthProviders,\n} from './identity-auth';\nexport type {\n FunctionInvokeOptions,\n FunctionInvokeResponse,\n FunctionInvokeSyncResponse\n} from './functions-api';\n\n// MCP client (talk to a raisin:McpServer over JSON-RPC)\nexport { McpClient } from './mcp';\nexport type {\n McpTransport,\n McpFrameStream,\n McpJsonRpcFrame,\n McpToolDescriptor,\n McpContentBlock,\n McpCallToolResult,\n McpResourceContents,\n McpReadResourceResult,\n McpResourceUpdate,\n McpResourceSubscription,\n} from './mcp';\n\n// Flow execution (WebSocket)\nexport { FlowsApi } from './flows';\nexport type {\n FlowRunResponse,\n FlowInstanceStatus,\n FlowInstanceStatusResponse,\n FlowExecutionEvent,\n StepStartedEvent,\n StepCompletedEvent,\n StepFailedEvent,\n FlowWaitingEvent,\n FlowResumedEvent,\n FlowCompletedEvent,\n FlowFailedEvent,\n TextChunkEvent,\n ToolCallStartedEvent,\n ToolCallCompletedEvent,\n ThoughtChunkEvent,\n ConversationCreatedEvent,\n MessageSavedEvent,\n LogEvent,\n} from './types/flow';\nexport { isTerminalEvent } from './types/flow';\n\n// Workflow definition types (canonical, shared with the flow designer)\nexport type {\n RaisinReference,\n ContainerType,\n StepErrorBehavior,\n FlowErrorStrategy,\n RetryConfig,\n RetryStrategy,\n HumanTaskType,\n CanonicalTaskType,\n TaskOption,\n HandoffTarget,\n ChatTerminationMode,\n ChatTerminationConfig,\n ChatStepConfig,\n AiToolMode,\n AiErrorBehavior,\n AiContainerConfig,\n FlowDefinitionNodeBase,\n FlowStepProperties,\n FlowDefinitionStep,\n ContainerRule,\n FanOutConfig,\n MergeStrategy,\n FlowDefinitionContainer,\n FlowDefinitionNode,\n FlowDefinition,\n InboxTask,\n InboxTaskStatus,\n TaskCompletionResult,\n} from './types/flow-definition';\nexport {\n RETRY_STRATEGIES,\n getRefDisplayName,\n getRefPath,\n isFlowDefinitionStep,\n isFlowDefinitionContainer,\n} from './types/flow-definition';\n\n// Inbox tasks (human-in-the-loop)\nexport { InboxApi } from './inbox';\nexport type {\n InboxApiOptions,\n ListTasksOptions,\n ListTasksResponse,\n} from './inbox';\n\n// Chat types\nexport type {\n ChatMessage,\n ChatEvent,\n Conversation,\n ConversationType,\n ConversationListItem,\n ConversationStatus,\n MessageBody,\n ChatTextChunkEvent,\n ChatAssistantMessageEvent,\n ChatWaitingEvent,\n ChatCompletedEvent,\n ChatFailedEvent,\n ChatDoneEvent,\n ChatToolCallStartedEvent,\n ChatToolCallCompletedEvent,\n ChatThoughtChunkEvent,\n ToolCallRecord,\n MessageChild,\n PlanTask,\n ChatConversationCreatedEvent,\n ChatMessageSavedEvent,\n ChatMessageDeliveredEvent,\n ChatLogEvent,\n} from './types/chat';\n\n// Conversation management (unified API)\nexport { ConversationManager, DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS } from './conversations';\nexport type {\n ListConversationsOptions,\n CreateConversationOptions as CreateConvoOptions,\n SendMessageOptions,\n ConversationSubscription,\n PlanActionReceipt,\n PlanActionOptions,\n ConversationManagerOptions,\n} from './conversations';\n\n// Conversation stores (framework-agnostic)\nexport { ConversationStore } from './stores/conversation-store';\nexport type {\n ConversationStoreSnapshot,\n ConversationStoreOptions,\n ToolCallInfo,\n} from './stores/conversation-store';\nexport { ConversationListStore } from './stores/conversation-list-store';\nexport type {\n ConversationListSnapshot,\n ConversationListStoreOptions,\n} from './stores/conversation-list-store';\n\n// Plan projection utility\nexport { projectPlansFromMessages } from './utils/plan-projection';\nexport type { PlanProjection, PlanProjectionTask } from './utils/plan-projection';\n\n// React conversation adapters\nexport { useConversation, useConversationList } from './integrations/react-conversation';\nexport type {\n ReactLike,\n UseConversationReturn,\n UseConversationListReturn,\n} from './integrations/react-conversation';\n\n// Svelte 5 conversation adapters (legacy path — prefer @raisindb/client/svelte)\nexport { createConversationAdapter, createConversationListAdapter } from './integrations/svelte-conversation';\n\n// Svelte 5 integration (full)\nexport {\n createAuthAdapter,\n createConnectionAdapter,\n createSqlAdapter,\n createSubscriptionAdapter,\n createFlowAdapter,\n RAISIN_CONTEXT_KEY,\n} from './integrations/svelte';\nexport type {\n AuthSnapshot,\n AuthAdapter,\n ConnectionSnapshot,\n ConnectionAdapter,\n SqlAdapterOptions,\n SqlSnapshot,\n SqlAdapter,\n SubscriptionAdapter,\n FlowSnapshot,\n FlowAdapterOptions,\n FlowAdapter,\n FlowStatus as SvelteFlowStatus,\n RaisinContext,\n} from './integrations/svelte';\n\n// React flow adapter\nexport { useFlow } from './integrations/react-flow';\nexport type {\n UseFlowOptions,\n UseFlowReturn,\n FlowStatus,\n} from './integrations/react-flow';\n\n// React integration (Provider + hooks factory)\nexport { createRaisinReact } from './integrations/react';\nexport type {\n RaisinReact,\n ReactLikeWithContext,\n RaisinProviderProps,\n RaisinContextValue,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlOptions,\n UseSqlReturn,\n UseSubscriptionOptions,\n} from './integrations/react';\n\n// Vue 3 integration (composables factory — also available as @raisindb/client/vue)\nexport { createRaisinVue } from './integrations/vue';\nexport type {\n RaisinVue,\n VueLike,\n VueRef,\n VueComputedRef,\n} from './integrations/vue';\n\n// Streaming (SSE)\nexport { SSEClient } from './streaming/sse-client';\nexport type {\n SSEEvent,\n SSEClientOptions,\n SSEConnectionState,\n SSEStateCallback,\n} from './streaming/sse-client';\n","/**\n * RaisinDB WebSocket client\n */\n\nimport { EventEmitter } from 'events';\nimport { Connection, ConnectionState, ConnectionOptions } from './connection';\nimport { RequestTracker } from './utils/request-tracker';\nimport {\n AuthManager,\n Credentials,\n AdminCredentials,\n isJwtCredentials,\n TokenStorage,\n LocalStorageTokenStorage,\n IdentityUser,\n IdentityAuthResponse,\n} from './auth';\nimport { EventHandler } from './events';\nimport { Database } from './database';\nimport {\n RequestEnvelope,\n ResponseEnvelope,\n RequestContext,\n RequestType,\n ResponseStatus,\n AuthenticatePayload,\n AuthenticateResponse,\n AuthenticateJwtPayload,\n AuthenticateJwtResponse,\n ConnectedMessage,\n encodeMessage,\n decodeMessage,\n isEventMessage,\n isResponseEnvelope,\n isConnectedMessage,\n} from './protocol';\nimport { RaisinHttpClient, HttpClientOptions, SignAssetOptions, SignedAssetUrl } from './http-client';\nimport { RaisinAuthError, RaisinTimeoutError } from './errors';\nimport { logger, LogLevel, setLogLevel } from './logger';\nimport { normalizeHomePath } from './utils/home-path';\nimport type { Upload, UploadOptions, BatchUpload, BatchUploadOptions } from './upload/types';\nimport { createFileSource } from './upload/file-source';\nimport { UploadManager } from './upload/uploader';\n\n/**\n * Client mode\n */\nexport type ClientMode = 'websocket' | 'http' | 'hybrid';\n\n// ============================================================================\n// Auth State Change Types (Firebase/Supabase-compatible pattern)\n// ============================================================================\n\n/**\n * Auth event types emitted by onAuthStateChange\n */\nexport type AuthEvent =\n | 'SIGNED_IN'\n | 'SIGNED_OUT'\n | 'TOKEN_REFRESHED'\n | 'SESSION_EXPIRED'\n | 'USER_UPDATED';\n\n/**\n * Auth state change payload\n */\nexport interface AuthStateChange {\n /** The auth event that occurred */\n event: AuthEvent;\n /** Current session state */\n session: {\n /** Current identity user or null if signed out */\n user: IdentityUser | null;\n /** Current access token or null if signed out */\n accessToken: string | null;\n /**\n * Current EFFECTIVE roles (direct + group + inherited) for the connected\n * user, or null/undefined when signed out. Populated from the WS auth\n * handshake so role-gated consumers can read roles from the event without a\n * separate call. Updated on SIGNED_IN, USER_UPDATED (incl. after a\n * server-pushed permission change), and reconnect.\n */\n roles?: string[] | null;\n };\n}\n\n/**\n * Callback for auth state changes\n */\nexport type AuthStateChangeCallback = (change: AuthStateChange) => void;\n\n/**\n * User change event payload (for user home node updates)\n */\nexport interface UserChangeEvent {\n /** The user's home node with updated data */\n node: UserNode;\n /** Type of change (e.g., 'node:updated') */\n changeType: string;\n}\n\n/**\n * Callback for user home node changes\n */\nexport type UserChangeCallback = (event: UserChangeEvent) => void;\n\n/**\n * Client options\n */\nexport interface ClientOptions {\n /** Connection options */\n connection?: ConnectionOptions;\n /** Token storage (default: in-memory) */\n tokenStorage?: TokenStorage;\n /** Request timeout in milliseconds (default: 30000) */\n requestTimeout?: number;\n /** Tenant ID (extracted from URL if not provided; default: \"default\") */\n tenantId?: string;\n /**\n * Repository name. When the URL has no path (e.g. `ws://host:8081`),\n * the client connects to the tenant-less `/ws/{repository}` route.\n * When the URL already carries a path, this overrides the repository\n * extracted from the URL (used for repo-scoped auth endpoints).\n */\n repository?: string;\n /** Default branch (default: \"main\") */\n defaultBranch?: string;\n /** Client mode (default: \"websocket\") */\n mode?: ClientMode;\n /** Log level (default: Info - minimal logging) */\n logLevel?: LogLevel;\n /** HTTP base URL for identity auth (derived from WS URL if not provided) */\n httpBaseUrl?: string;\n}\n\n/**\n * RaisinDB client\n */\n/**\n * Current user info\n */\nexport interface CurrentUser {\n /** User ID (identity UUID) */\n userId: string;\n /** Roles assigned to the user */\n roles?: string[];\n /** Whether this is an anonymous user */\n anonymous: boolean;\n /** The full user node from the repository (from CURRENT_USER()) */\n node?: UserNode;\n}\n\n/**\n * User node from the repository\n */\nexport interface UserNode {\n /** Node ID */\n id: string;\n /** Node path (e.g., '/users/internal/john-at-example-com') */\n path: string;\n /** Node name */\n name: string;\n /** Node type (e.g., 'raisin:User') */\n node_type: string;\n /** Node properties */\n properties: Record<string, unknown>;\n}\n\nexport class RaisinClient extends EventEmitter {\n private connection: Connection;\n private requestTracker: RequestTracker;\n private authManager: AuthManager;\n private eventHandler: EventHandler;\n private _context: RequestContext;\n private options: Required<Omit<ClientOptions, 'connection' | 'tokenStorage' | 'mode' | 'logLevel' | 'httpBaseUrl' | 'repository'>>;\n private _currentUser: CurrentUser | null = null;\n /** In-flight role re-resolve, used to coalesce concurrent refreshCurrentUser() calls. */\n #refreshingUser: Promise<void> | null = null;\n private _httpBaseUrl: string;\n private _repository: string;\n\n // Auth state change listeners (Firebase/Supabase pattern)\n private _authListeners: Set<AuthStateChangeCallback> = new Set();\n private _userChangeListeners: Set<UserChangeCallback> = new Set();\n private _userHomeSubscription: { unsubscribe: () => Promise<void> } | null = null;\n\n // Ready state: connected AND (authenticated OR no stored token)\n private _ready: boolean = false;\n private _readyListeners: Set<(ready: boolean) => void> = new Set();\n\n // Reconnection tracking\n private _previousConnectionState: ConnectionState = ConnectionState.Disconnected;\n private _reconnectedListeners: Set<() => void> = new Set();\n private _everConnected = false;\n\n // Requests queued while the connection is re-establishing.\n // Flushed after reconnect + re-auth; bounded by MAX_QUEUED_REQUESTS.\n private _queuedRequests: Array<{ requestId: string; encoded: Uint8Array }> = [];\n /** Hard cap on requests held while reconnecting; overflow rejects immediately. */\n private static readonly MAX_QUEUED_REQUESTS = 100;\n\n /**\n * Backoff delays (ms) between subscription-restore retries after reconnect.\n * @internal - overridable in tests\n */\n private _restoreRetryDelaysMs: number[] = [1000, 3000, 9000];\n\n // Upload manager (uses HTTP under the hood)\n private _uploadManager: UploadManager | null = null;\n\n constructor(url: string, options: ClientOptions = {}) {\n super();\n\n // Configure log level if provided\n if (options.logLevel !== undefined) {\n setLogLevel(options.logLevel);\n }\n\n // When a repository option is given and the URL has no path, build the\n // tenant-less /ws/{repository} URL internally.\n const connectionUrl = this.buildConnectionUrl(url, options.repository);\n\n this.options = {\n requestTimeout: options.requestTimeout ?? 30000,\n tenantId: options.tenantId ?? this.extractTenantFromUrl(connectionUrl),\n defaultBranch: options.defaultBranch ?? 'main',\n };\n\n // Derive HTTP base URL from WebSocket URL if not provided\n this._httpBaseUrl = options.httpBaseUrl ?? this.deriveHttpUrl(connectionUrl);\n\n // Extract repository from URL for repo-scoped auth endpoints\n this._repository = options.repository ?? this.extractRepositoryFromUrl(connectionUrl);\n\n // Initialize context\n this._context = {\n tenant_id: this.options.tenantId,\n branch: this.options.defaultBranch,\n };\n\n // Send the tenant on the WebSocket upgrade request so tenant-less /ws\n // URLs resolve to the right tenant - but ONLY when the caller explicitly\n // provided one (or the URL carries one). Header ABSENCE is the protocol's\n // \"use your default resolution\" signal; always asserting 'default' would\n // fight proxies that inject the real tenant header. Only effective where\n // the WebSocket implementation supports custom headers (Node.js `ws`);\n // browsers ignore it and rely on the server-side resolution.\n const explicitTenant =\n options.tenantId ?? (this.extractTenantFromUrl(url) !== 'default' ? this.options.tenantId : undefined);\n const connectionOptions: ConnectionOptions = {\n ...options.connection,\n headers: {\n ...(explicitTenant ? { 'x-tenant-id': explicitTenant } : {}),\n ...options.connection?.headers,\n },\n };\n\n // Initialize components\n this.connection = this.createConnection(connectionUrl, connectionOptions);\n this.requestTracker = new RequestTracker({\n defaultTimeout: this.options.requestTimeout,\n });\n this.authManager = new AuthManager(options.tokenStorage);\n this.eventHandler = new EventHandler((payload, requestType) =>\n this.sendRequestInternal(payload, requestType)\n );\n\n // Set up event handlers\n this.setupConnectionHandlers();\n }\n\n /**\n * Create the underlying WebSocket connection.\n * Seam for tests to inject a fake connection.\n * @internal\n */\n protected createConnection(url: string, options?: ConnectionOptions): Connection {\n return new Connection(url, options);\n }\n\n /**\n * Derive HTTP URL from WebSocket URL\n * ws://host:port/path -> http://host:port\n * wss://host:port/path -> https://host:port\n */\n private deriveHttpUrl(wsUrl: string): string {\n try {\n const url = wsUrl\n .replace(/^raisin:\\/\\//, 'ws://')\n .replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(url);\n const protocol = parsed.protocol === 'wss:' ? 'https:' : 'http:';\n return `${protocol}//${parsed.host}`;\n } catch {\n return 'http://localhost:8081';\n }\n }\n\n /**\n * Build the WebSocket connection URL.\n *\n * When a repository option is provided and the URL carries no path\n * (e.g. `ws://host:8081`), build the tenant-less `/ws/{repository}`\n * route internally. URLs that already carry a path are used as-is.\n */\n private buildConnectionUrl(url: string, repository?: string): string {\n if (!repository) {\n return url;\n }\n try {\n const wsUrl = url.replace(/^raisin:\\/\\//, 'ws://').replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(wsUrl);\n const hasPath = parsed.pathname.split('/').some((p) => p.length > 0);\n if (hasPath) {\n return url;\n }\n return `${url.replace(/\\/+$/, '')}/ws/${repository}`;\n } catch {\n return url;\n }\n }\n\n /**\n * Extract repository from URL\n * URL forms: /ws/{repo} (tenant-less, preferred), /sys/{tenant}/{repo}\n * (operator/multi-tenant), /{tenant}/{repo} (legacy).\n */\n private extractRepositoryFromUrl(url: string): string {\n try {\n const wsUrl = url.replace(/^raisin:\\/\\//, 'ws://').replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(wsUrl);\n const parts = parsed.pathname.split('/').filter((p) => p.length > 0);\n if (parts[0] === 'ws') {\n // /ws/{repo}\n return parts.length > 1 ? parts[1] : '';\n }\n if (parts[0] === 'sys') {\n // /sys/{tenant}/{repo}\n return parts.length > 2 ? parts[2] : '';\n }\n // Legacy /{tenant}/{repo}\n return parts.length > 1 ? parts[1] : '';\n } catch {\n return '';\n }\n }\n\n /**\n * Extract tenant ID from URL\n * URL forms: /ws/{repo} (tenant-less — no tenant in URL),\n * /sys/{tenant}/{repo} (canonical), /{tenant}/{repo} (legacy).\n * When the URL doesn't carry a tenant, fall back to 'default' — the\n * server's tenant middleware resolves it anyway (production derives the\n * tenant from the request itself), so an explicit tenantId is optional.\n */\n private extractTenantFromUrl(url: string): string {\n try {\n // Convert raisin:// to ws:// for URL parsing\n const wsUrl = url.replace(/^raisin:\\/\\//, 'ws://').replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(wsUrl);\n const parts = parsed.pathname.split('/').filter((p) => p.length > 0);\n if (parts[0] === 'ws') {\n // Tenant-less route: the server resolves the tenant from the\n // upgrade request (x-tenant-id header, falling back to 'default').\n return 'default';\n }\n if (parts[0] === 'sys') {\n return parts.length > 1 ? parts[1] : 'default';\n }\n return parts.length >= 2 ? parts[0] : 'default';\n } catch (error) {\n return 'default';\n }\n }\n\n /**\n * Set up connection event handlers\n */\n private setupConnectionHandlers(): void {\n this.connection.on('message', (data: ArrayBuffer) => {\n this.handleMessage(data);\n });\n\n this.connection.on('stateChange', (state: ConnectionState) => {\n const wasDisconnected =\n this._previousConnectionState === ConnectionState.Disconnected ||\n this._previousConnectionState === ConnectionState.Reconnecting;\n\n if (state === ConnectionState.Connected) {\n this._everConnected = true;\n }\n\n if (state === ConnectionState.Disconnected || state === ConnectionState.Closed) {\n // The connection is down for good (manual close, max reconnect\n // attempts reached, ...): cancel all pending requests, including\n // any held in the reconnect queue.\n this._queuedRequests = [];\n this.requestTracker.cancelAll();\n }\n\n // Handle reconnection: restore subscriptions after connection is re-established\n // Note: handleConnectedMessage() handles re-auth, then we restore subscriptions\n if (state === ConnectionState.Connected && wasDisconnected && this._previousConnectionState !== ConnectionState.Disconnected) {\n // This is a reconnection (not initial connection)\n // Subscription restoration happens after auth in handleConnectedMessage\n logger.info('[setupConnectionHandlers] Reconnection detected, will restore subscriptions after auth');\n }\n\n this._previousConnectionState = state;\n\n // Update ready state on all connection changes\n this._updateReadyState();\n });\n\n this.connection.on('error', (error: Error) => {\n logger.error('Connection error:', error);\n });\n }\n\n /**\n * Handle incoming message\n */\n private handleMessage(data: ArrayBuffer): void {\n logger.debug(`handleMessage() called - data size: ${data.byteLength} bytes`);\n try {\n logger.debug(`Attempting to decode MessagePack message...`);\n const message = decodeMessage(data);\n logger.debug(`Successfully decoded message`);\n logger.debug(`Message keys:`, Object.keys(message));\n logger.debug(`Message structure:`, JSON.stringify(message, null, 2));\n logger.debug(`Type check: isEvent=${isEventMessage(message)}, isResponse=${isResponseEnvelope(message)}, isConnected=${isConnectedMessage(message)}`);\n logger.debug(`Has 'status' property:`, 'status' in message);\n logger.debug(`Has 'subscription_id' property:`, 'subscription_id' in message);\n logger.debug(`Status value:`, (message as any).status);\n\n if (isConnectedMessage(message)) {\n // Handle connected message from server\n this.handleConnectedMessage(message);\n } else if (isEventMessage(message)) {\n // Out-of-band \"your permissions may have changed\" push (reserved\n // subscription id / event type, sent by the server after an\n // access-control write). Re-resolve roles instead of routing it to a\n // normal subscription callback. Keep in sync with the server\n // (raisin-transport-ws event_handler PERMISSIONS_EVENT_TYPE).\n if ((message as { event_type?: string }).event_type === 'permissions:changed') {\n logger.info('[permissions:changed] server signaled a role/permission change; re-resolving');\n void this.refreshCurrentUser();\n } else {\n // Handle event message\n logger.debug(`Routing to event handler`);\n this.eventHandler.handleEvent(message);\n }\n } else if (isResponseEnvelope(message)) {\n // Handle response message\n logger.debug(`Routing to response handler - request_id: ${(message as any).request_id}, status: ${(message as any).status}`);\n this.handleResponse(message);\n } else {\n logger.warn(`Unknown message type - not event or response`);\n }\n } catch (error) {\n logger.error('Error decoding message:', error);\n logger.error('Message data (first 100 bytes):', new Uint8Array(data.slice(0, 100)));\n }\n }\n\n /**\n * Handle connected message from server\n * Stores current user info for anonymous users\n *\n * NOTE: We do NOT store the anonymous token here because it would overwrite\n * any existing user JWT in localStorage. The anonymous token is only needed\n * for HTTP API calls when there's no existing session.\n */\n private handleConnectedMessage(message: ConnectedMessage): void {\n logger.info(`Connected to server - connection_id: ${message.connection_id}, anonymous: ${message.anonymous}`);\n\n // Check if this is a reconnection (we had subscriptions before)\n const hasActiveSubscriptions = this.eventHandler.getActiveSubscriptions().length > 0 ||\n this.eventHandler.hasStoredFilters();\n\n // Store current user info for anonymous users (but don't overwrite stored tokens!)\n if (message.anonymous && message.user_id) {\n // Only set anonymous user if we don't already have a stored token\n // (otherwise we're about to authenticate with the stored token)\n const hasStoredToken = this.authManager.storage.getAccessToken() !== null;\n if (!hasStoredToken) {\n this._currentUser = {\n userId: message.user_id,\n anonymous: true,\n // Anonymous users don't have a node in the repository\n };\n logger.debug(`Anonymous user info stored: ${message.user_id}`);\n // Anonymous user is ready immediately\n this._updateReadyState();\n this._flushQueuedRequests();\n\n // Restore subscriptions for anonymous users on reconnect\n if (hasActiveSubscriptions) {\n this._restoreSubscriptionsAndNotify();\n }\n } else {\n // Auto-authenticate with stored token on reconnect\n logger.info(`[handleConnectedMessage] Stored token found, auto-authenticating...`);\n this.autoReauthenticate()\n .then(async (authenticated) => {\n if (authenticated) {\n // After successful re-auth, deliver requests queued while down\n this._flushQueuedRequests();\n } else {\n this._rejectQueuedRequests(\n new RaisinAuthError(\n 'Re-authentication failed after reconnect',\n 'AUTH_TOKEN_EXPIRED',\n 401\n )\n );\n }\n // Restore subscriptions regardless (they may be readable anonymously)\n if (hasActiveSubscriptions) {\n await this._restoreSubscriptionsAndNotify();\n }\n })\n .catch((err) => {\n logger.error(`[handleConnectedMessage] Auto-authenticate failed:`, err);\n this._rejectQueuedRequests(\n err instanceof Error ? err : new Error('Re-authentication failed after reconnect')\n );\n });\n }\n } else {\n // Non-anonymous connection message: nothing to re-authenticate here\n this._flushQueuedRequests();\n }\n\n // Emit connected event\n this.emit('connected', {\n connectionId: message.connection_id,\n anonymous: message.anonymous,\n userId: message.user_id,\n });\n }\n\n /**\n * Restore subscriptions after reconnection and notify listeners.\n *\n * Retries with backoff (see `_restoreRetryDelaysMs`); on final failure a\n * `subscription_restore_failed` event is emitted so applications can\n * resync their state (e.g. reload lists and re-subscribe manually).\n * @internal\n */\n private async _restoreSubscriptionsAndNotify(): Promise<void> {\n const delays = this._restoreRetryDelaysMs;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n try {\n logger.info(\n `[_restoreSubscriptionsAndNotify] Restoring subscriptions (attempt ${attempt + 1}/${delays.length + 1})...`\n );\n await this.eventHandler.restoreSubscriptions({ retry: attempt > 0 });\n logger.info('[_restoreSubscriptionsAndNotify] Subscriptions restored successfully');\n\n // Notify reconnected listeners\n this._emitReconnected();\n return;\n } catch (error) {\n lastError = error;\n logger.error(\n `[_restoreSubscriptionsAndNotify] Restore attempt ${attempt + 1} failed:`,\n error\n );\n if (attempt < delays.length) {\n await new Promise((resolve) => setTimeout(resolve, delays[attempt]));\n }\n }\n }\n\n logger.error('[_restoreSubscriptionsAndNotify] Giving up after retries; events may be stale');\n this.emit(\n 'subscription_restore_failed',\n lastError instanceof Error ? lastError : new Error(String(lastError))\n );\n }\n\n /**\n * Emit reconnected event to all listeners\n * @internal\n */\n private _emitReconnected(): void {\n logger.info('[_emitReconnected] Emitting reconnected event');\n for (const callback of this._reconnectedListeners) {\n try {\n callback();\n } catch (err) {\n logger.error('[_emitReconnected] Listener error:', err);\n }\n }\n this.emit('reconnected');\n }\n\n /**\n * Auto-reauthenticate with stored JWT on reconnection\n *\n * @returns true if the session was re-authenticated, false otherwise\n * @internal\n */\n private async autoReauthenticate(): Promise<boolean> {\n const token = this.authManager.storage.getAccessToken();\n if (!token) {\n logger.warn('[autoReauthenticate] No stored token');\n return false;\n }\n\n // Check if token is expired\n const payload = AuthManager.parseToken(token);\n if (payload?.exp && typeof payload.exp === 'number') {\n if (payload.exp * 1000 < Date.now()) {\n logger.warn('[autoReauthenticate] Token expired, attempting refresh...');\n const refreshed = await this.refreshToken();\n if (!refreshed) {\n logger.error('[autoReauthenticate] Token refresh failed, clearing session');\n this.authManager.clear();\n this._currentUser = null;\n this._emitAuthEvent('SESSION_EXPIRED');\n return false;\n }\n // Use the new token\n const newToken = this.authManager.storage.getAccessToken();\n if (newToken) {\n await this.authenticate({ type: 'jwt', token: newToken });\n return true;\n }\n return false;\n }\n }\n\n // Authenticate with the stored token\n try {\n await this.authenticate({ type: 'jwt', token });\n logger.info('[autoReauthenticate] Successfully re-authenticated');\n return true;\n } catch (err) {\n logger.error('[autoReauthenticate] Failed to authenticate:', err);\n // Try to refresh token\n const refreshed = await this.refreshToken();\n if (refreshed) {\n const newToken = this.authManager.storage.getAccessToken();\n if (newToken) {\n await this.authenticate({ type: 'jwt', token: newToken });\n return true;\n }\n return false;\n } else {\n this.authManager.clear();\n this._currentUser = null;\n this._emitAuthEvent('SESSION_EXPIRED');\n return false;\n }\n }\n }\n\n /**\n * Handle response message\n */\n private handleResponse(response: ResponseEnvelope): void {\n const requestId = response.request_id;\n logger.debug(`handleResponse() called - request_id: ${requestId}, status: ${response.status}`);\n\n if (response.status === ResponseStatus.Success || response.status === ResponseStatus.Complete) {\n logger.debug(`Resolving request ${requestId} with success result`);\n this.requestTracker.resolveRequest(requestId, response.result);\n logger.debug(`Request ${requestId} resolved successfully`);\n } else if (response.status === ResponseStatus.Error) {\n logger.debug(`Rejecting request ${requestId} with error: ${response.error?.message}`);\n const error = new Error(\n response.error?.message ?? 'Unknown error'\n );\n (error as any).code = response.error?.code;\n (error as any).details = response.error?.details;\n this.requestTracker.rejectRequest(requestId, error);\n logger.debug(`Request ${requestId} rejected with error`);\n } else if (response.status === ResponseStatus.Streaming) {\n // Handle streaming responses (could be enhanced later)\n // For now, just resolve with the current chunk\n logger.debug(`Resolving streaming response for request ${requestId}`);\n this.requestTracker.resolveRequest(requestId, response.result);\n } else if (response.status === ResponseStatus.Acknowledged) {\n // Request acknowledged, continue waiting\n logger.debug(`Request ${requestId} acknowledged, waiting for completion`);\n } else {\n logger.warn(`Unknown response status: ${response.status} for request ${requestId}`);\n }\n }\n\n /**\n * Connect to the server\n */\n async connect(): Promise<void> {\n await this.connection.connect();\n }\n\n /**\n * Authenticate with credentials\n *\n * Supports two authentication modes:\n * - Admin auth: { username: string, password: string }\n * - JWT auth: { type: 'jwt', token: string }\n *\n * @param credentials - User credentials\n */\n async authenticate(credentials: Credentials): Promise<void> {\n if (isJwtCredentials(credentials)) {\n // JWT authentication for identity users\n logger.info('[authenticate] Starting JWT authentication...');\n const payload: AuthenticateJwtPayload = { token: credentials.token };\n const response = await this.sendRequestInternal(\n payload,\n RequestType.AuthenticateJwt\n ) as AuthenticateJwtResponse;\n\n // Store current user info from auth response\n // Note: User node can be fetched separately via fetchUserNode() if needed\n this._currentUser = {\n userId: response.user_id,\n roles: response.roles,\n anonymous: false,\n };\n logger.info(`[authenticate] JWT auth successful: user_id=${response.user_id}, roles=${JSON.stringify(response.roles)}`);\n\n // Emit authenticated event with JWT response\n this.emit('authenticated', response);\n } else {\n // Admin authentication with username/password\n const payload: AuthenticatePayload = AuthManager.createAuthPayload(credentials as AdminCredentials);\n const response = await this.sendRequestInternal(\n payload,\n RequestType.Authenticate\n ) as AuthenticateResponse;\n\n this.authManager.setTokens(response);\n\n // For admin auth, we don't have user_id in response, use 'admin' as placeholder\n this._currentUser = {\n userId: 'admin',\n anonymous: false,\n // Admin users don't have a node in the repository\n };\n\n // Emit authenticated event\n this.emit('authenticated', response);\n }\n }\n\n /**\n * Disconnect from the server\n */\n disconnect(): void {\n this.connection.disconnect();\n this.requestTracker.clear();\n this.eventHandler.clearAll();\n this.eventHandler.destroy();\n this.authManager.clear();\n this._currentUser = null;\n }\n\n // ============================================================================\n // Identity Authentication (Email/Password via HTTP)\n // ============================================================================\n\n /**\n * Login with email and password (identity auth)\n *\n * This uses HTTP /auth/{repo}/login endpoint, stores tokens, connects WebSocket,\n * authenticates the WebSocket, and fetches the user node via SQL.\n *\n * @param email - User's email address\n * @param password - User's password\n * @param repository - Repository name (used for auth endpoint)\n * @returns The authenticated user info\n *\n * @example\n * ```typescript\n * const client = new RaisinClient('ws://localhost:8081/sys/default/myrepo');\n * const user = await client.loginWithEmail('user@example.com', 'password', 'myrepo');\n * console.log('Logged in as:', user.email, 'home:', user.home);\n * ```\n */\n async loginWithEmail(\n email: string,\n password: string,\n repository: string\n ): Promise<IdentityUser> {\n logger.info('[loginWithEmail] Starting login...');\n\n // Override _repository with the explicitly provided value (URL extraction\n // can return the wrong segment for 3-segment paths like /sys/default/repo)\n if (repository) {\n this._repository = repository;\n }\n\n // 1. Call HTTP login endpoint\n const url = `${this._httpBaseUrl}/auth/${repository}/login`;\n logger.debug('[loginWithEmail] POST', url);\n\n const response = await this._fetchWithTimeout(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }));\n // Real Error instance; keeps `{ code, message }` fields for\n // backwards-compatible destructuring (IdentityAuthError shape).\n throw new RaisinAuthError(\n error.message || 'Login failed',\n error.code || 'LOGIN_FAILED',\n response.status\n );\n }\n\n const tokens: IdentityAuthResponse = await response.json();\n logger.info('[loginWithEmail] HTTP login successful, user_id:', tokens.identity.id);\n\n // 2. Store tokens\n this.authManager.storage.setAccessToken(tokens.access_token);\n this.authManager.storage.setRefreshToken(tokens.refresh_token);\n\n // 3. Connect WebSocket if not connected\n if (!this.connection.isConnected()) {\n logger.debug('[loginWithEmail] Connecting WebSocket...');\n await this.connect();\n }\n\n // 4. Authenticate WebSocket with JWT\n logger.debug('[loginWithEmail] Authenticating WebSocket with JWT...');\n await this.authenticate({ type: 'jwt', token: tokens.access_token });\n\n // 5. Fetch user node via SQL to get the correct path (fallback if HTTP response has no home)\n logger.debug('[loginWithEmail] Fetching user node via SQL RAISIN_CURRENT_USER()...');\n const userNode = await this.fetchUserNode(repository);\n\n // 6. Build user object (HTTP response takes precedence, SQL is fallback)\n logger.info('[loginWithEmail] HTTP response identity.home:', tokens.identity.home);\n logger.info('[loginWithEmail] SQL userNode?.path:', userNode?.path);\n const user: IdentityUser = {\n id: tokens.identity.id,\n email: tokens.identity.email,\n displayName: tokens.identity.display_name,\n avatarUrl: tokens.identity.avatar_url,\n emailVerified: tokens.identity.email_verified,\n home: tokens.identity.home ?? userNode?.path ?? null,\n };\n\n // 7. Store user in localStorage if using LocalStorageTokenStorage\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // 8. Update current user.\n // Preserve the roles that authenticate({type:'jwt'}) just resolved from the\n // server (client.ts authenticate() sets _currentUser.roles = response.roles).\n // This overwrite exists to attach the fetched user node; it must NOT discard\n // the effective roles, or getCurrentUser().roles would always be [].\n this._currentUser = {\n userId: user.id,\n roles: this._currentUser?.roles ?? [],\n anonymous: false,\n node: userNode ?? undefined,\n };\n\n // 9. Schedule auto-refresh (expires_at minus 5 minutes)\n const expiresInMs = RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n\n // 10. Subscribe to user home changes if available\n if (user.home) {\n await this._subscribeToUserHome(repository, user.home);\n }\n\n // 11. Emit auth events\n logger.info('[loginWithEmail] Login complete, user home:', user.home);\n this._emitAuthEvent('SIGNED_IN');\n this.emit('login', user);\n return user;\n }\n\n /**\n * Register a new user with email and password\n *\n * @param email - User's email address\n * @param password - User's password\n * @param repository - Repository name\n * @param displayName - Optional display name\n * @returns The registered user info\n */\n async registerWithEmail(\n email: string,\n password: string,\n repository: string,\n displayName?: string\n ): Promise<IdentityUser> {\n logger.info('[registerWithEmail] Starting registration...');\n\n // 1. Call HTTP register endpoint\n const url = `${this._httpBaseUrl}/auth/${repository}/register`;\n const response = await this._fetchWithTimeout(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password, display_name: displayName }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }));\n // Real Error instance; keeps `{ code, message }` fields for\n // backwards-compatible destructuring (IdentityAuthError shape).\n throw new RaisinAuthError(\n error.message || 'Registration failed',\n error.code || 'REGISTRATION_FAILED',\n response.status\n );\n }\n\n const tokens: IdentityAuthResponse = await response.json();\n logger.info('[registerWithEmail] Registration successful, user_id:', tokens.identity.id);\n\n // 2. Store tokens\n this.authManager.storage.setAccessToken(tokens.access_token);\n this.authManager.storage.setRefreshToken(tokens.refresh_token);\n\n // 3. Connect WebSocket if not connected\n if (!this.connection.isConnected()) {\n await this.connect();\n }\n\n // 4. Authenticate WebSocket with JWT\n await this.authenticate({ type: 'jwt', token: tokens.access_token });\n\n // 5. Fetch user node - note: might be null initially until job completes\n // Wait a bit for the user node creation job to complete\n await new Promise(resolve => setTimeout(resolve, 500));\n const userNode = await this.fetchUserNode(repository);\n\n // 6. Build user object (HTTP response takes precedence, SQL is fallback)\n logger.info('[registerWithEmail] HTTP response identity.home:', tokens.identity.home);\n logger.info('[registerWithEmail] SQL userNode?.path:', userNode?.path);\n const user: IdentityUser = {\n id: tokens.identity.id,\n email: tokens.identity.email,\n displayName: tokens.identity.display_name,\n avatarUrl: tokens.identity.avatar_url,\n emailVerified: tokens.identity.email_verified,\n home: tokens.identity.home ?? userNode?.path ?? null,\n };\n\n // 7. Store user in localStorage if using LocalStorageTokenStorage\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // 8. Update current user.\n // Preserve the roles that authenticate({type:'jwt'}) just resolved from the\n // server (client.ts authenticate() sets _currentUser.roles = response.roles).\n // This overwrite exists to attach the fetched user node; it must NOT discard\n // the effective roles, or getCurrentUser().roles would always be [].\n this._currentUser = {\n userId: user.id,\n roles: this._currentUser?.roles ?? [],\n anonymous: false,\n node: userNode ?? undefined,\n };\n\n // 9. Schedule auto-refresh (expires_at minus 5 minutes)\n const expiresInMs = RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n\n // 10. Subscribe to user home changes if available\n if (user.home) {\n await this._subscribeToUserHome(repository, user.home);\n }\n\n // 11. Emit auth events\n logger.info('[registerWithEmail] Registration complete, user home:', user.home);\n this._emitAuthEvent('SIGNED_IN');\n this.emit('register', user);\n return user;\n }\n\n /**\n * Logout - clear tokens and handle reconnection\n *\n * For SPAs, use `reconnect: true` (default) to stay connected as anonymous.\n * This allows the app to continue functioning without auth.\n *\n * @param options.reconnect - Reconnect as anonymous after logout (default: true for SPAs)\n * @param options.disconnect - Fully disconnect without reconnecting (default: false)\n *\n * @example\n * ```typescript\n * // SPA: logout and reconnect as anonymous (default)\n * await client.logout();\n *\n * // Fully disconnect (e.g., closing app)\n * await client.logout({ disconnect: true });\n * ```\n */\n async logout(options: { disconnect?: boolean; reconnect?: boolean } = {}): Promise<void> {\n logger.info('[logout] Logging out...');\n\n // Clear auto-refresh timer\n if (this._refreshTimer) {\n clearTimeout(this._refreshTimer);\n this._refreshTimer = undefined;\n }\n\n // Unsubscribe from user home\n await this._unsubscribeFromUserHome();\n\n // Clear tokens and user state\n this.authManager.clear();\n this._currentUser = null;\n\n // Determine behavior: reconnect by default unless disconnect is explicitly true\n const shouldDisconnect = options.disconnect === true;\n const shouldReconnect = !shouldDisconnect && (options.reconnect !== false);\n\n if (shouldReconnect) {\n // Disconnect and reconnect as anonymous (SPA flow)\n logger.info('[logout] Reconnecting as anonymous...');\n this.connection.disconnect();\n await this.connect();\n logger.info('[logout] Reconnected as anonymous');\n } else if (shouldDisconnect) {\n // Fully disconnect\n this.disconnect();\n }\n\n // Emit auth event\n this._emitAuthEvent('SIGNED_OUT');\n this.emit('logout');\n }\n\n /**\n * Initialize session from stored tokens\n *\n * This checks localStorage for existing tokens, connects WebSocket,\n * authenticates, and fetches the current user node. Call this on app startup.\n *\n * @param repository - Repository name for user node lookup\n * @returns The current user if session is valid, null otherwise\n *\n * @example\n * ```typescript\n * const client = new RaisinClient('ws://localhost:8081/sys/default/myrepo', {\n * tokenStorage: new LocalStorageTokenStorage('myapp')\n * });\n * const user = await client.initSession('myrepo');\n * if (user) {\n * console.log('Restored session for:', user.email);\n * } else {\n * // Redirect to login\n * }\n * ```\n */\n async initSession(repository: string): Promise<IdentityUser | null> {\n logger.info('[initSession] Initializing session from storage...');\n\n // Override _repository with the explicitly provided value (URL extraction\n // can return the wrong segment for 3-segment paths like /sys/default/repo)\n if (repository) {\n this._repository = repository;\n }\n\n const token = this.authManager.storage.getAccessToken();\n\n // Always connect WebSocket first (even for anonymous)\n if (!this.connection.isConnected()) {\n logger.debug('[initSession] Connecting WebSocket...');\n await this.connect();\n }\n\n if (!token) {\n logger.info('[initSession] No stored token found, connected as anonymous');\n return null;\n }\n\n // Check if token is expired (basic check)\n const payload = AuthManager.parseToken(token);\n if (payload && payload.exp && typeof payload.exp === 'number') {\n if (payload.exp * 1000 < Date.now()) {\n logger.info('[initSession] Token expired, attempting refresh...');\n\n // Delegate to refreshToken() rather than issuing our own refresh POST.\n // Refresh tokens are single-use (the server rotates them and revokes the\n // session on reuse), and connect() above can already have started a\n // refresh via autoReauthenticate(). Two refreshes racing on the same\n // stored token trip the server's reuse detection and kill the session.\n // refreshToken() is single-flighted, so both callers share one request.\n if (!this.authManager.storage.getRefreshToken()) {\n logger.warn('[initSession] No refresh token, clearing session');\n this.authManager.clear();\n return null;\n }\n\n const refreshed = await this.refreshToken();\n if (!refreshed) {\n logger.warn('[initSession] Token refresh failed, clearing session');\n this.authManager.clear();\n return null;\n }\n logger.info('[initSession] Token refreshed successfully');\n }\n }\n\n try {\n\n // Authenticate with stored token\n const currentToken = this.authManager.storage.getAccessToken();\n if (!currentToken) {\n return null;\n }\n\n logger.debug('[initSession] Authenticating WebSocket...');\n await this.authenticate({ type: 'jwt', token: currentToken });\n\n // Fetch user node via SQL\n logger.debug('[initSession] Fetching user node...');\n const userNode = await this.fetchUserNode(repository);\n\n // Get stored user or build from token\n let user: IdentityUser | null = null;\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n user = this.authManager.storage.getUser();\n }\n\n if (!user && payload) {\n // Build user from JWT payload (home is encoded in the token)\n user = {\n id: payload.sub as string,\n email: payload.email as string || '',\n displayName: payload.display_name as string || null,\n avatarUrl: null,\n emailVerified: false,\n home: (payload.home as string) ?? null,\n };\n }\n\n if (user) {\n // Update user home: SQL result > JWT payload > stored value\n const jwtHome = (payload?.home as string) ?? null;\n user.home = userNode?.path ?? jwtHome ?? user.home;\n\n // Update stored user\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // Preserve roles resolved by authenticate({type:'jwt'}) above — do not\n // clobber them with [] (that made getCurrentUser().roles empty after a\n // localStorage session restore).\n this._currentUser = {\n userId: user.id,\n roles: this._currentUser?.roles ?? [],\n anonymous: false,\n node: userNode ?? undefined,\n };\n\n // Schedule auto-refresh based on token expiration\n const currentToken = this.authManager.storage.getAccessToken();\n if (currentToken) {\n const tokenPayload = AuthManager.parseToken(currentToken);\n if (tokenPayload?.exp && typeof tokenPayload.exp === 'number') {\n const expiresInMs = (tokenPayload.exp * 1000) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n }\n }\n\n // Subscribe to user home changes if available\n if (user.home) {\n await this._subscribeToUserHome(repository, user.home);\n }\n\n logger.info('[initSession] Session restored for user:', user.email, 'home:', user.home);\n this._emitAuthEvent('SIGNED_IN');\n this.emit('session_restored', user);\n return user;\n }\n\n return null;\n } catch (err) {\n logger.warn('[initSession] Failed to restore session:', err);\n return null;\n }\n }\n\n /**\n * Get the stored identity user (from localStorage)\n */\n getStoredUser(): IdentityUser | null {\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n return this.authManager.storage.getUser();\n }\n return null;\n }\n\n /**\n * Check if there's a stored token (may or may not be valid)\n */\n hasStoredToken(): boolean {\n return this.authManager.storage.getAccessToken() !== null;\n }\n\n /**\n * Refresh the access token using the stored refresh token.\n *\n * This method:\n * 1. Gets the stored refresh token\n * 2. Calls the /auth/refresh endpoint\n * 3. Stores the new access and refresh tokens\n * 4. Returns the updated user info\n *\n * @returns The identity user if refresh was successful, null otherwise\n * @throws Error if no refresh token is stored or refresh fails\n */\n async refreshToken(): Promise<IdentityUser | null> {\n // Single-flight: refresh tokens are single-use. The server rotates the\n // token on every refresh and revokes the whole session if it ever sees a\n // stale generation (TOKEN_REUSE_DETECTED), since that is indistinguishable\n // from a stolen token being replayed. Several call sites can want a refresh\n // at once on startup — initSession(), connect() -> autoReauthenticate(),\n // the auto-refresh timer, and any 401 retry — so without this guard they\n // each POST the same stored token and we revoke our own session.\n if (this._refreshInFlight) {\n logger.debug('[refreshToken] Refresh already in flight, awaiting it');\n return this._refreshInFlight;\n }\n this._refreshInFlight = this._refreshToken().finally(() => {\n this._refreshInFlight = null;\n });\n return this._refreshInFlight;\n }\n\n /** In-flight refresh shared by concurrent refreshToken() callers. */\n private _refreshInFlight: Promise<IdentityUser | null> | null = null;\n\n private async _refreshToken(): Promise<IdentityUser | null> {\n const refreshToken = this.authManager.storage.getRefreshToken();\n if (!refreshToken) {\n logger.warn('[refreshToken] No refresh token available');\n return null;\n }\n\n try {\n logger.info('[refreshToken] Refreshing access token...');\n const url = this._repository\n ? `${this._httpBaseUrl}/auth/${this._repository}/refresh`\n : `${this._httpBaseUrl}/auth/refresh`;\n const response = await this._fetchWithTimeout(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n logger.error('[refreshToken] Refresh failed:', response.status, errorText);\n\n // A revoked-for-security response means the token was presented twice.\n // With single-flighting in place that should no longer be us, so treat\n // it as a real signal (either a genuine replay, or a second client\n // instance sharing this storage) rather than a routine expiry.\n if (/TOKEN_REUSE_DETECTED|TOKEN_FAMILY_MISMATCH/.test(errorText)) {\n logger.error(\n '[refreshToken] Session revoked by the server as a suspected token replay. ' +\n 'If this happened on a normal page load, two refreshes raced on the same token.',\n );\n }\n\n // Clear tokens on auth failure (401/403)\n if (response.status === 401 || response.status === 403) {\n this.authManager.clear();\n this._currentUser = null;\n this.emit('auth_error', new Error('Token refresh failed - session expired'));\n }\n return null;\n }\n\n const tokens: IdentityAuthResponse = await response.json();\n\n // Store new tokens\n this.authManager.storage.setAccessToken(tokens.access_token);\n this.authManager.storage.setRefreshToken(tokens.refresh_token);\n\n // Update user info\n const user: IdentityUser = {\n id: tokens.identity.id,\n email: tokens.identity.email,\n displayName: tokens.identity.display_name,\n avatarUrl: tokens.identity.avatar_url,\n emailVerified: tokens.identity.email_verified,\n home: null, // Will be updated on next query\n };\n\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // Schedule next refresh (token expires_at minus 5 minutes)\n const expiresInMs = RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n\n logger.info('[refreshToken] Token refreshed successfully');\n this._emitAuthEvent('TOKEN_REFRESHED');\n this.emit('token_refreshed', user);\n return user;\n } catch (err) {\n logger.error('[refreshToken] Error during token refresh:', err);\n return null;\n }\n }\n\n /**\n * Fetch with a timeout derived from `requestTimeout`.\n *\n * Aborts the request after `requestTimeout` ms and rejects with a\n * `RaisinTimeoutError`. If the caller provides its own AbortSignal in\n * `init.signal`, it is respected: an external abort rejects with the\n * original AbortError instead of a timeout error.\n * @internal\n */\n private async _fetchWithTimeout(url: string, init: RequestInit = {}): Promise<Response> {\n const timeoutMs = this.options.requestTimeout;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n const externalSignal = init.signal ?? undefined;\n if (externalSignal) {\n if (externalSignal.aborted) {\n controller.abort();\n } else {\n externalSignal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n }\n\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (error) {\n if (\n error instanceof Error &&\n error.name === 'AbortError' &&\n !externalSignal?.aborted\n ) {\n throw new RaisinTimeoutError(\n `Request to ${url} timed out after ${timeoutMs}ms`,\n 'REQUEST_TIMEOUT',\n timeoutMs\n );\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n\n /**\n * Normalize a token `expires_at` value to epoch milliseconds.\n *\n * Server endpoints are inconsistent: some return seconds, others\n * milliseconds. Anything above 1e11 can't be a seconds-epoch (year 5138),\n * so treat it as milliseconds.\n * @internal\n */\n private static expiresAtToMs(expiresAt: number): number {\n return expiresAt > 100_000_000_000 ? expiresAt : expiresAt * 1000;\n }\n\n /**\n * Schedule automatic token refresh\n * @internal\n */\n private scheduleAutoRefresh(delayMs: number): void {\n // Clear any existing timer\n if (this._refreshTimer) {\n clearTimeout(this._refreshTimer);\n }\n\n // Clamp to a sane window: at least 30s out (avoid refresh storms on\n // skewed clocks), at most ~24 days (setTimeout 32-bit overflow fires\n // immediately otherwise).\n const clamped = Math.min(Math.max(delayMs, 30_000), 0x7fffffff);\n\n logger.debug(`[scheduleAutoRefresh] Scheduling refresh in ${Math.round(clamped / 1000 / 60)} minutes`);\n\n this._refreshTimer = setTimeout(async () => {\n logger.info('[autoRefresh] Auto-refreshing token...');\n await this.refreshToken();\n }, clamped);\n }\n\n /** Timer for automatic token refresh */\n private _refreshTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Get a database/repository interface\n *\n * @param name - Repository name\n * @returns Database interface\n */\n database(name: string): Database {\n // Set repository in client context for this database\n this._context.repository = name;\n return new Database(\n name,\n this._context,\n (payload, requestType, contextOverride, requestOptions) =>\n this.sendRequestInternal(payload, requestType as RequestType, contextOverride, requestOptions),\n this.eventHandler,\n undefined,\n undefined,\n () => this.getUploadManager(),\n (options) => this.signAssetUrl(options),\n { httpBaseUrl: this._httpBaseUrl, authManager: this.authManager },\n );\n }\n\n /**\n * Send a request to the server\n *\n * If the connection is temporarily down (connecting/reconnecting, or\n * disconnected with auto-reconnect enabled), the request is queued and\n * flushed once the connection is re-established and re-authenticated.\n * Queued requests are still subject to their own request timeout, and the\n * queue is bounded (overflow rejects immediately).\n */\n private async sendRequestInternal(\n payload: unknown,\n requestType: RequestType | string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ): Promise<unknown> {\n const connected = this.connection.isConnected();\n if (!connected) {\n const state = this.connection.getState();\n const willReconnect =\n state === ConnectionState.Connecting ||\n state === ConnectionState.Reconnecting ||\n (state === ConnectionState.Disconnected &&\n this._everConnected &&\n this.connection.isAutoReconnectEnabled());\n\n if (!willReconnect) {\n throw new Error('Not connected to server');\n }\n\n if (this._queuedRequests.length >= RaisinClient.MAX_QUEUED_REQUESTS) {\n throw new Error(\n `Request queue is full (${RaisinClient.MAX_QUEUED_REQUESTS} requests pending while reconnecting)`\n );\n }\n }\n\n const requestId = this.requestTracker.generateRequestId();\n\n // Use provided context or default to this._context\n const context = contextOverride || this._context;\n\n logger.debug(`sendRequestInternal - request_id: ${requestId}, type: ${requestType}`);\n logger.debug(`Context:`, JSON.stringify(context, null, 2));\n\n // Create request envelope\n const request: RequestEnvelope = {\n request_id: requestId,\n type: requestType as RequestType,\n context,\n payload,\n };\n\n // Create promise for response\n const responsePromise = this.requestTracker.createRequest(\n requestId,\n requestOptions?.timeoutMs,\n );\n\n // Send request (or queue it while the connection is re-establishing)\n try {\n const encoded = encodeMessage(request);\n logger.debug(`Encoded request - ID: ${requestId}, type: ${requestType}, size: ${encoded.length} bytes`);\n if (connected) {\n this.connection.send(encoded);\n logger.debug(`Request sent - ID: ${requestId}`);\n } else {\n this._queuedRequests.push({ requestId, encoded });\n logger.debug(\n `Request queued while reconnecting - ID: ${requestId}, queue size: ${this._queuedRequests.length}`\n );\n }\n } catch (error) {\n logger.error(`Failed to send request - ID: ${requestId}:`, error);\n this.requestTracker.rejectRequest(\n requestId,\n error instanceof Error ? error : new Error('Failed to send request')\n );\n throw error;\n }\n\n return responsePromise;\n }\n\n /**\n * Flush requests queued while the connection was re-establishing.\n * Called after the connection is connected and (re-)authenticated.\n * @internal\n */\n private _flushQueuedRequests(): void {\n if (this._queuedRequests.length === 0) return;\n\n const queued = this._queuedRequests;\n this._queuedRequests = [];\n logger.info(`[_flushQueuedRequests] Flushing ${queued.length} queued request(s)`);\n\n for (const { requestId, encoded } of queued) {\n // Skip requests that already timed out while queued\n if (!this.requestTracker.hasPendingRequest(requestId)) continue;\n try {\n this.connection.send(encoded);\n } catch (error) {\n this.requestTracker.rejectRequest(\n requestId,\n error instanceof Error ? error : new Error('Failed to send queued request')\n );\n }\n }\n }\n\n /**\n * Reject all requests queued while the connection was re-establishing\n * (e.g. re-authentication failed after reconnect).\n * @internal\n */\n private _rejectQueuedRequests(error: Error): void {\n if (this._queuedRequests.length === 0) return;\n\n const queued = this._queuedRequests;\n this._queuedRequests = [];\n logger.warn(`[_rejectQueuedRequests] Rejecting ${queued.length} queued request(s): ${error.message}`);\n\n for (const { requestId } of queued) {\n this.requestTracker.rejectRequest(requestId, error);\n }\n }\n\n /**\n * Get the HTTP base URL derived from the WebSocket URL\n */\n get httpBaseUrl(): string {\n return this._httpBaseUrl;\n }\n\n /**\n * Get current connection state\n */\n getConnectionState(): ConnectionState {\n return this.connection.getState();\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connection.isConnected();\n }\n\n /**\n * Check if ready (connected AND authenticated)\n *\n * Returns true when the client is fully ready to make requests:\n * - WebSocket is connected AND\n * - Either authenticated (signed in) OR no stored token (anonymous is ok)\n *\n * Use this for UI indicators that should show \"connected\" only when\n * the client is actually ready to process requests.\n */\n isReady(): boolean {\n return this._ready;\n }\n\n /**\n * Subscribe to ready state changes\n *\n * The callback is invoked whenever the ready state changes.\n * Ready = connected AND (authenticated OR no stored token)\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onReadyStateChange((ready) => {\n * if (ready) {\n * console.log('Client is ready');\n * showGreenIndicator();\n * } else {\n * console.log('Client is not ready');\n * showRedIndicator();\n * }\n * });\n * ```\n *\n * @param callback - Function called when ready state changes\n * @returns Unsubscribe function\n */\n onReadyStateChange(callback: (ready: boolean) => void): () => void {\n this._readyListeners.add(callback);\n // Immediately call with current state\n callback(this._ready);\n return () => {\n this._readyListeners.delete(callback);\n };\n }\n\n /**\n * Check if authenticated\n */\n isAuthenticated(): boolean {\n return this.authManager.isAuthenticated();\n }\n\n /**\n * Get current user info\n *\n * Returns the current authenticated user's information including\n * their ID, node path in the repository, and roles.\n *\n * @returns Current user info or null if not connected/authenticated\n */\n getCurrentUser(): CurrentUser | null {\n return this._currentUser;\n }\n\n /**\n * Re-resolve the current user's EFFECTIVE roles from the server and refresh\n * `getCurrentUser()`.\n *\n * Roles are deliberately not embedded in the JWT (they are resolved live\n * server-side), so when an admin changes a user's roles/groups the token does\n * not change — the client must re-ask. This re-runs the WS JWT auth handshake\n * (which returns freshly resolved effective roles), updates `_currentUser`, and\n * emits `USER_UPDATED` so role-gated UI can react without a reload.\n *\n * Called automatically when the server pushes `permissions:changed` after an\n * access-control write, and exposed for on-demand refresh. Safe no-op when not\n * authenticated.\n */\n async refreshCurrentUser(): Promise<void> {\n // Coalesce concurrent re-resolves: a burst of `permissions:changed` pushes\n // (e.g. during package/role seeding) collapses into a single in-flight\n // handshake instead of a storm.\n if (this.#refreshingUser) return this.#refreshingUser;\n const token = this.authManager.storage.getAccessToken();\n if (!token) return;\n this.#refreshingUser = (async () => {\n const before = JSON.stringify(this._currentUser?.roles ?? null);\n const prevNode = this._currentUser?.node;\n try {\n // authenticate({type:'jwt'}) re-resolves roles and rebuilds _currentUser\n // (without the node); preserve the previously-fetched node.\n await this.authenticate({ type: 'jwt', token });\n if (this._currentUser && prevNode && !this._currentUser.node) {\n this._currentUser.node = prevNode;\n }\n // Only notify when the effective roles actually changed — avoids\n // redundant USER_UPDATED churn when a push carried no role change.\n const after = JSON.stringify(this._currentUser?.roles ?? null);\n if (after !== before) {\n this._emitAuthEvent('USER_UPDATED');\n }\n } catch (err) {\n logger.warn('[refreshCurrentUser] role re-resolve failed:', err);\n } finally {\n this.#refreshingUser = null;\n }\n })();\n return this.#refreshingUser;\n }\n\n /**\n * Get current user ID\n *\n * @returns User ID or null if not connected/authenticated\n */\n getCurrentUserId(): string | null {\n return this._currentUser?.userId ?? null;\n }\n\n /**\n * Get current user's node path in the repository\n *\n * @returns User's node path (e.g., '/users/internal/john-at-example-com') or null if not connected\n */\n getCurrentUserPath(): string | null {\n return this._currentUser?.node?.path ?? null;\n }\n\n /**\n * Fetch user node using SQL RAISIN_CURRENT_USER() function\n *\n * @param repository - Repository name to query\n * @returns User's full node from the repository, or null if query fails\n */\n async fetchUserNode(repository: string): Promise<UserNode | null> {\n logger.info('[fetchUserNode] Fetching user node for repository:', repository);\n try {\n // Use SQL to get the current user node (RAISIN_CURRENT_USER() returns the node as JSON)\n const db = this.database(repository);\n logger.info('[fetchUserNode] Executing SQL: SELECT RAISIN_CURRENT_USER() as user_node');\n const result = await db.executeSql('SELECT RAISIN_CURRENT_USER() as user_node');\n logger.info('[fetchUserNode] SQL result:', JSON.stringify(result));\n\n if (result.rows && result.rows.length > 0) {\n const row = result.rows[0] as unknown as { user_node: UserNode | null };\n logger.info('[fetchUserNode] User node:', row.user_node ? `path=${row.user_node.path}` : 'null');\n return row.user_node ?? null;\n }\n logger.info('[fetchUserNode] No rows returned');\n return null;\n } catch (err) {\n logger.warn('[fetchUserNode] Error fetching user node via SQL:', err);\n return null;\n }\n }\n\n /**\n * Get current tenant ID\n */\n getTenantId(): string {\n return this._context.tenant_id;\n }\n\n /**\n * Set branch for subsequent requests\n *\n * @param branch - Branch name\n */\n setBranch(branch: string): void {\n this._context.branch = branch;\n }\n\n /**\n * Get current branch\n */\n getBranch(): string {\n return this._context.branch ?? this.options.defaultBranch;\n }\n\n // ============================================================================\n // Auth State Change API (Firebase/Supabase-compatible)\n // ============================================================================\n\n /**\n * Listen for authentication state changes (Firebase/Supabase-compatible pattern)\n *\n * This method provides a reactive way to respond to auth events:\n * - SIGNED_IN: User logged in or session restored\n * - SIGNED_OUT: User logged out\n * - TOKEN_REFRESHED: Access token was refreshed\n * - SESSION_EXPIRED: Session expired (auto-logout triggered)\n * - USER_UPDATED: User's home node was updated\n *\n * @param callback - Function called on each auth state change\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onAuthStateChange(({ event, session }) => {\n * if (event === 'SIGNED_IN') {\n * console.log('User signed in:', session.user?.email);\n * } else if (event === 'SIGNED_OUT') {\n * console.log('User signed out');\n * }\n * });\n *\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n onAuthStateChange(callback: AuthStateChangeCallback): () => void {\n this._authListeners.add(callback);\n return () => {\n this._authListeners.delete(callback);\n };\n }\n\n /**\n * Listen for connection state changes\n *\n * @param callback - Function called on each connection state change\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onConnectionStateChange((state) => {\n * console.log('Connection state:', state);\n * if (state === ConnectionState.Disconnected) {\n * showOfflineIndicator();\n * }\n * });\n * ```\n */\n onConnectionStateChange(callback: (state: ConnectionState) => void): () => void {\n const handler = (state: ConnectionState) => callback(state);\n this.connection.on('stateChange', handler);\n return () => {\n this.connection.off('stateChange', handler);\n };\n }\n\n /**\n * Listen for reconnection events\n *\n * This callback fires after a successful reconnection when:\n * 1. The WebSocket connection is re-established\n * 2. Re-authentication (if needed) is complete\n * 3. Event subscriptions have been restored\n *\n * Use this to refresh application data after a server restart or network recovery.\n *\n * @param callback - Function called after successful reconnection\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onReconnected(() => {\n * console.log('Reconnected! Refreshing data...');\n * // Refresh conversations, sync state, etc.\n * await refreshData();\n * });\n * ```\n */\n onReconnected(callback: () => void): () => void {\n this._reconnectedListeners.add(callback);\n return () => {\n this._reconnectedListeners.delete(callback);\n };\n }\n\n /**\n * Listen for changes to the current user's home node\n *\n * This automatically subscribes to real-time updates on the user's home node\n * (e.g., /users/internal/john-at-example-com) when the user logs in.\n *\n * @param callback - Function called when user's home node is updated\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onUserChange(({ node, changeType }) => {\n * console.log('User home updated:', changeType);\n * console.log('New properties:', node.properties);\n * // Update UI with new avatar, displayName, preferences, etc.\n * });\n * ```\n */\n onUserChange(callback: UserChangeCallback): () => void {\n this._userChangeListeners.add(callback);\n return () => {\n this._userChangeListeners.delete(callback);\n };\n }\n\n /**\n * Get current session (sync getter)\n *\n * @returns Current session with user and access token, or null if not authenticated\n *\n * @example\n * ```typescript\n * const session = client.getSession();\n * if (session) {\n * console.log('Logged in as:', session.user?.email);\n * }\n * ```\n */\n getSession(): { user: IdentityUser | null; accessToken: string | null } | null {\n const accessToken = this.authManager.storage.getAccessToken();\n if (!accessToken) return null;\n return {\n user: this.getStoredUser(),\n accessToken,\n };\n }\n\n /**\n * Get current user (alias for getStoredUser, Supabase-compatible)\n *\n * @returns Current identity user or null\n */\n getUser(): IdentityUser | null {\n return this.getStoredUser();\n }\n\n /**\n * Emit auth event to all listeners\n * @internal\n */\n private _emitAuthEvent(event: AuthEvent): void {\n const session = {\n user: this.getStoredUser(),\n accessToken: this.authManager.storage.getAccessToken(),\n // Surface effective roles so role-gated consumers can react to\n // SIGNED_IN / USER_UPDATED without calling getCurrentUser() themselves.\n roles: this._currentUser?.roles ?? null,\n };\n const change: AuthStateChange = { event, session };\n\n for (const callback of this._authListeners) {\n try {\n callback(change);\n } catch (err) {\n logger.error('[_emitAuthEvent] Listener error:', err);\n }\n }\n\n // Update ready state after auth events\n this._updateReadyState();\n }\n\n /**\n * Update and emit ready state\n * Ready = connected AND (authenticated OR no stored token)\n * @internal\n */\n private _updateReadyState(): void {\n const connected = this.connection.isConnected();\n const hasToken = this.hasStoredToken();\n const user = this.getStoredUser();\n // Ready if: connected AND (no stored token OR user is signed in)\n const ready = connected && (!hasToken || user !== null);\n\n if (this._ready !== ready) {\n this._ready = ready;\n logger.debug('[_updateReadyState] Ready state changed:', ready, { connected, hasToken, user: user?.email });\n for (const callback of this._readyListeners) {\n try {\n callback(ready);\n } catch (err) {\n logger.error('[_updateReadyState] Listener error:', err);\n }\n }\n }\n }\n\n /**\n * Subscribe to user's home node for real-time updates\n * @internal\n */\n private async _subscribeToUserHome(repository: string, userHome: string): Promise<void> {\n // Unsubscribe from previous subscription if any\n await this._unsubscribeFromUserHome();\n\n // Strip a possible workspace prefix (e.g. \"/raisin:access_control/users/...\")\n userHome = normalizeHomePath(userHome) ?? userHome;\n\n try {\n const db = this.database(repository);\n // Extract workspace from path (e.g., \"/users/internal/john\" -> \"users\")\n const pathParts = userHome.split('/').filter(p => p.length > 0);\n if (pathParts.length === 0) {\n logger.warn('[_subscribeToUserHome] Invalid user home path:', userHome);\n return;\n }\n\n const workspace = pathParts[0];\n const events = db.workspace(workspace).events();\n\n logger.debug('[_subscribeToUserHome] Subscribing to user home:', userHome);\n const subscription = await events.subscribeToPath(userHome, (event) => {\n logger.debug('[_subscribeToUserHome] User home event:', event.event_type);\n\n // Emit to onUserChange listeners\n for (const callback of this._userChangeListeners) {\n try {\n callback({\n node: event.payload as unknown as UserNode,\n changeType: event.event_type,\n });\n } catch (err) {\n logger.error('[_subscribeToUserHome] Listener error:', err);\n }\n }\n\n // Also emit USER_UPDATED auth event\n this._emitAuthEvent('USER_UPDATED');\n });\n\n this._userHomeSubscription = subscription;\n logger.info('[_subscribeToUserHome] Subscribed to user home:', userHome);\n } catch (err) {\n logger.error('[_subscribeToUserHome] Failed to subscribe:', err);\n }\n }\n\n /**\n * Unsubscribe from user's home node\n * @internal\n */\n private async _unsubscribeFromUserHome(): Promise<void> {\n if (this._userHomeSubscription) {\n try {\n await this._userHomeSubscription.unsubscribe();\n } catch (err) {\n logger.warn('[_unsubscribeFromUserHome] Error during unsubscribe:', err);\n }\n this._userHomeSubscription = null;\n }\n }\n\n /**\n * Create a new repository\n *\n * @param repositoryId - Repository identifier\n * @param description - Repository description\n * @param config - Repository configuration\n * @returns Repository creation result\n */\n async createRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n description,\n config,\n },\n RequestType.RepositoryCreate\n );\n }\n\n /**\n * Get a repository by ID\n *\n * @param repositoryId - Repository identifier\n * @returns Repository information\n */\n async getRepository(repositoryId: string): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n },\n RequestType.RepositoryGet\n );\n }\n\n /**\n * List all repositories\n *\n * @returns Array of repository information\n */\n async listRepositories(): Promise<unknown[]> {\n const result = await this.sendRequestInternal(\n {},\n RequestType.RepositoryList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update a repository\n *\n * @param repositoryId - Repository identifier\n * @param description - New repository description\n * @param config - New repository configuration\n * @returns Repository update result\n */\n async updateRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n description,\n config,\n },\n RequestType.RepositoryUpdate\n );\n }\n\n /**\n * Delete a repository\n *\n * @param repositoryId - Repository identifier\n * @returns Repository deletion result\n */\n async deleteRepository(repositoryId: string): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n },\n RequestType.RepositoryDelete\n );\n }\n\n // ============================================================================\n // Upload Methods (use HTTP under the hood)\n // ============================================================================\n\n /**\n * Get or create the upload manager\n * @internal\n */\n private getUploadManager(): UploadManager {\n if (!this._uploadManager) {\n this._uploadManager = new UploadManager({\n baseUrl: this._httpBaseUrl,\n authManager: this.authManager,\n fetchImpl: fetch,\n requestTimeout: this.options.requestTimeout,\n });\n }\n return this._uploadManager;\n }\n\n /**\n * Create a resumable upload from a File or Blob (Browser)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support. Uses HTTP under the hood.\n *\n * @param file - File or Blob to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const client = new RaisinClient('raisin://localhost:8080/sys/default');\n * await client.connect();\n *\n * const file = document.querySelector('input').files[0];\n * const upload = await client.upload(file, {\n * repository: 'media',\n * workspace: 'assets',\n * path: '/videos/my-video.mp4',\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * const result = await upload.start();\n * ```\n */\n async upload(file: File | Blob, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(file);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Create a resumable upload from a file path (Node.js)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support. Uses HTTP under the hood.\n *\n * @param filePath - Path to the file to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const upload = await client.uploadFile('/path/to/file.zip', {\n * repository: 'data',\n * workspace: 'backups',\n * path: '/backup.zip'\n * });\n * await upload.start();\n * ```\n */\n async uploadFile(filePath: string, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(filePath);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Upload multiple files as a batch\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n * Uses HTTP under the hood.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param options - Batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await client.uploadFiles(files, {\n * repository: 'media',\n * workspace: 'assets',\n * basePath: '/uploads',\n * concurrency: 3,\n * onProgress: (p) => {\n * console.log(`${p.filesCompleted}/${p.filesTotal} files`);\n * console.log(`${Math.round(p.progress * 100)}% complete`);\n * },\n * onFileComplete: (file, result) => console.log(`Uploaded: ${file}`),\n * onFileError: (file, err) => console.error(`Failed: ${file}`, err),\n * });\n *\n * const result = await batch.start();\n * console.log(`Success: ${result.successful.length}, Failed: ${result.failed.length}`);\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n options: BatchUploadOptions\n ): Promise<BatchUpload> {\n const sources = await Promise.all(\n Array.from(files).map((f) => createFileSource(f))\n );\n const manager = this.getUploadManager();\n return manager.createBatchUpload(sources, options);\n }\n\n /**\n * Get an existing upload by ID\n *\n * @param uploadId - ID of the upload to retrieve\n * @returns Upload controller or undefined if not found\n */\n getUpload(uploadId: string): Upload | undefined {\n const manager = this.getUploadManager();\n return manager.getUpload(uploadId);\n }\n\n /**\n * Get all active uploads\n *\n * @returns Array of active upload controllers\n */\n getActiveUploads(): Upload[] {\n const manager = this.getUploadManager();\n return manager.getActiveUploads();\n }\n\n /**\n * Cancel all active uploads\n */\n async cancelAllUploads(): Promise<void> {\n const manager = this.getUploadManager();\n await manager.cancelAll();\n }\n\n // ============================================================================\n // Asset Signed URL Methods\n // ============================================================================\n\n /**\n * Get a signed URL for accessing an asset's binary content.\n *\n * Server validates user access before generating URL. The returned URL\n * can be used without authentication (signature provides access).\n *\n * @param options - Sign URL options\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const { url, expiresAt } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/image.jpeg',\n * command: 'display',\n * });\n *\n * // Use in <img> tag\n * document.querySelector('img').src = url;\n *\n * // Or force download\n * const { url: downloadUrl } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/document.pdf',\n * command: 'download',\n * });\n * ```\n */\n async signAssetUrl(options: SignAssetOptions): Promise<SignedAssetUrl> {\n const branch = options.branch ?? this._context.branch ?? 'main';\n // Add @propertyPath suffix if specified (for thumbnails, etc.)\n // Only add suffix when propertyPath is provided - maintains backward compatibility\n const pathWithProperty = options.propertyPath\n ? `${options.path}@${options.propertyPath}`\n : options.path;\n const endpoint = `/api/repository/${options.repository}/${branch}/head/${options.workspace}${pathWithProperty}/raisin:sign`;\n\n const response = await this._fetchWithTimeout(`${this._httpBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(this.authManager.isAuthenticated()\n ? { Authorization: `Bearer ${this.authManager.getAccessToken()}` }\n : {}),\n },\n body: JSON.stringify({\n command: options.command,\n expires_in: options.expiresIn ?? 300,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: 'Unknown error' }));\n throw new Error(error.message || `Failed to sign asset URL: ${response.status}`);\n }\n\n const data = await response.json();\n return {\n url: `${this._httpBaseUrl}${data.url}`,\n expiresAt: data.expiresAt ?? data.expires_at,\n };\n }\n\n /**\n * Create an HTTP-only client for server-side rendering\n *\n * This client uses HTTP REST API instead of WebSocket, making it suitable\n * for server-side rendering where WebSocket connections are not available.\n *\n * @param baseUrl - Base HTTP URL (e.g., \"http://localhost:8080\")\n * @param options - HTTP client options\n * @returns HTTP client instance\n *\n * @example\n * ```typescript\n * // In a React Router loader (server-side)\n * const client = RaisinClient.forSSR('http://localhost:8080', {\n * tenantId: 'default'\n * });\n * await client.authenticate({ username: 'admin', password: 'admin' });\n * const result = await client.database('social').executeSql('SELECT * FROM nodes');\n * ```\n */\n static forSSR(baseUrl: string, options?: HttpClientOptions): RaisinHttpClient {\n return new RaisinHttpClient(baseUrl, options);\n }\n\n /**\n * Create an HTTP client (alias for forSSR)\n *\n * @param baseUrl - Base HTTP URL\n * @param options - HTTP client options\n * @returns HTTP client instance\n */\n static createHttpClient(baseUrl: string, options?: HttpClientOptions): RaisinHttpClient {\n return RaisinClient.forSSR(baseUrl, options);\n }\n}\n","/**\n * Universal WebSocket connection manager\n *\n * Detects environment (browser vs Node.js) and uses appropriate WebSocket implementation.\n * Handles auto-reconnect, heartbeat, and connection state management.\n */\n\nimport { EventEmitter } from 'events';\nimport { ReconnectManager, ReconnectOptions } from './utils/reconnect';\nimport { logger } from './logger';\n\n/**\n * Connection state\n */\nexport enum ConnectionState {\n Disconnected = 'disconnected',\n Connecting = 'connecting',\n Connected = 'connected',\n Reconnecting = 'reconnecting',\n Closed = 'closed',\n}\n\n/**\n * Connection options\n */\nexport interface ConnectionOptions {\n /** Auto-reconnect on disconnect (default: true) */\n autoReconnect?: boolean;\n /** Reconnection options */\n reconnectOptions?: ReconnectOptions;\n /** Heartbeat interval in milliseconds (default: 30000, 0 to disable) */\n heartbeatInterval?: number;\n /** Heartbeat timeout in milliseconds (default: 5000) */\n heartbeatTimeout?: number;\n /** WebSocket protocols */\n protocols?: string | string[];\n /**\n * Extra headers to send on the WebSocket upgrade request\n * (e.g. `x-tenant-id` for tenant-less `/ws` URLs).\n *\n * Only honored by WebSocket implementations that support custom headers\n * (Node.js `ws` package). Browser WebSockets silently ignore them — the\n * server then resolves the tenant from the request (default: \"default\").\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Connection events\n */\nexport interface ConnectionEvents {\n stateChange: (state: ConnectionState) => void;\n message: (data: ArrayBuffer) => void;\n error: (error: Error) => void;\n close: (event: CloseEvent) => void;\n}\n\n/**\n * Type for WebSocket implementation (browser or Node.js)\n */\ntype WebSocketImpl = typeof WebSocket | typeof import('ws').WebSocket;\n\n/**\n * Get the appropriate WebSocket implementation for the current environment\n */\nfunction getWebSocketImpl(): WebSocketImpl {\n // Browser environment\n if (typeof WebSocket !== 'undefined') {\n return WebSocket as WebSocketImpl;\n }\n\n // Node.js environment\n try {\n // Use dynamic import to avoid bundler issues\n const ws = require('ws');\n return ws.WebSocket || ws.default || ws;\n } catch (error) {\n throw new Error(\n 'WebSocket implementation not found. In Node.js, please install the \"ws\" package: npm install ws'\n );\n }\n}\n\n/**\n * Universal WebSocket connection manager\n */\nexport class Connection extends EventEmitter {\n private ws?: WebSocket;\n private url: string;\n private state: ConnectionState = ConnectionState.Disconnected;\n private reconnectManager: ReconnectManager;\n private heartbeatTimer?: NodeJS.Timeout;\n private heartbeatTimeoutTimer?: NodeJS.Timeout;\n private options: Required<Omit<ConnectionOptions, 'reconnectOptions' | 'protocols' | 'headers'>> & {\n protocols?: string | string[];\n headers?: Record<string, string>;\n };\n private WebSocketImpl: WebSocketImpl;\n private manualClose = false;\n\n constructor(url: string, options: ConnectionOptions = {}) {\n super();\n // Convert raisin:// / raisins:// to ws:// / wss:// for the WebSocket layer\n this.url = url\n .replace(/^raisin:\\/\\//, 'ws://')\n .replace(/^raisins:\\/\\//, 'wss://');\n this.options = {\n autoReconnect: options.autoReconnect ?? true,\n heartbeatInterval: options.heartbeatInterval ?? 30000,\n heartbeatTimeout: options.heartbeatTimeout ?? 5000,\n protocols: options.protocols,\n headers: options.headers,\n };\n this.reconnectManager = new ReconnectManager(options.reconnectOptions);\n this.WebSocketImpl = getWebSocketImpl();\n }\n\n /**\n * Connect to the WebSocket server\n */\n async connect(): Promise<void> {\n if (this.state === ConnectionState.Connected || this.state === ConnectionState.Connecting) {\n return;\n }\n\n this.manualClose = false;\n this.setState(ConnectionState.Connecting);\n\n return new Promise((resolve, reject) => {\n try {\n // Create WebSocket instance.\n // The third argument (upgrade headers) is only understood by the\n // Node.js `ws` package. Browsers do NOT simply ignore it - Chromium\n // fails the handshake when a third argument is passed - so only pass\n // it to non-browser implementations. Browser connections rely on the\n // server-side tenant resolution instead of upgrade headers.\n const isBrowserWebSocket =\n typeof WebSocket !== 'undefined' && this.WebSocketImpl === WebSocket;\n this.ws = (\n isBrowserWebSocket || !this.options.headers\n ? new (this.WebSocketImpl as any)(this.url, this.options.protocols)\n : new (this.WebSocketImpl as any)(this.url, this.options.protocols, {\n headers: this.options.headers,\n })\n ) as WebSocket;\n\n // Set binary type for MessagePack\n this.ws.binaryType = 'arraybuffer';\n\n // Handle open event\n this.ws.onopen = () => {\n this.setState(ConnectionState.Connected);\n this.reconnectManager.reset();\n this.startHeartbeat();\n resolve();\n };\n\n // Handle message event\n this.ws.onmessage = (event: MessageEvent) => {\n logger.debug(`WebSocket onmessage fired - data type: ${typeof event.data}, is ArrayBuffer: ${event.data instanceof ArrayBuffer}`);\n this.resetHeartbeat();\n const data = event.data as ArrayBuffer;\n logger.debug(`Received binary message - size: ${data.byteLength} bytes`);\n logger.debug(`Emitting 'message' event to client handlers`);\n this.emit('message', data);\n };\n\n // Handle error event\n this.ws.onerror = () => {\n const error = new Error('WebSocket error occurred');\n this.emit('error', error);\n if (this.state === ConnectionState.Connecting) {\n reject(error);\n }\n };\n\n // Handle close event\n this.ws.onclose = (event: CloseEvent) => {\n this.stopHeartbeat();\n this.emit('close', event);\n\n if (!this.manualClose && this.options.autoReconnect) {\n this.setState(ConnectionState.Reconnecting);\n this.reconnect();\n } else {\n this.setState(ConnectionState.Disconnected);\n }\n\n if (this.state === ConnectionState.Connecting) {\n reject(new Error(`Connection closed: ${event.reason || 'Unknown reason'}`));\n }\n };\n } catch (error) {\n this.setState(ConnectionState.Disconnected);\n reject(error);\n }\n });\n }\n\n /**\n * Disconnect from the WebSocket server\n */\n disconnect(): void {\n this.manualClose = true;\n this.reconnectManager.cancelReconnect();\n this.stopHeartbeat();\n\n if (this.ws) {\n this.ws.close(1000, 'Client disconnect');\n this.ws = undefined;\n }\n\n this.setState(ConnectionState.Closed);\n }\n\n /**\n * Send data through the WebSocket\n *\n * @param data - Data to send (Uint8Array for MessagePack)\n */\n send(data: Uint8Array): void {\n if (this.state !== ConnectionState.Connected || !this.ws) {\n throw new Error('Cannot send data: not connected');\n }\n\n // Check actual WebSocket readyState\n if (this.ws.readyState !== 1) { // WebSocket.OPEN = 1\n logger.error(`WebSocket not open - readyState: ${this.ws.readyState} (0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED)`);\n throw new Error(`Cannot send data: WebSocket not open (readyState: ${this.ws.readyState})`);\n }\n\n logger.debug(`Sending message - size: ${data.length} bytes, readyState: ${this.ws.readyState}`);\n\n try {\n this.ws.send(data);\n logger.debug(`Message sent successfully`);\n } catch (error) {\n logger.error(`Failed to send message:`, error);\n throw new Error(`Failed to send data: ${error}`);\n }\n }\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.state === ConnectionState.Connected;\n }\n\n /**\n * Whether auto-reconnect is enabled for this connection.\n *\n * Used by the client to decide whether requests issued while the\n * connection is down can be queued (the connection will come back) or\n * should fail immediately.\n */\n isAutoReconnectEnabled(): boolean {\n return this.options.autoReconnect;\n }\n\n /**\n * Reconnect to the server\n */\n private reconnect(): void {\n const success = this.reconnectManager.scheduleReconnect(async () => {\n try {\n await this.connect();\n } catch (error) {\n // Error is already handled by connect()\n // Reconnection will be scheduled again if autoReconnect is enabled\n }\n });\n\n if (!success) {\n this.setState(ConnectionState.Disconnected);\n this.emit('error', new Error('Max reconnection attempts reached'));\n }\n }\n\n /**\n * Set connection state and emit event\n */\n private setState(state: ConnectionState): void {\n if (this.state !== state) {\n this.state = state;\n this.emit('stateChange', state);\n }\n }\n\n /**\n * Start heartbeat mechanism\n */\n private startHeartbeat(): void {\n if (this.options.heartbeatInterval <= 0) {\n return;\n }\n\n this.stopHeartbeat();\n\n // Note: WebSocket implementations (browser and ws library) automatically handle\n // ping/pong frames at the protocol level, so we don't need application-level heartbeat\n // that sends empty binary messages. The underlying WebSocket will keep the connection alive.\n }\n\n /**\n * Stop heartbeat mechanism\n */\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n }\n\n /**\n * Reset heartbeat timeout (called when message received)\n */\n private resetHeartbeat(): void {\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n }\n}\n","/**\n * Reconnection manager with exponential backoff\n */\n\n/**\n * Reconnection strategy options\n */\nexport interface ReconnectOptions {\n /** Initial delay in milliseconds (default: 1000) */\n initialDelay?: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelay?: number;\n /** Backoff multiplier (default: 2) */\n backoffMultiplier?: number;\n /** Maximum number of reconnection attempts (default: Infinity) */\n maxAttempts?: number;\n /** Add random jitter to delay (default: true). Jitter is +/- 25% of the computed delay. */\n jitter?: boolean;\n}\n\n/**\n * Reconnection manager with exponential backoff\n */\nexport class ReconnectManager {\n private currentDelay: number;\n private attempts = 0;\n private reconnectTimeout?: NodeJS.Timeout;\n private isReconnecting = false;\n\n private readonly initialDelay: number;\n private readonly maxDelay: number;\n private readonly backoffMultiplier: number;\n private readonly maxAttempts: number;\n private readonly jitter: boolean;\n\n constructor(options: ReconnectOptions = {}) {\n this.initialDelay = options.initialDelay ?? 1000;\n this.maxDelay = options.maxDelay ?? 30000;\n this.backoffMultiplier = options.backoffMultiplier ?? 2;\n this.maxAttempts = options.maxAttempts ?? Infinity;\n this.jitter = options.jitter ?? true;\n this.currentDelay = this.initialDelay;\n }\n\n /**\n * Schedule a reconnection attempt\n *\n * @param callback - Function to call when it's time to reconnect\n * @returns true if reconnection was scheduled, false if max attempts reached\n */\n scheduleReconnect(callback: () => void | Promise<void>): boolean {\n // Check if we've exceeded max attempts\n if (this.attempts >= this.maxAttempts) {\n return false;\n }\n\n // Clear any existing timeout\n this.cancelReconnect();\n\n this.isReconnecting = true;\n this.attempts++;\n\n // Apply jitter: +/- 25% of the computed delay\n let delay = this.currentDelay;\n if (this.jitter) {\n const jitterRange = delay * 0.25;\n delay += (Math.random() * 2 - 1) * jitterRange;\n delay = Math.max(0, Math.round(delay));\n }\n\n this.reconnectTimeout = setTimeout(async () => {\n try {\n await callback();\n // If successful, reset the delay\n this.reset();\n } catch (error) {\n // Increase delay for next attempt\n this.currentDelay = Math.min(\n this.currentDelay * this.backoffMultiplier,\n this.maxDelay\n );\n }\n }, delay);\n\n return true;\n }\n\n /**\n * Cancel any pending reconnection attempt\n */\n cancelReconnect(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = undefined;\n }\n this.isReconnecting = false;\n }\n\n /**\n * Reset the reconnection state (call after successful connection)\n */\n reset(): void {\n this.cancelReconnect();\n this.currentDelay = this.initialDelay;\n this.attempts = 0;\n }\n\n /**\n * Check if currently in reconnection mode\n */\n isActive(): boolean {\n return this.isReconnecting;\n }\n\n /**\n * Get the current number of reconnection attempts\n */\n getAttempts(): number {\n return this.attempts;\n }\n\n /**\n * Get the current delay in milliseconds\n */\n getCurrentDelay(): number {\n return this.currentDelay;\n }\n\n /**\n * Check if max attempts have been reached\n */\n hasReachedMaxAttempts(): boolean {\n return this.attempts >= this.maxAttempts;\n }\n}\n","/**\n * Configurable logger for RaisinDB client\n */\n\n/**\n * Log levels in order of verbosity (lower = less verbose)\n */\nexport enum LogLevel {\n Silent = 0,\n Error = 1,\n Warn = 2,\n Info = 3,\n Debug = 4,\n}\n\n/**\n * Logger configuration\n */\nexport interface LoggerConfig {\n /** Current log level (default: Error) */\n level: LogLevel;\n /** Prefix for all log messages (default: \"[RaisinDB]\") */\n prefix: string;\n}\n\n/**\n * Global logger configuration\n */\nlet config: LoggerConfig = {\n level: LogLevel.Error,\n prefix: '[RaisinDB]',\n};\n\n/**\n * Configure the logger\n *\n * @param options - Logger configuration options\n *\n * @example\n * ```typescript\n * import { configureLogger, LogLevel } from '@raisindb/client';\n *\n * // Enable debug logging\n * configureLogger({ level: LogLevel.Debug });\n *\n * // Disable all logging\n * configureLogger({ level: LogLevel.Silent });\n * ```\n */\nexport function configureLogger(options: Partial<LoggerConfig>): void {\n config = { ...config, ...options };\n}\n\n/**\n * Get current logger configuration\n */\nexport function getLoggerConfig(): LoggerConfig {\n return { ...config };\n}\n\n/**\n * Set log level\n *\n * @param level - Log level to set\n */\nexport function setLogLevel(level: LogLevel): void {\n config.level = level;\n}\n\n/**\n * Get current log level\n */\nexport function getLogLevel(): LogLevel {\n return config.level;\n}\n\n/**\n * Logger instance with level-aware logging methods\n */\nexport const logger = {\n /**\n * Log debug message (only shown when level >= Debug)\n */\n debug(...args: unknown[]): void {\n if (config.level >= LogLevel.Debug) {\n console.log(config.prefix, ...args);\n }\n },\n\n /**\n * Log info message (only shown when level >= Info)\n */\n info(...args: unknown[]): void {\n if (config.level >= LogLevel.Info) {\n console.log(config.prefix, ...args);\n }\n },\n\n /**\n * Log warning message (only shown when level >= Warn)\n */\n warn(...args: unknown[]): void {\n if (config.level >= LogLevel.Warn) {\n console.warn(config.prefix, ...args);\n }\n },\n\n /**\n * Log error message (only shown when level >= Error)\n */\n error(...args: unknown[]): void {\n if (config.level >= LogLevel.Error) {\n console.error(config.prefix, ...args);\n }\n },\n};\n\nif (typeof globalThis !== 'undefined') {\n (globalThis as any).__raisinDebug = (enable = true) => {\n setLogLevel(enable ? LogLevel.Debug : LogLevel.Error);\n console.log(`[RaisinDB] Debug logging ${enable ? 'ENABLED' : 'DISABLED'} (includes server handler logs)`);\n };\n}\n","/**\n * Request tracker for managing pending requests and their promises\n */\n\nimport { v4 as uuidv4 } from 'uuid';\n\n/**\n * Pending request information\n */\ninterface PendingRequest<T = unknown> {\n resolve: (value: T) => void;\n reject: (error: Error) => void;\n timeout?: NodeJS.Timeout;\n}\n\n/**\n * Request tracker options\n */\nexport interface RequestTrackerOptions {\n /** Default timeout in milliseconds (default: 30000) */\n defaultTimeout?: number;\n}\n\n/**\n * RequestTracker manages pending requests and their promises\n */\nexport class RequestTracker {\n private pendingRequests = new Map<string, PendingRequest>();\n private defaultTimeout: number;\n\n constructor(options: RequestTrackerOptions = {}) {\n this.defaultTimeout = options.defaultTimeout ?? 30000;\n }\n\n /**\n * Generate a new unique request ID\n */\n generateRequestId(): string {\n return uuidv4();\n }\n\n /**\n * Create a new tracked request\n *\n * @param requestId - Unique request ID\n * @param timeout - Timeout in milliseconds (uses default if not specified)\n * @returns Promise that resolves when response is received\n */\n createRequest<T = unknown>(requestId: string, timeout?: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timeoutMs = timeout ?? this.defaultTimeout;\n\n // Set up timeout\n const timeoutHandle = setTimeout(() => {\n this.rejectRequest(\n requestId,\n new Error(`Request ${requestId} timed out after ${timeoutMs}ms`)\n );\n }, timeoutMs);\n\n // Store pending request\n this.pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: timeoutHandle,\n });\n });\n }\n\n /**\n * Resolve a pending request\n *\n * @param requestId - Request ID to resolve\n * @param value - Value to resolve with\n */\n resolveRequest<T = unknown>(requestId: string, value: T): void {\n const pending = this.pendingRequests.get(requestId);\n if (pending) {\n if (pending.timeout) {\n clearTimeout(pending.timeout);\n }\n pending.resolve(value);\n this.pendingRequests.delete(requestId);\n }\n }\n\n /**\n * Reject a pending request\n *\n * @param requestId - Request ID to reject\n * @param error - Error to reject with\n */\n rejectRequest(requestId: string, error: Error): void {\n const pending = this.pendingRequests.get(requestId);\n if (pending) {\n if (pending.timeout) {\n clearTimeout(pending.timeout);\n }\n pending.reject(error);\n this.pendingRequests.delete(requestId);\n }\n }\n\n /**\n * Cancel a pending request\n *\n * @param requestId - Request ID to cancel\n */\n cancelRequest(requestId: string): void {\n this.rejectRequest(requestId, new Error(`Request ${requestId} was cancelled`));\n }\n\n /**\n * Check if a request is pending\n *\n * @param requestId - Request ID to check\n */\n hasPendingRequest(requestId: string): boolean {\n return this.pendingRequests.has(requestId);\n }\n\n /**\n * Get the number of pending requests\n */\n getPendingCount(): number {\n return this.pendingRequests.size;\n }\n\n /**\n * Cancel all pending requests\n */\n cancelAll(): void {\n const requestIds = Array.from(this.pendingRequests.keys());\n for (const requestId of requestIds) {\n this.cancelRequest(requestId);\n }\n }\n\n /**\n * Clear all pending requests without rejecting them\n * (useful during cleanup)\n */\n clear(): void {\n for (const pending of this.pendingRequests.values()) {\n if (pending.timeout) {\n clearTimeout(pending.timeout);\n }\n }\n this.pendingRequests.clear();\n }\n}\n","/**\n * JWT authentication manager\n */\n\nimport {\n AuthenticatePayload,\n AuthenticateResponse,\n RefreshTokenPayload,\n} from './protocol';\n\n/**\n * Token storage interface\n */\nexport interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string): void;\n getRefreshToken(): string | null;\n setRefreshToken(token: string): void;\n clear(): void;\n}\n\n/**\n * In-memory token storage (default)\n */\nexport class MemoryTokenStorage implements TokenStorage {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getRefreshToken(): string | null {\n return this.refreshToken;\n }\n\n setRefreshToken(token: string): void {\n this.refreshToken = token;\n }\n\n clear(): void {\n this.accessToken = null;\n this.refreshToken = null;\n }\n}\n\n/**\n * LocalStorage-based token storage for browser\n */\nexport class LocalStorageTokenStorage implements TokenStorage {\n private prefix: string;\n\n constructor(prefix: string = 'raisindb') {\n this.prefix = prefix;\n }\n\n getAccessToken(): string | null {\n if (typeof localStorage === 'undefined') return null;\n return localStorage.getItem(`${this.prefix}_access_token`);\n }\n\n setAccessToken(token: string): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(`${this.prefix}_access_token`, token);\n }\n\n getRefreshToken(): string | null {\n if (typeof localStorage === 'undefined') return null;\n return localStorage.getItem(`${this.prefix}_refresh_token`);\n }\n\n setRefreshToken(token: string): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(`${this.prefix}_refresh_token`, token);\n }\n\n clear(): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.removeItem(`${this.prefix}_access_token`);\n localStorage.removeItem(`${this.prefix}_refresh_token`);\n localStorage.removeItem(`${this.prefix}_user`);\n }\n\n /**\n * Store user data in localStorage\n */\n setUser(user: IdentityUser): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(`${this.prefix}_user`, JSON.stringify(user));\n }\n\n /**\n * Get stored user data from localStorage\n */\n getUser(): IdentityUser | null {\n if (typeof localStorage === 'undefined') return null;\n const userJson = localStorage.getItem(`${this.prefix}_user`);\n if (!userJson) return null;\n try {\n return JSON.parse(userJson);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Identity user information (from JWT/login response)\n */\nexport interface IdentityUser {\n /** Identity UUID */\n id: string;\n /** Email address */\n email: string;\n /** Display name */\n displayName: string | null;\n /** Avatar URL */\n avatarUrl: string | null;\n /** Whether email is verified */\n emailVerified: boolean;\n /** User's home node path in the repository (from JWT or RAISIN_CURRENT_USER) */\n home: string | null;\n}\n\n/**\n * Identity auth tokens response (from HTTP login/register)\n */\nexport interface IdentityAuthResponse {\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_at: number;\n identity: {\n id: string;\n email: string;\n display_name: string | null;\n avatar_url: string | null;\n email_verified: boolean;\n linked_providers: string[];\n /** User's home node path in the repository */\n home: string | null;\n };\n}\n\n/**\n * Identity auth error\n */\nexport interface IdentityAuthError {\n code: string;\n message: string;\n}\n\n/**\n * Admin authentication credentials (username/password)\n */\nexport interface AdminCredentials {\n username: string;\n password: string;\n}\n\n/**\n * JWT authentication credentials (identity users)\n * Used by SPAs that have obtained a JWT via HTTP API\n */\nexport interface JwtCredentials {\n type: 'jwt';\n token: string;\n}\n\n/**\n * Authentication credentials - either admin or JWT\n */\nexport type Credentials = AdminCredentials | JwtCredentials;\n\n/**\n * Type guard to check if credentials are JWT-based\n */\nexport function isJwtCredentials(credentials: Credentials): credentials is JwtCredentials {\n return 'type' in credentials && credentials.type === 'jwt';\n}\n\n/**\n * Authentication manager\n */\nexport class AuthManager {\n private _storage: TokenStorage;\n private expiresAt: number | null = null;\n private refreshTimer?: NodeJS.Timeout;\n\n constructor(storage?: TokenStorage) {\n this._storage = storage ?? new MemoryTokenStorage();\n }\n\n /**\n * Get storage (for direct token manipulation)\n */\n get storage(): TokenStorage {\n return this._storage;\n }\n\n /**\n * Store authentication response\n *\n * @param response - Authentication response from server\n */\n setTokens(response: AuthenticateResponse): void {\n this._storage.setAccessToken(response.access_token);\n this._storage.setRefreshToken(response.refresh_token);\n\n // Calculate expiration time (subtract 60 seconds for safety margin)\n const expiresInMs = (response.expires_in - 60) * 1000;\n this.expiresAt = Date.now() + expiresInMs;\n\n // Schedule automatic refresh\n this.scheduleTokenRefresh(expiresInMs);\n }\n\n /**\n * Get current access token\n */\n getAccessToken(): string | null {\n return this._storage.getAccessToken();\n }\n\n /**\n * Get current refresh token\n */\n getRefreshToken(): string | null {\n return this._storage.getRefreshToken();\n }\n\n /**\n * Check if authenticated\n */\n isAuthenticated(): boolean {\n const token = this._storage.getAccessToken();\n return token !== null && !this.isTokenExpired();\n }\n\n /**\n * Check if token is expired\n */\n isTokenExpired(): boolean {\n if (this.expiresAt === null) {\n return true;\n }\n return Date.now() >= this.expiresAt;\n }\n\n /**\n * Check if token needs refresh (within 5 minutes of expiration)\n */\n needsRefresh(): boolean {\n if (this.expiresAt === null) {\n return false;\n }\n const fiveMinutes = 5 * 60 * 1000;\n return Date.now() >= this.expiresAt - fiveMinutes;\n }\n\n /**\n * Clear authentication state\n */\n clear(): void {\n this._storage.clear();\n this.expiresAt = null;\n this.cancelTokenRefresh();\n }\n\n /**\n * Schedule automatic token refresh\n *\n * @param delayMs - Delay in milliseconds\n */\n private scheduleTokenRefresh(delayMs: number): void {\n this.cancelTokenRefresh();\n\n this.refreshTimer = setTimeout(() => {\n // Emit event that refresh is needed\n // The client should handle this by calling the refresh endpoint\n }, delayMs);\n }\n\n /**\n * Cancel scheduled token refresh\n */\n private cancelTokenRefresh(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = undefined;\n }\n }\n\n /**\n * Create authentication payload for admin auth\n *\n * @param credentials - Admin credentials\n */\n static createAuthPayload(credentials: AdminCredentials): AuthenticatePayload {\n return {\n username: credentials.username,\n password: credentials.password,\n };\n }\n\n /**\n * Create refresh token payload\n *\n * @param refreshToken - Refresh token\n */\n static createRefreshPayload(refreshToken: string): RefreshTokenPayload {\n return {\n refresh_token: refreshToken,\n };\n }\n\n /**\n * Parse JWT token (without verification)\n * This is just for extracting expiration time, not for security\n *\n * @param token - JWT token\n * @returns Parsed token payload or null if invalid\n */\n static parseToken(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(decoded);\n } catch (error) {\n return null;\n }\n }\n}\n","/**\n * WebSocket protocol definitions for RaisinDB\n *\n * This module defines TypeScript interfaces matching the Rust protocol.\n * All messages are serialized using MessagePack for efficiency.\n */\n\nimport { encode, decode } from '@msgpack/msgpack';\n\n// ============================================================================\n// Core Envelope Types\n// ============================================================================\n\n/**\n * Request envelope wrapping all client-to-server messages\n */\nexport interface RequestEnvelope {\n /** Unique identifier for this request (generated by client) */\n request_id: string;\n /** Type of request */\n type: RequestType;\n /** Request context (tenant, repository, workspace) */\n context: RequestContext;\n /** Request-specific payload */\n payload: unknown;\n}\n\n/**\n * Response envelope wrapping all server-to-client messages\n */\nexport interface ResponseEnvelope {\n /** Request ID this response corresponds to */\n request_id: string;\n /** Response status */\n status: ResponseStatus;\n /** Response data (if successful) */\n result?: unknown;\n /** Error information (if failed) */\n error?: ErrorInfo;\n /** Metadata for streaming responses */\n metadata?: ResponseMetadata;\n}\n\n/**\n * Payload of node events (`node:created`, `node:updated`, `node:deleted`, ...)\n * as emitted by the server's WebSocket event forwarder.\n *\n * All fields except `kind` are optional because the exact shape depends on\n * the event kind and subscription options (e.g. `node` is only present when\n * the subscription was created with `include_node: true`). Unknown extra\n * fields are accessible via the index signature.\n */\nexport interface NodeEventPayload {\n /** Event kind (e.g. \"Created\", \"Updated\", \"Deleted\", \"PropertyChanged { .. }\") */\n kind: string;\n /** Tenant the event originated from */\n tenant_id?: string;\n /** Repository the event originated from */\n repository_id?: string;\n /** Branch the event originated from */\n branch?: string;\n /** Workspace containing the node */\n workspace_id?: string;\n /** ID of the affected node */\n node_id?: string;\n /** Node type of the affected node */\n node_type?: string | null;\n /** Revision (HLC timestamp) of the change */\n revision?: string;\n /** Path of the affected node */\n path?: string | null;\n /** Full node data (only when subscribed with `include_node: true`) */\n node?: Node;\n /** Event metadata (source, related nodes, ...) */\n metadata?: Record<string, unknown> | null;\n /** Relation type (for `node:relation_added` / `node:relation_removed`) */\n relation_type?: string;\n /** Target node ID (for relation events) */\n target_node_id?: string;\n /** Changed property name (for `node:property_changed`) */\n property?: string;\n /** Related node ID, if provided in event metadata */\n related_node_id?: string;\n /** Related workspace, if provided in event metadata */\n related_workspace?: string;\n /** Relation direction, if provided in event metadata */\n relation_direction?: string;\n /** Additional event-specific fields */\n [key: string]: unknown;\n}\n\n/**\n * Event message for server-initiated events (subscriptions)\n *\n * Defaults the payload type to {@link NodeEventPayload} (the most common\n * case). Pass a type parameter for other event families\n * (e.g. `EventMessage<MyRepositoryEventPayload>`).\n */\nexport interface EventMessage<TPayload = NodeEventPayload> {\n /** Unique event ID */\n event_id: string;\n /** Subscription ID this event belongs to */\n subscription_id: string;\n /** Event type */\n event_type: string;\n /** Event payload */\n payload: TPayload;\n /** Timestamp of the event (ISO 8601 string) */\n timestamp: string;\n}\n\n/**\n * Connected message sent by server on WebSocket connection\n * Includes anonymous token for HTTP API calls when anonymous access is enabled\n */\nexport interface ConnectedMessage {\n /** Message type identifier */\n type: 'connected';\n /** Connection ID assigned by server */\n connection_id: string;\n /** Whether this is an anonymous connection */\n anonymous: boolean;\n /** JWT token for HTTP API calls (only for anonymous connections) */\n token?: string;\n /** User ID (for anonymous connections, a generated UUID) */\n user_id?: string;\n}\n\n/**\n * Request context containing scope information\n */\nexport interface RequestContext {\n /** Tenant ID */\n tenant_id: string;\n /** Repository ID (optional for some operations) */\n repository?: string;\n /** Branch name (optional, defaults to \"main\") */\n branch?: string;\n /** Workspace ID (optional for some operations) */\n workspace?: string;\n /** Revision/commit ID for time-travel queries (optional) */\n revision?: string;\n /** Transaction ID for transactional operations (optional) */\n transaction_id?: string;\n}\n\n// ============================================================================\n// Enums\n// ============================================================================\n\n/**\n * Type of request\n */\nexport enum RequestType {\n // Authentication\n Authenticate = 'authenticate',\n AuthenticateJwt = 'authenticate_jwt',\n RefreshToken = 'refresh_token',\n\n // Node operations\n NodeCreate = 'node_create',\n NodeUpdate = 'node_update',\n NodeDelete = 'node_delete',\n NodeGet = 'node_get',\n NodeQuery = 'node_query',\n NodeQueryByPath = 'node_query_by_path',\n NodeQueryByProperty = 'node_query_by_property',\n\n // Tree operations\n NodeListChildren = 'node_list_children',\n NodeGetTree = 'node_get_tree',\n NodeGetTreeFlat = 'node_get_tree_flat',\n\n // Node manipulation operations\n NodeMove = 'node_move',\n NodeRename = 'node_rename',\n NodeCopy = 'node_copy',\n NodeCopyTree = 'node_copy_tree',\n NodeReorder = 'node_reorder',\n NodeMoveChildBefore = 'node_move_child_before',\n NodeMoveChildAfter = 'node_move_child_after',\n NodeApplyChildOrder = 'node_apply_child_order',\n\n // Property path operations\n PropertyGet = 'property_get',\n PropertyUpdate = 'property_update',\n\n // Relationship operations\n RelationAdd = 'relation_add',\n RelationRemove = 'relation_remove',\n RelationsGet = 'relations_get',\n\n // SQL queries\n SqlQuery = 'sql_query',\n\n // Workspace operations\n WorkspaceCreate = 'workspace_create',\n WorkspaceGet = 'workspace_get',\n WorkspaceList = 'workspace_list',\n WorkspaceDelete = 'workspace_delete',\n WorkspaceUpdate = 'workspace_update',\n\n // Branch operations\n BranchCreate = 'branch_create',\n BranchGet = 'branch_get',\n BranchList = 'branch_list',\n BranchDelete = 'branch_delete',\n BranchGetHead = 'branch_get_head',\n BranchUpdateHead = 'branch_update_head',\n BranchMerge = 'branch_merge',\n BranchCompare = 'branch_compare',\n BranchDiff = 'branch_diff',\n BranchCopyNodes = 'branch_copy_nodes',\n\n // Tag operations\n TagCreate = 'tag_create',\n TagGet = 'tag_get',\n TagList = 'tag_list',\n TagDelete = 'tag_delete',\n\n // NodeType operations\n NodeTypeCreate = 'node_type_create',\n NodeTypeGet = 'node_type_get',\n NodeTypeList = 'node_type_list',\n NodeTypeUpdate = 'node_type_update',\n NodeTypeDelete = 'node_type_delete',\n NodeTypePublish = 'node_type_publish',\n NodeTypeUnpublish = 'node_type_unpublish',\n NodeTypeValidate = 'node_type_validate',\n NodeTypeGetResolved = 'node_type_get_resolved',\n\n // Archetype operations\n ArchetypeCreate = 'archetype_create',\n ArchetypeGet = 'archetype_get',\n ArchetypeList = 'archetype_list',\n ArchetypeUpdate = 'archetype_update',\n ArchetypeDelete = 'archetype_delete',\n ArchetypePublish = 'archetype_publish',\n ArchetypeUnpublish = 'archetype_unpublish',\n ArchetypeGetResolved = 'archetype_get_resolved',\n\n // ElementType operations\n ElementTypeCreate = 'element_type_create',\n ElementTypeGet = 'element_type_get',\n ElementTypeList = 'element_type_list',\n ElementTypeUpdate = 'element_type_update',\n ElementTypeDelete = 'element_type_delete',\n ElementTypePublish = 'element_type_publish',\n ElementTypeUnpublish = 'element_type_unpublish',\n ElementTypeGetResolved = 'element_type_get_resolved',\n\n // Search operations\n FullTextSearch = 'full_text_search',\n VectorSearch = 'vector_search',\n\n // Event subscriptions\n Subscribe = 'subscribe',\n Unsubscribe = 'unsubscribe',\n\n // Repository management\n RepositoryCreate = 'repository_create',\n RepositoryGet = 'repository_get',\n RepositoryList = 'repository_list',\n RepositoryUpdate = 'repository_update',\n RepositoryDelete = 'repository_delete',\n\n // Audit operations\n AuditQuery = 'audit_query',\n\n // Binary operations\n BinaryUpload = 'binary_upload',\n BinaryDownload = 'binary_download',\n\n // Batch operations\n Batch = 'batch',\n\n // Transaction operations\n TransactionBegin = 'transaction_begin',\n TransactionCommit = 'transaction_commit',\n TransactionRollback = 'transaction_rollback',\n\n // Flow operations\n FlowRun = 'flow_run',\n FlowResume = 'flow_resume',\n FlowGetInstanceStatus = 'flow_get_instance_status',\n FlowCancel = 'flow_cancel',\n FlowSubscribeEvents = 'flow_subscribe_events',\n FlowUnsubscribeEvents = 'flow_unsubscribe_events',\n\n // Function operations\n FunctionInvoke = 'function_invoke',\n FunctionInvokeSync = 'function_invoke_sync',\n\n // Scheduled invocation operations (one-shot, time-based function/flow runs)\n ScheduledInvocationCreate = 'scheduled_invocation_create',\n ScheduledInvocationCancel = 'scheduled_invocation_cancel',\n ScheduledInvocationList = 'scheduled_invocation_list',\n ScheduledInvocationGet = 'scheduled_invocation_get',\n}\n\n/**\n * Response status\n */\nexport enum ResponseStatus {\n /** Request succeeded, complete result included */\n Success = 'success',\n /** Request failed, error information included */\n Error = 'error',\n /** Streaming response, more chunks to come */\n Streaming = 'streaming',\n /** Final chunk of a streaming response */\n Complete = 'complete',\n /** Request acknowledged, processing asynchronously */\n Acknowledged = 'acknowledged',\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Error information\n */\nexport interface ErrorInfo {\n /** Error code */\n code: string;\n /** Human-readable error message */\n message: string;\n /** Additional error details */\n details?: unknown;\n}\n\n/**\n * Response metadata for streaming and pagination\n */\nexport interface ResponseMetadata {\n /** Current chunk number (for streaming) */\n chunk?: number;\n /** Total number of chunks (if known) */\n total_chunks?: number;\n /** Total number of results (for pagination) */\n total?: number;\n /** Has more results available */\n has_more?: boolean;\n /** Credits consumed (for backpressure) */\n credits_consumed?: number;\n}\n\n// ============================================================================\n// Node Operation Types\n// ============================================================================\n\n/**\n * Node data structure\n */\n/**\n * A reference to a related node in the graph database\n */\nexport interface RelationRef {\n /** ID of the target node */\n target: string;\n /** Workspace containing the target node */\n workspace: string;\n /** Node type of the target (for filtering) */\n target_node_type: string;\n /** Semantic relationship type (e.g., \"references\", \"links_to\") */\n relation_type: string;\n /** Optional weight for graph algorithms */\n weight?: number;\n}\n\n/**\n * An incoming relationship record including the source node metadata\n */\nexport interface IncomingRelation {\n /** Workspace containing the source node */\n source_workspace: string;\n /** ID of the source node */\n source_node_id: string;\n /** Relationship details pointing to the current node */\n relation: RelationRef;\n}\n\n/**\n * Complete incoming/outgoing relationship information for a node\n */\nexport interface NodeRelationships {\n /** Relationships originating from this node */\n outgoing: RelationRef[];\n /** Relationships targeting this node */\n incoming: IncomingRelation[];\n}\n\n/**\n * A content node in RaisinDB's hierarchical structure\n */\nexport interface Node {\n /** Unique identifier for this node */\n id: string;\n /** Display name of the node (used in URLs and hierarchical paths) */\n name: string;\n /** Full path to this node in the tree (e.g., \"/content/my-page\") */\n path: string;\n /** The NodeType name that defines this node's schema */\n node_type: string;\n /** Optional archetype for specialized rendering */\n archetype?: string;\n /** Key-value map of properties, validated against the NodeType schema */\n properties: Record<string, PropertyValue>;\n /** Ordered list of child node IDs */\n children: string[];\n /** Fractional index for ordering among siblings (Base62 string) */\n order_key: string;\n /** Whether this node has children (computed field) */\n has_children?: boolean;\n /**\n * Name of the parent node (not the full path, just the name).\n * Example: If path is \"/content/docs/page1\", parent should be \"docs\"\n */\n parent?: string;\n /** Version number for this node (incremented on updates) */\n version: number;\n /** Timestamp when this node was created (ISO 8601 string) */\n created_at?: string;\n /** Timestamp when this node was last updated (ISO 8601 string) */\n updated_at?: string;\n /** Timestamp when this node was published (ISO 8601 string, null if unpublished) */\n published_at?: string;\n /** User ID who published this node */\n published_by?: string;\n /** User ID who last updated this node */\n updated_by?: string;\n /** User ID who created this node */\n created_by?: string;\n /** Translations for multi-language support */\n translations?: Record<string, PropertyValue>;\n /** Tenant ID for multi-tenant deployments */\n tenant_id?: string;\n /** Workspace this node belongs to */\n workspace?: string;\n /** Owner user ID (for access control) */\n owner_id?: string;\n /** Relations to other nodes */\n relations: RelationRef[];\n}\n\n/**\n * Property value types\n */\nexport type PropertyValue =\n | string\n | number\n | boolean\n | null\n | PropertyValue[]\n | { [key: string]: PropertyValue };\n\n/**\n * Node create payload\n */\nexport interface NodeCreatePayload {\n node_type: string;\n path: string;\n properties: Record<string, PropertyValue>;\n content?: unknown;\n}\n\n/**\n * Deep create/upsert payload. `path` is the full node path; missing ancestor\n * folders are auto-created as `parent_node_type` (defaults to `raisin:Folder`).\n */\nexport interface NodeCreateDeepPayload {\n node_type: string;\n path: string;\n properties: Record<string, PropertyValue>;\n content?: unknown;\n parent_node_type?: string;\n}\n\n/**\n * Node update payload\n */\nexport interface NodeUpdatePayload {\n node_id: string;\n properties: Record<string, PropertyValue>;\n content?: unknown;\n}\n\n/**\n * Node delete payload\n */\nexport interface NodeDeletePayload {\n node_id: string;\n}\n\n/**\n * Node get payload\n */\nexport interface NodeGetPayload {\n node_id: string;\n}\n\n/**\n * Node history payload (git-style \"file history\").\n * Identify the node by either `node_id` or `path`.\n */\nexport interface NodeHistoryPayload {\n node_id?: string;\n path?: string;\n /** Maximum number of revisions to return (newest first). Unbounded if omitted. */\n limit?: number;\n}\n\n/**\n * A single entry in a node's revision history (newest first).\n *\n * Use `revision` with `atRevision(revision)` reads to fetch the full snapshot\n * of that historical version.\n */\nexport interface RevisionEntry {\n /** HLC revision string (\"timestamp-counter\"), usable with atRevision(). */\n revision: string;\n /** When this revision was written (ISO 8601 string). */\n updated_at?: string;\n /** User ID who authored this revision. */\n updated_by?: string;\n /** True when the node was deleted at this revision (tombstone). */\n deleted: boolean;\n}\n\n/**\n * Audit-log query payload. Identify the node by either `node_id` or `path`.\n * Audit logs are only produced for NodeTypes marked `auditable`.\n */\nexport interface AuditQueryPayload {\n node_id?: string;\n path?: string;\n}\n\n/**\n * A single audit-log entry for a node.\n *\n * Only produced for NodeTypes marked `auditable`. Distinct from a\n * {@link RevisionEntry} (the always-on structural MVCC history).\n */\nexport interface AuditLogEntry {\n id: string;\n node_id: string;\n path: string;\n workspace: string;\n /** User ID that performed the action (the node's `updated_by` at write time). */\n user_id?: string;\n /** Action performed, e.g. \"Create\" | \"Update\" | \"Delete\" | \"Publish\" | … */\n action: string;\n /** ISO 8601 timestamp. */\n timestamp: string;\n details?: string;\n}\n\n/**\n * Node query payload\n */\nexport interface NodeQueryPayload {\n query: unknown;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Relationship add payload\n */\nexport interface RelationAddPayload {\n source_path: string;\n target_workspace: string;\n target_path: string;\n weight?: number;\n relation_type?: string;\n}\n\n/**\n * Relationship remove payload\n */\nexport interface RelationRemovePayload {\n source_path: string;\n target_workspace: string;\n target_path: string;\n}\n\n/**\n * Relationship list payload\n */\nexport interface RelationsGetPayload {\n node_path: string;\n}\n\n/**\n * SQL query payload\n */\nexport interface SqlQueryPayload {\n /** SQL query string */\n query: string;\n /** Parameters for the query (for injection protection) */\n params?: unknown[];\n}\n\n/**\n * SQL query result\n */\nexport interface SqlResult {\n columns: string[];\n rows: Record<string, unknown>[];\n row_count: number;\n}\n\n// ============================================================================\n// Workspace Operation Types\n// ============================================================================\n\n/**\n * Workspace data structure\n */\nexport interface Workspace {\n id: string;\n name: string;\n description?: string;\n allowed_node_types?: string[];\n allowed_root_node_types?: string[];\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Workspace create payload\n */\nexport interface WorkspaceCreatePayload {\n name: string;\n description?: string;\n}\n\n/**\n * Workspace get payload\n */\nexport interface WorkspaceGetPayload {\n name: string;\n}\n\n/**\n * Workspace delete payload\n */\nexport interface WorkspaceDeletePayload {\n name: string;\n}\n\n/**\n * Workspace update payload\n */\nexport interface WorkspaceUpdatePayload {\n name: string;\n description?: string;\n allowed_node_types?: string[];\n allowed_root_node_types?: string[];\n}\n\n// ============================================================================\n// Transaction Operation Types\n// ============================================================================\n\n/**\n * Transaction begin payload\n */\nexport interface TransactionBeginPayload {\n /** Optional commit message */\n message?: string;\n /** Optional actor identifier */\n actor?: string;\n}\n\n/**\n * Transaction begin response\n */\nexport interface TransactionBeginResponse {\n /** Unique transaction ID */\n transaction_id: string;\n}\n\n/**\n * Transaction commit payload\n */\nexport interface TransactionCommitPayload {}\n\n/**\n * Transaction commit response\n */\nexport interface TransactionCommitResponse {\n /** Revision (HLC timestamp) assigned to this commit in format \"timestamp-counter\" (e.g., \"1762780281515-0\") */\n revision: string;\n /** Unique commit ID */\n commit_id: string;\n}\n\n/**\n * Transaction rollback payload\n */\nexport interface TransactionRollbackPayload {}\n\n// ============================================================================\n// Event Subscription Types\n// ============================================================================\n\n/**\n * Subscribe payload\n */\nexport interface SubscribePayload {\n /** Filters for this subscription */\n filters: SubscriptionFilters;\n}\n\n/**\n * Subscription filters\n */\nexport interface SubscriptionFilters {\n /** Filter by workspace */\n workspace?: string;\n /**\n * Filter by path pattern.\n *\n * Semantics: a plain path matches only that exact node (no implicit\n * prefix matching), `*` matches exactly one path segment, `**` matches\n * recursively (e.g. \"/folder/**\" for all descendants of \"/folder\").\n */\n path?: string;\n /** Filter by event types */\n event_types?: string[];\n /** Filter by node type */\n node_type?: string;\n /** Include full node data in event payload (default: false) */\n include_node?: boolean;\n}\n\n/**\n * Unsubscribe payload\n */\nexport interface UnsubscribePayload {\n /** Subscription ID to cancel */\n subscription_id: string;\n}\n\n/**\n * Subscription response\n */\nexport interface SubscriptionResponse {\n /** Unique subscription ID */\n subscription_id: string;\n}\n\n// ============================================================================\n// Authentication Types\n// ============================================================================\n\n/**\n * Authenticate payload (admin user with username/password)\n */\nexport interface AuthenticatePayload {\n username: string;\n password: string;\n}\n\n/**\n * Authenticate with JWT token (identity user)\n *\n * Used by SPAs and clients that have already obtained a JWT token\n * via HTTP API (e.g., /auth/{repo}/login)\n */\nexport interface AuthenticateJwtPayload {\n /** JWT access token from identity provider */\n token: string;\n}\n\n/**\n * Authenticate response (admin auth)\n */\nexport interface AuthenticateResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n}\n\n/**\n * Authenticate JWT response (identity auth)\n */\nexport interface AuthenticateJwtResponse {\n /** User ID from the JWT */\n user_id: string;\n /** Effective roles assigned to the user */\n roles: string[];\n}\n\n/**\n * Refresh token payload\n */\nexport interface RefreshTokenPayload {\n refresh_token: string;\n}\n\n// ============================================================================\n// MessagePack Utilities\n// ============================================================================\n\n/**\n * Encode a message to MessagePack binary format\n */\nexport function encodeMessage(message: RequestEnvelope): Uint8Array {\n return encode(message);\n}\n\n/**\n * Decode a MessagePack binary message\n */\nexport function decodeMessage(data: ArrayBuffer | Uint8Array): ResponseEnvelope | EventMessage {\n const decoded = decode(data) as ResponseEnvelope | EventMessage;\n\n // Type guard: check if it's an event message\n if ('subscription_id' in decoded && 'event_type' in decoded) {\n return decoded as EventMessage;\n }\n\n return decoded as ResponseEnvelope;\n}\n\n/**\n * Type guard to check if a message is an event\n */\nexport function isEventMessage(message: ResponseEnvelope | EventMessage): message is EventMessage {\n return 'subscription_id' in message && 'event_type' in message;\n}\n\n/**\n * Type guard to check if a message is a response\n */\nexport function isResponseEnvelope(message: ResponseEnvelope | EventMessage): message is ResponseEnvelope {\n return 'status' in message && !('subscription_id' in message);\n}\n\n/**\n * Type guard to check if a message is a connected message\n */\nexport function isConnectedMessage(message: unknown): message is ConnectedMessage {\n return (\n typeof message === 'object' &&\n message !== null &&\n 'type' in message &&\n (message as ConnectedMessage).type === 'connected'\n );\n}\n","/**\n * Event subscription system\n */\n\nimport {\n EventMessage,\n SubscriptionFilters,\n SubscribePayload,\n UnsubscribePayload,\n SubscriptionResponse,\n RequestType,\n} from './protocol';\nimport { logger } from './logger';\n\n/**\n * Event callback function\n */\nexport type EventCallback = (event: EventMessage) => void;\n\n/**\n * Subscription interface\n */\nexport interface Subscription {\n /** Unique subscription ID */\n id: string;\n /** Unsubscribe from events */\n unsubscribe(): Promise<void>;\n /** Check if subscription is active */\n isActive(): boolean;\n}\n\n/**\n * Internal tracking for deduplicated subscriptions\n */\ninterface FilterSubscriptionEntry {\n /** Server-side subscription ID */\n serverId: string;\n /** Original filters (for reconnection) */\n filters: SubscriptionFilters;\n /** All callbacks registered for this filter combination */\n callbacks: Set<EventCallback>;\n /** Set while the entry still needs to be re-subscribed after a reconnect */\n restorePending?: boolean;\n}\n\n/** Default deduplication window in milliseconds (5 seconds) */\nconst DEFAULT_DEDUP_WINDOW_MS = 5000;\n\n/**\n * Event handler for managing subscriptions with deduplication\n *\n * Multiple subscribe() calls with identical filters will share a single\n * server-side subscription, reducing network overhead and server load.\n *\n * Event deduplication is enabled by default to prevent duplicate event\n * delivery during rapid reconnection scenarios.\n */\nexport class EventHandler {\n /** Map: server subscription ID -> filter hash (for event routing) */\n private subscriptions = new Map<string, string>();\n\n /** Map: filter hash -> subscription entry (for deduplication) */\n private filterSubscriptions = new Map<string, FilterSubscriptionEntry>();\n\n /** Map: callback -> filter hash (for unsubscribe lookup) */\n private callbackToHash = new Map<EventCallback, string>();\n\n /** Map: event_id -> expiration timestamp (for event deduplication) */\n private recentEventIds = new Map<string, number>();\n\n /** Deduplication window in milliseconds */\n private dedupWindowMs: number;\n\n /** Cleanup timer for expired event IDs */\n private dedupCleanupTimer?: ReturnType<typeof setInterval>;\n\n private sendRequest: (\n payload: SubscribePayload | UnsubscribePayload,\n requestType: RequestType\n ) => Promise<unknown>;\n\n constructor(\n sendRequest: (\n payload: SubscribePayload | UnsubscribePayload,\n requestType: RequestType\n ) => Promise<unknown>,\n options?: { dedupWindowMs?: number }\n ) {\n this.sendRequest = sendRequest;\n this.dedupWindowMs = options?.dedupWindowMs ?? DEFAULT_DEDUP_WINDOW_MS;\n\n // Start cleanup timer for expired event IDs (runs every 10 seconds)\n this.dedupCleanupTimer = setInterval(() => {\n this.cleanupExpiredEventIds();\n }, 10000);\n }\n\n /**\n * Cleanup resources (call when client is disconnected)\n */\n destroy(): void {\n if (this.dedupCleanupTimer) {\n clearInterval(this.dedupCleanupTimer);\n this.dedupCleanupTimer = undefined;\n }\n this.recentEventIds.clear();\n }\n\n /**\n * Remove expired event IDs from the deduplication cache\n * @internal\n */\n private cleanupExpiredEventIds(): void {\n const now = Date.now();\n for (const [eventId, expiration] of this.recentEventIds) {\n if (expiration <= now) {\n this.recentEventIds.delete(eventId);\n }\n }\n }\n\n /**\n * Track an event ID for deduplication\n * @internal\n */\n private trackEventId(eventId: string): void {\n const expiration = Date.now() + this.dedupWindowMs;\n this.recentEventIds.set(eventId, expiration);\n }\n\n /**\n * Check if an event ID has been seen recently\n * @internal\n */\n private isEventDuplicate(eventId: string): boolean {\n const expiration = this.recentEventIds.get(eventId);\n if (!expiration) return false;\n return expiration > Date.now();\n }\n\n /**\n * Create a deterministic hash of subscription filters\n *\n * Two subscriptions with identical filters will produce the same hash,\n * allowing deduplication.\n */\n private hashFilters(filters: SubscriptionFilters): string {\n // Sort event_types for consistent hashing\n const sortedEventTypes = filters.event_types\n ? [...filters.event_types].sort()\n : undefined;\n\n // Create deterministic JSON string\n return JSON.stringify({\n workspace: filters.workspace ?? null,\n path: filters.path ?? null,\n event_types: sortedEventTypes ?? null,\n node_type: filters.node_type ?? null,\n include_node: filters.include_node ?? false,\n });\n }\n\n /**\n * Subscribe to events with filters\n *\n * If a subscription with identical filters already exists, the callback\n * is added to the existing subscription instead of creating a new one.\n *\n * Path filter semantics (matched server-side):\n * - A plain path matches **only that exact node** — there is no implicit\n * prefix matching.\n * - `*` matches exactly one path segment (e.g. `/inbox/*` matches\n * `/inbox/a` but not `/inbox/a/b`).\n * - `**` matches recursively (e.g. `/inbox/**` matches all descendants\n * of `/inbox`, but not `/inbox` itself).\n *\n * @param filters - Event filters\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribe(\n filters: SubscriptionFilters,\n callback: EventCallback\n ): Promise<Subscription> {\n const hash = this.hashFilters(filters);\n\n // Check for existing subscription with same filters\n const existing = this.filterSubscriptions.get(hash);\n if (existing) {\n logger.debug('Reusing existing subscription with identical filters');\n existing.callbacks.add(callback);\n this.callbackToHash.set(callback, hash);\n\n return this.createSubscriptionHandle(existing.serverId, callback, hash);\n }\n\n // Create new server subscription\n const payload: SubscribePayload = { filters };\n const response = (await this.sendRequest(\n payload,\n RequestType.Subscribe\n )) as SubscriptionResponse;\n\n const serverId = response.subscription_id;\n\n // Track the new subscription\n this.filterSubscriptions.set(hash, {\n serverId,\n filters,\n callbacks: new Set([callback]),\n });\n this.subscriptions.set(serverId, hash);\n this.callbackToHash.set(callback, hash);\n\n return this.createSubscriptionHandle(serverId, callback, hash);\n }\n\n /**\n * Create a subscription handle for the callback\n */\n private createSubscriptionHandle(\n serverId: string,\n callback: EventCallback,\n hash: string\n ): Subscription {\n return {\n id: serverId,\n unsubscribe: async () => {\n await this.unsubscribeCallback(callback);\n },\n isActive: () => {\n const entry = this.filterSubscriptions.get(hash);\n return entry?.callbacks.has(callback) ?? false;\n },\n };\n }\n\n /**\n * Unsubscribe a specific callback\n *\n * Only sends unsubscribe to server when the last callback is removed.\n */\n private async unsubscribeCallback(callback: EventCallback): Promise<void> {\n const hash = this.callbackToHash.get(callback);\n if (!hash) {\n logger.warn('Callback not found in subscription map');\n return;\n }\n\n const entry = this.filterSubscriptions.get(hash);\n if (!entry) {\n logger.warn('Subscription entry not found for hash');\n return;\n }\n\n // Remove this callback\n entry.callbacks.delete(callback);\n this.callbackToHash.delete(callback);\n\n // If no more callbacks, unsubscribe from server\n if (entry.callbacks.size === 0) {\n const payload: UnsubscribePayload = { subscription_id: entry.serverId };\n await this.sendRequest(payload, RequestType.Unsubscribe);\n\n this.filterSubscriptions.delete(hash);\n this.subscriptions.delete(entry.serverId);\n }\n }\n\n /**\n * Unsubscribe from events by subscription ID\n *\n * @param subscriptionId - Subscription ID to cancel\n * @deprecated Use subscription.unsubscribe() instead\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const hash = this.subscriptions.get(subscriptionId);\n if (!hash) {\n // Fall back to direct unsubscribe for backwards compatibility\n const payload: UnsubscribePayload = { subscription_id: subscriptionId };\n await this.sendRequest(payload, RequestType.Unsubscribe);\n return;\n }\n\n const entry = this.filterSubscriptions.get(hash);\n if (!entry) {\n return;\n }\n\n // Remove all callbacks and unsubscribe from server\n for (const callback of entry.callbacks) {\n this.callbackToHash.delete(callback);\n }\n entry.callbacks.clear();\n\n const payload: UnsubscribePayload = { subscription_id: subscriptionId };\n await this.sendRequest(payload, RequestType.Unsubscribe);\n\n this.filterSubscriptions.delete(hash);\n this.subscriptions.delete(subscriptionId);\n }\n\n /**\n * Handle incoming event message\n *\n * Routes event to all callbacks registered for the subscription.\n * Automatically deduplicates events using event_id within a 5-second window.\n *\n * @param event - Event message from server\n */\n handleEvent(event: EventMessage): void {\n // Deduplicate events using event_id\n if (event.event_id && this.isEventDuplicate(event.event_id)) {\n logger.debug('Skipping duplicate event:', event.event_id);\n return;\n }\n\n // Track this event for deduplication\n if (event.event_id) {\n this.trackEventId(event.event_id);\n }\n\n const hash = this.subscriptions.get(event.subscription_id);\n if (!hash) {\n logger.warn('Received event for unknown subscription:', event.subscription_id);\n return;\n }\n\n const entry = this.filterSubscriptions.get(hash);\n if (!entry) {\n logger.warn('No entry found for subscription hash');\n return;\n }\n\n // Call all registered callbacks\n for (const callback of entry.callbacks) {\n try {\n callback(event);\n } catch (error) {\n logger.error('Error in event callback:', error);\n }\n }\n }\n\n /**\n * Get all active subscription IDs\n */\n getActiveSubscriptions(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Check if a subscription is active\n *\n * @param subscriptionId - Subscription ID to check\n */\n hasSubscription(subscriptionId: string): boolean {\n return this.subscriptions.has(subscriptionId);\n }\n\n /**\n * Clear all subscriptions (used during disconnect)\n */\n clearAll(): void {\n this.subscriptions.clear();\n this.filterSubscriptions.clear();\n this.callbackToHash.clear();\n }\n\n /**\n * Check if there are stored filters that need restoration\n * Used to detect if we need to restore subscriptions on reconnect\n */\n hasStoredFilters(): boolean {\n return this.filterSubscriptions.size > 0 || this.callbackToHash.size > 0;\n }\n\n /**\n * Register a direct listener for flow events by subscription ID.\n * Used by FlowsApi to receive flow execution events via WS.\n */\n addFlowEventListener(subscriptionId: string, callback: EventCallback): void {\n // Create a synthetic entry so handleEvent routes events to this callback\n const hash = `__flow__${subscriptionId}`;\n this.filterSubscriptions.set(hash, {\n serverId: subscriptionId,\n filters: {} as SubscriptionFilters,\n callbacks: new Set([callback]),\n });\n this.subscriptions.set(subscriptionId, hash);\n this.callbackToHash.set(callback, hash);\n }\n\n /**\n * Remove a flow event listener by subscription ID.\n */\n removeFlowEventListener(subscriptionId: string): void {\n const hash = this.subscriptions.get(subscriptionId);\n if (!hash) return;\n\n const entry = this.filterSubscriptions.get(hash);\n if (entry) {\n for (const callback of entry.callbacks) {\n this.callbackToHash.delete(callback);\n }\n this.filterSubscriptions.delete(hash);\n }\n this.subscriptions.delete(subscriptionId);\n }\n\n /**\n * Restore subscriptions after reconnect\n *\n * Re-subscribes to the server with the original filters for all active\n * subscription entries. Failed entries are kept (with their callbacks)\n * and marked pending so a retry call can re-attempt them without\n * duplicating already-restored subscriptions.\n *\n * @param options.retry - When true, only re-attempts entries that failed\n * in a previous call (instead of re-subscribing everything)\n * @throws Error if any subscription could not be restored\n */\n async restoreSubscriptions(options?: { retry?: boolean }): Promise<void> {\n if (!options?.retry) {\n // Fresh restore session: every entry needs a new server-side\n // subscription; drop stale routing IDs from the old connection.\n for (const entry of this.filterSubscriptions.values()) {\n this.subscriptions.delete(entry.serverId);\n entry.restorePending = true;\n }\n }\n\n // Collect entries to restore (can't modify map while iterating)\n const entriesToRestore = Array.from(this.filterSubscriptions.entries())\n .filter(([, entry]) => entry.restorePending);\n\n let failureCount = 0;\n let lastError: unknown;\n\n // Re-subscribe each pending entry\n for (const [hash, entry] of entriesToRestore) {\n if (entry.callbacks.size === 0) {\n entry.restorePending = false;\n continue;\n }\n\n try {\n const payload: SubscribePayload = { filters: entry.filters };\n const response = (await this.sendRequest(\n payload,\n RequestType.Subscribe\n )) as SubscriptionResponse;\n\n const newServerId = response.subscription_id;\n\n // Update mappings with new server ID\n entry.serverId = newServerId;\n entry.restorePending = false;\n this.subscriptions.set(newServerId, hash);\n\n // Update callbackToHash (hash stays the same, just verify it's set)\n for (const callback of entry.callbacks) {\n this.callbackToHash.set(callback, hash);\n }\n } catch (error) {\n logger.error('Failed to restore subscription:', error);\n failureCount++;\n lastError = error;\n // Keep the entry pending so a retry can re-attempt it\n }\n }\n\n if (failureCount > 0) {\n const message = lastError instanceof Error ? lastError.message : String(lastError);\n throw new Error(\n `Failed to restore ${failureCount} subscription(s) after reconnect: ${message}`\n );\n }\n }\n}\n\n/**\n * Event subscriptions interface for workspace\n */\nexport class EventSubscriptions {\n private eventHandler: EventHandler;\n private filters: Partial<SubscriptionFilters>;\n\n constructor(eventHandler: EventHandler, filters: Partial<SubscriptionFilters> = {}) {\n this.eventHandler = eventHandler;\n this.filters = filters;\n }\n\n /**\n * Subscribe to events\n *\n * @param filters - Additional filters (merged with workspace filters)\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribe(\n filters: Partial<SubscriptionFilters>,\n callback: EventCallback\n ): Promise<Subscription> {\n // Merge workspace filters with provided filters\n const mergedFilters: SubscriptionFilters = {\n ...this.filters,\n ...filters,\n } as SubscriptionFilters;\n\n return this.eventHandler.subscribe(mergedFilters, callback);\n }\n\n /**\n * Subscribe to specific event types\n *\n * @param eventTypes - Event types to subscribe to\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribeToTypes(eventTypes: string[], callback: EventCallback): Promise<Subscription> {\n return this.subscribe({ event_types: eventTypes }, callback);\n }\n\n /**\n * Subscribe to events for a specific path\n *\n * Path pattern semantics (matched server-side):\n * - A plain path matches **only that exact node** — there is no implicit\n * prefix matching, so `/folder` does NOT match `/folder/child`.\n * - `*` matches exactly one path segment: `/folder/*` matches\n * `/folder/child` but not `/folder/child/grandchild`.\n * - `**` matches recursively: `/folder/**` matches every descendant of\n * `/folder` (but not `/folder` itself).\n *\n * @param path - Path pattern (e.g. \"/folder\", \"/folder/*\", \"/folder/**\")\n * @param callback - Callback function for events\n * @param options - Optional subscription options\n * @param options.includeNode - Include full node data in event payload (default: false)\n * @returns Subscription object\n */\n async subscribeToPath(\n path: string,\n callback: EventCallback,\n options?: { includeNode?: boolean }\n ): Promise<Subscription> {\n const filters: Partial<SubscriptionFilters> = { path };\n if (options?.includeNode) {\n filters.include_node = true;\n }\n return this.subscribe(filters, callback);\n }\n\n /**\n * Subscribe to events for a specific node type\n *\n * @param nodeType - Node type to filter by\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribeToNodeType(nodeType: string, callback: EventCallback): Promise<Subscription> {\n return this.subscribe({ node_type: nodeType }, callback);\n }\n}\n","/**\n * Node operations interface\n */\n\nimport {\n Node,\n PropertyValue,\n NodeCreatePayload,\n NodeCreateDeepPayload,\n NodeUpdatePayload,\n NodeDeletePayload,\n NodeGetPayload,\n NodeHistoryPayload,\n NodeQueryPayload,\n RelationAddPayload,\n RelationRemovePayload,\n RelationsGetPayload,\n NodeRelationships,\n RevisionEntry,\n AuditQueryPayload,\n AuditLogEntry,\n} from './protocol';\n\n/**\n * Options for creating a node\n */\nexport interface NodeCreateOptions {\n /** Node type */\n type: string;\n /** Node path */\n path: string;\n /** Node properties */\n properties?: Record<string, PropertyValue>;\n /** Node content (optional) */\n content?: unknown;\n}\n\n/**\n * Options for creating/upserting a node with auto-created ancestor folders\n */\nexport interface NodeCreateDeepOptions extends NodeCreateOptions {\n /** NodeType used for auto-created ancestor folders (defaults to `raisin:Folder`) */\n parentNodeType?: string;\n}\n\n/**\n * Options for updating a node\n */\nexport interface NodeUpdateOptions {\n /** Properties to update */\n properties?: Record<string, PropertyValue>;\n /** Content to update (optional) */\n content?: unknown;\n}\n\n/**\n * Options for querying nodes\n */\nexport interface NodeQueryOptions {\n /** Query object */\n query: unknown;\n /** Maximum number of results */\n limit?: number;\n /** Offset for pagination */\n offset?: number;\n}\n\n/**\n * Node operations interface\n */\nexport class NodeOperations {\n private sendRequest: (payload: unknown, requestType?: string) => Promise<unknown>;\n private workspace?: string;\n\n constructor(\n sendRequest: (payload: unknown, requestType?: string) => Promise<unknown>,\n workspace?: string\n ) {\n this.sendRequest = sendRequest;\n this.workspace = workspace;\n }\n\n /**\n * Create a new node\n *\n * @param options - Node creation options\n * @returns Created node\n */\n async create(options: NodeCreateOptions): Promise<Node> {\n const payload: NodeCreatePayload = {\n node_type: options.type,\n path: options.path,\n properties: options.properties ?? {},\n content: options.content,\n };\n\n const result = await this.sendRequest(payload);\n return result as Node;\n }\n\n /**\n * Create a node, auto-creating any missing ancestor folders.\n *\n * @param options - Node creation options (with optional `parentNodeType`)\n * @returns Created node\n */\n async createDeep(options: NodeCreateDeepOptions): Promise<Node> {\n const payload: NodeCreateDeepPayload = {\n node_type: options.type,\n path: options.path,\n properties: options.properties ?? {},\n content: options.content,\n parent_node_type: options.parentNodeType,\n };\n\n const result = await this.sendRequest(payload, 'node_create_deep');\n return result as Node;\n }\n\n /**\n * Upsert a node by path (create-or-update), auto-creating any missing ancestor folders.\n *\n * @param options - Node creation options (with optional `parentNodeType`)\n * @returns Upserted node\n */\n async upsertDeep(options: NodeCreateDeepOptions): Promise<Node> {\n const payload: NodeCreateDeepPayload = {\n node_type: options.type,\n path: options.path,\n properties: options.properties ?? {},\n content: options.content,\n parent_node_type: options.parentNodeType,\n };\n\n const result = await this.sendRequest(payload, 'node_upsert_deep');\n return result as Node;\n }\n\n /**\n * Update an existing node\n *\n * @param id - Node ID\n * @param options - Node update options\n * @returns Updated node\n */\n async update(id: string, options: NodeUpdateOptions): Promise<Node> {\n const payload: NodeUpdatePayload = {\n node_id: id,\n properties: options.properties ?? {},\n content: options.content,\n };\n\n const result = await this.sendRequest(payload);\n return result as Node;\n }\n\n /**\n * Delete a node\n *\n * @param id - Node ID\n * @returns true if deleted successfully\n */\n async delete(id: string): Promise<boolean> {\n const payload: NodeDeletePayload = {\n node_id: id,\n };\n\n await this.sendRequest(payload);\n return true;\n }\n\n /**\n * Get a node by ID\n *\n * @param id - Node ID\n * @returns Node or null if not found\n */\n async get(id: string): Promise<Node | null> {\n const payload: NodeGetPayload = {\n node_id: id,\n };\n\n try {\n const result = await this.sendRequest(payload);\n return result as Node;\n } catch (error) {\n // If node not found, return null\n if (error instanceof Error && error.message.includes('not found')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * List a node's revision history (git-style \"file history\"), newest first.\n *\n * Each entry carries the `revision` (usable with `atRevision()` reads to\n * fetch the full snapshot), plus when/who and whether the node was deleted\n * at that revision. Always available regardless of the NodeType `auditable`\n * flag — it reflects the structural MVCC version history.\n *\n * @param id - Node ID\n * @param options - Optional `{ limit }` to cap the number of revisions\n * @returns Array of revision entries (newest first)\n *\n * @example\n * ```typescript\n * const history = await ws.nodes().history(nodeId, { limit: 50 });\n * for (const rev of history) {\n * const snapshot = await ws.atRevision(rev.revision).nodes().get(nodeId);\n * }\n * ```\n */\n async history(id: string, options?: { limit?: number }): Promise<RevisionEntry[]> {\n const payload: NodeHistoryPayload = {\n node_id: id,\n limit: options?.limit,\n };\n const result = await this.sendRequest(payload, 'node_history');\n return (result as RevisionEntry[]) ?? [];\n }\n\n /**\n * List a node's revision history by path (newest first).\n *\n * @param path - Node path\n * @param options - Optional `{ limit }` to cap the number of revisions\n * @returns Array of revision entries (newest first)\n */\n async historyByPath(path: string, options?: { limit?: number }): Promise<RevisionEntry[]> {\n const payload: NodeHistoryPayload = {\n path,\n limit: options?.limit,\n };\n const result = await this.sendRequest(payload, 'node_history');\n return (result as RevisionEntry[]) ?? [];\n }\n\n /**\n * Query a node's audit-log entries by ID.\n *\n * Audit logs are only produced for NodeTypes marked `auditable`. This is\n * distinct from {@link history}, which is the always-on structural revision\n * history available for every node.\n *\n * @param id - Node ID\n * @returns Array of audit-log entries\n */\n async auditLog(id: string): Promise<AuditLogEntry[]> {\n const payload: AuditQueryPayload = { node_id: id };\n const result = await this.sendRequest(payload, 'audit_query');\n return (result as AuditLogEntry[]) ?? [];\n }\n\n /**\n * Query a node's audit-log entries by path.\n *\n * @param path - Node path\n * @returns Array of audit-log entries\n */\n async auditLogByPath(path: string): Promise<AuditLogEntry[]> {\n const payload: AuditQueryPayload = { path };\n const result = await this.sendRequest(payload, 'audit_query');\n return (result as AuditLogEntry[]) ?? [];\n }\n\n /**\n * Query nodes\n *\n * @param options - Query options\n * @returns Array of nodes\n */\n async query(options: NodeQueryOptions): Promise<Node[]> {\n const payload: NodeQueryPayload = {\n query: options.query,\n limit: options.limit,\n offset: options.offset,\n };\n\n const result = await this.sendRequest(payload);\n return result as Node[];\n }\n\n /**\n * Get a node by path\n *\n * @param path - Node path\n * @returns Node or null if not found\n */\n async getByPath(path: string): Promise<Node | null> {\n try {\n const result = await this.query({\n query: { path },\n limit: 1,\n });\n return result.length > 0 ? result[0] : null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Query nodes by property\n *\n * @param propertyName - Property name\n * @param propertyValue - Property value\n * @param limit - Maximum number of results\n * @returns Array of nodes\n */\n async queryByProperty(\n propertyName: string,\n propertyValue: PropertyValue,\n limit?: number\n ): Promise<Node[]> {\n return this.query({\n query: {\n properties: {\n [propertyName]: propertyValue,\n },\n },\n limit,\n });\n }\n\n /**\n * Query nodes by type\n *\n * @param nodeType - Node type\n * @param limit - Maximum number of results\n * @returns Array of nodes\n */\n async queryByType(nodeType: string, limit?: number): Promise<Node[]> {\n return this.query({\n query: { node_type: nodeType },\n limit,\n });\n }\n\n /**\n * Get children of a node\n *\n * @param parentId - Parent node ID\n * @param limit - Maximum number of results\n * @returns Array of child nodes\n */\n async getChildren(parentId: string, limit?: number): Promise<Node[]> {\n return this.query({\n query: { parent: parentId },\n limit,\n });\n }\n\n /**\n * Get children by path\n *\n * @param parentPath - Parent node path\n * @param limit - Maximum number of results\n * @returns Array of child nodes\n */\n async getChildrenByPath(parentPath: string, limit?: number): Promise<Node[]> {\n const parent = await this.getByPath(parentPath);\n if (!parent) {\n return [];\n }\n return this.getChildren(parent.id, limit);\n }\n\n // ========================================================================\n // Tree Operations\n // ========================================================================\n\n /**\n * List children of a parent node, in editorial (drag-and-drop) order.\n *\n * @param parentPath - Path of the parent node\n * @returns Array of child nodes\n */\n async listChildren(parentPath: string): Promise<Node[]> {\n const { items } = await this.listChildrenPage(parentPath);\n return items;\n }\n\n /**\n * List one page of a parent's children, in editorial order.\n *\n * Pagination is keyset-based: pass the previous response's `nextCursor` back as\n * `cursor` to get the following page. `nextCursor` is `null` on the last page.\n * Treat the cursor as opaque — do not parse or construct it.\n *\n * @param parentPath - Path of the parent node\n * @param options - `cursor` from a previous page, and page `limit`\n */\n async listChildrenPage(\n parentPath: string,\n options: { cursor?: string; limit?: number } = {},\n ): Promise<{ items: Node[]; nextCursor: string | null }> {\n const payload: Record<string, unknown> = {\n parent_path: parentPath,\n };\n if (options.cursor !== undefined) payload.cursor = options.cursor;\n if (options.limit !== undefined) payload.limit = options.limit;\n\n const result = await this.sendRequest(payload, 'node_list_children');\n\n // The paginated shape is `{ nodes, next_cursor }`; a bare array means an\n // older server that ignored the cursor arguments.\n if (Array.isArray(result)) {\n return { items: result as Node[], nextCursor: null };\n }\n const page = result as { nodes?: Node[]; next_cursor?: unknown };\n return {\n items: page.nodes ?? [],\n nextCursor:\n page.next_cursor == null ? null : JSON.stringify(page.next_cursor),\n };\n }\n\n /**\n * Get a node tree starting from a root node\n *\n * @param rootPath - Path of the root node\n * @param maxDepth - Maximum depth to traverse (optional)\n * @returns Root node with nested children\n */\n async getTree(rootPath: string, maxDepth?: number): Promise<Node> {\n const payload: { root_path: string; max_depth?: number } = {\n root_path: rootPath,\n };\n\n if (maxDepth !== undefined) {\n payload.max_depth = maxDepth;\n }\n\n const result = await this.sendRequest(payload, 'node_get_tree');\n return result as Node;\n }\n\n /**\n * Get a flattened node tree starting from a root node\n *\n * @param rootPath - Path of the root node\n * @param maxDepth - Maximum depth to traverse (optional)\n * @returns Array of nodes in tree order\n */\n async getTreeFlat(rootPath: string, maxDepth?: number): Promise<Node[]> {\n const payload: { root_path: string; max_depth?: number } = {\n root_path: rootPath,\n };\n\n if (maxDepth !== undefined) {\n payload.max_depth = maxDepth;\n }\n\n const result = await this.sendRequest(payload, 'node_get_tree_flat');\n return result as Node[];\n }\n\n // ========================================================================\n // Node Manipulation Operations\n // ========================================================================\n\n /**\n * Move a node to a new parent\n *\n * @param fromPath - Source node path\n * @param toParentPath - Destination parent path\n * @returns Moved node\n */\n async move(fromPath: string, toParentPath: string): Promise<Node> {\n const payload = {\n from_path: fromPath,\n to_parent_path: toParentPath,\n };\n\n const result = await this.sendRequest(payload, 'node_move');\n return result as Node;\n }\n\n /**\n * Rename a node\n *\n * @param nodePath - Node path\n * @param newName - New name for the node\n * @returns Renamed node\n */\n async rename(nodePath: string, newName: string): Promise<Node> {\n // Server NodeRenamePayload expects `old_path` (not `node_path`).\n const payload = {\n old_path: nodePath,\n new_name: newName,\n };\n\n const result = await this.sendRequest(payload, 'node_rename');\n return result as Node;\n }\n\n /**\n * Copy a node to a new parent (shallow copy)\n *\n * @param fromPath - Source node path\n * @param toParentPath - Destination parent path\n * @param newName - New name for the copied node (optional)\n * @returns Copied node\n */\n async copy(fromPath: string, toParentPath: string, newName?: string): Promise<Node> {\n // Server NodeCopyPayload expects `source_path` / `target_parent`.\n const payload: { source_path: string; target_parent: string; new_name?: string } = {\n source_path: fromPath,\n target_parent: toParentPath,\n };\n\n if (newName !== undefined) {\n payload.new_name = newName;\n }\n\n const result = await this.sendRequest(payload, 'node_copy');\n return result as Node;\n }\n\n /**\n * Copy a node tree to a new parent (deep copy with all children)\n *\n * @param fromPath - Source node path\n * @param toParentPath - Destination parent path\n * @param newName - New name for the copied node (optional)\n * @returns Copied node tree\n */\n async copyTree(fromPath: string, toParentPath: string, newName?: string): Promise<Node> {\n // Server NodeCopyTreePayload expects `source_path` / `target_parent`.\n const payload: { source_path: string; target_parent: string; new_name?: string } = {\n source_path: fromPath,\n target_parent: toParentPath,\n };\n\n if (newName !== undefined) {\n payload.new_name = newName;\n }\n\n const result = await this.sendRequest(payload, 'node_copy_tree');\n return result as Node;\n }\n\n /**\n * Move a child to a specific position among its siblings.\n *\n * Positions are 0-based; a position past the end appends. The server owns the\n * fractional order key — you name a position, it mints the key.\n *\n * @param parentPath - Parent node path\n * @param childName - Name of the child to move (not a full path)\n * @param position - Target 0-based position among the parent's children\n * @returns The reordered node, carrying its newly assigned `order_key`\n */\n async reorder(parentPath: string, childName: string, position: number): Promise<Node> {\n const payload = {\n parent_path: parentPath,\n child_name: childName,\n position,\n };\n\n const result = await this.sendRequest(payload, 'node_reorder');\n return result as Node;\n }\n\n /**\n * Move a child so it sits immediately before one of its siblings.\n *\n * @param parentPath - Parent node path\n * @param childName - Name of the child to move (not a full path)\n * @param beforeChildName - Name of the sibling to sit before\n */\n async moveChildBefore(\n parentPath: string,\n childName: string,\n beforeChildName: string,\n ): Promise<void> {\n const payload = {\n parent_path: parentPath,\n child_name: childName,\n before_child_name: beforeChildName,\n };\n\n await this.sendRequest(payload, 'node_move_child_before');\n }\n\n /**\n * Move a child so it sits immediately after one of its siblings.\n *\n * @param parentPath - Parent node path\n * @param childName - Name of the child to move (not a full path)\n * @param afterChildName - Name of the sibling to sit after\n */\n async moveChildAfter(\n parentPath: string,\n childName: string,\n afterChildName: string,\n ): Promise<void> {\n const payload = {\n parent_path: parentPath,\n child_name: childName,\n after_child_name: afterChildName,\n };\n\n await this.sendRequest(payload, 'node_move_child_after');\n }\n\n /**\n * Replay a parent's child order from another branch onto the current branch.\n *\n * Carries node sibling-order across branches — useful for selective publish\n * flows, where copying node content (e.g. via SQL) does not move the ordering\n * index. Only children that exist under the parent on both branches are\n * reordered. The target branch is the connection's current branch.\n *\n * @param parentPath - Parent node path\n * @param sourceBranch - Branch to copy the child order FROM\n */\n async applyChildOrder(parentPath: string, sourceBranch: string): Promise<void> {\n const payload = {\n parent_path: parentPath,\n source_branch: sourceBranch,\n };\n\n await this.sendRequest(payload, 'node_apply_child_order');\n }\n\n // ========================================================================\n // Relationship Operations\n // ========================================================================\n\n /**\n * Add a relationship between two nodes\n *\n * @param nodePath - Source node path\n * @param relationType - Type of relationship\n * @param targetNodePath - Target node path\n * @param weight - Optional relationship weight (legacy signature)\n * @returns True if the relation exists after the call\n */\n async addRelation(\n nodePath: string,\n relationType: string,\n targetNodePath: string,\n weightOrOptions?: number | RelationAddOptions\n ): Promise<boolean> {\n const options =\n typeof weightOrOptions === 'number'\n ? { weight: weightOrOptions }\n : weightOrOptions;\n\n const payload: RelationAddPayload = {\n source_path: nodePath,\n target_workspace: this.resolveTargetWorkspace(options),\n target_path: targetNodePath,\n relation_type: relationType,\n };\n\n if (options?.weight !== undefined) {\n payload.weight = options.weight;\n }\n\n const result = await this.sendRequest(payload, 'relation_add');\n return this.parseSuccess(result);\n }\n\n /**\n * Remove a relationship between two nodes\n *\n * @param nodePath - Source node path\n * @param targetPathOrRelationType - Target node path (preferred) or legacy relation type\n * @param targetPathOrOptions - Target path for the legacy signature or mutation options\n * @param options - Relationship options when using the legacy signature\n * @returns True if the relation was removed or no longer exists\n */\n async removeRelation(\n nodePath: string,\n targetPathOrRelationType: string,\n targetPathOrOptions?: string | RelationRemoveOptions,\n options?: RelationRemoveOptions\n ): Promise<boolean> {\n let targetPath: string;\n let resolvedOptions: RelationRemoveOptions | undefined;\n\n if (typeof targetPathOrOptions === 'string') {\n // Legacy signature: removeRelation(source, relationType, targetPath)\n targetPath = targetPathOrOptions;\n resolvedOptions = options;\n } else {\n // Preferred signature: removeRelation(source, targetPath, options?)\n targetPath = targetPathOrRelationType;\n resolvedOptions = targetPathOrOptions;\n }\n\n const payload: RelationRemovePayload = {\n source_path: nodePath,\n target_workspace: this.resolveTargetWorkspace(resolvedOptions),\n target_path: targetPath,\n };\n\n const result = await this.sendRequest(payload, 'relation_remove');\n return this.parseSuccess(result);\n }\n\n /**\n * Get all incoming and outgoing relationships for a node\n *\n * @param nodePath - Node path\n * @returns Relationship summary including incoming/outgoing edges\n */\n async getRelationships(nodePath: string): Promise<NodeRelationships> {\n const payload: RelationsGetPayload = {\n node_path: nodePath,\n };\n\n const result = await this.sendRequest(payload, 'relations_get');\n return result as NodeRelationships;\n }\n\n /**\n * Determine which workspace to target for relationship operations\n */\n private resolveTargetWorkspace(options?: RelationTargetOptions): string {\n const workspace = options?.targetWorkspace ?? this.workspace;\n if (!workspace) {\n throw new Error(\n 'targetWorkspace is required when workspace context is not set'\n );\n }\n return workspace;\n }\n\n /**\n * Normalize success responses from relationship mutations\n */\n private parseSuccess(result: unknown): boolean {\n if (typeof result === 'boolean') {\n return result;\n }\n if (\n result &&\n typeof result === 'object' &&\n 'success' in result &&\n typeof (result as { success?: unknown }).success !== 'undefined'\n ) {\n return Boolean((result as { success?: boolean }).success);\n }\n return true;\n }\n}\n\ninterface RelationTargetOptions {\n targetWorkspace?: string;\n}\n\ninterface RelationAddOptions extends RelationTargetOptions {\n weight?: number;\n}\n\ntype RelationRemoveOptions = RelationTargetOptions;\n","/**\n * Transaction support for RaisinDB\n */\n\nimport {\n RequestContext,\n RequestType,\n TransactionBeginPayload,\n TransactionBeginResponse,\n TransactionCommitPayload,\n TransactionCommitResponse,\n TransactionRollbackPayload,\n} from './protocol';\nimport { NodeOperations } from './nodes';\n\n/**\n * Transaction options\n */\nexport interface TransactionOptions {\n /** Optional commit message */\n message?: string;\n /** Optional actor identifier */\n actor?: string;\n}\n\n/**\n * Transaction class for executing multiple operations atomically\n */\nexport class Transaction {\n private sendRequest: (payload: unknown, requestType: string, contextOverride?: RequestContext) => Promise<unknown>;\n private context: RequestContext;\n private transactionId?: string;\n private isActive: boolean = false;\n private nodeOps?: NodeOperations;\n\n constructor(\n context: RequestContext,\n sendRequest: (payload: unknown, requestType: string, contextOverride?: RequestContext) => Promise<unknown>\n ) {\n this.context = context;\n this.sendRequest = sendRequest;\n }\n\n /**\n * Begin the transaction\n *\n * @param options - Transaction options\n * @returns This transaction instance for chaining\n */\n async begin(options?: TransactionOptions): Promise<Transaction> {\n if (this.isActive) {\n throw new Error('Transaction already active');\n }\n\n const payload: TransactionBeginPayload = {\n message: options?.message,\n actor: options?.actor,\n };\n\n const response = await this.sendRequest(\n payload,\n RequestType.TransactionBegin,\n this.context\n ) as TransactionBeginResponse;\n\n this.transactionId = response.transaction_id;\n this.isActive = true;\n\n // Create NodeOperations with transaction context\n const txContext: RequestContext = {\n ...this.context,\n transaction_id: this.transactionId,\n };\n\n this.nodeOps = new NodeOperations(\n (payload: unknown, requestType?: string) =>\n this.sendRequest(payload, requestType || 'node_create', txContext),\n txContext.workspace\n );\n\n return this;\n }\n\n /**\n * Get node operations scoped to this transaction\n *\n * @returns NodeOperations instance\n */\n nodes(): NodeOperations {\n if (!this.isActive || !this.nodeOps) {\n throw new Error('Transaction not active. Call begin() first.');\n }\n return this.nodeOps;\n }\n\n /**\n * Commit the transaction\n *\n * @returns Transaction commit response\n */\n async commit(): Promise<TransactionCommitResponse> {\n if (!this.isActive) {\n throw new Error('Transaction not active');\n }\n\n const payload: TransactionCommitPayload = {};\n\n const txContext: RequestContext = {\n ...this.context,\n transaction_id: this.transactionId,\n };\n\n try {\n const response = await this.sendRequest(\n payload,\n RequestType.TransactionCommit,\n txContext\n ) as TransactionCommitResponse;\n\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n\n return response;\n } catch (error) {\n // Transaction failed, mark as inactive\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n throw error;\n }\n }\n\n /**\n * Rollback the transaction\n */\n async rollback(): Promise<void> {\n if (!this.isActive) {\n throw new Error('Transaction not active');\n }\n\n const payload: TransactionRollbackPayload = {};\n\n const txContext: RequestContext = {\n ...this.context,\n transaction_id: this.transactionId,\n };\n\n try {\n await this.sendRequest(\n payload,\n RequestType.TransactionRollback,\n txContext\n );\n\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n } catch (error) {\n // Even if rollback fails, mark as inactive\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n throw error;\n }\n }\n\n /**\n * Get transaction ID\n */\n getTransactionId(): string | undefined {\n return this.transactionId;\n }\n\n /**\n * Check if transaction is active\n */\n isTransactionActive(): boolean {\n return this.isActive;\n }\n}\n","/**\n * File source abstraction for Browser and Node.js environments\n *\n * Provides a unified interface for reading file data in chunks,\n * supporting both browser File/Blob APIs and Node.js filesystem.\n */\n\n// ============================================================================\n// FileSource Interface\n// ============================================================================\n\n/**\n * Abstract interface for reading file data in chunks\n */\nexport interface FileSource {\n /** Total size of the file in bytes */\n readonly size: number;\n /** Name of the file */\n readonly name: string;\n /** MIME type of the file (optional) */\n readonly type?: string;\n /**\n * Read a slice of the file\n *\n * @param start - Start byte offset (inclusive)\n * @param end - End byte offset (exclusive)\n * @returns ArrayBuffer containing the slice data\n */\n slice(start: number, end: number): Promise<ArrayBuffer>;\n}\n\n// ============================================================================\n// Browser Implementation\n// ============================================================================\n\n/**\n * FileSource implementation for browser File/Blob objects\n */\nexport class BrowserFileSource implements FileSource {\n private readonly _file: File | Blob;\n\n /**\n * Create a browser file source\n *\n * @param file - File or Blob object\n */\n constructor(file: File | Blob) {\n this._file = file;\n }\n\n /**\n * Total size in bytes\n */\n get size(): number {\n return this._file.size;\n }\n\n /**\n * File name (or \"blob\" for Blob objects)\n */\n get name(): string {\n return 'name' in this._file ? this._file.name : 'blob';\n }\n\n /**\n * MIME type\n */\n get type(): string | undefined {\n return this._file.type || undefined;\n }\n\n /**\n * Read a slice of the file\n */\n async slice(start: number, end: number): Promise<ArrayBuffer> {\n const blob = this._file.slice(start, end);\n return blob.arrayBuffer();\n }\n}\n\n// ============================================================================\n// Node.js Implementation\n// ============================================================================\n\n/**\n * FileSource implementation for Node.js file paths\n *\n * Uses lazy initialization to avoid blocking on construction.\n * The fs module is dynamically imported to support browser bundling.\n */\nexport class NodeFileSource implements FileSource {\n private _size = 0;\n private readonly _name: string;\n private readonly _filePath: string;\n private _initialized = false;\n private _fsPromises: typeof import('fs/promises') | null = null;\n\n /**\n * Create a Node.js file source\n *\n * @param filePath - Path to the file\n * @param fsPromises - Optional fs/promises module (for testing)\n */\n constructor(\n filePath: string,\n fsPromises?: typeof import('fs/promises')\n ) {\n this._filePath = filePath;\n this._fsPromises = fsPromises ?? null;\n // Extract filename from path\n const parts = filePath.split(/[/\\\\]/);\n this._name = parts[parts.length - 1] || 'file';\n }\n\n /**\n * Initialize the file source (load fs module and get file stats)\n */\n private async init(): Promise<void> {\n if (this._initialized) {\n return;\n }\n\n // Dynamically import fs/promises if not provided\n if (!this._fsPromises) {\n if (!isNodeEnvironment()) {\n throw new Error(\n 'NodeFileSource requires Node.js (fs/promises is not available in browsers). ' +\n 'In the browser, use a File or Blob object instead.'\n );\n }\n // Dynamic import with a computed specifier so bundlers (Vite, etc.)\n // don't try to resolve \"fs/promises\" into browser bundles.\n const specifier = 'fs/promises';\n this._fsPromises = (await import(\n /* @vite-ignore */ /* webpackIgnore: true */ specifier\n )) as typeof import('fs/promises');\n }\n\n // Get file stats to determine size\n const stats = await this._fsPromises.stat(this._filePath);\n this._size = stats.size;\n this._initialized = true;\n }\n\n /**\n * Total size in bytes\n *\n * Note: Returns 0 until initialized via slice() call\n */\n get size(): number {\n return this._size;\n }\n\n /**\n * File name\n */\n get name(): string {\n return this._name;\n }\n\n /**\n * MIME type (not available for Node.js files)\n */\n get type(): string | undefined {\n return undefined;\n }\n\n /**\n * Read a slice of the file\n */\n async slice(start: number, end: number): Promise<ArrayBuffer> {\n await this.init();\n\n // Open file for reading\n const fd = await this._fsPromises!.open(this._filePath, 'r');\n\n try {\n const length = end - start;\n const buffer = Buffer.alloc(length);\n await fd.read(buffer, 0, length, start);\n\n // Convert Buffer to ArrayBuffer\n return buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength\n );\n } finally {\n await fd.close();\n }\n }\n\n /**\n * Ensure the file source is initialized\n *\n * Call this before accessing size to ensure it's populated.\n */\n async ensureInitialized(): Promise<void> {\n await this.init();\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Detect the runtime environment\n */\nfunction isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Create a FileSource from various inputs\n *\n * Automatically detects the input type and environment:\n * - File/Blob objects use BrowserFileSource\n * - String paths use NodeFileSource (Node.js only)\n *\n * @param input - File, Blob, or file path string\n * @returns Promise resolving to a FileSource\n * @throws Error if input type is not supported in the current environment\n */\nexport async function createFileSource(\n input: File | Blob | string\n): Promise<FileSource> {\n // Handle string paths (Node.js file path)\n if (typeof input === 'string') {\n if (!isNodeEnvironment()) {\n throw new Error(\n 'File path strings are only supported in Node.js. ' +\n 'In the browser, use a File or Blob object.'\n );\n }\n\n const source = new NodeFileSource(input);\n // Force initialization to populate size\n await source.ensureInitialized();\n return source;\n }\n\n // Handle File/Blob objects\n if (input instanceof Blob) {\n return new BrowserFileSource(input);\n }\n\n throw new Error(\n 'Unsupported input type. Expected File, Blob, or file path string.'\n );\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Get the content type for a file\n *\n * @param source - FileSource or filename\n * @returns MIME type or undefined\n */\nexport function getContentType(source: FileSource | string): string | undefined {\n if (typeof source === 'string') {\n return getMimeTypeFromExtension(source);\n }\n\n if (source.type) {\n return source.type;\n }\n\n return getMimeTypeFromExtension(source.name);\n}\n\n/**\n * Get MIME type from file extension\n */\nfunction getMimeTypeFromExtension(filename: string): string | undefined {\n const ext = filename.split('.').pop()?.toLowerCase();\n\n if (!ext) {\n return undefined;\n }\n\n const mimeTypes: Record<string, string> = {\n // Images\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n\n // Videos\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n wmv: 'video/x-ms-wmv',\n flv: 'video/x-flv',\n\n // Audio\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n m4a: 'audio/mp4',\n flac: 'audio/flac',\n aac: 'audio/aac',\n\n // Documents\n pdf: 'application/pdf',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n\n // Archives\n zip: 'application/zip',\n rar: 'application/vnd.rar',\n '7z': 'application/x-7z-compressed',\n tar: 'application/x-tar',\n gz: 'application/gzip',\n\n // Text\n txt: 'text/plain',\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n json: 'application/json',\n xml: 'application/xml',\n csv: 'text/csv',\n md: 'text/markdown',\n\n // Other\n wasm: 'application/wasm',\n woff: 'font/woff',\n woff2: 'font/woff2',\n ttf: 'font/ttf',\n otf: 'font/otf',\n eot: 'application/vnd.ms-fontobject',\n };\n\n return mimeTypes[ext];\n}\n\n/**\n * Calculate the number of chunks for a file\n *\n * @param fileSize - Total file size in bytes\n * @param chunkSize - Size of each chunk in bytes\n * @returns Number of chunks\n */\nexport function calculateChunkCount(fileSize: number, chunkSize: number): number {\n return Math.ceil(fileSize / chunkSize);\n}\n\n/**\n * Get the byte range for a specific chunk\n *\n * @param chunkIndex - Zero-based chunk index\n * @param chunkSize - Size of each chunk in bytes\n * @param fileSize - Total file size in bytes\n * @returns Object with start and end byte offsets\n */\nexport function getChunkRange(\n chunkIndex: number,\n chunkSize: number,\n fileSize: number\n): { start: number; end: number } {\n const start = chunkIndex * chunkSize;\n const end = Math.min(start + chunkSize, fileSize);\n return { start, end };\n}\n","/**\n * Workspace operations interface\n */\n\nimport { NodeOperations } from './nodes';\nimport { EventSubscriptions, EventHandler } from './events';\nimport { Transaction } from './transactions';\nimport {\n Workspace,\n WorkspaceCreatePayload,\n WorkspaceGetPayload,\n WorkspaceDeletePayload,\n WorkspaceUpdatePayload,\n RequestContext,\n} from './protocol';\nimport { logger } from './logger';\nimport type { Upload, UploadOptions, BatchUpload, BatchUploadOptions } from './upload/types';\nimport type { UploadManager } from './upload/uploader';\nimport { createFileSource } from './upload/file-source';\nimport type { SignAssetOptions, SignedAssetUrl } from './http-client';\n\n/**\n * Options for creating a workspace\n */\nexport interface WorkspaceCreateOptions {\n /** Workspace name */\n name: string;\n /** Workspace description */\n description?: string;\n}\n\n/**\n * Options for updating a workspace\n */\nexport interface WorkspaceUpdateOptions {\n /** Workspace description */\n description?: string;\n /** Allowed node types */\n allowed_node_types?: string[];\n /** Allowed root node types */\n allowed_root_node_types?: string[];\n}\n\n/**\n * Workspace interface for content operations\n */\nexport class WorkspaceClient {\n private name: string;\n private _context: RequestContext;\n private sendRequest: (payload: unknown, requestType?: string) => Promise<unknown>;\n private eventHandler: EventHandler;\n private nodeOps?: NodeOperations;\n private eventSubs?: EventSubscriptions;\n private branch?: string;\n private revision?: string;\n private getUploadManager?: () => UploadManager;\n private getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>;\n\n constructor(\n name: string,\n context: RequestContext,\n sendRequest: (payload: unknown, requestType?: string, contextOverride?: RequestContext) => Promise<unknown>,\n eventHandler: EventHandler,\n branch?: string,\n revision?: string,\n getUploadManager?: () => UploadManager,\n getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>\n ) {\n this.name = name;\n this.branch = branch;\n this.revision = revision;\n // Store context with workspace set\n this._context = {\n ...context,\n workspace: name,\n branch: branch || context.branch,\n revision: revision || context.revision\n };\n // Wrap sendRequest to always include our workspace context\n this.sendRequest = (payload: unknown, requestType?: string) => {\n logger.debug('WorkspaceClient sendRequest wrapper called');\n logger.debug('WorkspaceClient workspace context:', JSON.stringify(this._context, null, 2));\n return sendRequest(payload, requestType, this._context);\n };\n this.eventHandler = eventHandler;\n this.getUploadManager = getUploadManager;\n this.getSignAssetUrl = getSignAssetUrl;\n }\n\n /**\n * Get the workspace name\n */\n getName(): string {\n return this.name;\n }\n\n /**\n * Create a new WorkspaceClient instance scoped to a specific branch.\n *\n * @param branch - Branch name\n * @returns New WorkspaceClient instance with branch context\n */\n onBranch(branch: string): WorkspaceClient {\n return new WorkspaceClient(\n this.name,\n this._context,\n this.sendRequest,\n this.eventHandler,\n branch,\n this.revision,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n\n /**\n * Create a new WorkspaceClient instance scoped to a specific revision/commit.\n *\n * @param revision - Revision/commit ID\n * @returns New WorkspaceClient instance with revision context\n */\n atRevision(revision: string): WorkspaceClient {\n return new WorkspaceClient(\n this.name,\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.branch,\n revision,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n\n /**\n * Get node operations for this workspace\n */\n nodes(): NodeOperations {\n if (!this.nodeOps) {\n this.nodeOps = new NodeOperations(\n (payload, requestType?) =>\n this.sendRequest(payload, requestType || this.inferRequestType(payload)),\n this.name\n );\n }\n return this.nodeOps;\n }\n\n /**\n * Get event subscriptions for this workspace\n */\n events(): EventSubscriptions {\n if (!this.eventSubs) {\n this.eventSubs = new EventSubscriptions(this.eventHandler, {\n workspace: this.name,\n });\n }\n return this.eventSubs;\n }\n\n /**\n * Create a new transaction for this workspace\n *\n * @returns Transaction instance\n *\n * @example\n * ```typescript\n * const tx = ws.transaction();\n * await tx.begin({ message: 'Create initial content' });\n *\n * try {\n * await tx.nodes().create({ type: 'Page', path: '/home', properties: { title: 'Home' } });\n * await tx.nodes().create({ type: 'Page', path: '/about', properties: { title: 'About' } });\n * await tx.commit();\n * } catch (error) {\n * await tx.rollback();\n * throw error;\n * }\n * ```\n */\n transaction(): Transaction {\n // Need to pass the raw sendRequest that accepts contextOverride\n // We can't use this.sendRequest because it always injects workspace context\n // Transaction will handle context management\n\n // Extract the original sendRequest from the constructor parameter\n // by creating a new wrapper that bypasses our workspace context injection\n const rawSendRequest = (payload: unknown, requestType: string, _contextOverride?: RequestContext) => {\n // Use the sendRequest but respect the contextOverride from Transaction\n return this.sendRequest(payload, requestType);\n };\n\n return new Transaction(this._context, rawSendRequest);\n }\n\n // ============================================================================\n // Upload Methods (convenience methods that delegate to UploadManager)\n // ============================================================================\n\n /**\n * Create a resumable upload for this workspace (Browser)\n *\n * Convenience method that pre-fills repository and workspace context.\n *\n * @param file - File or Blob to upload\n * @param path - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const upload = await ws.upload(file, '/videos/my-video.mp4', {\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * await upload.start();\n * ```\n */\n async upload(\n file: File | Blob,\n path: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n if (!this.getUploadManager) {\n throw new Error('Upload not available: client does not support uploads');\n }\n\n const fileSource = await createFileSource(file);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n repository: this._context.repository!,\n workspace: this.name,\n path,\n branch: options?.branch ?? this._context.branch,\n });\n }\n\n /**\n * Create a resumable upload for this workspace (Node.js)\n *\n * Convenience method that pre-fills repository and workspace context.\n *\n * @param filePath - Path to the file to upload\n * @param nodePath - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('data').workspace('backups');\n * const upload = await ws.uploadFile('/path/to/backup.zip', '/backup.zip');\n * await upload.start();\n * ```\n */\n async uploadFile(\n filePath: string,\n nodePath: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n if (!this.getUploadManager) {\n throw new Error('Upload not available: client does not support uploads');\n }\n\n const fileSource = await createFileSource(filePath);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n repository: this._context.repository!,\n workspace: this.name,\n path: nodePath,\n branch: options?.branch ?? this._context.branch,\n });\n }\n\n /**\n * Upload multiple files to this workspace\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param basePath - Base path for all uploads (files go to basePath/filename)\n * @param options - Additional batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await ws.uploadFiles(files, '/uploads', {\n * concurrency: 3,\n * onProgress: (p) => console.log(`${p.filesCompleted}/${p.filesTotal}`),\n * });\n * const result = await batch.start();\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n basePath: string,\n options?: Partial<Omit<BatchUploadOptions, 'repository' | 'workspace' | 'basePath'>>\n ): Promise<BatchUpload> {\n if (!this.getUploadManager) {\n throw new Error('Upload not available: client does not support uploads');\n }\n\n const sources = await Promise.all(\n Array.from(files).map((f) => createFileSource(f))\n );\n const manager = this.getUploadManager();\n return manager.createBatchUpload(sources, {\n ...options,\n repository: this._context.repository!,\n workspace: this.name,\n basePath,\n branch: options?.branch ?? this._context.branch,\n });\n }\n\n // ============================================================================\n // Asset Signed URL Methods\n // ============================================================================\n\n /**\n * Get a signed URL for an asset in this workspace\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param path - Path to the asset node\n * @param command - 'download' (forces download) or 'display' (shows inline)\n * @param options - Optional settings: expiresIn (seconds), propertyPath (e.g., 'thumbnail')\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const { url } = await ws.signAssetUrl('/files/image.jpeg', 'display');\n * document.querySelector('img').src = url;\n *\n * // Get thumbnail instead of main file\n * const { url: thumbUrl } = await ws.signAssetUrl('/files/image.jpeg', 'display', { propertyPath: 'thumbnail' });\n * ```\n */\n async signAssetUrl(\n path: string,\n command: 'download' | 'display' = 'display',\n options?: { expiresIn?: number; propertyPath?: string }\n ): Promise<SignedAssetUrl> {\n if (!this.getSignAssetUrl) {\n throw new Error('SignAssetUrl not available: client does not support it');\n }\n return this.getSignAssetUrl({\n repository: this._context.repository!,\n workspace: this.name,\n path,\n command,\n branch: this._context.branch,\n expiresIn: options?.expiresIn,\n propertyPath: options?.propertyPath,\n });\n }\n\n /**\n * Infer request type from payload\n * This is a helper to determine the correct RequestType enum value\n */\n private inferRequestType(payload: unknown): string {\n if (typeof payload !== 'object' || payload === null) {\n throw new Error('Invalid payload');\n }\n\n const keys = Object.keys(payload);\n\n if ('node_type' in payload && 'path' in payload) {\n return 'node_create';\n }\n if ('node_id' in payload && 'properties' in payload) {\n return 'node_update';\n }\n if ('node_id' in payload && keys.length === 1) {\n if ((payload as any).node_id) {\n return 'node_get';\n }\n return 'node_delete';\n }\n if ('query' in payload) {\n return 'node_query';\n }\n\n throw new Error('Unable to infer request type from payload');\n }\n}\n\n/**\n * Workspace management operations\n */\nexport class WorkspaceManager {\n private _context: RequestContext;\n private sendRequest: (payload: unknown, requestType?: string, contextOverride?: RequestContext) => Promise<unknown>;\n private eventHandler: EventHandler;\n private getUploadManager?: () => UploadManager;\n private getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>;\n\n constructor(\n context: RequestContext,\n sendRequest: (payload: unknown, requestType?: string, contextOverride?: RequestContext) => Promise<unknown>,\n eventHandler: EventHandler,\n getUploadManager?: () => UploadManager,\n getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>\n ) {\n this._context = context;\n this.sendRequest = sendRequest;\n this.eventHandler = eventHandler;\n this.getUploadManager = getUploadManager;\n this.getSignAssetUrl = getSignAssetUrl;\n }\n\n /**\n * Get a workspace client for operations\n *\n * @param name - Workspace name\n * @returns Workspace client\n */\n workspace(name: string): WorkspaceClient {\n return new WorkspaceClient(\n name,\n this._context,\n this.sendRequest,\n this.eventHandler,\n undefined,\n undefined,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n\n /**\n * Create a new workspace\n *\n * @param options - Workspace creation options\n * @returns Created workspace\n */\n async create(options: WorkspaceCreateOptions): Promise<Workspace> {\n const payload: WorkspaceCreatePayload = {\n name: options.name,\n description: options.description,\n };\n\n const result = await this.sendRequest(payload, 'workspace_create');\n return result as Workspace;\n }\n\n /**\n * Get workspace metadata\n *\n * @param name - Workspace name\n * @returns Workspace metadata\n */\n async get(name: string): Promise<Workspace | null> {\n const payload: WorkspaceGetPayload = {\n name,\n };\n\n try {\n const result = await this.sendRequest(payload, 'workspace_get');\n return result as Workspace;\n } catch (error) {\n if (error instanceof Error && error.message.includes('not found')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * List all workspaces\n *\n * @returns Array of workspaces\n */\n async list(): Promise<Workspace[]> {\n const result = await this.sendRequest({}, 'workspace_list');\n return result as Workspace[];\n }\n\n /**\n * Update workspace metadata\n *\n * @param name - Workspace name\n * @param options - Update options\n * @returns Updated workspace\n */\n async update(name: string, options: WorkspaceUpdateOptions): Promise<Workspace> {\n const payload: WorkspaceUpdatePayload = {\n name,\n description: options.description,\n allowed_node_types: options.allowed_node_types,\n allowed_root_node_types: options.allowed_root_node_types,\n };\n\n const result = await this.sendRequest(payload, 'workspace_update');\n return result as Workspace;\n }\n\n /**\n * Delete a workspace\n *\n * @param name - Workspace name\n * @returns true if deleted successfully\n */\n async delete(name: string): Promise<boolean> {\n const payload: WorkspaceDeletePayload = {\n name,\n };\n\n await this.sendRequest(payload, 'workspace_delete');\n return true;\n }\n}\n","/**\n * SQL query support with template literals\n */\n\nimport { SqlQueryPayload, SqlResult } from './protocol';\n\n/**\n * SQL query builder with template literal support\n */\nexport class SqlQuery {\n private sendRequest: (payload: SqlQueryPayload) => Promise<unknown>;\n\n constructor(sendRequest: (payload: SqlQueryPayload) => Promise<unknown>) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Execute a SQL query using template literals\n *\n * @param strings - Template literal strings\n * @param values - Template literal values (automatically parameterized)\n * @returns SQL query result\n *\n * @example\n * ```typescript\n * const results = await sql`SELECT * FROM nodes WHERE node_type = ${nodeType}`;\n * ```\n */\n async query(strings: TemplateStringsArray, ...values: unknown[]): Promise<SqlResult> {\n // Build parameterized query\n let query = strings[0];\n for (let i = 0; i < values.length; i++) {\n query += `$${i + 1}` + strings[i + 1];\n }\n\n const payload: SqlQueryPayload = {\n query,\n params: values,\n };\n\n const result = await this.sendRequest(payload);\n return result as SqlResult;\n }\n\n /**\n * Execute a raw SQL query with explicit parameters\n *\n * @param query - SQL query string with $1, $2, etc. placeholders\n * @param params - Query parameters\n * @returns SQL query result\n *\n * @example\n * ```typescript\n * const results = await sql.execute(\n * 'SELECT * FROM nodes WHERE node_type = $1 AND created_at > $2',\n * ['page', '2024-01-01']\n * );\n * ```\n */\n async execute(query: string, params?: unknown[]): Promise<SqlResult> {\n const payload: SqlQueryPayload = {\n query,\n params,\n };\n\n const result = await this.sendRequest(payload);\n return result as SqlResult;\n }\n\n /**\n * Execute a raw SQL query without parameters\n * Use with caution - prefer parameterized queries for safety\n *\n * @param query - SQL query string\n * @returns SQL query result\n */\n async raw(query: string): Promise<SqlResult> {\n return this.execute(query);\n }\n}\n\n/**\n * Helper function to create SQL template literal handler\n *\n * @param sendRequest - Function to send SQL query request\n * @returns Template literal function\n */\nexport function createSqlHandler(\n sendRequest: (payload: SqlQueryPayload) => Promise<unknown>\n): (strings: TemplateStringsArray, ...values: unknown[]) => Promise<SqlResult> {\n const sqlQuery = new SqlQuery(sendRequest);\n return (strings: TemplateStringsArray, ...values: unknown[]) =>\n sqlQuery.query(strings, ...values);\n}\n","/**\n * NodeType management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class NodeTypes {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new NodeType\n */\n async create(name: string, nodeType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n node_type: nodeType\n },\n RequestType.NodeTypeCreate\n );\n }\n\n /**\n * Get a NodeType by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeGet\n );\n }\n\n /**\n * List all NodeTypes\n */\n async list(publishedOnly = false): Promise<unknown[]> {\n const result = await this.sendRequest(\n {\n published_only: publishedOnly\n },\n RequestType.NodeTypeList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update a NodeType\n */\n async update(name: string, nodeType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n node_type: nodeType\n },\n RequestType.NodeTypeUpdate\n );\n }\n\n /**\n * Delete a NodeType\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeDelete\n );\n }\n\n /**\n * Publish a NodeType\n */\n async publish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypePublish\n );\n }\n\n /**\n * Unpublish a NodeType\n */\n async unpublish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeUnpublish\n );\n }\n\n /**\n * Validate a node against its NodeType\n */\n async validate(node: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n node\n },\n RequestType.NodeTypeValidate\n );\n }\n\n /**\n * Get resolved NodeType with full inheritance applied\n */\n async getResolved(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeGetResolved\n );\n }\n}\n","/**\n * Archetype management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class Archetypes {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new Archetype\n */\n async create(name: string, archetype: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n archetype\n },\n RequestType.ArchetypeCreate\n );\n }\n\n /**\n * Get an Archetype by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeGet\n );\n }\n\n /**\n * List all Archetypes\n */\n async list(publishedOnly = false): Promise<unknown[]> {\n const result = await this.sendRequest(\n {\n published_only: publishedOnly\n },\n RequestType.ArchetypeList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update an Archetype\n */\n async update(name: string, archetype: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n archetype\n },\n RequestType.ArchetypeUpdate\n );\n }\n\n /**\n * Delete an Archetype\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeDelete\n );\n }\n\n /**\n * Publish an Archetype\n */\n async publish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypePublish\n );\n }\n\n /**\n * Unpublish an Archetype\n */\n async unpublish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeUnpublish\n );\n }\n\n /**\n * Get resolved Archetype with full inheritance applied\n */\n async getResolved(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeGetResolved\n );\n }\n}\n","/**\n * ElementType management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class ElementTypes {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new ElementType\n */\n async create(name: string, elementType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n element_type: elementType\n },\n RequestType.ElementTypeCreate\n );\n }\n\n /**\n * Get an ElementType by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeGet\n );\n }\n\n /**\n * List all ElementTypes\n */\n async list(publishedOnly = false): Promise<unknown[]> {\n const result = await this.sendRequest(\n {\n published_only: publishedOnly\n },\n RequestType.ElementTypeList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update an ElementType\n */\n async update(name: string, elementType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n element_type: elementType\n },\n RequestType.ElementTypeUpdate\n );\n }\n\n /**\n * Delete an ElementType\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeDelete\n );\n }\n\n /**\n * Publish an ElementType\n */\n async publish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypePublish\n );\n }\n\n /**\n * Unpublish an ElementType\n */\n async unpublish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeUnpublish\n );\n }\n\n /**\n * Get resolved ElementType with full inheritance applied\n */\n async getResolved(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeGetResolved\n );\n }\n}\n","/**\n * Branch management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\n/**\n * Branch divergence information (similar to \"N commits ahead/behind\").\n */\nexport interface BranchDivergence {\n /** Number of commits on the compared branch not on the base branch */\n ahead: number;\n /** Number of commits on the base branch not on the compared branch */\n behind: number;\n /** Common ancestor revision (HLC string, e.g. \"1705584000000-5\") */\n common_ancestor: string;\n}\n\n/**\n * Per-node change in a branch diff (relative to the merge-base).\n */\nexport interface NodeDiffInfo {\n /** Node id that changed */\n node_id: string;\n /** Workspace the node belongs to */\n workspace: string;\n /** Path on the diffed branch (null when only a tombstone exists, e.g. some deletes) */\n path: string | null;\n /** Operation: \"added\" | \"modified\" | \"deleted\" | \"reordered\" */\n operation: string;\n /** Translation locale when the change is to a translation (absent = base node) */\n translation_locale?: string;\n}\n\n/**\n * Per-node diff of a branch relative to a base branch's merge-base.\n *\n * Unlike {@link BranchDivergence} (ahead/behind counts only), this\n * enumerates exactly which nodes changed since the two branches diverged.\n */\nexport interface BranchDiff {\n /** The common ancestor (merge-base) the diff is computed against (HLC string) */\n common_ancestor: string;\n /** Nodes present on the branch but not on the base */\n added: NodeDiffInfo[];\n /** Nodes changed on the branch (operation \"modified\" / \"reordered\") */\n modified: NodeDiffInfo[];\n /** Nodes removed on the branch */\n deleted: NodeDiffInfo[];\n}\n\n/**\n * Per-node change from a cross-branch node-set copy.\n */\nexport interface CrossBranchNodeChange {\n /** Node id (ids are preserved across branches) */\n node_id: string;\n /** Path of the node on the target branch */\n path: string;\n /** NodeType of the node */\n node_type: string;\n /** Operation on the target branch: \"added\" | \"modified\" | \"deleted\" */\n operation: string;\n}\n\n/**\n * Summary of a cross-branch node-set copy (see {@link Branches.copyNodes}).\n */\nexport interface CrossBranchCopySummary {\n /** Number of nodes written to the target branch (added + modified) */\n copied: number;\n /** Number of target-branch nodes pruned (deleteMissing only) */\n deleted: number;\n /** The single revision all changes were committed under (HLC string) */\n revision: string;\n /** Per-node change list */\n changes: CrossBranchNodeChange[];\n}\n\nexport class Branches {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new branch\n */\n async create(\n name: string,\n options?: {\n fromRevision?: string;\n fromBranch?: string;\n }\n ): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n from_revision: options?.fromRevision,\n from_branch: options?.fromBranch\n },\n RequestType.BranchCreate\n );\n }\n\n /**\n * Get a branch by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.BranchGet\n );\n }\n\n /**\n * List all branches\n */\n async list(): Promise<unknown[]> {\n const result = await this.sendRequest(\n {},\n RequestType.BranchList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Delete a branch\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.BranchDelete\n );\n }\n\n /**\n * Get the HEAD revision of a branch\n */\n async getHead(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.BranchGetHead\n );\n }\n\n /**\n * Update the HEAD revision of a branch\n */\n async updateHead(name: string, revision: string): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n revision\n },\n RequestType.BranchUpdateHead\n );\n }\n\n /**\n * Merge a source branch into a target branch\n */\n async merge(\n sourceBranch: string,\n targetBranch: string,\n options?: {\n strategy?: string;\n message?: string;\n }\n ): Promise<unknown> {\n return this.sendRequest(\n {\n source_branch: sourceBranch,\n target_branch: targetBranch,\n strategy: options?.strategy,\n message: options?.message\n },\n RequestType.BranchMerge\n );\n }\n\n /**\n * Compare two branches to calculate divergence\n */\n async compare(branch: string, baseBranch: string): Promise<BranchDivergence> {\n return this.sendRequest(\n {\n branch,\n base_branch: baseBranch\n },\n RequestType.BranchCompare\n ) as Promise<BranchDivergence>;\n }\n\n /**\n * Per-node diff of `branch` relative to `baseBranch` (added/modified/deleted).\n *\n * Cheaper than reading both branch listings: cost scales with the number of\n * changed nodes since the branches diverged, not the total content.\n */\n async diff(branch: string, baseBranch: string): Promise<BranchDiff> {\n return this.sendRequest(\n {\n branch,\n base_branch: baseBranch\n },\n RequestType.BranchDiff\n ) as Promise<BranchDiff>;\n }\n\n /**\n * Copy a node set from `sourceBranch` onto `targetBranch` (branch\n * promotion): node ids are preserved, so repeated copies update the same\n * target nodes; all changes land in ONE atomic commit on the target branch.\n *\n * Each root's parent path must already exist on the target branch. With\n * `deleteMissing`, target nodes under the roots that are absent from the\n * copied source set are pruned (one-way sync).\n *\n * `sourceRevision` pins the read to a point in time. A promotion of a large\n * set is not instantaneous, so without it the copy reads each node when its\n * turn comes and a writer working in parallel lands partly inside the result\n * — a torn snapshot. Pass the revision captured when the operation was\n * decided (see `getHead`) to copy exactly that state. The target branch is\n * always resolved at its head: the pin says WHAT to copy, never where.\n */\n async copyNodes(\n sourceBranch: string,\n targetBranch: string,\n opts: {\n workspace: string;\n roots: string[];\n recursive?: boolean;\n deleteMissing?: boolean;\n sourceRevision?: string;\n }\n ): Promise<CrossBranchCopySummary> {\n return this.sendRequest(\n {\n source_branch: sourceBranch,\n target_branch: targetBranch,\n workspace: opts.workspace,\n roots: opts.roots,\n recursive: opts.recursive ?? true,\n delete_missing: opts.deleteMissing ?? false,\n source_revision: opts.sourceRevision ?? null\n },\n RequestType.BranchCopyNodes\n ) as Promise<CrossBranchCopySummary>;\n }\n}\n","/**\n * One-shot scheduled invocation operations.\n *\n * Schedule a single future run of a server-side function or flow, cancel it\n * before it fires (by job id or a caller-supplied external key), and inspect\n * pending/completed invocations. Scheduling is restart-safe: the invocation\n * is persisted server-side and fires even if the server restarts before\n * `runAt`.\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\n/** What a scheduled invocation targets. */\nexport type ScheduledInvocationTargetKind = 'function' | 'flow';\n\n/** Options for {@link SchedulerApi.schedule}. */\nexport interface ScheduleInvocationOptions {\n /** \"function\" or \"flow\" */\n targetKind: ScheduledInvocationTargetKind;\n /** Path of the target function or flow node */\n targetPath: string;\n /** Input passed to the target when it fires */\n input?: unknown;\n /** When to fire — RFC3339 string or Date (a past time fires immediately) */\n runAt: string | Date;\n /** Caller-supplied idempotency/lookup key (find or cancel by this later) */\n externalKey?: string;\n /** Branch the invocation executes against (default \"main\") */\n branch?: string;\n /** Workspace the invocation executes against (default \"functions\") */\n workspace?: string;\n /** Retry attempts if the invocation fails (default 0 — one-shot) */\n maxRetries?: number;\n}\n\n/** Result of scheduling an invocation. */\nexport interface ScheduledInvocationRef {\n job_id: string;\n invocation_id: string;\n status: string;\n run_at: string;\n}\n\n/** A scheduled invocation as returned by get/list. */\nexport interface ScheduledInvocation {\n job_id: string;\n invocation_id: string;\n target_kind: string;\n target_path: string | null;\n input: unknown;\n actor: string | null;\n external_key: string | null;\n run_at: string | null;\n /** \"scheduled\" | \"running\" | \"completed\" | \"cancelled\" | \"failed\" */\n status: string;\n error: string | null;\n result: unknown;\n}\n\n/** Filters for {@link SchedulerApi.list}. */\nexport interface ListInvocationsFilter {\n externalKey?: string;\n status?: string;\n}\n\nexport class SchedulerApi {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Schedule a one-shot invocation of a function or flow at a fixed time.\n */\n async schedule(options: ScheduleInvocationOptions): Promise<ScheduledInvocationRef> {\n const runAt =\n options.runAt instanceof Date ? options.runAt.toISOString() : options.runAt;\n return this.sendRequest(\n {\n target_kind: options.targetKind,\n target_path: options.targetPath,\n input: options.input ?? {},\n run_at: runAt,\n external_key: options.externalKey,\n branch: options.branch,\n workspace: options.workspace,\n max_retries: options.maxRetries\n },\n RequestType.ScheduledInvocationCreate\n ) as Promise<ScheduledInvocationRef>;\n }\n\n /**\n * Cancel a pending invocation before it fires, by job id or external key.\n */\n async cancel(\n ref: string | { jobId?: string; externalKey?: string }\n ): Promise<{ job_id: string; status: string }> {\n const payload =\n typeof ref === 'string'\n ? { job_id: ref }\n : { job_id: ref.jobId, external_key: ref.externalKey };\n return this.sendRequest(\n payload,\n RequestType.ScheduledInvocationCancel\n ) as Promise<{ job_id: string; status: string }>;\n }\n\n /**\n * List this repository's scheduled invocations.\n */\n async list(filter?: ListInvocationsFilter): Promise<ScheduledInvocation[]> {\n const result = (await this.sendRequest(\n {\n external_key: filter?.externalKey,\n status: filter?.status\n },\n RequestType.ScheduledInvocationList\n )) as { invocations?: ScheduledInvocation[] };\n return result?.invocations ?? [];\n }\n\n /**\n * Fetch a single scheduled invocation, by job id or external key.\n */\n async get(\n ref: string | { jobId?: string; externalKey?: string }\n ): Promise<ScheduledInvocation> {\n const payload =\n typeof ref === 'string'\n ? { job_id: ref }\n : { job_id: ref.jobId, external_key: ref.externalKey };\n return this.sendRequest(\n payload,\n RequestType.ScheduledInvocationGet\n ) as Promise<ScheduledInvocation>;\n }\n}\n","/**\n * Tag management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class Tags {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new tag\n */\n async create(name: string, revision: string, message?: string): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n revision,\n message\n },\n RequestType.TagCreate\n );\n }\n\n /**\n * Get a tag by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.TagGet\n );\n }\n\n /**\n * List all tags\n */\n async list(): Promise<unknown[]> {\n const result = await this.sendRequest(\n {},\n RequestType.TagList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Delete a tag\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.TagDelete\n );\n }\n}\n","/**\n * FlowsApi - WebSocket-based flow operations.\n *\n * Routes all flow operations through the existing WebSocket connection\n * instead of separate HTTP/SSE requests.\n */\n\nimport type { RequestContext, EventMessage } from './protocol';\nimport { RequestType } from './protocol';\nimport type { EventHandler } from './events';\nimport type {\n FlowRunResponse,\n FlowExecutionEvent,\n FlowInstanceStatusResponse,\n} from './types/flow';\n\ntype SendRequestFn = (\n payload: unknown,\n requestType: string,\n contextOverride?: RequestContext,\n) => Promise<unknown>;\n\nexport class FlowsApi {\n private context: RequestContext;\n private sendRequest: SendRequestFn;\n private eventHandler: EventHandler;\n\n constructor(\n repository: string,\n context: RequestContext,\n sendRequest: SendRequestFn,\n eventHandler: EventHandler,\n ) {\n this.context = { ...context, repository };\n this.sendRequest = sendRequest;\n this.eventHandler = eventHandler;\n }\n\n /** Run a flow by path */\n async run(\n flowPath: string,\n input: Record<string, unknown> = {},\n ): Promise<FlowRunResponse> {\n return (await this.sendRequest(\n { flow_path: flowPath, input },\n RequestType.FlowRun,\n this.context,\n )) as FlowRunResponse;\n }\n\n /** Get instance status */\n async getInstanceStatus(instanceId: string): Promise<FlowInstanceStatusResponse> {\n return (await this.sendRequest(\n { instance_id: instanceId },\n RequestType.FlowGetInstanceStatus,\n this.context,\n )) as FlowInstanceStatusResponse;\n }\n\n /** Resume a waiting flow */\n async resume(instanceId: string, data: unknown): Promise<FlowRunResponse> {\n return (await this.sendRequest(\n { instance_id: instanceId, resume_data: data },\n RequestType.FlowResume,\n this.context,\n )) as FlowRunResponse;\n }\n\n /** Cancel a running flow */\n async cancel(instanceId: string): Promise<void> {\n await this.sendRequest(\n { instance_id: instanceId },\n RequestType.FlowCancel,\n this.context,\n );\n }\n\n /**\n * Subscribe to flow execution events.\n * Returns an async iterable of FlowExecutionEvent + unsubscribe function.\n * Uses WS EventMessage subscription pattern.\n */\n async subscribeEvents(instanceId: string): Promise<{\n events: AsyncIterable<FlowExecutionEvent>;\n unsubscribe: () => Promise<void>;\n }> {\n // 1. Subscribe on server - get subscription_id back\n const response = (await this.sendRequest(\n { instance_id: instanceId },\n RequestType.FlowSubscribeEvents,\n this.context,\n )) as { subscription_id: string };\n\n const subscriptionId = response.subscription_id;\n\n // 2. Create async queue for events\n const queue = createAsyncQueue<FlowExecutionEvent>();\n\n // 3. Register callback for EventMessages with this subscription_id\n const callback = (event: EventMessage) => {\n const payload = event.payload as unknown as FlowExecutionEvent;\n queue.push(payload);\n if (\n payload.type === 'flow_completed' ||\n payload.type === 'flow_failed'\n ) {\n queue.end();\n }\n };\n\n // Register the subscription_id -> callback in the event handler\n this.eventHandler.addFlowEventListener(subscriptionId, callback);\n\n return {\n events: queue,\n unsubscribe: async () => {\n this.eventHandler.removeFlowEventListener(subscriptionId);\n queue.end();\n try {\n await this.sendRequest(\n { subscription_id: subscriptionId },\n RequestType.FlowUnsubscribeEvents,\n this.context,\n );\n } catch {\n // Best effort - server may have already cleaned up\n }\n },\n };\n }\n}\n\n/**\n * Simple async queue that implements AsyncIterable.\n * Push events from callbacks, consume them with for-await-of.\n */\nfunction createAsyncQueue<T>(): AsyncIterableQueue<T> {\n const buffer: T[] = [];\n let resolve: ((value: IteratorResult<T>) => void) | null = null;\n let done = false;\n\n return {\n push(item: T) {\n if (done) return;\n if (resolve) {\n const r = resolve;\n resolve = null;\n r({ done: false, value: item });\n } else {\n buffer.push(item);\n }\n },\n end() {\n done = true;\n if (resolve) {\n const r = resolve;\n resolve = null;\n r({ done: true, value: undefined });\n }\n },\n [Symbol.asyncIterator]() {\n return {\n next(): Promise<IteratorResult<T>> {\n if (buffer.length > 0) {\n return Promise.resolve({ done: false, value: buffer.shift()! });\n }\n if (done) {\n return Promise.resolve({ done: true, value: undefined });\n }\n return new Promise<IteratorResult<T>>((r) => {\n resolve = r;\n });\n },\n return(): Promise<IteratorResult<T>> {\n done = true;\n resolve = null;\n buffer.length = 0;\n return Promise.resolve({ done: true, value: undefined });\n },\n };\n },\n };\n}\n\ninterface AsyncIterableQueue<T> extends AsyncIterable<T> {\n push(item: T): void;\n end(): void;\n}\n","/**\n * FunctionsApi - Transport-agnostic function invocation.\n *\n * Invoke server-side functions through WebSocket or HTTP.\n * Functions can be queued as background jobs (async) or executed inline (sync).\n */\n\nimport type { RequestContext } from './protocol';\nimport { RequestType } from './protocol';\n\ntype SendRequestFn = (\n payload: unknown,\n requestType: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number },\n) => Promise<unknown>;\n\nexport interface FunctionInvokeResponse {\n execution_id: string;\n job_id: string;\n status?: string;\n completed?: boolean;\n timed_out?: boolean;\n waited?: boolean;\n result?: unknown;\n error?: string;\n duration_ms?: number;\n logs?: string[];\n}\n\nexport interface FunctionInvokeSyncResponse {\n execution_id: string;\n result?: unknown;\n error?: string;\n duration_ms?: number;\n logs?: string[];\n}\n\nexport interface FunctionInvokeOptions {\n waitForResult?: boolean;\n waitTimeoutMs?: number;\n requestTimeoutMs?: number;\n}\n\n/**\n * FunctionsApi for WebSocket transport.\n *\n * Sends function invocation requests over the existing WS connection.\n */\nexport class FunctionsApi {\n private context: RequestContext;\n private sendRequest: SendRequestFn;\n\n constructor(\n repository: string,\n context: RequestContext,\n sendRequest: SendRequestFn,\n ) {\n this.context = { ...context, repository };\n this.sendRequest = sendRequest;\n }\n\n /**\n * Invoke a server-side function by name (async).\n *\n * Queues a `FunctionExecution` job and returns the execution and job IDs\n * immediately. The function runs asynchronously on the server.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution ID and job ID for tracking\n */\n async invoke(\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ): Promise<FunctionInvokeResponse> {\n const effectiveRequestTimeoutMs = options?.requestTimeoutMs;\n let effectiveWaitTimeoutMs = options?.waitTimeoutMs;\n if (options?.waitForResult) {\n const transportTimeoutBudget = effectiveRequestTimeoutMs ?? 30000;\n effectiveWaitTimeoutMs = Math.min(\n effectiveWaitTimeoutMs ?? transportTimeoutBudget,\n transportTimeoutBudget,\n );\n }\n\n return (await this.sendRequest(\n {\n function_name: functionName,\n input: input ?? {},\n wait_for_completion: options?.waitForResult ?? false,\n wait_timeout_ms: effectiveWaitTimeoutMs,\n },\n RequestType.FunctionInvoke,\n this.context,\n effectiveRequestTimeoutMs != null ? { timeoutMs: effectiveRequestTimeoutMs } : undefined,\n )) as FunctionInvokeResponse;\n }\n\n /**\n * Invoke a server-side function synchronously.\n *\n * Executes the function inline on the server and returns the result\n * directly. Bypasses the job queue for immediate execution.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution result including output, logs, and duration\n */\n async invokeSync(\n functionName: string,\n input?: Record<string, unknown>,\n ): Promise<FunctionInvokeSyncResponse> {\n return (await this.sendRequest(\n { function_name: functionName, input: input ?? {} },\n RequestType.FunctionInvokeSync,\n this.context,\n )) as FunctionInvokeSyncResponse;\n }\n}\n\n/**\n * HTTP-backed FunctionsApi for SSR / RaisinHttpClient.\n *\n * Calls `POST /api/functions/{repo}/{name}/invoke` via the HTTP client.\n */\nexport class HttpFunctionsApi {\n constructor(\n private repository: string,\n private invokeFn: (\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ) => Promise<FunctionInvokeResponse>,\n private invokeSyncFn: (\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n ) => Promise<FunctionInvokeSyncResponse>,\n ) {}\n\n /**\n * Invoke a server-side function by name (async).\n *\n * Calls the HTTP invoke endpoint and returns the execution and job IDs.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution ID and job ID for tracking\n */\n async invoke(\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ): Promise<FunctionInvokeResponse> {\n return this.invokeFn(this.repository, functionName, input, options);\n }\n\n /**\n * Invoke a server-side function synchronously.\n *\n * Calls the HTTP invoke endpoint with `sync: true` and returns the\n * result directly.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution result including output, logs, and duration\n */\n async invokeSync(\n functionName: string,\n input?: Record<string, unknown>,\n ): Promise<FunctionInvokeSyncResponse> {\n return this.invokeSyncFn(this.repository, functionName, input);\n }\n}\n","/**\n * Error types for the RaisinDB JS SDK.\n *\n * Provides a structured error hierarchy for programmatic error handling.\n * All errors extend RaisinError and include a string `code` field for\n * easy matching in switch statements or error handlers.\n *\n * @example\n * ```typescript\n * import { RaisinError, RaisinConnectionError } from '@raisindb/client';\n *\n * try {\n * await flows.run('/flows/my-flow', {});\n * } catch (err) {\n * if (err instanceof RaisinConnectionError) {\n * console.log('Network issue:', err.code);\n * }\n * }\n * ```\n */\n\n// ============================================================================\n// Error Codes\n// ============================================================================\n\n/** Error codes for connection errors */\nexport type ConnectionErrorCode =\n | 'CONNECTION_FAILED'\n | 'CONNECTION_LOST'\n | 'SSE_STREAM_ERROR';\n\n/**\n * Error codes for authentication errors.\n *\n * Includes the well-known codes plus any server-provided code string\n * (e.g. identity endpoints return codes like `LOGIN_FAILED`).\n */\nexport type AuthErrorCode =\n | 'AUTH_UNAUTHORIZED'\n | 'AUTH_FORBIDDEN'\n | 'AUTH_TOKEN_EXPIRED'\n | 'LOGIN_FAILED'\n | 'REGISTRATION_FAILED'\n // eslint-disable-next-line @typescript-eslint/ban-types\n | (string & {});\n\n/** Error codes for flow execution errors */\nexport type FlowErrorCode =\n | 'FLOW_NOT_FOUND'\n | 'FLOW_EXECUTION_FAILED'\n | 'FLOW_INSTANCE_NOT_FOUND'\n | 'FLOW_RESUME_FAILED';\n\n/** Error codes for timeout errors */\nexport type TimeoutErrorCode =\n | 'REQUEST_TIMEOUT'\n | 'CONNECTION_TIMEOUT'\n | 'POLL_TIMEOUT'\n | 'SSE_INACTIVITY_TIMEOUT';\n\n/** Error codes for abort/cancellation errors */\nexport type AbortErrorCode = 'ABORTED';\n\n/** All error codes */\nexport type RaisinErrorCode =\n | ConnectionErrorCode\n | AuthErrorCode\n | FlowErrorCode\n | TimeoutErrorCode\n | AbortErrorCode;\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\n/**\n * Base error class for all RaisinDB SDK errors.\n *\n * All SDK errors extend this class, making it easy to catch any\n * RaisinDB-specific error with a single `instanceof` check.\n */\nexport class RaisinError extends Error {\n /** String error code for programmatic handling */\n readonly code: RaisinErrorCode;\n /** Optional additional details */\n readonly details?: unknown;\n\n constructor(message: string, code: RaisinErrorCode, details?: unknown) {\n super(message);\n this.name = 'RaisinError';\n this.code = code;\n this.details = details;\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Thrown when a network or connection failure occurs.\n *\n * This includes SSE stream errors, fetch failures, and lost connections.\n */\nexport class RaisinConnectionError extends RaisinError {\n /** HTTP status code, if available */\n readonly status?: number;\n\n constructor(message: string, code: ConnectionErrorCode, options?: { status?: number; details?: unknown }) {\n super(message, code, options?.details);\n this.name = 'RaisinConnectionError';\n this.status = options?.status;\n }\n}\n\n/**\n * Thrown when an authentication or authorization failure occurs.\n *\n * This includes 401 Unauthorized, 403 Forbidden, and expired tokens.\n */\nexport class RaisinAuthError extends RaisinError {\n /** HTTP status code (401 or 403) */\n readonly status: number;\n\n constructor(message: string, code: AuthErrorCode, status: number, details?: unknown) {\n super(message, code, details);\n this.name = 'RaisinAuthError';\n this.status = status;\n }\n}\n\n/**\n * Thrown when a flow execution error occurs.\n *\n * This includes flow not found, execution failures, and resume errors.\n */\nexport class RaisinFlowError extends RaisinError {\n /** Flow instance ID, if available */\n readonly instanceId?: string;\n\n constructor(message: string, code: FlowErrorCode, instanceId?: string, details?: unknown) {\n super(message, code, details);\n this.name = 'RaisinFlowError';\n this.instanceId = instanceId;\n }\n}\n\n/**\n * Thrown when a request or operation times out.\n *\n * Includes the timeout duration for debugging.\n */\nexport class RaisinTimeoutError extends RaisinError {\n /** Timeout duration in milliseconds */\n readonly timeoutMs: number;\n\n constructor(message: string, code: TimeoutErrorCode, timeoutMs: number, details?: unknown) {\n super(message, code, details);\n this.name = 'RaisinTimeoutError';\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Thrown when an operation is aborted via AbortSignal.\n */\nexport class RaisinAbortError extends RaisinError {\n constructor(message = 'Operation was aborted') {\n super(message, 'ABORTED');\n this.name = 'RaisinAbortError';\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Classify an HTTP response error into the appropriate RaisinError subclass.\n *\n * @internal\n */\nexport function classifyHttpError(\n status: number,\n message: string,\n details?: unknown,\n): RaisinError {\n if (status === 401) {\n return new RaisinAuthError(message, 'AUTH_UNAUTHORIZED', status, details);\n }\n if (status === 403) {\n return new RaisinAuthError(message, 'AUTH_FORBIDDEN', status, details);\n }\n if (status === 404) {\n return new RaisinFlowError(message, 'FLOW_NOT_FOUND', undefined, details);\n }\n return new RaisinConnectionError(message, 'CONNECTION_FAILED', { status, details });\n}\n","/**\n * SSE (Server-Sent Events) client for streaming flow execution events.\n *\n * Uses fetch-based approach for better control over connection lifecycle,\n * headers, and reconnection compared to the native EventSource API.\n */\n\nimport { logger } from '../logger';\nimport { ReconnectManager, type ReconnectOptions } from '../utils/reconnect';\nimport { RaisinConnectionError, RaisinAuthError, RaisinAbortError, RaisinTimeoutError } from '../errors';\n\n/**\n * Parsed SSE event from the wire format\n */\nexport interface SSEEvent<T = unknown> {\n /** SSE event type (from \"event:\" field) */\n type: string;\n /** Parsed event data */\n data: T;\n /** SSE event ID (from \"id:\" field, if present) */\n id?: string;\n}\n\n/**\n * SSE connection state\n */\nexport type SSEConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';\n\n/**\n * Callback for SSE connection state changes\n */\nexport type SSEStateCallback = (state: SSEConnectionState) => void;\n\n/**\n * Options for creating an SSE client\n */\nexport interface SSEClientOptions {\n /** HTTP headers to include (e.g., Authorization) */\n headers?: Record<string, string>;\n /** Event types to filter for (if empty, all events are passed through) */\n eventTypes?: string[];\n /** Reconnection options (uses ReconnectManager) */\n reconnect?: ReconnectOptions & {\n /** Whether to automatically reconnect on disconnect (default: true) */\n enabled?: boolean;\n };\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n /** Connection state change callback */\n onStateChange?: SSEStateCallback;\n /** Last-Event-ID for resuming streams */\n lastEventId?: string;\n /** External AbortSignal for cancellation */\n signal?: AbortSignal;\n /** HTTP method (default: 'GET'). Use 'POST' to avoid path in URL params. */\n method?: 'GET' | 'POST';\n /** Request body for POST requests (JSON-serialized automatically) */\n body?: unknown;\n /**\n * Inactivity timeout in milliseconds (default: disabled).\n *\n * The timer is reset whenever any bytes arrive on the stream (events,\n * comments/keep-alives, partial frames). If the stream produces nothing\n * for this long — including a fetch that never responds — the connection\n * is torn down. With reconnection enabled the client reconnects; with\n * reconnection disabled the stream ends with a `RaisinTimeoutError`\n * (code `SSE_INACTIVITY_TIMEOUT`).\n */\n inactivityTimeoutMs?: number;\n}\n\n/**\n * Parse a single SSE message block into event type, data, and id.\n *\n * SSE wire format:\n * event: <type>\\n\n * data: <json>\\n\n * id: <id>\\n\n * \\n\n */\nfunction parseSSEBlock(block: string): { event: string; data: string; id?: string } | null {\n let event = 'message';\n let data = '';\n let id: string | undefined;\n\n const lines = block.split('\\n');\n for (const line of lines) {\n if (line.startsWith('event:')) {\n event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n // Accumulate data lines (SSE spec allows multi-line data)\n if (data) data += '\\n';\n data += line.slice(5).trim();\n } else if (line.startsWith('id:')) {\n id = line.slice(3).trim();\n }\n // Lines starting with \":\" are comments (keep-alive), ignore them\n // Empty lines are block separators, handled by the caller\n }\n\n if (!data) return null;\n\n return { event, data, id };\n}\n\n/**\n * Fetch-based SSE client with reconnection, filtering, and AsyncIterable support.\n *\n * @example\n * ```typescript\n * const sse = new SSEClient('https://api.example.com/events/flow/123', {\n * headers: { Authorization: `Bearer ${token}` },\n * eventTypes: ['step_started', 'step_completed', 'flow_completed'],\n * });\n *\n * // AsyncIterable usage\n * for await (const event of sse) {\n * console.log(event.type, event.data);\n * }\n *\n * // Callback usage\n * sse.connect((event) => {\n * console.log(event.type, event.data);\n * });\n *\n * // Cleanup\n * sse.close();\n * ```\n */\nexport class SSEClient<T = unknown> implements AsyncIterable<SSEEvent<T>> {\n private url: string;\n private options: SSEClientOptions;\n private abortController: AbortController | null = null;\n private reconnectManager: ReconnectManager;\n private fetchImpl: typeof fetch;\n private _state: SSEConnectionState = 'disconnected';\n private _lastEventId?: string;\n private eventTypeSet: Set<string> | null;\n private autoReconnect: boolean;\n private externalSignal?: AbortSignal;\n private inactivityTimeoutMs?: number;\n\n constructor(url: string, options: SSEClientOptions = {}) {\n this.url = url;\n this.options = options;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this._lastEventId = options.lastEventId;\n this.autoReconnect = options.reconnect?.enabled ?? true;\n this.externalSignal = options.signal;\n this.inactivityTimeoutMs = options.inactivityTimeoutMs;\n this.eventTypeSet = options.eventTypes?.length\n ? new Set(options.eventTypes)\n : null;\n\n this.reconnectManager = new ReconnectManager({\n initialDelay: options.reconnect?.initialDelay ?? 1000,\n maxDelay: options.reconnect?.maxDelay ?? 30000,\n backoffMultiplier: options.reconnect?.backoffMultiplier ?? 2,\n maxAttempts: options.reconnect?.maxAttempts ?? Infinity,\n });\n }\n\n /** Current connection state */\n get state(): SSEConnectionState {\n return this._state;\n }\n\n /**\n * Returns a promise that resolves once the SSE connection is established.\n *\n * Useful for ensuring the connection is ready before triggering events\n * on the server side (e.g., calling resume before consuming the stream).\n * If the client is already connected, resolves immediately.\n */\n waitUntilConnected(): Promise<void> {\n if (this._state === 'connected') return Promise.resolve();\n return new Promise<void>((resolve, reject) => {\n const originalOnState = this.options.onStateChange;\n this.options.onStateChange = (state) => {\n originalOnState?.(state);\n if (state === 'connected') {\n // Restore original callback and resolve\n this.options.onStateChange = originalOnState;\n resolve();\n } else if (state === 'disconnected') {\n this.options.onStateChange = originalOnState;\n reject(new Error('SSE connection failed'));\n }\n };\n });\n }\n\n /** Last received event ID */\n get lastEventId(): string | undefined {\n return this._lastEventId;\n }\n\n private setState(state: SSEConnectionState): void {\n if (this._state !== state) {\n this._state = state;\n this.options.onStateChange?.(state);\n }\n }\n\n /**\n * Connect and consume events via callback.\n *\n * @param onEvent - Called for each matching SSE event\n * @param onError - Called when an error occurs (optional)\n */\n async connect(\n onEvent: (event: SSEEvent<T>) => void,\n onError?: (error: Error) => void,\n ): Promise<void> {\n this.close();\n await this.startStream(onEvent, onError);\n }\n\n /**\n * Close the SSE connection and stop reconnection attempts.\n */\n close(): void {\n this.reconnectManager.cancelReconnect();\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n this.setState('disconnected');\n }\n\n /**\n * AsyncIterable interface: allows `for await (const event of sseClient)`.\n *\n * The iterator ends when close() is called or the server closes the stream\n * (and auto-reconnect is disabled or max attempts are exhausted).\n */\n async *[Symbol.asyncIterator](): AsyncIterator<SSEEvent<T>> {\n // Use a queue and resolve-based approach for backpressure\n type QueueItem =\n | { done: false; value: SSEEvent<T> }\n | { done: true; error?: Error };\n\n const queue: QueueItem[] = [];\n let resolve: ((item: QueueItem) => void) | null = null;\n let finished = false;\n\n const push = (item: QueueItem) => {\n if (finished) return;\n if (resolve) {\n const r = resolve;\n resolve = null;\n r(item);\n } else {\n queue.push(item);\n }\n };\n\n const pull = (): Promise<QueueItem> => {\n const queued = queue.shift();\n if (queued) return Promise.resolve(queued);\n return new Promise<QueueItem>((r) => {\n resolve = r;\n });\n };\n\n // Start streaming in the background\n this.startStream(\n (event) => push({ done: false, value: event }),\n (error) => push({ done: true, error }),\n ).then(() => {\n push({ done: true });\n }).catch((error) => {\n push({ done: true, error });\n });\n\n try {\n while (!finished) {\n const item = await pull();\n if (item.done) {\n finished = true;\n if (item.error) {\n throw item.error;\n }\n return;\n }\n yield item.value;\n }\n } finally {\n finished = true;\n this.close();\n }\n }\n\n /**\n * Core streaming loop: connects, reads the SSE stream, and handles reconnection.\n */\n private async startStream(\n onEvent: (event: SSEEvent<T>) => void,\n onError?: (error: Error) => void,\n ): Promise<void> {\n while (true) {\n try {\n await this.readStream(onEvent);\n\n // Stream ended cleanly (server closed connection)\n if (!this.autoReconnect || this._state === 'disconnected') {\n return;\n }\n\n // Schedule reconnection\n this.setState('reconnecting');\n const scheduled = await this.waitForReconnect();\n if (!scheduled) {\n // Max attempts reached\n logger.warn('SSE max reconnection attempts reached');\n this.setState('disconnected');\n return;\n }\n } catch (error) {\n if (this._state === 'disconnected') {\n // close() was called, exit cleanly\n return;\n }\n\n const err = error instanceof Error ? error : new Error(String(error));\n\n // AbortError means close() was called or external AbortSignal fired\n if (err.name === 'AbortError' || err instanceof RaisinAbortError) {\n return;\n }\n\n // Inactivity timeout: reconnect silently if enabled, otherwise end\n // the stream with the typed timeout error.\n if (err instanceof RaisinTimeoutError && err.code === 'SSE_INACTIVITY_TIMEOUT') {\n logger.warn('SSE inactivity timeout:', err.message);\n if (!this.autoReconnect) {\n this.setState('disconnected');\n onError?.(err);\n throw err;\n }\n this.setState('reconnecting');\n const scheduled = await this.waitForReconnect();\n if (!scheduled) {\n logger.warn('SSE max reconnection attempts reached');\n this.setState('disconnected');\n onError?.(err);\n throw err;\n }\n continue;\n }\n\n logger.error('SSE connection error:', err.message);\n onError?.(err);\n\n if (!this.autoReconnect) {\n this.setState('disconnected');\n throw err;\n }\n\n // Schedule reconnection\n this.setState('reconnecting');\n const scheduled = await this.waitForReconnect();\n if (!scheduled) {\n logger.warn('SSE max reconnection attempts reached');\n this.setState('disconnected');\n throw err;\n }\n }\n }\n }\n\n /**\n * Perform a single fetch and read the response body as SSE stream.\n */\n private async readStream(onEvent: (event: SSEEvent<T>) => void): Promise<void> {\n this.abortController = new AbortController();\n this.setState('connecting');\n\n // If an external signal is provided, forward its abort to our internal controller\n if (this.externalSignal) {\n if (this.externalSignal.aborted) {\n this.abortController.abort();\n } else {\n const ctrl = this.abortController;\n this.externalSignal.addEventListener('abort', () => ctrl.abort(), { once: true });\n }\n }\n\n const headers: Record<string, string> = {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...this.options.headers,\n };\n\n // Resume from last event ID if available\n if (this._lastEventId) {\n headers['Last-Event-ID'] = this._lastEventId;\n }\n\n const method = this.options.method ?? 'GET';\n const fetchOptions: RequestInit = {\n method,\n headers,\n signal: this.abortController.signal,\n };\n if (method === 'POST' && this.options.body !== undefined) {\n (fetchOptions.headers as Record<string, string>)['Content-Type'] = 'application/json';\n fetchOptions.body = JSON.stringify(this.options.body);\n }\n\n const response = await this.withInactivityTimeout(\n this.fetchImpl(this.url, fetchOptions),\n );\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n const msg = `SSE connection failed: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`;\n if (response.status === 401 || response.status === 403) {\n throw new RaisinAuthError(\n msg,\n response.status === 401 ? 'AUTH_UNAUTHORIZED' : 'AUTH_FORBIDDEN',\n response.status,\n );\n }\n throw new RaisinConnectionError(msg, 'SSE_STREAM_ERROR', { status: response.status });\n }\n\n if (!response.body) {\n throw new RaisinConnectionError('SSE response has no body', 'SSE_STREAM_ERROR');\n }\n\n this.setState('connected');\n this.reconnectManager.reset();\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await this.withInactivityTimeout(reader.read());\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const blocks = buffer.split('\\n\\n');\n // Last element is incomplete, keep it in the buffer\n buffer = blocks.pop() ?? '';\n\n for (const block of blocks) {\n const trimmed = block.trim();\n if (!trimmed) continue;\n\n const parsed = parseSSEBlock(trimmed);\n if (!parsed) continue;\n\n // Track event ID for reconnection\n if (parsed.id) {\n this._lastEventId = parsed.id;\n }\n\n // Apply event type filter\n if (this.eventTypeSet && !this.eventTypeSet.has(parsed.event)) {\n continue;\n }\n\n // Parse JSON data\n let data: T;\n try {\n data = JSON.parse(parsed.data) as T;\n } catch {\n // If data isn't valid JSON, pass it as-is\n data = parsed.data as unknown as T;\n }\n\n const sseEvent = {\n type: parsed.event,\n data,\n id: parsed.id,\n };\n onEvent(sseEvent);\n }\n }\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // Releasing while a read is pending can throw in some implementations\n }\n }\n }\n\n /**\n * Race a stream operation against the inactivity timeout.\n *\n * If no bytes (or response) arrive within `inactivityTimeoutMs`, the\n * internal connection is aborted and the operation rejects with a\n * `RaisinTimeoutError` (code `SSE_INACTIVITY_TIMEOUT`). The timer is\n * effectively reset on every chunk because each `reader.read()` is\n * wrapped individually.\n */\n private withInactivityTimeout<T>(promise: Promise<T>): Promise<T> {\n const timeoutMs = this.inactivityTimeoutMs;\n if (!timeoutMs || timeoutMs <= 0) return promise;\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n // Swallow the eventual rejection of the underlying promise\n // (e.g. AbortError after we abort) to avoid unhandled rejections.\n promise.catch(() => undefined);\n this.abortController?.abort();\n reject(\n new RaisinTimeoutError(\n `SSE stream inactive for ${timeoutMs}ms`,\n 'SSE_INACTIVITY_TIMEOUT',\n timeoutMs,\n ),\n );\n }, timeoutMs);\n\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n }\n\n /**\n * Wait for the reconnect manager to schedule a reconnection attempt.\n * Returns true if reconnection was scheduled, false if max attempts reached.\n */\n private waitForReconnect(): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const scheduled = this.reconnectManager.scheduleReconnect(() => {\n resolve(true);\n });\n if (!scheduled) {\n resolve(false);\n }\n });\n }\n}\n","import type { ChatDoneEvent, ChatEvent } from '../types/chat';\n\n/**\n * Detect safety-net done events emitted by backend recovery paths.\n *\n * These events can appear while async tool calls are still running.\n * They carry `recovered: true` and an empty content payload.\n */\nexport function isRecoveredDoneEvent(event: ChatEvent): event is ChatDoneEvent & { recovered: true } {\n if (event.type !== 'done') return false;\n const done = event as ChatDoneEvent & { recovered?: unknown };\n if (done.recovered !== true) return false;\n return typeof done.content !== 'string' || done.content.trim().length === 0;\n}\n\n","/**\n * User home path normalization.\n *\n * Some server responses (JWT claims, RAISIN_CURRENT_USER(), identity\n * endpoints) return the user home as a workspace-prefixed path like\n * `/raisin:access_control/users/internal/alice`, while others return the\n * workspace-relative form `/users/internal/alice`. SDK code that builds\n * child paths (inbox, chats, outbox) expects the workspace-relative form.\n */\n\n/** Workspace prefix that may leak into user home paths */\nconst ACCESS_CONTROL_PREFIX = '/raisin:access_control';\n\n/**\n * Normalize a user home path to its workspace-relative form.\n *\n * Strips a leading `/raisin:access_control` workspace prefix and trailing\n * slashes, so `/raisin:access_control/users/internal/alice/` becomes\n * `/users/internal/alice`. Paths without the prefix are returned unchanged\n * (modulo trailing-slash trimming). Returns `null` for empty input.\n *\n * @example\n * ```typescript\n * normalizeHomePath('/raisin:access_control/users/internal/alice');\n * // => '/users/internal/alice'\n * normalizeHomePath('/users/internal/alice');\n * // => '/users/internal/alice'\n * ```\n */\nexport function normalizeHomePath(home: string | null | undefined): string | null {\n if (home === null || home === undefined) return null;\n\n let path = home.trim();\n if (path.length === 0) return null;\n\n if (path === ACCESS_CONTROL_PREFIX) return '/';\n if (path.startsWith(`${ACCESS_CONTROL_PREFIX}/`)) {\n path = path.slice(ACCESS_CONTROL_PREFIX.length);\n }\n\n // Trim trailing slashes (but keep root \"/\")\n while (path.length > 1 && path.endsWith('/')) {\n path = path.slice(0, -1);\n }\n\n return path;\n}\n","/**\n * Unified ConversationManager for RaisinDB.\n *\n * Merges all conversation operations (previously split across ChatClient,\n * ConversationClient, and FlowClient) into a single API accessed via\n * `db.conversations`.\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n *\n * // List conversations\n * const convos = await db.conversations.list({ type: 'ai_chat' });\n *\n * // Create a new conversation with an agent\n * const convo = await db.conversations.create({ participant: '/agents/support' });\n *\n * // Send a message and stream the response\n * for await (const event of db.conversations.sendMessage(convo.conversationPath, 'Hello!', { stream: true })) {\n * if (event.type === 'text_chunk') process.stdout.write(event.text);\n * }\n *\n * // Get full message history\n * const messages = await db.conversations.getMessages(convo.conversationPath);\n * ```\n */\n\nimport type { AuthManager } from './auth';\nimport type {\n ChatEvent,\n ChatMessage,\n Conversation,\n ConversationType,\n ConversationListItem,\n ToolCallRecord,\n MessageChild,\n PlanTask,\n} from './types/chat';\nimport { logger } from './logger';\nimport { SSEClient } from './streaming/sse-client';\nimport { RaisinAbortError, RaisinTimeoutError, classifyHttpError } from './errors';\nimport type { SqlResult } from './protocol';\nimport { isRecoveredDoneEvent } from './utils/chat-events';\nimport { normalizeHomePath } from './utils/home-path';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Options for listing conversations */\nexport interface ListConversationsOptions {\n /** Filter by conversation type */\n type?: ConversationType;\n /** Maximum number of conversations to return */\n limit?: number;\n /** Abort signal */\n signal?: AbortSignal;\n}\n\n/** Options for creating a conversation */\nexport interface CreateConversationOptions {\n /**\n * Participant identifier — auto-detects agents vs users.\n *\n * Agent paths (e.g. `/agents/support` or `agent:support`) create an\n * `ai_chat` conversation. Anything else creates a `direct_message`.\n */\n participant: string;\n /** Optional subject line */\n subject?: string;\n /** Additional input data passed to the conversation */\n input?: Record<string, unknown>;\n /** Abort signal */\n signal?: AbortSignal;\n}\n\n/** Default inactivity timeout for sendMessage SSE streams (2 minutes) */\nexport const DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS = 120_000;\n\n/** Options for sending a message */\nexport interface SendMessageOptions {\n /** Whether to stream events via SSE (default: true) */\n stream?: boolean;\n /** Abort signal */\n signal?: AbortSignal;\n /**\n * Inactivity timeout for the per-turn SSE stream in milliseconds\n * (default: 120000). If the stream produces no bytes for this long,\n * the turn ends with a synthetic `waiting` event instead of hanging\n * forever. Set to 0 to disable.\n */\n inactivityTimeoutMs?: number;\n}\n\n/** Handle for a persistent conversation SSE subscription */\nexport interface ConversationSubscription {\n /** Close the SSE connection */\n unsubscribe(): void;\n /** Wait until the SSE connection is established */\n waitUntilConnected(): Promise<void>;\n}\n\n/** Immediate receipt for queued plan actions (non-blocking). */\nexport interface PlanActionReceipt {\n accepted: boolean;\n action: 'approve' | 'reject';\n actionId: string;\n planPath: string;\n executionId: string;\n jobId: string;\n status?: string;\n}\n\n/** Options for plan actions */\nexport interface PlanActionOptions {\n actionId?: string;\n requestTimeoutMs?: number;\n}\n\n/** Options for constructing the ConversationManager */\nexport interface ConversationManagerOptions {\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n /** Request timeout in milliseconds (default: 60000) */\n requestTimeout?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Internal type for SQL query response */\ninterface SqlQueryResponse {\n columns?: string[];\n rows?: Record<string, unknown>[];\n}\n\ninterface SqlInvokeReceipt {\n execution_id?: string;\n job_id?: string;\n}\n\n// ---------------------------------------------------------------------------\n// ConversationManager\n// ---------------------------------------------------------------------------\n\n/**\n * Unified conversation manager for RaisinDB.\n *\n * Handles the full lifecycle: listing, creating, opening, deleting, messaging,\n * streaming, and plan approval/rejection for all conversation types.\n */\nexport class ConversationManager {\n private baseUrl: string;\n private repository: string;\n private authManager: AuthManager;\n private fetchImpl: typeof fetch;\n private requestTimeout: number;\n\n private executeSql?: (query: string, params?: unknown[]) => Promise<SqlResult>;\n private cachedUserId?: string;\n private cachedUserHome?: string;\n\n constructor(\n baseUrl: string,\n repository: string,\n authManager: AuthManager,\n options: ConversationManagerOptions = {},\n executeSql?: (query: string, params?: unknown[]) => Promise<SqlResult>,\n ) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.repository = repository;\n this.authManager = authManager;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.requestTimeout = options.requestTimeout ?? 60000;\n this.executeSql = executeSql;\n }\n\n // ==========================================================================\n // User context\n // ==========================================================================\n\n private async ensureCurrentUser(): Promise<{ userId: string; userHome: string }> {\n if (this.cachedUserId && this.cachedUserHome) {\n return { userId: this.cachedUserId, userHome: this.cachedUserHome };\n }\n const result = await this.sqlQuery(\n `SELECT RAISIN_CURRENT_USER()->>'path'::String as home, RAISIN_CURRENT_USER()->>'id'::String as user_id`,\n );\n if (!result?.rows?.[0]) throw new Error('User not authenticated');\n const row = result.rows[0] as Record<string, unknown>;\n const userHome = normalizeHomePath(row.home as string);\n if (!userHome) throw new Error('User home path not found');\n this.cachedUserHome = userHome;\n this.cachedUserId = (row.user_id as string) || userHome;\n return { userId: this.cachedUserId, userHome };\n }\n\n // ==========================================================================\n // Conversation listing\n // ==========================================================================\n\n /**\n * List conversations for the current user.\n */\n async list(options?: ListConversationsOptions): Promise<ConversationListItem[]> {\n const workspace = 'raisin:access_control';\n const { userHome } = await this.ensureCurrentUser();\n\n const sql = `\n SELECT id, path, properties, created_at, updated_at\n FROM '${workspace}'\n WHERE node_type = 'raisin:Conversation'\n AND DESCENDANT_OF($1)\n ${options?.type ? \"AND properties->>'conversation_type'::String = $2\" : ''}\n ORDER BY updated_at DESC\n ${options?.limit ? `LIMIT ${options.limit}` : ''}\n `;\n const params = options?.type\n ? [`${userHome}/inbox/chats`, options.type]\n : [`${userHome}/inbox/chats`];\n const response = await this.sqlQuery(sql, params);\n\n if (!response || !Array.isArray(response.rows)) return [];\n\n const rows = response.rows as unknown as Record<string, unknown>[];\n return rows.map((row: any) => {\n const props = row.properties ?? {};\n return {\n id: row.id,\n type: (props.conversation_type as ConversationType) ?? 'ai_chat',\n conversationPath: row.path,\n conversationWorkspace: workspace,\n agentRef: props.agent_ref,\n participants: props.participants,\n unreadCount: props.unread_count,\n lastMessage: props.last_message,\n updatedAt: row.updated_at ?? row.created_at,\n } satisfies ConversationListItem;\n });\n }\n\n // ==========================================================================\n // Conversation lifecycle\n // ==========================================================================\n\n /**\n * Create a new conversation.\n *\n * `participant` auto-detects whether the target is an agent or a user:\n * - Paths starting with `/agents/` or `agent:` create an `ai_chat`\n * - Everything else creates a `direct_message`\n */\n async create(options: CreateConversationOptions): Promise<Conversation> {\n logger.info('[ConversationManager] Creating conversation', { participant: options.participant });\n const conversationId = `chat-${crypto.randomUUID()}`;\n const workspace = 'raisin:access_control';\n\n const recipientId = this.normalizeRecipientId(options.participant);\n const isAgent = recipientId.startsWith('agent:');\n const conversationType: ConversationType = isAgent ? 'ai_chat' : 'direct_message';\n const agentPath = isAgent ? this.normalizeAgentPath(options.participant) : undefined;\n\n const { userId, userHome } = await this.ensureCurrentUser();\n const conversationPath = `${userHome}/inbox/chats/${conversationId}`;\n\n await this.ensureFolderNode(workspace, `${userHome}/inbox`, 'Inbox');\n await this.ensureFolderNode(workspace, `${userHome}/inbox/chats`, 'Chats');\n\n const participants = [userId, recipientId].filter(Boolean);\n\n const properties: Record<string, unknown> = {\n conversation_type: conversationType,\n conversation_id: conversationId,\n subject: options.subject || 'Chat',\n participants,\n stream_channel: `chat:${conversationId}`,\n unread_count: 0,\n ...(agentPath ? {\n agent_ref: { 'raisin:path': agentPath, 'raisin:workspace': 'functions' },\n } : {}),\n ...(options.input ?? {}),\n };\n\n const sql = `\n INSERT INTO '${workspace}' (path, node_type, properties)\n VALUES ($1, 'raisin:Conversation', $2::jsonb)\n RETURNING id, path\n `;\n const result = await this.sqlQuery(sql, [conversationPath, JSON.stringify(properties)]);\n\n if (!result?.rows?.[0]) throw new Error('Failed to create conversation');\n\n const resultRow = result.rows[0] as Record<string, unknown>;\n const now = new Date().toISOString();\n\n logger.info('[ConversationManager] Conversation created', { path: conversationPath });\n\n return {\n id: resultRow.id as string,\n type: conversationType,\n agentRef: agentPath,\n participants,\n conversationPath,\n conversationWorkspace: workspace,\n initialEvents: [\n { type: 'conversation_created', conversationPath, workspace, timestamp: now },\n { type: 'waiting', timestamp: now },\n ],\n };\n }\n\n /**\n * Open an existing conversation by path.\n * Returns null if not found.\n */\n async open(conversationPath: string): Promise<Conversation | null> {\n const workspace = 'raisin:access_control';\n try {\n const sql = `SELECT id, path, properties, created_at FROM '${workspace}' WHERE path = $1 AND node_type = 'raisin:Conversation' LIMIT 1`;\n const response = await this.sqlQuery(sql, [conversationPath]);\n\n if (!response || !Array.isArray(response.rows) || response.rows.length === 0) {\n return null;\n }\n\n const rows = response.rows as unknown as Record<string, unknown>[];\n const row = rows[0];\n const props = (row.properties ?? {}) as Record<string, unknown>;\n\n return {\n id: row.id as string,\n type: (props.conversation_type as ConversationType) ?? 'ai_chat',\n agentRef: props.agent_ref as string | undefined,\n participants: props.participants as string[] | undefined,\n participantDetails: props.participant_details as Record<string, { display_name: string }> | undefined,\n unreadCount: props.unread_count as number | undefined,\n lastMessage: props.last_message as { content: string; sender_id: string; created_at: string } | undefined,\n conversationPath,\n conversationWorkspace: workspace,\n initialEvents: [{ type: 'waiting', timestamp: new Date().toISOString() }],\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Delete a conversation and all its children.\n */\n async delete(conversationPath: string): Promise<void> {\n const workspace = 'raisin:access_control';\n await this.sqlQuery(\n `DELETE FROM '${workspace}' WHERE path = $1 OR path LIKE $2`,\n [conversationPath, `${conversationPath}/%`],\n );\n }\n\n /**\n * Mark a conversation as read by setting unread_count to 0.\n */\n async markAsRead(conversationPath: string): Promise<void> {\n const workspace = 'raisin:access_control';\n await this.sqlQuery(\n `UPDATE '${workspace}' SET properties = jsonb_set(properties, '{unread_count}', '0'::jsonb) WHERE path = $1 AND node_type = 'raisin:Conversation'`,\n [conversationPath],\n );\n }\n\n /**\n * Mark a single message as read by the current user.\n */\n async markMessageAsRead(messagePath: string): Promise<void> {\n const workspace = 'raisin:access_control';\n const now = new Date().toISOString();\n await this.sqlQuery(\n `UPDATE '${workspace}' SET properties = jsonb_set(properties, '{read_at}', $2::jsonb) WHERE path = $1 AND node_type = 'raisin:Message'`,\n [messagePath, JSON.stringify(now)],\n );\n }\n\n // ==========================================================================\n // Messaging\n // ==========================================================================\n\n /**\n * Get the full message history for a conversation.\n */\n async getMessages(conversationPath: string): Promise<ChatMessage[]> {\n return this.getMessagesFromNodeTree(conversationPath);\n }\n\n /**\n * Send a message to a conversation.\n *\n * Returns an `AsyncIterable<ChatEvent>` for streaming. By default streams\n * via SSE. Set `options.stream = false` to fire-and-forget.\n */\n async *sendMessage(\n conversationPath: string,\n content: string,\n options?: SendMessageOptions,\n ): AsyncIterable<ChatEvent> {\n const shouldStream = options?.stream !== false;\n\n logger.debug('[ConversationManager] Starting SSE stream for message send');\n\n if (!shouldStream) {\n await this.createUserMessage(conversationPath, content);\n yield { type: 'waiting', timestamp: new Date().toISOString() };\n return;\n }\n\n const workspace = 'raisin:access_control';\n const streamTarget = await this.resolveConversationStreamTarget(conversationPath, workspace);\n\n // Subscribe to SSE BEFORE creating the message so we don't miss events.\n const sseUrl = `${this.baseUrl}/api/conversations/${this.repository}/events`;\n const headers: Record<string, string> = {};\n const token = this.authManager.getAccessToken();\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n const sse = new SSEClient<ChatEvent>(sseUrl, {\n headers,\n eventTypes: ['conversation-event', 'message'],\n reconnect: { enabled: false },\n fetch: this.fetchImpl,\n signal: options?.signal,\n method: 'POST',\n body: { channel: streamTarget.channel, path: streamTarget.path },\n inactivityTimeoutMs:\n options?.inactivityTimeoutMs ?? DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS,\n });\n\n const iterator = sse[Symbol.asyncIterator]();\n let pendingFirst: Promise<IteratorResult<{ type: string; data: ChatEvent }>> | null = iterator.next();\n\n try {\n await sse.waitUntilConnected();\n } catch {\n // Avoid an unhandled rejection if the iterator errors after we bail\n pendingFirst?.catch(() => undefined);\n pendingFirst = null;\n sse.close();\n logger.debug('SSE connection failed, falling back to create-only');\n }\n\n // Create the user message node\n try {\n await this.createUserMessage(conversationPath, content);\n } catch (error) {\n logger.error('[ConversationManager] Failed to create user message', error);\n sse.close();\n throw error;\n }\n\n // Stream events from SSE\n if (pendingFirst) {\n try {\n while (true) {\n let result;\n if (pendingFirst) {\n result = await pendingFirst;\n pendingFirst = null;\n } else {\n result = await iterator.next();\n }\n\n if (result.done) break;\n\n const event = result.value.data;\n if (isRecoveredDoneEvent(event)) {\n logger.debug('[ConversationManager] Ignoring recovered done event while turn may still be active');\n continue;\n }\n if (event.type === 'done' && event.dispatchPhase && event.dispatchPhase !== 'terminal') {\n logger.debug('[ConversationManager] Ignoring non-terminal done event');\n continue;\n }\n yield event;\n\n if (event.type === 'done' || event.type === 'completed' || event.type === 'failed' || event.type === 'waiting') {\n return;\n }\n }\n } catch (error) {\n if (error instanceof RaisinTimeoutError && error.code === 'SSE_INACTIVITY_TIMEOUT') {\n // The SSE stream went silent mid-turn. End the turn gracefully so\n // chat UIs don't hang; the persistent subscription / message reload\n // will pick up any late events.\n logger.warn(\n `[ConversationManager] SSE stream inactive for ${error.timeoutMs}ms, ending turn with synthetic waiting event`,\n );\n yield { type: 'waiting', timestamp: new Date().toISOString() };\n return;\n }\n throw error;\n } finally {\n sse.close();\n }\n }\n\n yield { type: 'waiting', timestamp: new Date().toISOString() };\n }\n\n /**\n * Create a user message in a conversation.\n *\n * The message node triggers server-side handlers (via triggers);\n * events arrive via the persistent subscription.\n */\n async createUserMessage(conversationPath: string, content: string): Promise<void> {\n logger.debug('[ConversationManager] Creating user message', { path: conversationPath });\n const workspace = 'raisin:access_control';\n const { userId, userHome } = await this.ensureCurrentUser();\n const messageId = crypto.randomUUID();\n\n const properties = await this.loadConversationProperties(conversationPath, workspace);\n const participants = Array.isArray(properties?.participants)\n ? (properties.participants as unknown[])\n : [];\n let recipientId = participants.find((p) =>\n typeof p === 'string' && p.length > 0 && p !== userId && p !== userHome\n ) as string | undefined;\n if (recipientId) recipientId = this.normalizeRecipientId(recipientId);\n\n const conversationId = (typeof properties?.conversation_id === 'string' && properties.conversation_id.length > 0)\n ? (properties.conversation_id as string)\n : conversationPath.split('/').pop() || '';\n\n if (!recipientId) {\n throw new Error(`Conversation recipient not found for ${conversationPath}`);\n }\n\n const messagePath = `${userHome}/outbox/msg-${messageId}`;\n const outboxProperties = {\n role: 'user',\n message_type: 'chat',\n status: 'pending',\n sender_id: userId,\n sender_path: userHome,\n recipient_id: recipientId,\n body: { content, message_text: content, thread_id: conversationId },\n conversation_id: conversationId,\n client_id: messageId,\n created_at: new Date().toISOString(),\n };\n\n await this.sqlQuery(\n `INSERT INTO '${workspace}' (path, node_type, properties) VALUES ($1, 'raisin:Message', $2::jsonb) RETURNING id`,\n [messagePath, JSON.stringify(outboxProperties)],\n );\n }\n\n // ==========================================================================\n // Persistent subscription\n // ==========================================================================\n\n /**\n * Subscribe to a conversation's events via a persistent SSE connection.\n *\n * Keeps a long-lived connection that survives across turns. Useful for\n * receiving async events between turns (background tool results, agent-\n * initiated messages, etc.). Auto-reconnects on disconnect.\n */\n subscribe(\n conversationPath: string,\n onEvent: (event: ChatEvent) => void,\n options?: { signal?: AbortSignal },\n ): ConversationSubscription {\n logger.info('[ConversationManager] Subscribing to SSE', { path: conversationPath });\n const sseUrl = `${this.baseUrl}/api/conversations/${this.repository}/events`;\n const headers: Record<string, string> = {};\n const token = this.authManager.getAccessToken();\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n let sse: SSEClient<ChatEvent> | null = null;\n let unsubscribed = false;\n\n const setupPromise = (async () => {\n const streamTarget = await this.resolveConversationStreamTarget(conversationPath);\n if (unsubscribed) return null;\n\n sse = new SSEClient<ChatEvent>(sseUrl, {\n headers,\n eventTypes: ['conversation-event', 'message'],\n reconnect: { enabled: true },\n fetch: this.fetchImpl,\n signal: options?.signal,\n method: 'POST',\n body: { channel: streamTarget.channel, path: streamTarget.path },\n });\n\n sse.connect(\n (sseEvent) => onEvent(sseEvent.data),\n (error) => logger.error('Conversation SSE error:', error.message),\n );\n return sse;\n })();\n\n return {\n unsubscribe: () => {\n unsubscribed = true;\n sse?.close();\n },\n waitUntilConnected: async () => {\n const activeSse = await setupPromise;\n if (!activeSse) return;\n await activeSse.waitUntilConnected();\n },\n };\n }\n\n // ==========================================================================\n // Plan actions\n // ==========================================================================\n\n /**\n * Approve a pending plan without waiting for completion.\n * Returns an enqueue receipt; final state is observed via conversation events.\n */\n async approvePlan(planPath: string, options?: PlanActionOptions): Promise<PlanActionReceipt> {\n logger.info('[ConversationManager] Plan action: approve', { path: planPath });\n return this.invokePlanAction('approve', planPath, undefined, options);\n }\n\n /**\n * Reject a pending plan without waiting for completion.\n */\n async rejectPlan(planPath: string, feedback?: string, options?: PlanActionOptions): Promise<PlanActionReceipt> {\n logger.info('[ConversationManager] Plan action: reject', { path: planPath });\n return this.invokePlanAction('reject', planPath, feedback, options);\n }\n\n // ==========================================================================\n // One-shot convenience\n // ==========================================================================\n\n /**\n * One-shot chat: create a conversation, send a message, return response.\n */\n async chat(\n participant: string,\n message: string,\n options?: { signal?: AbortSignal; input?: Record<string, unknown> },\n ): Promise<{ response: string; conversationPath: string }> {\n const convo = await this.create({\n participant,\n input: options?.input,\n signal: options?.signal,\n });\n\n let response = '';\n for await (const event of this.sendMessage(convo.conversationPath, message, {\n signal: options?.signal,\n stream: true,\n })) {\n if (event.type === 'text_chunk') response += event.text;\n }\n\n return { response, conversationPath: convo.conversationPath };\n }\n\n // ==========================================================================\n // Health checks (used by ConversationStore watchdog)\n // ==========================================================================\n\n /**\n * Query pending (in-flight) tool calls from the node tree.\n * Used by ConversationStore to rebuild `_activeToolCalls` on reload.\n */\n async getActiveToolCalls(\n conversationPath: string,\n ): Promise<{ id: string; name: string; status: string }[]> {\n const workspace = 'raisin:access_control';\n const sql = `\n SELECT id, properties->>'function_name'::String as name, properties->>'status'::String as status\n FROM '${workspace}'\n WHERE DESCENDANT_OF($1)\n AND node_type = 'raisin:AIToolCall'\n AND properties->>'status'::String IN ('pending', 'running')\n ORDER BY created_at ASC\n `;\n try {\n const response = await this.sqlQuery(sql, [conversationPath]);\n if (!response?.rows || !Array.isArray(response.rows)) return [];\n return (response.rows as any[]).map((row: any) => ({\n id: row.id ?? '',\n name: row.name ?? '',\n status: row.status ?? 'pending',\n }));\n } catch {\n return [];\n }\n }\n\n /**\n * Check the health of the latest assistant turn.\n * Returns 'streaming' if the turn appears active, 'done' if it's finished,\n * or 'unknown' if no assistant message is found.\n */\n async checkTurnHealth(\n conversationPath: string,\n ): Promise<'streaming' | 'done' | 'unknown'> {\n const workspace = 'raisin:access_control';\n const sql = `\n SELECT properties->>'status'::String as status,\n properties->>'finish_reason'::String as finish_reason,\n properties->>'dispatch_phase'::String as dispatch_phase\n FROM '${workspace}'\n WHERE CHILD_OF($1)\n AND node_type = 'raisin:Message'\n AND properties->>'role'::String = 'assistant'\n ORDER BY created_at DESC LIMIT 1\n `;\n try {\n const response = await this.sqlQuery(sql, [conversationPath]);\n if (!response?.rows || !Array.isArray(response.rows) || response.rows.length === 0) {\n return 'unknown';\n }\n const row = response.rows[0] as Record<string, unknown>;\n const finishReason = row.finish_reason as string | undefined;\n const dispatchPhase = row.dispatch_phase as string | undefined;\n if (dispatchPhase) {\n return dispatchPhase === 'terminal' ? 'done' : 'streaming';\n }\n // If the message has a terminal finish_reason, the turn is done\n if (finishReason && finishReason !== 'tool_calls') {\n return 'done';\n }\n return 'streaming';\n } catch {\n return 'unknown';\n }\n }\n\n // ==========================================================================\n // Internal: message loading from node tree\n // ==========================================================================\n\n private async getMessagesFromNodeTree(conversationPath: string, workspace?: string): Promise<ChatMessage[]> {\n const ws = workspace ?? 'raisin:access_control';\n\n const [msgResponse, childResponse] = await Promise.all([\n this.sqlQuery(\n `SELECT id, path, name, properties, created_at FROM '${ws}' WHERE CHILD_OF('${conversationPath}') AND node_type = 'raisin:Message' AND (properties->>'message_type'::String IS NULL OR properties->>'message_type'::String NOT IN ('ai_tool_call', 'ai_tool_result', 'ai_thought')) ORDER BY created_at ASC`,\n ),\n this.sqlQuery(\n `SELECT id, path, name, node_type, properties, created_at FROM '${ws}' WHERE DESCENDANT_OF('${conversationPath}') AND node_type IN ('raisin:AIPlan', 'raisin:AITask', 'raisin:AIThought', 'raisin:AICostRecord') ORDER BY created_at ASC`,\n ),\n ]);\n\n if (!msgResponse || !Array.isArray(msgResponse.rows)) return [];\n\n // Group child nodes by parent message path; collect tasks separately\n const childrenByMsg = new Map<string, MessageChild[]>();\n const tasksByPlan = new Map<string, PlanTask[]>();\n const planByPath = new Map<string, MessageChild>();\n\n for (const row of ((childResponse?.rows ?? []) as any[])) {\n const parts = (row.path as string).split('/');\n\n if (row.node_type === 'raisin:AITask') {\n const planPath = parts.slice(0, -1).join('/');\n const tasks = tasksByPlan.get(planPath) ?? [];\n tasks.push({\n id: row.id,\n title: row.properties?.title ?? row.name,\n status: row.properties?.status ?? 'pending',\n });\n tasksByPlan.set(planPath, tasks);\n continue;\n }\n\n const msgPath = parts.slice(0, -1).join('/');\n const children = childrenByMsg.get(msgPath) ?? [];\n const child: MessageChild = {\n id: row.id,\n path: row.path,\n type:\n row.node_type === 'raisin:AIPlan'\n ? 'plan'\n : row.node_type === 'raisin:AICostRecord'\n ? 'cost'\n : 'thought',\n content: row.properties?.content ?? '',\n status: row.properties?.status ?? 'completed',\n };\n if (child.type === 'plan') {\n child.planTitle = row.properties?.title;\n child.toolName = 'create_plan';\n planByPath.set(row.path, child);\n } else if (child.type === 'cost') {\n const inputTokens = Number(row.properties?.input_tokens ?? 0);\n const outputTokens = Number(row.properties?.output_tokens ?? 0);\n const totalTokens = Number(row.properties?.total_tokens ?? (inputTokens + outputTokens));\n const costUsdRaw = Number(row.properties?.cost_usd);\n const durationMsRaw = Number(row.properties?.duration_ms);\n child.model = row.properties?.model ?? undefined;\n child.provider = row.properties?.provider ?? undefined;\n child.inputTokens = Number.isFinite(inputTokens) ? inputTokens : 0;\n child.outputTokens = Number.isFinite(outputTokens) ? outputTokens : 0;\n child.totalTokens = Number.isFinite(totalTokens) ? totalTokens : 0;\n child.costUsd = Number.isFinite(costUsdRaw) ? costUsdRaw : undefined;\n child.durationMs = Number.isFinite(durationMsRaw) ? durationMsRaw : undefined;\n child.content = `tokens: ${child.totalTokens ?? 0}`;\n }\n children.push(child);\n childrenByMsg.set(msgPath, children);\n }\n\n for (const [planPath, tasks] of tasksByPlan) {\n const plan = planByPath.get(planPath);\n if (plan) plan.tasks = tasks;\n }\n\n // Filter out empty intermediate continuation messages and tool-echo messages\n const filteredRows = (msgResponse.rows as any[]).filter((row: any) => {\n const props = row.properties ?? {};\n const msgContent = props.content\n ?? (typeof props.body === 'string' ? props.body : props.body?.content)\n ?? '';\n const finishReason = props.finish_reason ?? '';\n const msgType = props.message_type ?? '';\n\n // Skip empty messages with finish_reason=tool_calls (intermediate continuations)\n if (!msgContent.trim() && finishReason === 'tool_calls') return false;\n\n // Skip tool-echo messages like \"Calling update-task\"\n if (msgType === 'chat' && /^Calling\\s+[\\w-]+\\s*$/.test(msgContent.trim())) return false;\n\n return true;\n });\n\n return filteredRows.map((row: any) => {\n const props = row.properties ?? {};\n const message: ChatMessage = {\n role: props.role ?? 'assistant',\n content: props.content\n ?? (typeof props.body === 'string' ? props.body : props.body?.content)\n ?? props.data?.content\n ?? '',\n timestamp: row.created_at ?? new Date().toISOString(),\n id: row.id,\n path: row.path,\n children: childrenByMsg.get(row.path),\n };\n\n if (props.agent) message.agent = props.agent;\n if (props.finish_reason) message.finishReason = props.finish_reason;\n if (typeof props.dispatch_phase === 'string') {\n message.dispatchPhase = props.dispatch_phase as ChatMessage['dispatchPhase'];\n }\n if (typeof props.orchestration_mode === 'string') {\n message.orchestrationMode = props.orchestration_mode as ChatMessage['orchestrationMode'];\n }\n if (typeof props.orchestration_round === 'number') {\n message.orchestrationRound = props.orchestration_round;\n }\n if (props.terminal_reason_internal !== undefined) {\n message.terminalReasonInternal = (props.terminal_reason_internal ?? null) as string | null;\n }\n if (props.sender_id) message.senderId = props.sender_id;\n if (props.sender_display_name) message.senderDisplayName = props.sender_display_name;\n if (props.status) message.status = props.status;\n if (props.message_type) message.messageType = props.message_type;\n if (props.data && typeof props.data === 'object' && !Array.isArray(props.data)) {\n message.data = props.data as Record<string, unknown>;\n }\n\n if (Array.isArray(props.tool_calls) && props.tool_calls.length > 0) {\n message.toolCalls = props.tool_calls.map((tc: any) => ({\n id: tc.id ?? '',\n name: tc.name ?? tc.function?.name ?? '',\n arguments: tc.arguments ?? tc.function?.arguments,\n } satisfies ToolCallRecord));\n }\n\n if (props.tool_call_id) message.toolCallId = props.tool_call_id;\n\n if (Array.isArray(props.children) && props.children.length > 0) {\n const inlineChildren: MessageChild[] = props.children.map((c: any) => ({\n id: c.id ?? '',\n path: c.path,\n type: c.type ?? 'thought',\n content: c.content ?? '',\n toolName: c.tool_name,\n toolInput: c.tool_input,\n status: c.status,\n model: c.model,\n provider: c.provider,\n inputTokens: c.input_tokens,\n outputTokens: c.output_tokens,\n totalTokens: c.total_tokens,\n costUsd: c.cost_usd,\n durationMs: c.duration_ms,\n } satisfies MessageChild));\n message.children = [...(message.children ?? []), ...inlineChildren];\n }\n\n return message;\n });\n }\n\n // ==========================================================================\n // Internal: plan action\n // ==========================================================================\n\n private async invokePlanAction(\n action: 'approve' | 'reject',\n planPath: string,\n feedback: string | undefined,\n options?: PlanActionOptions,\n ): Promise<PlanActionReceipt> {\n const actionId = options?.actionId?.trim() || crypto.randomUUID();\n const payload: Record<string, unknown> = {\n action,\n plan_path: planPath,\n plan_action_id: actionId,\n };\n if (action === 'reject' && feedback?.trim()) {\n payload.feedback = feedback.trim();\n }\n\n const query = await this.sqlQuery(\n `SELECT INVOKE($1, $2::jsonb, $3) AS invoke`,\n ['/lib/raisin/ai/plan-approval-handler', JSON.stringify(payload), 'functions'],\n );\n const row = query?.rows?.[0] as Record<string, unknown> | undefined;\n const invoke = (row?.invoke ?? row?.INVOKE ?? null) as SqlInvokeReceipt | string | null;\n\n let receipt: SqlInvokeReceipt | null = null;\n if (invoke && typeof invoke === 'object') {\n receipt = invoke;\n } else if (typeof invoke === 'string' && invoke.trim()) {\n try { receipt = JSON.parse(invoke) as SqlInvokeReceipt; }\n catch { throw new Error(`Invalid SQL INVOKE receipt payload: ${invoke}`); }\n }\n\n if (!receipt?.job_id || !receipt?.execution_id) {\n throw new Error('Plan action was not accepted by the backend queue');\n }\n\n return {\n accepted: true,\n action,\n actionId,\n planPath,\n executionId: receipt.execution_id,\n jobId: receipt.job_id,\n status: 'scheduled',\n };\n }\n\n // ==========================================================================\n // Internal: HTTP + SQL helpers\n // ==========================================================================\n\n private async httpRequest<T>(options: {\n method: string;\n path: string;\n body?: unknown;\n signal?: AbortSignal;\n timeoutMs?: number;\n }): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\n const token = this.authManager.getAccessToken();\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n const controller = new AbortController();\n const requestTimeout = options.timeoutMs ?? this.requestTimeout;\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n if (options.signal) {\n if (options.signal.aborted) {\n clearTimeout(timeoutId);\n throw new RaisinAbortError();\n }\n options.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n } catch { errorMessage = errorText || `HTTP ${response.status}: ${response.statusText}`; }\n throw classifyHttpError(response.status, errorMessage);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) return (await response.json()) as T;\n return undefined as unknown as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof RaisinAbortError || error instanceof RaisinTimeoutError) throw error;\n if (error instanceof Error && error.name === 'AbortError') {\n if (options.signal?.aborted) throw new RaisinAbortError();\n throw new RaisinTimeoutError(`Request timeout after ${requestTimeout}ms`, 'REQUEST_TIMEOUT', requestTimeout);\n }\n throw error;\n }\n }\n\n private async sqlQuery(sql: string, params?: unknown[]): Promise<SqlQueryResponse> {\n if (this.executeSql) {\n const result = await this.executeSql(sql, params);\n return { columns: result.columns, rows: result.rows as unknown as Record<string, unknown>[] };\n }\n return this.httpRequest<SqlQueryResponse>({\n method: 'POST',\n path: `/api/sql/${this.repository}/query`,\n body: { sql, params },\n });\n }\n\n private async resolveConversationStreamTarget(\n conversationPath: string,\n workspace = 'raisin:access_control',\n ): Promise<{ channel: string; path: string }> {\n try {\n const result = await this.sqlQuery(\n `SELECT properties FROM '${workspace}' WHERE path = $1 AND node_type = 'raisin:Conversation' LIMIT 1`,\n [conversationPath],\n );\n const row = result?.rows?.[0] as Record<string, unknown> | undefined;\n const properties = (row?.properties ?? {}) as Record<string, unknown>;\n const streamChannel = properties.stream_channel;\n if (typeof streamChannel === 'string' && streamChannel.length > 0) {\n return { channel: streamChannel, path: conversationPath };\n }\n const conversationId = typeof properties.conversation_id === 'string'\n ? properties.conversation_id\n : (conversationPath.split('/').pop() || '');\n if (conversationId) return { channel: `chat:${conversationId}`, path: conversationPath };\n } catch (error) {\n logger.debug('Failed to resolve conversation stream channel, deriving from path', error);\n }\n const conversationId = conversationPath.split('/').pop() || conversationPath;\n return { channel: `chat:${conversationId}`, path: conversationPath };\n }\n\n private async loadConversationProperties(\n conversationPath: string,\n workspace = 'raisin:access_control',\n ): Promise<Record<string, unknown> | null> {\n const result = await this.sqlQuery(\n `SELECT properties FROM '${workspace}' WHERE path = $1 AND node_type = 'raisin:Conversation' LIMIT 1`,\n [conversationPath],\n );\n const row = result?.rows?.[0] as Record<string, unknown> | undefined;\n if (!row) return null;\n return (row.properties ?? null) as Record<string, unknown> | null;\n }\n\n private normalizeRecipientId(participant: string): string {\n if (participant.startsWith('agent:')) return participant;\n if (participant.startsWith('/agents/')) {\n const parts = participant.split('/').filter(Boolean);\n if (parts.length >= 2) return `agent:${parts[1]}`;\n }\n return participant;\n }\n\n private normalizeAgentPath(participant: string): string {\n if (participant.startsWith('/agents/')) return participant;\n if (participant.startsWith('agent:')) return `/agents/${participant.slice('agent:'.length)}`;\n return participant;\n }\n\n private async ensureFolderNode(workspace: string, path: string, title: string): Promise<void> {\n await this.sqlQuery(\n `UPSERT INTO '${workspace}' (path, node_type, properties) VALUES ($1, 'raisin:Folder', $2::jsonb)`,\n [path, JSON.stringify({ title })],\n );\n }\n}\n","/**\n * FlowClient for executing and monitoring RaisinDB flows.\n *\n * Provides methods to:\n * - Run a flow by path and receive an instance ID\n * - Stream real-time execution events via SSE\n * - Resume a waiting flow with external data\n * - Respond to human tasks within a flow\n *\n * @example\n * ```typescript\n * import { RaisinHttpClient } from '@raisindb/client';\n * import { FlowClient } from '@raisindb/client/flow-client';\n *\n * const httpClient = new RaisinHttpClient('http://localhost:8081');\n * await httpClient.authenticate({ username: 'admin', password: 'admin' });\n *\n * const flows = new FlowClient(httpClient, 'my-repo');\n *\n * // Start a flow\n * const { instance_id } = await flows.run('/flows/my-flow', { key: 'value' });\n *\n * // Stream events\n * for await (const event of flows.streamEvents(instance_id)) {\n * console.log(event.type, event);\n * if (event.type === 'flow_completed') break;\n * }\n * ```\n */\n\nimport type { AuthManager } from './auth';\nimport type { FlowsApi } from './flows';\nimport type {\n FlowRunResponse,\n FlowExecutionEvent,\n FlowInstanceStatusResponse,\n FlowCompletedEvent,\n FlowFailedEvent,\n} from './types/flow';\nimport { SSEClient, type SSEEvent } from './streaming/sse-client';\nimport {\n classifyHttpError,\n RaisinAbortError,\n RaisinTimeoutError,\n} from './errors';\n\n/** Options for creating a FlowClient */\nexport interface FlowClientOptions {\n /** Request timeout in milliseconds (default: 60000 for long-running flows) */\n requestTimeout?: number;\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n}\n\n/** Result from `runAndWait()` */\nexport interface FlowRunResult {\n /** Flow instance ID */\n instanceId: string;\n /** Terminal status */\n status: 'completed' | 'failed';\n /** Flow output (when completed) */\n output?: unknown;\n /** Error message (when failed) */\n error?: string;\n}\n\n/** Result from `runAndCollect()` */\nexport interface FlowCollectResult {\n /** Flow instance ID */\n instanceId: string;\n /** All collected events */\n events: FlowExecutionEvent[];\n}\n\n/**\n * Minimal interface the FlowClient needs from the HTTP client.\n * This avoids a hard dependency on the full RaisinHttpClient class.\n */\ninterface HttpClientLike {\n /** Get the auth manager for token access */\n getAuthManager(): AuthManager;\n}\n\n/**\n * Client for executing and monitoring RaisinDB flows.\n *\n * Uses the HTTP REST API for flow operations and SSE for real-time event streaming.\n */\nexport class FlowClient {\n private baseUrl: string;\n private repository: string;\n private authManager: AuthManager;\n private fetchImpl: typeof fetch;\n private requestTimeout: number;\n private flowsApi?: FlowsApi;\n\n /**\n * Create a new FlowClient.\n *\n * @param baseUrl - Base HTTP URL of the RaisinDB server (e.g., \"http://localhost:8081\")\n * @param repository - Repository name\n * @param authManager - Auth manager for token access\n * @param options - Additional options\n * @param flowsApi - Optional FlowsApi for WebSocket-based flow operations\n */\n constructor(\n baseUrl: string,\n repository: string,\n authManager: AuthManager,\n options: FlowClientOptions = {},\n flowsApi?: FlowsApi,\n ) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.repository = repository;\n this.authManager = authManager;\n this.fetchImpl = options.fetch ?? fetch;\n this.requestTimeout = options.requestTimeout ?? 60000;\n this.flowsApi = flowsApi;\n }\n\n /**\n * Create a FlowClient from an existing RaisinHttpClient.\n *\n * @param httpClient - An authenticated RaisinHttpClient instance\n * @param baseUrl - Base HTTP URL (same as the one used for the HTTP client)\n * @param repository - Repository name\n * @param options - Additional options\n */\n static fromHttpClient(\n httpClient: HttpClientLike,\n baseUrl: string,\n repository: string,\n options: FlowClientOptions = {},\n flowsApi?: FlowsApi,\n ): FlowClient {\n return new FlowClient(\n baseUrl,\n repository,\n httpClient.getAuthManager(),\n options,\n flowsApi,\n );\n }\n\n // ==========================================================================\n // Flow Execution\n // ==========================================================================\n\n /**\n * Execute a flow by path.\n *\n * Creates a FlowInstance and queues it for execution. Returns immediately\n * with the instance ID - use `streamEvents()` to monitor progress.\n *\n * @param flowPath - Path to the raisin:Flow node (e.g., \"/flows/my-flow\")\n * @param input - Input data passed to the flow\n * @returns Flow run response with instance_id and job_id\n *\n * @example\n * ```typescript\n * const result = await flows.run('/flows/process-order', {\n * orderId: 'ord-123',\n * items: [{ sku: 'ABC', qty: 2 }],\n * });\n * console.log('Instance:', result.instance_id);\n * ```\n */\n async run(\n flowPath: string,\n input: Record<string, unknown> = {},\n options?: { signal?: AbortSignal },\n ): Promise<FlowRunResponse> {\n if (this.flowsApi) {\n return this.flowsApi.run(flowPath, input);\n }\n const response = await this.request<FlowRunResponse>({\n method: 'POST',\n path: `/api/flows/${this.repository}/run`,\n body: { flow_path: flowPath, input },\n signal: options?.signal,\n });\n return response;\n }\n\n // ==========================================================================\n // Instance Status\n // ==========================================================================\n\n /**\n * Get the current status of a flow instance.\n *\n * Returns the instance status, variables, and metadata. Useful for\n * polling-based approaches where SSE is not reliable (e.g., initial\n * flow execution where events may be missed).\n *\n * @param instanceId - Flow instance ID (from `run()`)\n * @returns Instance status including variables and flow path\n *\n * @example\n * ```typescript\n * const status = await flows.getInstanceStatus('instance-123');\n * console.log('Status:', status.status); // 'waiting', 'completed', etc.\n * ```\n */\n async getInstanceStatus(\n instanceId: string,\n options?: { signal?: AbortSignal },\n ): Promise<FlowInstanceStatusResponse> {\n if (this.flowsApi) {\n return this.flowsApi.getInstanceStatus(instanceId);\n }\n return this.request<FlowInstanceStatusResponse>({\n method: 'GET',\n path: `/api/flows/${this.repository}/instances/${instanceId}`,\n signal: options?.signal,\n });\n }\n\n // ==========================================================================\n // Event Streaming (SSE)\n // ==========================================================================\n\n /**\n * Stream real-time execution events for a flow instance via SSE.\n *\n * Returns an async iterable that yields FlowExecutionEvent objects.\n * The stream automatically closes when a terminal event is received\n * (flow_completed or flow_failed).\n *\n * @param instanceId - Flow instance ID (from `run()`)\n * @returns Async iterable of flow execution events\n *\n * @example\n * ```typescript\n * const { instance_id } = await flows.run('/flows/my-flow', { key: 'value' });\n *\n * for await (const event of flows.streamEvents(instance_id)) {\n * switch (event.type) {\n * case 'step_started':\n * console.log(`Step ${event.node_id} started`);\n * break;\n * case 'step_completed':\n * console.log(`Step ${event.node_id} completed in ${event.duration_ms}ms`);\n * break;\n * case 'text_chunk':\n * process.stdout.write(event.text);\n * break;\n * case 'flow_completed':\n * console.log('Flow done:', event.output);\n * break;\n * case 'flow_failed':\n * console.error('Flow failed:', event.error);\n * break;\n * }\n * }\n * ```\n */\n async *streamEvents(\n instanceId: string,\n options?: { signal?: AbortSignal },\n ): AsyncIterable<FlowExecutionEvent> {\n if (this.flowsApi) {\n const sub = await this.flowsApi.subscribeEvents(instanceId);\n try {\n for await (const event of sub.events) {\n if (options?.signal?.aborted) throw new RaisinAbortError();\n yield event;\n if (event.type === 'flow_completed' || event.type === 'flow_failed') {\n return;\n }\n }\n } finally {\n await sub.unsubscribe();\n }\n return;\n }\n const url = `${this.baseUrl}/api/flows/${this.repository}/instances/${instanceId}/events`;\n const headers: Record<string, string> = {};\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const sse = new SSEClient<FlowExecutionEvent>(url, {\n headers,\n eventTypes: ['flow-event', 'message'],\n reconnect: { enabled: false },\n fetch: this.fetchImpl,\n signal: options?.signal,\n });\n\n try {\n for await (const sseEvent of sse) {\n const event = sseEvent.data;\n yield event;\n\n // Stop on terminal events\n if (\n event.type === 'flow_completed' ||\n event.type === 'flow_failed'\n ) {\n return;\n }\n }\n } finally {\n sse.close();\n }\n }\n\n /**\n * Create an eagerly-connected event stream for a flow instance.\n *\n * Unlike `streamEvents()` (a lazy async generator), this method opens the\n * SSE connection immediately and waits until it is established before\n * returning. This is critical for resume flows: you must subscribe to\n * events BEFORE calling `resume()`, otherwise events emitted between\n * the resume and the SSE connection are lost.\n *\n * @param instanceId - Flow instance ID\n * @returns Object with an async iterable `events` and a `close()` method\n */\n async createEventStream(\n instanceId: string,\n options?: { signal?: AbortSignal },\n ): Promise<{\n events: AsyncIterable<FlowExecutionEvent>;\n close: () => void;\n }> {\n if (this.flowsApi) {\n const sub = await this.flowsApi.subscribeEvents(instanceId);\n return {\n events: sub.events,\n close: () => { sub.unsubscribe(); },\n };\n }\n const url = `${this.baseUrl}/api/flows/${this.repository}/instances/${instanceId}/events`;\n const headers: Record<string, string> = {};\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const sse = new SSEClient<FlowExecutionEvent>(url, {\n headers,\n eventTypes: ['flow-event', 'message'],\n reconnect: { enabled: false },\n fetch: this.fetchImpl,\n signal: options?.signal,\n });\n\n // Kick-start the async generator to initiate the SSE connection.\n // Async generators are lazy — the body (which calls startStream)\n // only executes when .next() is called.\n const iterator = sse[Symbol.asyncIterator]();\n let pendingFirst: Promise<IteratorResult<SSEEvent<FlowExecutionEvent>>> | null = iterator.next();\n\n // Now that startStream is running, wait for the HTTP response\n await sse.waitUntilConnected();\n\n // Wrap in a terminal-event-aware iterable\n const events: AsyncIterable<FlowExecutionEvent> = {\n [Symbol.asyncIterator]() {\n return {\n async next() {\n let result;\n if (pendingFirst) {\n result = await pendingFirst;\n pendingFirst = null;\n } else {\n result = await iterator.next();\n }\n if (result.done) return { done: true as const, value: undefined };\n const event = result.value.data;\n return { done: false, value: event };\n },\n async return() {\n await iterator.return?.();\n sse.close();\n return { done: true as const, value: undefined };\n },\n };\n },\n };\n\n return { events, close: () => sse.close() };\n }\n\n // ==========================================================================\n // Flow Resume & Human Task\n // ==========================================================================\n\n /**\n * Resume a flow instance that is in a waiting state.\n *\n * Use this when a flow is waiting for external input (tool results,\n * external events, etc.). The resume data is passed to the waiting step.\n *\n * @param instanceId - Flow instance ID\n * @param data - Resume data to pass to the waiting step\n *\n * @example\n * ```typescript\n * await flows.resume('instance-123', {\n * tool_name: 'get_weather',\n * result: { temperature: 72, conditions: 'sunny' },\n * });\n * ```\n */\n async resume(\n instanceId: string,\n data: unknown,\n options?: { signal?: AbortSignal },\n ): Promise<void> {\n if (this.flowsApi) {\n await this.flowsApi.resume(instanceId, data);\n return;\n }\n await this.request<void>({\n method: 'POST',\n path: `/api/flows/${this.repository}/instances/${instanceId}/resume`,\n body: { resume_data: data },\n signal: options?.signal,\n });\n }\n\n /**\n * Respond to a human task within a flow.\n *\n * When a flow is waiting on a human_task step (approval, input, review),\n * use this method to submit the response. Completion is validated\n * (caller must be the task's assignee or an admin) and resumes the flow.\n *\n * Note: prefer `InboxApi` for full inbox functionality (listing tasks,\n * task details); this is a convenience passthrough to the same endpoint.\n *\n * @param instanceId - Flow instance ID (unused; kept for API stability)\n * @param taskId - The inbox task node ID (or path)\n * @param response - The response data\n *\n * @example\n * ```typescript\n * // Approve a task\n * await flows.respondToHumanTask('instance-123', 'task-abc', {\n * action: 'approve',\n * comment: 'Looks good!',\n * });\n * ```\n */\n async respondToHumanTask(\n _instanceId: string,\n taskId: string,\n response: unknown,\n options?: { signal?: AbortSignal },\n ): Promise<void> {\n await this.request<void>({\n method: 'POST',\n path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}/complete`,\n body: { response },\n signal: options?.signal,\n });\n }\n\n // ==========================================================================\n // Convenience Methods\n // ==========================================================================\n\n /**\n * Run a flow and wait for the final result.\n *\n * Starts the flow, streams all events, and returns the terminal outcome.\n * This is a one-shot helper for fire-and-forget flows where you only\n * care about the final output.\n *\n * @param flowPath - Path to the raisin:Flow node\n * @param input - Input data passed to the flow\n * @param options - Optional abort signal\n * @returns The flow outcome including output or error\n *\n * @example\n * ```typescript\n * const result = await flows.runAndWait('/flows/process-order', { orderId: '123' });\n * if (result.status === 'completed') {\n * console.log('Output:', result.output);\n * }\n * ```\n */\n async runAndWait(\n flowPath: string,\n input: Record<string, unknown> = {},\n options?: { signal?: AbortSignal },\n ): Promise<FlowRunResult> {\n const { instance_id } = await this.run(flowPath, input, options);\n\n for await (const event of this.streamEvents(instance_id, options)) {\n if (event.type === 'flow_completed') {\n return {\n instanceId: instance_id,\n status: 'completed',\n output: (event as FlowCompletedEvent).output,\n };\n }\n if (event.type === 'flow_failed') {\n return {\n instanceId: instance_id,\n status: 'failed',\n error: (event as FlowFailedEvent).error,\n };\n }\n }\n\n return { instanceId: instance_id, status: 'failed', error: 'Stream ended without terminal event' };\n }\n\n /**\n * Run a flow and collect all events into an array.\n *\n * Starts the flow, streams all events, and returns them as a collected array.\n * Useful for testing, logging, or post-processing all flow events.\n *\n * @param flowPath - Path to the raisin:Flow node\n * @param input - Input data passed to the flow\n * @param options - Optional abort signal\n * @returns The instance ID and all collected events\n *\n * @example\n * ```typescript\n * const { events } = await flows.runAndCollect('/flows/etl-pipeline', { source: 'db' });\n * const steps = events.filter(e => e.type === 'step_completed');\n * console.log(`Completed ${steps.length} steps`);\n * ```\n */\n async runAndCollect(\n flowPath: string,\n input: Record<string, unknown> = {},\n options?: { signal?: AbortSignal },\n ): Promise<FlowCollectResult> {\n const { instance_id } = await this.run(flowPath, input, options);\n const events: FlowExecutionEvent[] = [];\n\n for await (const event of this.streamEvents(instance_id, options)) {\n events.push(event);\n }\n\n return { instanceId: instance_id, events };\n }\n\n // ==========================================================================\n // Internal HTTP request helper\n // ==========================================================================\n\n private async request<T>(options: {\n method: string;\n path: string;\n body?: unknown;\n signal?: AbortSignal;\n }): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);\n\n // Forward external signal to our internal controller\n if (options.signal) {\n if (options.signal.aborted) {\n clearTimeout(timeoutId);\n throw new RaisinAbortError();\n }\n options.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n } catch {\n errorMessage =\n errorText || `HTTP ${response.status}: ${response.statusText}`;\n }\n\n throw classifyHttpError(response.status, errorMessage);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return (await response.json()) as T;\n }\n\n return undefined as unknown as T;\n } catch (error) {\n clearTimeout(timeoutId);\n // Re-throw our own errors as-is\n if (error instanceof RaisinAbortError || error instanceof RaisinTimeoutError) {\n throw error;\n }\n if (error instanceof Error && error.name === 'AbortError') {\n // Distinguish external abort from internal timeout\n if (options.signal?.aborted) {\n throw new RaisinAbortError();\n }\n throw new RaisinTimeoutError(\n `Request timeout after ${this.requestTimeout}ms`,\n 'REQUEST_TIMEOUT',\n this.requestTimeout,\n );\n }\n throw error;\n }\n }\n}\n","/**\n * InboxApi for human-in-the-loop tasks.\n *\n * Inbox tasks are the primitive workflows use for approvals, input\n * requests, reviews, and generic actions. A `human_task` step creates a\n * task in the assignee's inbox and pauses the flow; completing the task\n * resumes it. Assignees can be users OR AI agents - agents decide tasks\n * automatically (with escalation back to humans), and both complete tasks\n * through the same API.\n *\n * @example\n * ```typescript\n * const inbox = new InboxApi('http://localhost:8081', 'my-repo', authManager);\n *\n * // List my pending tasks\n * const { tasks } = await inbox.listTasks({ status: 'pending' });\n *\n * // Approve the first one\n * await inbox.completeTask(tasks[0].id, {\n * action: 'approve',\n * comment: 'Looks good!',\n * });\n * ```\n */\n\nimport type { AuthManager } from './auth';\nimport type { InboxTask, TaskCompletionResult } from './types/flow-definition';\nimport {\n classifyHttpError,\n RaisinAbortError,\n RaisinTimeoutError,\n} from './errors';\n\n/** Options for creating an InboxApi */\nexport interface InboxApiOptions {\n /** Request timeout in milliseconds (default: 30000) */\n requestTimeout?: number;\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n}\n\n/** Filters for listing inbox tasks */\nexport interface ListTasksOptions {\n /** Filter by status */\n status?: 'pending' | 'completed' | 'expired' | 'cancelled';\n /** List another principal's inbox (admins only) */\n assignee?: string;\n /** Abort signal */\n signal?: AbortSignal;\n}\n\n/** Response from listing inbox tasks */\nexport interface ListTasksResponse {\n /** The inbox owner the tasks belong to */\n assignee: string;\n /** Number of tasks returned */\n count: number;\n /** The tasks, pending first, then by priority and due time */\n tasks: InboxTask[];\n}\n\n/**\n * Client for the inbox task endpoints.\n */\nexport class InboxApi {\n private baseUrl: string;\n private repository: string;\n private authManager: AuthManager;\n private fetchImpl: typeof fetch;\n private requestTimeout: number;\n\n constructor(\n baseUrl: string,\n repository: string,\n authManager: AuthManager,\n options: InboxApiOptions = {},\n ) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.repository = repository;\n this.authManager = authManager;\n this.fetchImpl = options.fetch ?? fetch;\n this.requestTimeout = options.requestTimeout ?? 30000;\n }\n\n /**\n * List the caller's inbox tasks.\n *\n * Tasks are sorted pending-first, then by priority (highest first) and\n * due time (earliest first).\n */\n async listTasks(options: ListTasksOptions = {}): Promise<ListTasksResponse> {\n const params = new URLSearchParams();\n if (options.status) params.set('status', options.status);\n if (options.assignee) params.set('assignee', options.assignee);\n const query = params.size > 0 ? `?${params.toString()}` : '';\n\n return this.request<ListTasksResponse>({\n method: 'GET',\n path: `/api/inbox/${this.repository}${query}`,\n signal: options.signal,\n });\n }\n\n /**\n * Get a single inbox task by ID (or path).\n */\n async getTask(\n taskId: string,\n options?: { signal?: AbortSignal },\n ): Promise<InboxTask> {\n return this.request<InboxTask>({\n method: 'GET',\n path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}`,\n signal: options?.signal,\n });\n }\n\n /**\n * Complete an inbox task.\n *\n * The caller must be the task's assignee (or an admin). Completion marks\n * the task done, records who decided, and resumes the owning flow.\n *\n * @param taskId - Task node ID (or path)\n * @param response - The response payload:\n * - approval tasks: `{ action: '<option value>', comment?: string }`\n * - input tasks: the input value(s) matching the task's input_schema\n * - review/action tasks: any acknowledgement payload\n *\n * @example\n * ```typescript\n * await inbox.completeTask('task-123', { action: 'approve' });\n * ```\n */\n async completeTask(\n taskId: string,\n response: unknown,\n options?: { signal?: AbortSignal },\n ): Promise<TaskCompletionResult> {\n return this.request<TaskCompletionResult>({\n method: 'POST',\n path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}/complete`,\n body: { response },\n signal: options?.signal,\n });\n }\n\n // ==========================================================================\n // Internal HTTP request helper\n // ==========================================================================\n\n private async request<T>(options: {\n method: string;\n path: string;\n body?: unknown;\n signal?: AbortSignal;\n }): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);\n\n if (options.signal) {\n if (options.signal.aborted) {\n clearTimeout(timeoutId);\n throw new RaisinAbortError();\n }\n options.signal.addEventListener('abort', () => controller.abort(), {\n once: true,\n });\n }\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n } catch {\n errorMessage =\n errorText || `HTTP ${response.status}: ${response.statusText}`;\n }\n throw classifyHttpError(response.status, errorMessage);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return (await response.json()) as T;\n }\n return undefined as unknown as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (\n error instanceof RaisinAbortError ||\n error instanceof RaisinTimeoutError\n ) {\n throw error;\n }\n if (error instanceof Error && error.name === 'AbortError') {\n if (options.signal?.aborted) {\n throw new RaisinAbortError();\n }\n throw new RaisinTimeoutError(\n `Request timeout after ${this.requestTimeout}ms`,\n 'REQUEST_TIMEOUT',\n this.requestTimeout,\n );\n }\n throw error;\n }\n }\n}\n","/**\n * Database/repository interface\n */\n\nimport { WorkspaceClient, WorkspaceManager } from './workspace';\nimport { SqlQuery, createSqlHandler } from './sql';\nimport { EventHandler } from './events';\nimport { RequestContext, SqlQueryPayload, SqlResult } from './protocol';\nimport { NodeTypes } from './node-types';\nimport { Archetypes } from './archetypes';\nimport { ElementTypes } from './element-types';\nimport { Branches } from './branches';\nimport { SchedulerApi } from './scheduler';\nimport { Tags } from './tags';\nimport { FlowsApi } from './flows';\nimport { FunctionsApi } from './functions-api';\nimport { ConversationManager } from './conversations';\nimport { FlowClient } from './flow-client';\nimport { InboxApi } from './inbox';\nimport type { AuthManager } from './auth';\nimport type { UploadManager } from './upload/uploader';\nimport type { SignAssetOptions, SignedAssetUrl } from './http-client';\n\n/**\n * Options for HTTP-based features (chat, flow) on a Database instance.\n * Provided automatically when the Database is created via `RaisinClient.database()`.\n */\nexport interface DatabaseHttpOptions {\n /** HTTP base URL of the RaisinDB server */\n httpBaseUrl?: string;\n /** Auth manager for token access */\n authManager?: AuthManager;\n}\n\n/**\n * Database interface for repository operations\n */\nexport class Database {\n private repository: string;\n private _context: RequestContext;\n private sendRequest: (\n payload: unknown,\n requestType?: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ) => Promise<unknown>;\n private eventHandler: EventHandler;\n private workspaceManager?: WorkspaceManager;\n private sqlQuery?: SqlQuery;\n private sqlHandler?: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<SqlResult>;\n private branch?: string;\n private revision?: string;\n private getUploadManager?: () => UploadManager;\n private getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>;\n private httpOptions?: DatabaseHttpOptions;\n private _flowsApi?: FlowsApi;\n private _functionsApi?: FunctionsApi;\n private _conversationManager?: ConversationManager;\n private _flowClient?: FlowClient;\n private _inboxApi?: InboxApi;\n\n constructor(\n repository: string,\n context: RequestContext,\n sendRequest: (\n payload: unknown,\n requestType: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ) => Promise<unknown>,\n eventHandler: EventHandler,\n branch?: string,\n revision?: string,\n getUploadManager?: () => UploadManager,\n getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>,\n httpOptions?: DatabaseHttpOptions,\n ) {\n this.repository = repository;\n this.branch = branch;\n this.revision = revision;\n this._context = {\n ...context,\n repository,\n branch: branch || context.branch,\n revision: revision || context.revision\n };\n // Wrap sendRequest to use our context by default, but allow override\n this.sendRequest = (\n payload: unknown,\n requestType?: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ) => sendRequest(\n payload,\n requestType || 'node_create',\n contextOverride || this._context,\n requestOptions\n );\n this.eventHandler = eventHandler;\n this.getUploadManager = getUploadManager;\n this.getSignAssetUrl = getSignAssetUrl;\n this.httpOptions = httpOptions;\n }\n\n /**\n * Get the repository name\n */\n getRepository(): string {\n return this.repository;\n }\n\n /**\n * Create a new Database instance scoped to a specific branch.\n *\n * @param branch - Branch name\n * @returns New Database instance with branch context\n */\n onBranch(branch: string): Database {\n return new Database(\n this.repository,\n this._context,\n this.sendRequest,\n this.eventHandler,\n branch,\n this.revision,\n this.getUploadManager,\n this.getSignAssetUrl,\n this.httpOptions,\n );\n }\n\n /**\n * Create a new Database instance scoped to a specific revision/commit.\n *\n * @param revision - Revision/commit ID\n * @returns New Database instance with revision context\n */\n atRevision(revision: string): Database {\n return new Database(\n this.repository,\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.branch,\n revision,\n this.getUploadManager,\n this.getSignAssetUrl,\n this.httpOptions,\n );\n }\n\n /**\n * Get a workspace client\n *\n * @param name - Workspace name\n * @returns Workspace client for operations\n */\n workspace(name: string): WorkspaceClient {\n if (!this.workspaceManager) {\n this.workspaceManager = new WorkspaceManager(\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n return this.workspaceManager.workspace(name);\n }\n\n /**\n * Get workspace management operations\n */\n workspaces(): WorkspaceManager {\n if (!this.workspaceManager) {\n this.workspaceManager = new WorkspaceManager(\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n return this.workspaceManager;\n }\n\n /**\n * Create a new workspace (convenience method)\n *\n * @param name - Workspace name\n * @param description - Workspace description\n * @returns Created workspace\n */\n async createWorkspace(name: string, description?: string): Promise<unknown> {\n return this.workspaces().create({ name, description });\n }\n\n /**\n * List all workspaces (convenience method)\n *\n * @returns Array of workspaces\n */\n async listWorkspaces(): Promise<unknown[]> {\n return this.workspaces().list();\n }\n\n /**\n * Execute SQL query using template literals\n *\n * @param strings - Template literal strings\n * @param values - Template literal values\n * @returns SQL query result\n *\n * @example\n * ```typescript\n * const results = await db.sql`SELECT * FROM nodes WHERE node_type = ${'Page'}`;\n * ```\n */\n async sql(strings: TemplateStringsArray, ...values: unknown[]): Promise<SqlResult> {\n if (!this.sqlHandler) {\n this.sqlHandler = createSqlHandler((payload: SqlQueryPayload) =>\n this.sendRequest(payload, 'sql_query')\n );\n }\n return this.sqlHandler(strings, ...values);\n }\n\n /**\n * Get SQL query builder for more advanced queries\n */\n getSqlQuery(): SqlQuery {\n if (!this.sqlQuery) {\n this.sqlQuery = new SqlQuery((payload: SqlQueryPayload) =>\n this.sendRequest(payload, 'sql_query')\n );\n }\n return this.sqlQuery;\n }\n\n /**\n * Execute a raw SQL query\n *\n * @param query - SQL query string\n * @param params - Query parameters\n * @returns SQL query result\n */\n async executeSql(query: string, params?: unknown[]): Promise<SqlResult> {\n return this.getSqlQuery().execute(query, params);\n }\n\n /**\n * Get NodeTypes management operations\n */\n nodeTypes(): NodeTypes {\n return new NodeTypes(this._context, this.sendRequest);\n }\n\n /**\n * Get Archetypes management operations\n */\n archetypes(): Archetypes {\n return new Archetypes(this._context, this.sendRequest);\n }\n\n /**\n * Get ElementTypes management operations\n */\n elementTypes(): ElementTypes {\n return new ElementTypes(this._context, this.sendRequest);\n }\n\n /**\n * Get Branches management operations\n */\n branches(): Branches {\n return new Branches(this._context, this.sendRequest);\n }\n\n /**\n * Get Tags management operations\n */\n tags(): Tags {\n return new Tags(this._context, this.sendRequest);\n }\n\n /**\n * Get SchedulerApi for one-shot scheduled invocations (time-based\n * function/flow runs).\n */\n scheduler(): SchedulerApi {\n return new SchedulerApi(this._context, this.sendRequest);\n }\n\n /**\n * Get FlowsApi for running flows via WebSocket\n */\n flows(): FlowsApi {\n if (!this._flowsApi) {\n this._flowsApi = new FlowsApi(\n this.repository,\n this._context,\n this.sendRequest,\n this.eventHandler,\n );\n }\n return this._flowsApi;\n }\n\n /**\n * Get FunctionsApi for invoking server-side functions via WebSocket\n */\n functions(): FunctionsApi {\n if (!this._functionsApi) {\n this._functionsApi = new FunctionsApi(\n this.repository,\n this._context,\n this.sendRequest,\n );\n }\n return this._functionsApi;\n }\n\n /**\n * Get a pre-configured ConversationManager for managing conversations.\n *\n * Unified API for conversation lifecycle, messaging, streaming, and\n * plan approval/rejection. Replaces the previous ChatClient and\n * ConversationClient split.\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const convos = await db.conversations.list({ type: 'ai_chat' });\n * const convo = await db.conversations.create({ participant: '/agents/support' });\n * ```\n */\n get conversations(): ConversationManager {\n if (!this._conversationManager) {\n if (!this.httpOptions?.httpBaseUrl || !this.httpOptions?.authManager) {\n throw new Error(\n 'db.conversations requires HTTP context. Use client.database() to get a Database with conversation support.',\n );\n }\n this._conversationManager = new ConversationManager(\n this.httpOptions.httpBaseUrl,\n this.repository,\n this.httpOptions.authManager,\n {},\n (query: string, params?: unknown[]) => this.executeSql(query, params),\n );\n }\n return this._conversationManager;\n }\n\n /**\n * Get a pre-configured FlowClient for executing flows via HTTP/SSE.\n *\n * Requires the Database to have been created via `RaisinClient.database()`\n * (which automatically provides HTTP context). Throws if HTTP context is unavailable.\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const result = await db.flow.runAndWait('/flows/my-flow', { key: 'value' });\n * ```\n */\n get flow(): FlowClient {\n if (!this._flowClient) {\n if (!this.httpOptions?.httpBaseUrl || !this.httpOptions?.authManager) {\n throw new Error(\n 'db.flow requires HTTP context. Use client.database() to get a Database with flow support.',\n );\n }\n this._flowClient = new FlowClient(\n this.httpOptions.httpBaseUrl,\n this.repository,\n this.httpOptions.authManager,\n {},\n this.flows(),\n );\n }\n return this._flowClient;\n }\n\n /**\n * Get a pre-configured InboxApi for human-in-the-loop tasks.\n *\n * Requires the Database to have been created via `RaisinClient.database()`\n * (which automatically provides HTTP context).\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const { tasks } = await db.inbox.listTasks({ status: 'pending' });\n * await db.inbox.completeTask(tasks[0].id, { action: 'approve' });\n * ```\n */\n get inbox(): InboxApi {\n if (!this._inboxApi) {\n if (!this.httpOptions?.httpBaseUrl || !this.httpOptions?.authManager) {\n throw new Error(\n 'db.inbox requires HTTP context. Use client.database() to get a Database with inbox support.',\n );\n }\n this._inboxApi = new InboxApi(\n this.httpOptions.httpBaseUrl,\n this.repository,\n this.httpOptions.authManager,\n );\n }\n return this._inboxApi;\n }\n\n /**\n * Get EventHandler for subscribing to real-time events\n *\n * Path filter semantics for subscriptions (matched server-side):\n * - A plain path matches **only that exact node** — there is no implicit\n * prefix matching.\n * - `*` matches exactly one path segment (`/inbox/*` matches `/inbox/a`,\n * not `/inbox/a/b`).\n * - `**` matches recursively (`/inbox/**` matches all descendants of\n * `/inbox`, but not `/inbox` itself).\n */\n events(): EventHandler {\n return this.eventHandler;\n }\n}\n","/**\n * RaisinDB HTTP client for server-side rendering (SSR)\n *\n * This client uses HTTP REST API instead of WebSocket for initial data fetching\n * during server-side rendering. After client hydration, applications can upgrade\n * to WebSocket mode for real-time updates.\n */\n\nimport { EventEmitter } from 'events';\nimport { AuthManager, Credentials, AdminCredentials, isJwtCredentials, TokenStorage } from './auth';\nimport {\n RequestContext,\n SqlResult,\n Node,\n Workspace,\n NodeCreatePayload,\n WorkspaceCreatePayload,\n WorkspaceUpdatePayload,\n AuthenticatePayload,\n AuthenticateResponse,\n} from './protocol';\nimport {\n HttpFunctionsApi,\n type FunctionInvokeOptions,\n type FunctionInvokeResponse,\n type FunctionInvokeSyncResponse\n} from './functions-api';\nimport type { Upload, UploadOptions, BatchUpload, BatchUploadOptions } from './upload/types';\nimport { createFileSource } from './upload/file-source';\nimport { UploadManager } from './upload/uploader';\nimport { HttpNodeTypes, HttpArchetypes, HttpElementTypes } from './http-schema';\nimport { McpClient, type McpTransport, type McpFrameStream, type McpJsonRpcFrame } from './mcp';\nimport { SSEClient } from './streaming/sse-client';\nimport { IdentityAuthApi, type IdentityAuthResult } from './identity-auth';\n\n/**\n * Current user info\n */\nexport interface CurrentUser {\n /** User ID (identity UUID) */\n userId: string;\n /** Roles assigned to the user */\n roles?: string[];\n /** Whether this is an anonymous user */\n anonymous: boolean;\n /** The full user node from the repository */\n node?: UserNode;\n}\n\n/**\n * User node from the repository\n */\nexport interface UserNode {\n /** Node ID */\n id: string;\n /** Node path (e.g., '/users/internal/john-at-example-com') */\n path: string;\n /** Node name */\n name: string;\n /** Node type (e.g., 'raisin:User') */\n node_type: string;\n /** Node properties */\n properties: Record<string, unknown>;\n}\n\n/**\n * Response from /auth/{repo}/me endpoint\n */\ninterface AuthMeResponse {\n user_id: string;\n user_path: string;\n user_node?: UserNode;\n roles: string[];\n anonymous: boolean;\n}\n\n/**\n * HTTP client options\n */\nexport interface HttpClientOptions {\n /** Token storage (default: in-memory) */\n tokenStorage?: TokenStorage;\n /** Request timeout in milliseconds (default: 30000) */\n requestTimeout?: number;\n /** Tenant ID */\n tenantId?: string;\n /** Default branch (default: \"main\") */\n defaultBranch?: string;\n /** Custom fetch implementation (for testing or custom behavior) */\n fetch?: typeof fetch;\n}\n\n/**\n * HTTP response wrapper\n */\ninterface HttpResponse<T = unknown> {\n data: T;\n status: number;\n headers: Headers;\n}\n\n/**\n * Options for signing an asset URL\n */\nexport interface SignAssetOptions {\n /** Repository name */\n repository: string;\n /** Workspace name */\n workspace: string;\n /** Path to the asset node */\n path: string;\n /** Command type: 'download' forces download, 'display' shows inline */\n command: 'download' | 'display';\n /** Branch (default: context branch or \"main\") */\n branch?: string;\n /** Expiry time in seconds (default: 300) */\n expiresIn?: number;\n /** Property path to access (default: 'file'). Use 'thumbnail' for thumbnail images. */\n propertyPath?: string;\n}\n\n/**\n * Signed URL response\n */\nexport interface SignedAssetUrl {\n /** The signed URL for accessing the asset */\n url: string;\n /** When the URL expires (ISO 8601) */\n expiresAt: string;\n /** @deprecated Use expiresAt instead */\n expires_at?: string;\n}\n\n/**\n * RaisinDB HTTP client for SSR\n */\nexport class RaisinHttpClient extends EventEmitter {\n private baseUrl: string;\n private authManager: AuthManager;\n private _context: RequestContext;\n private options: Required<Omit<HttpClientOptions, 'tokenStorage' | 'fetch'>>;\n private fetchImpl: typeof fetch;\n /** Monotonic JSON-RPC id counter for MCP requests. */\n private _mcpRequestId = 0;\n private _currentUser: CurrentUser | null = null;\n private _uploadManager: UploadManager | null = null;\n\n constructor(baseUrl: string, options: HttpClientOptions = {}) {\n super();\n\n // Remove trailing slash from baseUrl\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n\n this.options = {\n requestTimeout: options.requestTimeout ?? 30000,\n tenantId: options.tenantId ?? 'default',\n defaultBranch: options.defaultBranch ?? 'main',\n };\n\n // Initialize context\n this._context = {\n tenant_id: this.options.tenantId,\n branch: this.options.defaultBranch,\n };\n\n // Initialize auth manager\n this.authManager = new AuthManager(options.tokenStorage);\n\n // Use custom fetch or global fetch\n this.fetchImpl = options.fetch ?? fetch;\n }\n\n /**\n * Authenticate with credentials\n *\n * Supports two authentication modes:\n * - Admin auth: { username: string, password: string }\n * - JWT auth: { type: 'jwt', token: string }\n *\n * @param credentials - User credentials\n */\n async authenticate(credentials: Credentials, repository?: string): Promise<void> {\n if (isJwtCredentials(credentials)) {\n // For HTTP client, JWT auth is typically done via Authorization header\n // Just store the token for future requests\n this.authManager.storage.setAccessToken(credentials.token);\n\n // Fetch user info from /auth/{repo}/me endpoint if repository is provided\n if (repository) {\n try {\n const userInfo = await this.fetchCurrentUser(repository);\n if (userInfo) {\n this._currentUser = userInfo;\n }\n } catch {\n // User info fetch failed, continue without it\n }\n }\n\n // Emit authenticated event\n this.emit('authenticated', { type: 'jwt', token: credentials.token });\n } else {\n // Admin authentication with username/password\n const payload: AuthenticatePayload = AuthManager.createAuthPayload(credentials as AdminCredentials);\n\n // The admin auth endpoint returns { token, user_id, username, ... }\n // (NOT the WebSocket protocol's { access_token, refresh_token }).\n const response = await this.request<\n AuthenticateResponse & { token?: string; user_id?: string; username?: string }\n >({\n method: 'POST',\n path: `/api/raisindb/sys/${this._context.tenant_id}/auth`,\n body: payload,\n skipAuth: true,\n });\n\n if (response.data.token) {\n this.authManager.storage.setAccessToken(response.data.token);\n } else {\n this.authManager.setTokens(response.data);\n }\n\n // Set admin user info\n this._currentUser = {\n userId: response.data.user_id ?? 'admin',\n anonymous: false,\n };\n\n // Emit authenticated event\n this.emit('authenticated', response.data);\n }\n }\n\n /**\n * Execute SQL query\n *\n * @param repository - Repository name\n * @param query - SQL query string\n * @param params - Query parameters\n * @param branch - Optional branch (uses new /api/sql/{repo}/{branch} endpoint)\n * @returns SQL query result\n */\n async executeSql(\n repository: string,\n query: string,\n params?: unknown[],\n branch?: string\n ): Promise<SqlResult> {\n // Note: The HTTP API expects 'sql' field, not 'query'\n const payload = {\n sql: query,\n params: params || [],\n };\n\n // Use branch-specific endpoint if branch is provided\n const path = branch\n ? `/api/sql/${repository}/${branch}`\n : `/api/sql/${repository}`;\n\n const response = await this.request<SqlResult>({\n method: 'POST',\n path,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Get a node by ID\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodeId - Node ID\n * @returns Node data\n */\n async getNode(\n repository: string,\n workspace: string,\n nodeId: string\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n const response = await this.request<Node>({\n method: 'GET',\n path: `/api/repository/${repository}/${branch}/head/${workspace}/$ref/${nodeId}`,\n });\n\n return response.data;\n }\n\n /**\n * Get a node by path\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodePath - Node path (e.g., \"/content/my-page\")\n * @returns Node data\n */\n async getNodeByPath(\n repository: string,\n workspace: string,\n nodePath: string\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n // Ensure path starts with /\n const path = nodePath.startsWith('/') ? nodePath : `/${nodePath}`;\n\n const response = await this.request<Node>({\n method: 'GET',\n path: `/api/repository/${repository}/${branch}/head/${workspace}${path}`,\n });\n\n return response.data;\n }\n\n /**\n * Create a new node\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param payload - Node creation payload\n * @returns Created node\n */\n async createNode(\n repository: string,\n workspace: string,\n payload: NodeCreatePayload\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n const response = await this.request<Node>({\n method: 'POST',\n path: `/api/repository/${repository}/${branch}/head/${workspace}/`,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Update a node\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodeId - Node ID\n * @param properties - Properties to update\n * @returns Updated node\n */\n async updateNode(\n repository: string,\n workspace: string,\n nodeId: string,\n properties: Record<string, unknown>\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n // First get the node to get its path\n const node = await this.getNode(repository, workspace, nodeId);\n\n const response = await this.request<Node>({\n method: 'PUT',\n path: `/api/repository/${repository}/${branch}/head/${workspace}${node.path}`,\n body: { properties },\n });\n\n return response.data;\n }\n\n /**\n * Delete a node\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodeId - Node ID\n */\n async deleteNode(\n repository: string,\n workspace: string,\n nodeId: string\n ): Promise<void> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n // First get the node to get its path\n const node = await this.getNode(repository, workspace, nodeId);\n\n await this.request<void>({\n method: 'DELETE',\n path: `/api/repository/${repository}/${branch}/head/${workspace}${node.path}`,\n });\n }\n\n /**\n * List workspaces\n *\n * @param repository - Repository name\n * @returns Array of workspaces\n */\n async listWorkspaces(repository: string): Promise<Workspace[]> {\n const response = await this.request<Workspace[]>({\n method: 'GET',\n path: `/api/workspaces/${repository}`,\n });\n\n return response.data;\n }\n\n /**\n * Get a workspace\n *\n * @param repository - Repository name\n * @param name - Workspace name\n * @returns Workspace data\n */\n async getWorkspace(repository: string, name: string): Promise<Workspace> {\n const response = await this.request<Workspace>({\n method: 'GET',\n path: `/api/workspaces/${repository}/${name}`,\n });\n\n return response.data;\n }\n\n /**\n * Create a workspace\n *\n * @param repository - Repository name\n * @param payload - Workspace creation payload\n * @returns Created workspace\n */\n async createWorkspace(\n repository: string,\n payload: WorkspaceCreatePayload\n ): Promise<Workspace> {\n const response = await this.request<Workspace>({\n method: 'POST',\n path: `/api/workspaces/${repository}`,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Update a workspace\n *\n * @param repository - Repository name\n * @param name - Workspace name\n * @param payload - Workspace update payload\n * @returns Updated workspace\n */\n async updateWorkspace(\n repository: string,\n name: string,\n payload: WorkspaceUpdatePayload\n ): Promise<Workspace> {\n const response = await this.request<Workspace>({\n method: 'PUT',\n path: `/api/workspaces/${repository}/${name}`,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Delete a workspace\n *\n * @param repository - Repository name\n * @param name - Workspace name\n */\n async deleteWorkspace(repository: string, name: string): Promise<void> {\n await this.request<void>({\n method: 'DELETE',\n path: `/api/workspaces/${repository}/${name}`,\n });\n }\n\n /**\n * Create a new repository\n *\n * @param repositoryId - Repository identifier\n * @param description - Repository description\n * @param config - Repository configuration\n * @returns Repository creation result\n */\n async createRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'POST',\n path: '/api/repositories',\n body: {\n repository_id: repositoryId,\n description,\n config,\n },\n });\n\n return response.data;\n }\n\n /**\n * Get a repository by ID\n *\n * @param repositoryId - Repository identifier\n * @returns Repository information\n */\n async getRepository(repositoryId: string): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'GET',\n path: `/api/repositories/${repositoryId}`,\n });\n\n return response.data;\n }\n\n /**\n * List all repositories\n *\n * @returns Array of repository information\n */\n async listRepositories(): Promise<unknown[]> {\n const response = await this.request<unknown[]>({\n method: 'GET',\n path: '/api/repositories',\n });\n\n return response.data;\n }\n\n /**\n * Update a repository\n *\n * @param repositoryId - Repository identifier\n * @param description - New repository description\n * @param config - New repository configuration\n * @returns Repository update result\n */\n async updateRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'PUT',\n path: `/api/repositories/${repositoryId}`,\n body: {\n description,\n config,\n },\n });\n\n return response.data;\n }\n\n /**\n * Delete a repository\n *\n * @param repositoryId - Repository identifier\n * @returns Repository deletion result\n */\n async deleteRepository(repositoryId: string): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'DELETE',\n path: `/api/repositories/${repositoryId}`,\n });\n\n return response.data;\n }\n\n /**\n * Set branch for subsequent requests\n *\n * @param branch - Branch name\n */\n setBranch(branch: string): void {\n this._context.branch = branch;\n }\n\n /**\n * Get current branch\n */\n getBranch(): string {\n return this._context.branch ?? this.options.defaultBranch;\n }\n\n /**\n * Get current tenant ID\n */\n getTenantId(): string {\n return this._context.tenant_id;\n }\n\n /**\n * Check if authenticated\n */\n isAuthenticated(): boolean {\n return this.authManager.isAuthenticated();\n }\n\n /**\n * Get current user info\n *\n * Returns the current authenticated user's information including\n * their ID, node in the repository, and roles.\n *\n * @returns Current user info or null if not authenticated\n */\n getCurrentUser(): CurrentUser | null {\n return this._currentUser;\n }\n\n /**\n * Get current user ID\n *\n * @returns User ID or null if not authenticated\n */\n getCurrentUserId(): string | null {\n return this._currentUser?.userId ?? null;\n }\n\n /**\n * Get current user's node path in the repository\n *\n * @returns User's node path (e.g., '/users/internal/john-at-example-com') or null\n */\n getCurrentUserPath(): string | null {\n return this._currentUser?.node?.path ?? null;\n }\n\n /**\n * Fetch current user info from /auth/{repo}/me endpoint\n *\n * @param repository - Repository name\n * @returns Current user info or null if fetch fails\n */\n async fetchCurrentUser(repository: string): Promise<CurrentUser | null> {\n try {\n const response = await this.request<AuthMeResponse>({\n method: 'GET',\n path: `/auth/${repository}/me`,\n });\n\n return {\n userId: response.data.user_id,\n roles: response.data.roles,\n anonymous: response.data.anonymous,\n node: response.data.user_node,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Get auth manager (for token access)\n */\n getAuthManager(): AuthManager {\n return this.authManager;\n }\n\n // ============================================================================\n // Identity Authentication\n // ============================================================================\n\n /**\n * Identity authentication (magic link, password, providers) for one\n * repository.\n *\n * Identities are per repository — their home nodes and roles live there — so\n * the repository is required rather than inferred from client state, which\n * would silently sign somebody into whichever one happened to be current.\n *\n * ```ts\n * const auth = client.auth('studio');\n * await auth.sendMagicLink('a@example.com', {\n * redirectUrl: 'https://app.example.com/account/callback',\n * });\n * // …on the callback route:\n * const tokens = readTokensFromFragment(window.location.hash);\n * if (tokens) client.setIdentityTokens(tokens.accessToken, tokens.refreshToken);\n * ```\n */\n auth(repository: string): IdentityAuthApi {\n return new IdentityAuthApi(repository, async (options) => {\n const response = await this.request({\n method: options.method,\n path: options.path,\n body: options.body,\n skipAuth: options.skipAuth,\n });\n return response.data as never;\n });\n }\n\n /**\n * Adopt an identity's tokens for every subsequent call on this client.\n *\n * Takes the loose form so it serves both callers: the whole result of a\n * sign-in, and the pair recovered from a redirect fragment (which carries no\n * identity object and may carry no refresh token).\n */\n setIdentityTokens(\n accessTokenOrResult: string | IdentityAuthResult,\n refreshToken?: string | null,\n ): void {\n if (typeof accessTokenOrResult === 'string') {\n this.authManager.storage.setAccessToken(accessTokenOrResult);\n if (refreshToken) this.authManager.storage.setRefreshToken(refreshToken);\n return;\n }\n const result = accessTokenOrResult;\n this.authManager.setTokens({\n access_token: result.access_token,\n refresh_token: result.refresh_token,\n // The server reports an absolute expiry; AuthManager schedules from a\n // duration. Deriving it here keeps the refresh timer honest instead of\n // leaving it unset, which reads as \"never expires\".\n expires_in: Math.max(0, result.expires_at - Math.floor(Date.now() / 1000)),\n } as AuthenticateResponse);\n }\n\n /** Forget the current identity's tokens. */\n clearIdentityTokens(): void {\n this.authManager.clear();\n }\n\n // ============================================================================\n // Upload Methods\n // ============================================================================\n\n /**\n * Get or create the upload manager\n */\n private getUploadManager(): UploadManager {\n if (!this._uploadManager) {\n this._uploadManager = new UploadManager({\n baseUrl: this.baseUrl,\n authManager: this.authManager,\n fetchImpl: this.fetchImpl,\n requestTimeout: this.options.requestTimeout,\n });\n }\n return this._uploadManager;\n }\n\n /**\n * Create a resumable upload from a File or Blob (Browser)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support.\n *\n * @param file - File or Blob to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const file = document.querySelector('input').files[0];\n * const upload = await client.upload(file, {\n * repository: 'media',\n * workspace: 'assets',\n * path: '/videos/my-video.mp4',\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * const result = await upload.start();\n * ```\n */\n async upload(file: File | Blob, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(file);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Create a resumable upload from a file path (Node.js)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support.\n *\n * @param filePath - Path to the file to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const upload = await client.uploadFile('/path/to/file.zip', {\n * repository: 'data',\n * workspace: 'backups',\n * path: '/backup.zip'\n * });\n * await upload.start();\n * ```\n */\n async uploadFile(filePath: string, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(filePath);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Resume an existing upload by ID\n *\n * Note: This requires the upload session to still be valid on the server.\n * Sessions typically expire after 24 hours.\n *\n * @param uploadId - ID of the upload to resume\n * @returns Upload controller\n */\n getUpload(uploadId: string): Upload | undefined {\n const manager = this.getUploadManager();\n return manager.getUpload(uploadId);\n }\n\n /**\n * Get all active uploads\n *\n * @returns Array of active upload controllers\n */\n getActiveUploads(): Upload[] {\n const manager = this.getUploadManager();\n return manager.getActiveUploads();\n }\n\n /**\n * Cancel all active uploads\n */\n async cancelAllUploads(): Promise<void> {\n const manager = this.getUploadManager();\n await manager.cancelAll();\n }\n\n // ============================================================================\n // Asset Signed URL Methods\n // ============================================================================\n\n /**\n * Get a signed URL for accessing an asset's binary content.\n *\n * Server validates user access before generating URL. The returned URL\n * can be used without authentication (signature provides access).\n *\n * @param options - Sign URL options\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const { url, expiresAt } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/image.jpeg',\n * command: 'display',\n * });\n *\n * // Use in <img> tag\n * document.querySelector('img').src = url;\n *\n * // Or force download\n * const { url: downloadUrl } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/document.pdf',\n * command: 'download',\n * });\n * ```\n */\n async signAssetUrl(options: SignAssetOptions): Promise<SignedAssetUrl> {\n const branch = options.branch ?? this._context.branch ?? 'main';\n // Add @propertyPath suffix if specified (for thumbnails, etc.)\n // Only add suffix when propertyPath is provided - maintains backward compatibility\n const pathWithProperty = options.propertyPath\n ? `${options.path}@${options.propertyPath}`\n : options.path;\n const endpoint = `/api/repository/${options.repository}/${branch}/head/${options.workspace}${pathWithProperty}/raisin:sign`;\n\n const response = await this.request<SignedAssetUrl>({\n method: 'POST',\n path: endpoint,\n body: {\n command: options.command,\n expires_in: options.expiresIn ?? 300,\n },\n });\n\n return {\n url: `${this.baseUrl}${response.data.url}`,\n expiresAt: response.data.expiresAt ?? response.data.expires_at,\n };\n }\n\n /**\n * Upload multiple files as a batch\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param options - Batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await client.uploadFiles(files, {\n * repository: 'media',\n * workspace: 'assets',\n * basePath: '/uploads',\n * concurrency: 3,\n * onProgress: (p) => {\n * console.log(`${p.filesCompleted}/${p.filesTotal} files`);\n * console.log(`${Math.round(p.progress * 100)}% complete`);\n * },\n * onFileComplete: (file, result) => console.log(`Uploaded: ${file}`),\n * onFileError: (file, err) => console.error(`Failed: ${file}`, err),\n * });\n *\n * const result = await batch.start();\n * console.log(`Success: ${result.successful.length}, Failed: ${result.failed.length}`);\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n options: BatchUploadOptions\n ): Promise<BatchUpload> {\n const sources = await Promise.all(\n Array.from(files).map((f) => createFileSource(f))\n );\n const manager = this.getUploadManager();\n return manager.createBatchUpload(sources, options);\n }\n\n /**\n * Make an HTTP request\n *\n * @param options - Request options\n * @returns HTTP response\n */\n private async request<T = unknown>(options: {\n method: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n skipAuth?: boolean;\n timeoutMs?: number;\n }): Promise<HttpResponse<T>> {\n const url = `${this.baseUrl}${options.path}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n\n // Send the token whenever we hold one.\n //\n // Deliberately NOT gated on `isAuthenticated()`. That asks whether the\n // token is known to be unexpired, and an expiry we never learned reads as\n // expired — so a client given a bare token (`authenticate({type:'jwt'})`,\n // `setIdentityTokens(token)`) sent no Authorization header at all and every\n // call ran anonymously. It failed silently, because an anonymous read\n // returns an empty result rather than a 401.\n //\n // The server is the authority on whether a token is still good. Withholding\n // it locally turns a 401 the caller could act on into a wrong answer.\n if (!options.skipAuth) {\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n }\n\n // Create AbortController for timeout\n const controller = new AbortController();\n const requestTimeout = options.timeoutMs ?? this.options.requestTimeout;\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Handle error responses\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n let errorCode: string = response.statusText;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n errorCode = errorJson.code || errorCode;\n } catch {\n errorMessage = errorText || `HTTP ${response.status}: ${response.statusText}`;\n }\n\n const error = new Error(errorMessage);\n (error as any).code = errorCode;\n (error as any).status = response.status;\n throw error;\n }\n\n // Parse response\n const contentType = response.headers.get('content-type');\n let data: T;\n\n if (contentType?.includes('application/json')) {\n data = await response.json();\n } else {\n data = (await response.text()) as unknown as T;\n }\n\n return {\n data,\n status: response.status,\n headers: response.headers,\n };\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new Error(`Request timeout after ${requestTimeout}ms`);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Invoke a server-side function by name.\n *\n * Calls `POST /api/functions/{repo}/{name}/invoke`.\n *\n * @param repository - Repository name\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution ID and job ID for tracking\n */\n async invokeFunction(\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ): Promise<FunctionInvokeResponse> {\n const requestTimeoutMs = options?.requestTimeoutMs ?? this.options.requestTimeout;\n let waitTimeoutMs = options?.waitTimeoutMs;\n if (options?.waitForResult) {\n waitTimeoutMs = Math.min(waitTimeoutMs ?? requestTimeoutMs, requestTimeoutMs);\n }\n\n const response = await this.request<FunctionInvokeResponse>({\n method: 'POST',\n path: `/api/functions/${repository}/${functionName}/invoke`,\n body: {\n input: input ?? {},\n wait_for_completion: options?.waitForResult ?? false,\n wait_timeout_ms: waitTimeoutMs\n },\n timeoutMs: requestTimeoutMs,\n });\n return response.data;\n }\n\n /**\n * Invoke a server-side function synchronously.\n *\n * Calls `POST /api/functions/{repo}/{name}/invoke` with `sync: true`.\n * The function executes inline and the result is returned directly.\n *\n * @param repository - Repository name\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution result including output, logs, and duration\n */\n async invokeFunctionSync(\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n ): Promise<FunctionInvokeSyncResponse> {\n const response = await this.request<FunctionInvokeSyncResponse>({\n method: 'POST',\n path: `/api/functions/${repository}/${functionName}/invoke`,\n body: { input: input ?? {}, sync: true },\n });\n return response.data;\n }\n\n /**\n * Send one JSON-RPC request to an MCP server endpoint and return its\n * unwrapped `result`.\n *\n * Calls `POST /mcp/{repo}/{branch}/{slug}` carrying a single JSON-RPC 2.0\n * message. MCP errors are returned in the JSON-RPC envelope (HTTP `200`), so\n * this method inspects the body's `error` member and throws on failure.\n *\n * @internal Used by {@link McpClient} via the transport built in `mcp()`.\n */\n async mcpRpc(\n repository: string,\n branch: string,\n slug: string,\n method: string,\n params?: unknown,\n ): Promise<unknown> {\n const id = ++this._mcpRequestId;\n const response = await this.request<McpJsonRpcFrame>({\n method: 'POST',\n path: `/mcp/${repository}/${branch}/${slug}`,\n body: {\n jsonrpc: '2.0',\n id,\n method,\n ...(params !== undefined ? { params } : {}),\n },\n });\n const frame = response.data;\n if (frame?.error) {\n const err = new Error(frame.error.message || `MCP error ${frame.error.code}`);\n (err as any).code = frame.error.code;\n (err as any).data = frame.error.data;\n throw err;\n }\n return frame?.result;\n }\n\n /**\n * Open the `resources/subscribe` SSE stream for an MCP server endpoint.\n *\n * Streams JSON-RPC frames (the subscription ack followed by\n * `notifications/resources/updated` frames) from\n * `POST /mcp/{repo}/{branch}/{slug}`.\n *\n * @internal Used by {@link McpClient} via the transport built in `mcp()`.\n */\n mcpSubscribe(\n repository: string,\n branch: string,\n slug: string,\n method: string,\n params: unknown,\n ): McpFrameStream {\n const headers: Record<string, string> = {};\n // Same rule as `request()`: hold a token, send it. Gating on\n // `isAuthenticated()` dropped it whenever the expiry was unknown, which\n // opened the stream anonymously.\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n const sse = new SSEClient<McpJsonRpcFrame>(\n `${this.baseUrl}/mcp/${repository}/${branch}/${slug}`,\n {\n method: 'POST',\n body: {\n jsonrpc: '2.0',\n id: ++this._mcpRequestId,\n method,\n params,\n },\n headers,\n fetch: this.fetchImpl,\n reconnect: { enabled: false },\n },\n );\n return {\n close: () => sse.close(),\n async *[Symbol.asyncIterator](): AsyncIterator<McpJsonRpcFrame> {\n for await (const event of sse) {\n yield event.data;\n }\n },\n };\n }\n\n /**\n * Get an {@link McpClient} for a content-declared MCP server.\n *\n * @param slug - The `raisin:McpServer` slug (resolved in the `mcp` workspace).\n * @param branch - Branch to address; defaults to the client's current branch.\n */\n mcp(slug: string, branch?: string): McpClient {\n const repository = this._context.repository;\n if (!repository) {\n throw new Error('mcp() requires a repository; call database(name) first');\n }\n const effectiveBranch = branch ?? this.getBranch();\n const transport: McpTransport = {\n rpc: (m, p) => this.mcpRpc(repository, effectiveBranch, slug, m, p),\n subscribe: (m, p) => this.mcpSubscribe(repository, effectiveBranch, slug, m, p),\n };\n return new McpClient(transport);\n }\n\n /**\n * Make a management REST request and return the parsed body.\n *\n * @internal Used by the HTTP schema-management helpers\n * ({@link HttpNodeTypes}/{@link HttpArchetypes}/{@link HttpElementTypes}) to\n * reuse the client's centralized auth, timeout, and base-URL handling.\n */\n async managementRequest<T = unknown>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const response = await this.request<T>({ method, path, body });\n return response.data;\n }\n\n /**\n * Get a simplified database interface for SSR\n * This returns an HTTP-based database client\n */\n database(name: string): HttpDatabase {\n this._context.repository = name;\n return new HttpDatabase(name, this);\n }\n}\n\n/**\n * HTTP-based database interface for SSR\n */\nexport class HttpDatabase {\n private branch?: string;\n\n constructor(\n private repository: string,\n private client: RaisinHttpClient,\n branch?: string\n ) {\n this.branch = branch;\n }\n\n /**\n * Get the repository name\n */\n getRepository(): string {\n return this.repository;\n }\n\n /**\n * Get the current branch (if set)\n */\n getBranch(): string | undefined {\n return this.branch;\n }\n\n /**\n * Create a new HttpDatabase instance scoped to a specific branch.\n *\n * @param branch - Branch name\n * @returns New HttpDatabase instance with branch context\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const staging = db.onBranch('staging');\n * const result = await staging.executeSql('SELECT * FROM content');\n * ```\n */\n onBranch(branch: string): HttpDatabase {\n return new HttpDatabase(this.repository, this.client, branch);\n }\n\n /**\n * Execute SQL query\n *\n * @param query - SQL query string\n * @param params - Query parameters\n * @returns SQL query result\n */\n async executeSql(query: string, params?: unknown[]): Promise<SqlResult> {\n return this.client.executeSql(this.repository, query, params, this.branch);\n }\n\n /**\n * Get workspace client\n */\n workspace(name: string): HttpWorkspaceClient {\n return new HttpWorkspaceClient(this.repository, name, this.client);\n }\n\n /**\n * List workspaces\n */\n async listWorkspaces(): Promise<Workspace[]> {\n return this.client.listWorkspaces(this.repository);\n }\n\n /**\n * Get a workspace\n */\n async getWorkspace(name: string): Promise<Workspace> {\n return this.client.getWorkspace(this.repository, name);\n }\n\n /**\n * Create a workspace\n */\n async createWorkspace(name: string, description?: string): Promise<Workspace> {\n return this.client.createWorkspace(this.repository, { name, description });\n }\n\n /**\n * Get FunctionsApi for invoking server-side functions via HTTP\n */\n functions(): HttpFunctionsApi {\n return new HttpFunctionsApi(\n this.repository,\n (repo, name, input, options) => this.client.invokeFunction(repo, name, input, options),\n (repo, name, input) => this.client.invokeFunctionSync(repo, name, input),\n );\n }\n\n /**\n * Get an {@link McpClient} for a content-declared MCP server on this database.\n *\n * @param slug - The `raisin:McpServer` slug (resolved in the `mcp` workspace).\n * @returns A client scoped to `{repo}/{branch}/{slug}`, using this database's\n * branch (falling back to the HTTP client's current branch).\n */\n mcp(slug: string): McpClient {\n const transport: McpTransport = {\n rpc: (m, p) =>\n this.client.mcpRpc(this.repository, this.schemaBranch(), slug, m, p),\n subscribe: (m, p) =>\n this.client.mcpSubscribe(this.repository, this.schemaBranch(), slug, m, p),\n };\n return new McpClient(transport);\n }\n\n /** Effective branch for management calls. */\n private schemaBranch(): string {\n return this.branch ?? this.client.getBranch();\n }\n\n /** NodeType management (get/list/getResolved/create/update/delete/publish/unpublish). */\n nodeTypes(): HttpNodeTypes {\n return new HttpNodeTypes(this.repository, this.schemaBranch(), this.client);\n }\n\n /** Archetype management (get/list/getResolved/create/update/delete/publish/unpublish). */\n archetypes(): HttpArchetypes {\n return new HttpArchetypes(this.repository, this.schemaBranch(), this.client);\n }\n\n /** ElementType management (get/list/getResolved/create/update/delete/publish/unpublish). */\n elementTypes(): HttpElementTypes {\n return new HttpElementTypes(this.repository, this.schemaBranch(), this.client);\n }\n}\n\n/**\n * HTTP-based workspace client for SSR\n */\nexport class HttpWorkspaceClient {\n constructor(\n private repository: string,\n private workspace: string,\n private client: RaisinHttpClient\n ) {}\n\n /**\n * Get workspace name\n */\n getWorkspace(): string {\n return this.workspace;\n }\n\n /**\n * Get a node by ID\n */\n async getNode(nodeId: string): Promise<Node> {\n return this.client.getNode(this.repository, this.workspace, nodeId);\n }\n\n /**\n * Get a node by path\n */\n async getNodeByPath(nodePath: string): Promise<Node> {\n return this.client.getNodeByPath(this.repository, this.workspace, nodePath);\n }\n\n /**\n * Create a node\n */\n async createNode(payload: NodeCreatePayload): Promise<Node> {\n return this.client.createNode(this.repository, this.workspace, payload);\n }\n\n /**\n * Update a node\n */\n async updateNode(nodeId: string, properties: Record<string, unknown>): Promise<Node> {\n return this.client.updateNode(this.repository, this.workspace, nodeId, properties);\n }\n\n /**\n * Delete a node\n */\n async deleteNode(nodeId: string): Promise<void> {\n return this.client.deleteNode(this.repository, this.workspace, nodeId);\n }\n\n /**\n * Create a resumable upload for this workspace (Browser)\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param file - File or Blob to upload\n * @param path - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const upload = await ws.upload(file, '/videos/my-video.mp4', {\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * await upload.start();\n * ```\n */\n async upload(\n file: File | Blob,\n path: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n return this.client.upload(file, {\n ...options,\n repository: this.repository,\n workspace: this.workspace,\n path,\n });\n }\n\n /**\n * Create a resumable upload for this workspace (Node.js)\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param filePath - Path to the file to upload\n * @param nodePath - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('data').workspace('backups');\n * const upload = await ws.uploadFile('/path/to/backup.zip', '/backup.zip');\n * await upload.start();\n * ```\n */\n async uploadFile(\n filePath: string,\n nodePath: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n return this.client.uploadFile(filePath, {\n ...options,\n repository: this.repository,\n workspace: this.workspace,\n path: nodePath,\n });\n }\n\n /**\n * Upload multiple files to this workspace\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param basePath - Base path for all uploads (files go to basePath/filename)\n * @param options - Additional batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await ws.uploadFiles(files, '/uploads', {\n * concurrency: 3,\n * onProgress: (p) => console.log(`${p.filesCompleted}/${p.filesTotal}`),\n * });\n * const result = await batch.start();\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n basePath: string,\n options?: Partial<Omit<BatchUploadOptions, 'repository' | 'workspace' | 'basePath'>>\n ): Promise<BatchUpload> {\n return this.client.uploadFiles(files, {\n ...options,\n repository: this.repository,\n workspace: this.workspace,\n basePath,\n });\n }\n\n /**\n * Get a signed URL for an asset in this workspace\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param path - Path to the asset node\n * @param command - 'download' (forces download) or 'display' (shows inline)\n * @param options - Optional settings: expiresIn (seconds), propertyPath (e.g., 'thumbnail')\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const { url } = await ws.signAssetUrl('/files/image.jpeg', 'display');\n * document.querySelector('img').src = url;\n *\n * // Get thumbnail instead of main file\n * const { url: thumbUrl } = await ws.signAssetUrl('/files/image.jpeg', 'display', { propertyPath: 'thumbnail' });\n * ```\n */\n async signAssetUrl(\n path: string,\n command: 'download' | 'display' = 'display',\n options?: { expiresIn?: number; propertyPath?: string }\n ): Promise<SignedAssetUrl> {\n return this.client.signAssetUrl({\n repository: this.repository,\n workspace: this.workspace,\n path,\n command,\n expiresIn: options?.expiresIn,\n propertyPath: options?.propertyPath,\n });\n }\n}\n","/**\n * Upload type definitions for resumable chunked uploads\n *\n * This module defines types for the resumable upload system supporting\n * files up to 10GB+ with progress tracking, pause/resume, and auto-retry.\n */\n\nimport type { Node } from '../protocol';\n\n// ============================================================================\n// Upload Status\n// ============================================================================\n\n/**\n * Possible states of an upload\n */\nexport type UploadStatus =\n | 'pending'\n | 'uploading'\n | 'paused'\n | 'completing'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\n// ============================================================================\n// Upload Options\n// ============================================================================\n\n/**\n * Options for creating a resumable upload\n */\nexport interface UploadOptions {\n /** Repository to upload to */\n repository: string;\n /** Branch name (default: \"main\") */\n branch?: string;\n /** Workspace to store the node */\n workspace: string;\n /** Path for the new node */\n path: string;\n /** Node type (default: \"raisin:Asset\") */\n nodeType?: string;\n /** Additional metadata for the node */\n metadata?: Record<string, unknown>;\n /** Chunk size in bytes (default: 10MB) */\n chunkSize?: number;\n /** Progress callback */\n onProgress?: (progress: UploadProgress) => void;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n /** Commit message for the upload */\n commitMessage?: string;\n /** Actor/user identifier for the commit */\n commitActor?: string;\n /** Enable automatic retry on retryable errors (default: true) */\n autoRetry?: boolean;\n /** Maximum number of retry attempts (default: 3) */\n maxRetries?: number;\n}\n\n// ============================================================================\n// Upload Progress\n// ============================================================================\n\n/**\n * Progress information for an upload\n */\nexport interface UploadProgress {\n /** Bytes uploaded so far */\n bytesUploaded: number;\n /** Total bytes to upload */\n bytesTotal: number;\n /** Progress as a fraction (0-1) */\n progress: number;\n /** Current upload speed in bytes/second */\n speed: number;\n /** Estimated time remaining in seconds */\n eta: number;\n /** Current chunk being uploaded (1-indexed) */\n currentChunk: number;\n /** Total number of chunks */\n totalChunks: number;\n /** Current upload status */\n status: UploadStatus;\n}\n\n// ============================================================================\n// Upload Result\n// ============================================================================\n\n/**\n * Result of a completed upload\n */\nexport interface UploadResult {\n /** The created node */\n node: Node;\n /** Revision/commit ID */\n revision?: string;\n /** Storage key for the binary content */\n storageKey: string;\n}\n\n// ============================================================================\n// Upload Interface\n// ============================================================================\n\n/**\n * Interface for controlling an upload\n */\nexport interface Upload {\n /** Unique upload ID */\n id: string;\n /** Start or resume the upload */\n start(): Promise<UploadResult>;\n /** Pause the upload */\n pause(): void;\n /** Resume a paused upload */\n resume(): Promise<UploadResult>;\n /** Cancel the upload */\n cancel(): Promise<void>;\n /** Get current progress */\n getProgress(): UploadProgress;\n /** Check if the upload is currently active */\n isActive(): boolean;\n}\n\n// ============================================================================\n// API Request/Response Types\n// ============================================================================\n\n/**\n * Request payload for creating an upload session\n */\nexport interface CreateUploadRequest {\n /** Repository name */\n repository: string;\n /** Branch name */\n branch: string;\n /** Workspace name */\n workspace: string;\n /** Node path */\n path: string;\n /** Original filename */\n filename: string;\n /** Total file size in bytes */\n file_size: number;\n /** Content MIME type */\n content_type?: string;\n /** Node type for the created node */\n node_type?: string;\n /** Chunk size in bytes */\n chunk_size?: number;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Response from creating an upload session\n */\nexport interface CreateUploadResponse {\n /** Unique upload session ID */\n upload_id: string;\n /** URL for uploading chunks */\n upload_url: string;\n /** Chunk size determined by server */\n chunk_size: number;\n /** Total number of chunks expected */\n total_chunks: number;\n /** Session expiration time */\n expires_at: string;\n}\n\n/**\n * Response from uploading a chunk\n */\nexport interface ChunkUploadResponse {\n /** Upload session ID */\n upload_id: string;\n /** Total bytes received so far */\n bytes_received: number;\n /** Total bytes expected */\n bytes_total: number;\n /** Number of chunks completed */\n chunks_completed: number;\n /** Total number of chunks */\n chunks_total: number;\n /** Progress as a fraction (0-1) */\n progress: number;\n}\n\n/**\n * Response from getting upload status\n */\nexport interface UploadStatusResponse {\n /** Upload session ID */\n upload_id: string;\n /** Session status */\n status: string;\n /** Bytes received so far */\n bytes_received: number;\n /** Total bytes expected */\n bytes_total: number;\n /** Chunks completed */\n chunks_completed: number;\n /** Total chunks */\n chunks_total: number;\n /** Session expiration time */\n expires_at: string;\n}\n\n/**\n * Request payload for completing an upload\n */\nexport interface CompleteUploadRequest {\n /** Optional commit message */\n commit_message?: string;\n /** Optional commit actor */\n commit_actor?: string;\n}\n\n/**\n * Response from completing an upload\n */\nexport interface CompleteUploadResponse {\n /** The created node */\n node: Node;\n /** Revision/commit ID */\n revision?: string;\n /** Storage key for the binary */\n storage_key: string;\n}\n\n// ============================================================================\n// Retry Options\n// ============================================================================\n\n/**\n * Options for retry behavior\n */\nexport interface RetryOptions {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds */\n baseDelay: number;\n /** Maximum delay in milliseconds */\n maxDelay: number;\n /** Use exponential backoff */\n exponentialBackoff: boolean;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Error codes for upload operations\n */\nexport enum UploadErrorCode {\n /** Invalid file (empty, too large, etc.) */\n INVALID_FILE = 'INVALID_FILE',\n /** File exceeds maximum size limit */\n FILE_TOO_LARGE = 'FILE_TOO_LARGE',\n /** Upload session has expired */\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n /** Upload session not found */\n SESSION_NOT_FOUND = 'SESSION_NOT_FOUND',\n /** Chunk offset doesn't match expected position */\n CHUNK_OFFSET_MISMATCH = 'CHUNK_OFFSET_MISMATCH',\n /** Chunk checksum verification failed */\n CHECKSUM_MISMATCH = 'CHECKSUM_MISMATCH',\n /** Backend storage error */\n STORAGE_ERROR = 'STORAGE_ERROR',\n /** Server-side error */\n SERVER_ERROR = 'SERVER_ERROR',\n /** Network connectivity error */\n NETWORK_ERROR = 'NETWORK_ERROR',\n /** Request timeout */\n TIMEOUT = 'TIMEOUT',\n /** Upload was cancelled */\n CANCELLED = 'CANCELLED',\n}\n\n/**\n * Custom error class for upload operations\n */\nexport class UploadError extends Error {\n /**\n * Create an upload error\n *\n * @param message - Human-readable error message\n * @param code - Error code\n * @param retryable - Whether this error can be retried\n * @param details - Additional error details\n */\n constructor(\n message: string,\n public readonly code: UploadErrorCode,\n public readonly retryable: boolean,\n public readonly details?: unknown\n ) {\n super(message);\n this.name = 'UploadError';\n // Maintain proper stack trace in V8\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, UploadError);\n }\n }\n\n /**\n * Create a network error\n */\n static networkError(message: string, details?: unknown): UploadError {\n return new UploadError(message, UploadErrorCode.NETWORK_ERROR, true, details);\n }\n\n /**\n * Create a timeout error\n */\n static timeoutError(message: string, details?: unknown): UploadError {\n return new UploadError(message, UploadErrorCode.TIMEOUT, true, details);\n }\n\n /**\n * Create a cancelled error\n */\n static cancelledError(message = 'Upload was cancelled'): UploadError {\n return new UploadError(message, UploadErrorCode.CANCELLED, false);\n }\n\n /**\n * Create a session expired error\n */\n static sessionExpiredError(uploadId: string): UploadError {\n return new UploadError(\n `Upload session ${uploadId} has expired`,\n UploadErrorCode.SESSION_EXPIRED,\n false,\n { uploadId }\n );\n }\n\n /**\n * Create a session not found error\n */\n static sessionNotFoundError(uploadId: string): UploadError {\n return new UploadError(\n `Upload session ${uploadId} not found`,\n UploadErrorCode.SESSION_NOT_FOUND,\n false,\n { uploadId }\n );\n }\n\n /**\n * Create an error from an HTTP response\n */\n static fromResponse(status: number, body: unknown): UploadError {\n const message = typeof body === 'object' && body !== null && 'message' in body\n ? String((body as { message: unknown }).message)\n : `HTTP error ${status}`;\n\n // Map HTTP status to error code\n let code: UploadErrorCode;\n let retryable: boolean;\n\n switch (status) {\n case 400:\n code = UploadErrorCode.INVALID_FILE;\n retryable = false;\n break;\n case 404:\n code = UploadErrorCode.SESSION_NOT_FOUND;\n retryable = false;\n break;\n case 409:\n code = UploadErrorCode.CHUNK_OFFSET_MISMATCH;\n retryable = false;\n break;\n case 410:\n code = UploadErrorCode.SESSION_EXPIRED;\n retryable = false;\n break;\n case 413:\n code = UploadErrorCode.FILE_TOO_LARGE;\n retryable = false;\n break;\n case 500:\n case 502:\n case 503:\n case 504:\n code = UploadErrorCode.SERVER_ERROR;\n retryable = true;\n break;\n default:\n code = UploadErrorCode.SERVER_ERROR;\n retryable = status >= 500;\n }\n\n return new UploadError(message, code, retryable, body);\n }\n}\n\n// ============================================================================\n// Default Values\n// ============================================================================\n\n/** Default chunk size: 10 MB */\nexport const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024;\n\n/** Default maximum retries */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** Default base delay for retries: 1 second */\nexport const DEFAULT_RETRY_BASE_DELAY = 1000;\n\n/** Default maximum delay for retries: 30 seconds */\nexport const DEFAULT_RETRY_MAX_DELAY = 30000;\n\n/** Default node type for uploads */\nexport const DEFAULT_NODE_TYPE = 'raisin:Asset';\n\n/** Default branch */\nexport const DEFAULT_BRANCH = 'main';\n\n/** Default concurrency for batch uploads */\nexport const DEFAULT_BATCH_CONCURRENCY = 3;\n\n// ============================================================================\n// Batch Upload Types\n// ============================================================================\n\n/**\n * Progress for a single file in a batch upload\n */\nexport interface BatchFileProgress {\n /** Filename */\n file: string;\n /** Current upload status */\n status: UploadStatus;\n /** Bytes uploaded so far */\n bytesUploaded: number;\n /** Total bytes to upload */\n bytesTotal: number;\n /** Progress as a fraction (0-1) */\n progress: number;\n /** Error if upload failed */\n error?: Error;\n}\n\n/**\n * Aggregate progress across all files in a batch upload\n */\nexport interface BatchProgress {\n /** Total number of files in the batch */\n filesTotal: number;\n /** Number of files completed successfully */\n filesCompleted: number;\n /** Number of files that failed */\n filesFailed: number;\n /** Number of files currently uploading */\n filesInProgress: number;\n /** Number of files waiting in queue */\n filesPending: number;\n /** Total bytes uploaded across all files */\n bytesUploaded: number;\n /** Total bytes across all files */\n bytesTotal: number;\n /** Overall progress as a fraction (0-1) */\n progress: number;\n /** Aggregate upload speed in bytes/second */\n speed: number;\n /** Estimated time remaining in seconds */\n eta: number;\n /** Per-file progress details */\n files: BatchFileProgress[];\n}\n\n/**\n * Result of a completed batch upload\n */\nexport interface BatchUploadResult {\n /** Successfully uploaded files */\n successful: Array<{ file: string; result: UploadResult }>;\n /** Files that failed to upload */\n failed: Array<{ file: string; error: Error }>;\n}\n\n/**\n * Options for batch upload operations\n */\nexport interface BatchUploadOptions {\n /** Repository to upload to */\n repository: string;\n /** Branch name (default: \"main\") */\n branch?: string;\n /** Workspace to store the nodes */\n workspace: string;\n /** Base path - files will be uploaded to basePath/filename */\n basePath?: string;\n /** Custom function to determine path for each file */\n pathResolver?: (file: { name: string; size: number }) => string;\n /** Node type (default: \"raisin:Asset\") */\n nodeType?: string;\n /** Additional metadata for all nodes */\n metadata?: Record<string, unknown>;\n /** Chunk size in bytes (default: 10MB) */\n chunkSize?: number;\n /** Max concurrent uploads (default: 3) */\n concurrency?: number;\n /** Progress callback for aggregate progress */\n onProgress?: (progress: BatchProgress) => void;\n /** Called when individual file completes */\n onFileComplete?: (file: string, result: UploadResult) => void;\n /** Called when individual file fails */\n onFileError?: (file: string, error: Error) => void;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n /** Commit message for all uploads */\n commitMessage?: string;\n /** Actor/user identifier for all commits */\n commitActor?: string;\n /** Enable automatic retry on retryable errors (default: true) */\n autoRetry?: boolean;\n /** Maximum number of retry attempts per file (default: 3) */\n maxRetries?: number;\n /** Continue uploading remaining files if one fails (default: true) */\n continueOnError?: boolean;\n}\n\n/**\n * Interface for controlling a batch upload\n */\nexport interface BatchUpload {\n /** Start all uploads */\n start(): Promise<BatchUploadResult>;\n /** Pause all active uploads */\n pause(): void;\n /** Resume paused uploads */\n resume(): Promise<BatchUploadResult>;\n /** Cancel all uploads */\n cancel(): Promise<void>;\n /** Get current aggregate progress */\n getProgress(): BatchProgress;\n /** Check if any uploads are active */\n isActive(): boolean;\n}\n","/**\n * Retry utility with exponential backoff and jitter\n *\n * Implements a robust retry strategy for handling transient failures\n * in upload operations.\n */\n\nimport {\n RetryOptions,\n UploadError,\n UploadErrorCode,\n DEFAULT_MAX_RETRIES,\n DEFAULT_RETRY_BASE_DELAY,\n DEFAULT_RETRY_MAX_DELAY,\n} from './types';\n\n// ============================================================================\n// Default Options\n// ============================================================================\n\n/**\n * Default retry options\n */\nexport const DEFAULT_RETRY_OPTIONS: RetryOptions = {\n maxRetries: DEFAULT_MAX_RETRIES,\n baseDelay: DEFAULT_RETRY_BASE_DELAY,\n maxDelay: DEFAULT_RETRY_MAX_DELAY,\n exponentialBackoff: true,\n};\n\n// ============================================================================\n// Retry Context\n// ============================================================================\n\n/**\n * Context passed to retry callbacks\n */\nexport interface RetryContext {\n /** Current attempt number (1-indexed) */\n attempt: number;\n /** Total attempts allowed */\n maxAttempts: number;\n /** Last error that occurred */\n lastError: Error | null;\n /** Whether this is a retry (not the first attempt) */\n isRetry: boolean;\n}\n\n/**\n * Callback for retry events\n */\nexport type RetryCallback = (context: RetryContext) => void;\n\n// ============================================================================\n// Delay Calculation\n// ============================================================================\n\n/**\n * Calculate delay with exponential backoff and jitter\n *\n * Uses the formula: delay = min(maxDelay, baseDelay * 2^attempt + jitter)\n * Jitter is a random value between 0 and 30% of the base delay.\n *\n * @param attempt - Current attempt number (0-indexed)\n * @param options - Retry options\n * @returns Delay in milliseconds\n */\nexport function calculateDelay(attempt: number, options: RetryOptions): number {\n const { baseDelay, maxDelay, exponentialBackoff } = options;\n\n let delay: number;\n\n if (exponentialBackoff) {\n // Exponential: baseDelay * 2^attempt\n delay = baseDelay * Math.pow(2, attempt);\n } else {\n // Linear: just use base delay\n delay = baseDelay;\n }\n\n // Add jitter (0-30% of base delay)\n const jitter = Math.random() * 0.3 * baseDelay;\n delay += jitter;\n\n // Cap at max delay\n return Math.min(delay, maxDelay);\n}\n\n/**\n * Sleep for a given number of milliseconds\n *\n * @param ms - Milliseconds to sleep\n * @param signal - Optional abort signal\n * @returns Promise that resolves after the delay\n * @throws UploadError if aborted\n */\nexport async function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n // Check if already aborted\n if (signal?.aborted) {\n reject(UploadError.cancelledError());\n return;\n }\n\n const timeoutId = setTimeout(resolve, ms);\n\n // Listen for abort\n if (signal) {\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(UploadError.cancelledError());\n };\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n // Clean up listener after timeout\n setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n }, ms);\n }\n });\n}\n\n// ============================================================================\n// Retry Functions\n// ============================================================================\n\n/**\n * Determine if an error is retryable\n *\n * @param error - Error to check\n * @returns True if the error can be retried\n */\nexport function isRetryableError(error: unknown): boolean {\n // UploadError has explicit retryable flag\n if (error instanceof UploadError) {\n return error.retryable;\n }\n\n // Check for common retryable error patterns\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Network errors\n if (\n message.includes('network') ||\n message.includes('fetch') ||\n message.includes('connection') ||\n message.includes('econnreset') ||\n message.includes('econnrefused') ||\n message.includes('etimedout') ||\n message.includes('timeout')\n ) {\n return true;\n }\n\n // Check error name/type\n const name = error.name.toLowerCase();\n if (name === 'networkerror' || name === 'typeerror') {\n // TypeError can occur with fetch on network failures\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Execute a function with retry logic\n *\n * @param fn - Async function to execute\n * @param options - Retry options\n * @param signal - Optional abort signal\n * @param onRetry - Optional callback for retry events\n * @returns Result of the function\n * @throws Last error if all retries are exhausted\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> = {},\n signal?: AbortSignal,\n onRetry?: RetryCallback\n): Promise<T> {\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\n const maxAttempts = opts.maxRetries + 1; // Total attempts = retries + 1\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n // Check for abort\n if (signal?.aborted) {\n throw UploadError.cancelledError();\n }\n\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry if not retryable\n if (!isRetryableError(error)) {\n throw error;\n }\n\n // Don't retry if this was the last attempt\n if (attempt >= maxAttempts - 1) {\n throw error;\n }\n\n // Calculate delay\n const delay = calculateDelay(attempt, opts);\n\n // Notify retry callback\n if (onRetry) {\n onRetry({\n attempt: attempt + 1,\n maxAttempts,\n lastError,\n isRetry: true,\n });\n }\n\n // Wait before next attempt\n await sleep(delay, signal);\n }\n }\n\n // Should not reach here, but TypeScript needs a return\n throw lastError ?? new Error('Retry failed');\n}\n\n// ============================================================================\n// Retry Builder (Fluent API)\n// ============================================================================\n\n/**\n * Builder for creating retry configurations\n *\n * @example\n * ```typescript\n * const result = await new RetryBuilder()\n * .maxRetries(5)\n * .baseDelay(2000)\n * .onRetry((ctx) => console.log(`Retry ${ctx.attempt}/${ctx.maxAttempts}`))\n * .execute(() => uploadChunk(data));\n * ```\n */\nexport class RetryBuilder {\n private options: RetryOptions = { ...DEFAULT_RETRY_OPTIONS };\n private signal?: AbortSignal;\n private retryCallback?: RetryCallback;\n\n /**\n * Set maximum number of retries\n */\n maxRetries(count: number): this {\n this.options.maxRetries = count;\n return this;\n }\n\n /**\n * Set base delay in milliseconds\n */\n baseDelay(ms: number): this {\n this.options.baseDelay = ms;\n return this;\n }\n\n /**\n * Set maximum delay in milliseconds\n */\n maxDelay(ms: number): this {\n this.options.maxDelay = ms;\n return this;\n }\n\n /**\n * Enable or disable exponential backoff\n */\n exponentialBackoff(enabled: boolean): this {\n this.options.exponentialBackoff = enabled;\n return this;\n }\n\n /**\n * Set abort signal\n */\n withSignal(signal: AbortSignal): this {\n this.signal = signal;\n return this;\n }\n\n /**\n * Set retry callback\n */\n onRetry(callback: RetryCallback): this {\n this.retryCallback = callback;\n return this;\n }\n\n /**\n * Execute a function with retry\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n return withRetry(fn, this.options, this.signal, this.retryCallback);\n }\n}\n\n// ============================================================================\n// Error Classification\n// ============================================================================\n\n/**\n * Classify an error for retry decisions\n */\nexport interface ErrorClassification {\n /** Error code */\n code: UploadErrorCode;\n /** Whether the error is retryable */\n retryable: boolean;\n /** Suggested delay multiplier for this error type */\n delayMultiplier: number;\n /** Human-readable description */\n description: string;\n}\n\n/**\n * Classify an error for retry decisions\n *\n * @param error - Error to classify\n * @returns Error classification\n */\nexport function classifyError(error: unknown): ErrorClassification {\n if (error instanceof UploadError) {\n return {\n code: error.code,\n retryable: error.retryable,\n delayMultiplier: getDelayMultiplier(error.code),\n description: error.message,\n };\n }\n\n // Handle generic errors\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Timeout errors - moderate backoff\n if (message.includes('timeout')) {\n return {\n code: UploadErrorCode.TIMEOUT,\n retryable: true,\n delayMultiplier: 1.5,\n description: 'Request timed out',\n };\n }\n\n // Network errors - aggressive backoff\n if (\n message.includes('network') ||\n message.includes('connection') ||\n message.includes('econnreset')\n ) {\n return {\n code: UploadErrorCode.NETWORK_ERROR,\n retryable: true,\n delayMultiplier: 2.0,\n description: 'Network connection error',\n };\n }\n }\n\n // Unknown error - conservative approach\n return {\n code: UploadErrorCode.SERVER_ERROR,\n retryable: false,\n delayMultiplier: 1.0,\n description: 'Unknown error',\n };\n}\n\n/**\n * Get delay multiplier for an error code\n */\nfunction getDelayMultiplier(code: UploadErrorCode): number {\n switch (code) {\n case UploadErrorCode.NETWORK_ERROR:\n return 2.0; // Network issues - wait longer\n case UploadErrorCode.TIMEOUT:\n return 1.5; // Timeouts - moderate wait\n case UploadErrorCode.SERVER_ERROR:\n return 1.5; // Server overload - moderate wait\n case UploadErrorCode.STORAGE_ERROR:\n return 1.0; // Storage issues - normal wait\n default:\n return 1.0;\n }\n}\n","/**\n * Batch upload implementation for multiple files\n *\n * Provides concurrent upload of multiple files with:\n * - Configurable concurrency limit\n * - Aggregate and per-file progress tracking\n * - Pause/resume/cancel support\n * - Error handling with continue-on-error option\n */\n\nimport type {\n BatchUpload,\n BatchUploadOptions,\n BatchUploadResult,\n BatchProgress,\n BatchFileProgress,\n UploadResult,\n UploadStatus,\n} from './types';\nimport {\n DEFAULT_BATCH_CONCURRENCY,\n DEFAULT_BRANCH,\n DEFAULT_NODE_TYPE,\n DEFAULT_CHUNK_SIZE,\n DEFAULT_MAX_RETRIES,\n} from './types';\nimport type { FileSource } from './file-source';\nimport type { UploaderConfig } from './uploader';\nimport { Uploader } from './uploader';\n\n// ============================================================================\n// Speed Tracker for Batch\n// ============================================================================\n\n/**\n * Track aggregate upload speed using a sliding window\n */\nclass BatchSpeedTracker {\n private samples: Array<{ bytes: number; timestamp: number }> = [];\n private readonly windowSize: number;\n private readonly maxSamples: number;\n\n constructor(windowSizeMs = 5000, maxSamples = 50) {\n this.windowSize = windowSizeMs;\n this.maxSamples = maxSamples;\n }\n\n addSample(bytes: number): void {\n const now = Date.now();\n this.samples.push({ bytes, timestamp: now });\n\n // Remove old samples\n const cutoff = now - this.windowSize;\n this.samples = this.samples.filter((s) => s.timestamp > cutoff);\n\n // Limit max samples\n if (this.samples.length > this.maxSamples) {\n this.samples = this.samples.slice(-this.maxSamples);\n }\n }\n\n getSpeed(): number {\n if (this.samples.length < 2) {\n return 0;\n }\n\n const first = this.samples[0];\n const last = this.samples[this.samples.length - 1];\n const timeDelta = (last.timestamp - first.timestamp) / 1000;\n\n if (timeDelta === 0) {\n return 0;\n }\n\n const totalBytes = this.samples.reduce((sum, s) => sum + s.bytes, 0);\n return totalBytes / timeDelta;\n }\n\n getEta(remainingBytes: number): number {\n const speed = this.getSpeed();\n if (speed === 0) {\n return 0;\n }\n return remainingBytes / speed;\n }\n\n reset(): void {\n this.samples = [];\n }\n}\n\n// ============================================================================\n// File State\n// ============================================================================\n\ninterface FileState {\n file: FileSource;\n status: UploadStatus;\n bytesUploaded: number;\n uploader: Uploader | null;\n result: UploadResult | null;\n error: Error | null;\n}\n\n// ============================================================================\n// Batch Uploader\n// ============================================================================\n\n/**\n * Manages concurrent upload of multiple files\n */\nexport class BatchUploader implements BatchUpload {\n private readonly config: UploaderConfig;\n private readonly files: FileSource[];\n private readonly options: Required<\n Omit<\n BatchUploadOptions,\n 'onProgress' | 'onFileComplete' | 'onFileError' | 'signal' | 'pathResolver' | 'metadata' | 'commitMessage' | 'commitActor'\n >\n > &\n Pick<BatchUploadOptions, 'onProgress' | 'onFileComplete' | 'onFileError' | 'signal' | 'pathResolver' | 'metadata' | 'commitMessage' | 'commitActor'>;\n\n private readonly fileStates: Map<string, FileState> = new Map();\n private readonly queue: string[] = [];\n private readonly speedTracker = new BatchSpeedTracker();\n\n private activeWorkers = 0;\n private paused = false;\n private cancelled = false;\n private started = false;\n private resolveWhenResumed: (() => void) | null = null;\n private lastBytesUploaded = 0;\n\n /**\n * Create a batch uploader\n */\n constructor(\n config: UploaderConfig,\n files: FileSource[],\n options: BatchUploadOptions\n ) {\n this.config = config;\n this.files = files;\n\n // Merge with defaults\n this.options = {\n repository: options.repository,\n branch: options.branch ?? DEFAULT_BRANCH,\n workspace: options.workspace,\n basePath: options.basePath ?? '',\n pathResolver: options.pathResolver,\n nodeType: options.nodeType ?? DEFAULT_NODE_TYPE,\n metadata: options.metadata,\n chunkSize: options.chunkSize ?? DEFAULT_CHUNK_SIZE,\n concurrency: options.concurrency ?? DEFAULT_BATCH_CONCURRENCY,\n onProgress: options.onProgress,\n onFileComplete: options.onFileComplete,\n onFileError: options.onFileError,\n signal: options.signal,\n commitMessage: options.commitMessage,\n commitActor: options.commitActor,\n autoRetry: options.autoRetry ?? true,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n continueOnError: options.continueOnError ?? true,\n };\n\n // Initialize file states\n for (const file of files) {\n this.fileStates.set(file.name, {\n file,\n status: 'pending',\n bytesUploaded: 0,\n uploader: null,\n result: null,\n error: null,\n });\n this.queue.push(file.name);\n }\n }\n\n /**\n * Start all uploads\n */\n async start(): Promise<BatchUploadResult> {\n if (this.started && !this.paused) {\n throw new Error('Batch upload already started');\n }\n\n this.started = true;\n this.paused = false;\n this.cancelled = false;\n\n // Link external abort signal\n if (this.options.signal) {\n this.options.signal.addEventListener('abort', () => {\n this.cancel();\n });\n }\n\n // Start workers\n const concurrency = Math.min(this.options.concurrency, this.queue.length);\n const workers = Array(concurrency)\n .fill(null)\n .map(() => this.worker());\n\n await Promise.all(workers);\n\n return this.getResult();\n }\n\n /**\n * Pause all active uploads\n */\n pause(): void {\n if (!this.started || this.paused || this.cancelled) {\n return;\n }\n\n this.paused = true;\n\n // Pause all active uploaders\n for (const state of this.fileStates.values()) {\n if (state.uploader && state.status === 'uploading') {\n state.uploader.pause();\n state.status = 'paused';\n }\n }\n\n this.emitProgress();\n }\n\n /**\n * Resume paused uploads\n */\n async resume(): Promise<BatchUploadResult> {\n if (!this.paused) {\n throw new Error('Batch upload is not paused');\n }\n\n this.paused = false;\n\n // Resume all paused uploaders\n for (const state of this.fileStates.values()) {\n if (state.status === 'paused') {\n state.status = 'uploading';\n }\n }\n\n // Wake up waiting workers\n if (this.resolveWhenResumed) {\n this.resolveWhenResumed();\n this.resolveWhenResumed = null;\n }\n\n this.emitProgress();\n\n // Continue with remaining uploads\n return this.start();\n }\n\n /**\n * Cancel all uploads\n */\n async cancel(): Promise<void> {\n this.cancelled = true;\n this.paused = false;\n\n // Cancel all active uploaders\n const cancelPromises: Promise<void>[] = [];\n for (const state of this.fileStates.values()) {\n if (state.uploader && (state.status === 'uploading' || state.status === 'paused')) {\n cancelPromises.push(state.uploader.cancel());\n state.status = 'cancelled';\n }\n }\n\n // Mark pending files as cancelled\n for (const state of this.fileStates.values()) {\n if (state.status === 'pending') {\n state.status = 'cancelled';\n }\n }\n\n // Wake up waiting workers\n if (this.resolveWhenResumed) {\n this.resolveWhenResumed();\n this.resolveWhenResumed = null;\n }\n\n await Promise.all(cancelPromises);\n\n this.emitProgress();\n }\n\n /**\n * Get current aggregate progress\n */\n getProgress(): BatchProgress {\n const fileProgresses: BatchFileProgress[] = [];\n\n let bytesUploaded = 0;\n let bytesTotal = 0;\n let filesCompleted = 0;\n let filesFailed = 0;\n let filesInProgress = 0;\n let filesPending = 0;\n\n for (const state of this.fileStates.values()) {\n const fileProgress: BatchFileProgress = {\n file: state.file.name,\n status: state.status,\n bytesUploaded: state.bytesUploaded,\n bytesTotal: state.file.size,\n progress: state.file.size > 0 ? state.bytesUploaded / state.file.size : 0,\n error: state.error ?? undefined,\n };\n fileProgresses.push(fileProgress);\n\n bytesUploaded += state.bytesUploaded;\n bytesTotal += state.file.size;\n\n switch (state.status) {\n case 'completed':\n filesCompleted++;\n break;\n case 'failed':\n filesFailed++;\n break;\n case 'uploading':\n case 'completing':\n filesInProgress++;\n break;\n case 'pending':\n case 'paused':\n filesPending++;\n break;\n }\n }\n\n const progress = bytesTotal > 0 ? bytesUploaded / bytesTotal : 0;\n const speed = this.speedTracker.getSpeed();\n const remainingBytes = bytesTotal - bytesUploaded;\n const eta = this.speedTracker.getEta(remainingBytes);\n\n return {\n filesTotal: this.files.length,\n filesCompleted,\n filesFailed,\n filesInProgress,\n filesPending,\n bytesUploaded,\n bytesTotal,\n progress,\n speed,\n eta,\n files: fileProgresses,\n };\n }\n\n /**\n * Check if any uploads are active\n */\n isActive(): boolean {\n return this.started && !this.paused && !this.cancelled && this.activeWorkers > 0;\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n /**\n * Worker that processes files from the queue\n */\n private async worker(): Promise<void> {\n this.activeWorkers++;\n\n try {\n while (this.queue.length > 0 && !this.cancelled) {\n // Wait if paused\n if (this.paused) {\n await this.waitForResume();\n if (this.cancelled) break;\n }\n\n // Get next file from queue\n const fileName = this.queue.shift();\n if (!fileName) break;\n\n const state = this.fileStates.get(fileName);\n if (!state) continue;\n\n // Upload the file\n await this.uploadFile(state);\n }\n } finally {\n this.activeWorkers--;\n }\n }\n\n /**\n * Wait until resume() is called\n */\n private async waitForResume(): Promise<void> {\n return new Promise((resolve) => {\n this.resolveWhenResumed = resolve;\n });\n }\n\n /**\n * Upload a single file\n */\n private async uploadFile(state: FileState): Promise<void> {\n const path = this.resolvePath(state.file);\n\n // Create uploader\n const uploader = new Uploader(\n this.config,\n state.file,\n {\n repository: this.options.repository,\n branch: this.options.branch,\n workspace: this.options.workspace,\n path,\n nodeType: this.options.nodeType,\n metadata: this.options.metadata,\n chunkSize: this.options.chunkSize,\n commitMessage: this.options.commitMessage,\n commitActor: this.options.commitActor,\n autoRetry: this.options.autoRetry,\n maxRetries: this.options.maxRetries,\n onProgress: (progress) => {\n state.bytesUploaded = progress.bytesUploaded;\n state.status = progress.status;\n this.updateSpeedTracker();\n this.emitProgress();\n },\n }\n );\n\n state.uploader = uploader;\n state.status = 'uploading';\n\n try {\n const result = await uploader.start();\n state.status = 'completed';\n state.result = result;\n state.bytesUploaded = state.file.size;\n\n // Notify file complete\n this.options.onFileComplete?.(state.file.name, result);\n } catch (error) {\n state.status = 'failed';\n state.error = error instanceof Error ? error : new Error(String(error));\n\n // Notify file error\n this.options.onFileError?.(state.file.name, state.error);\n\n // Stop if not continuing on error\n if (!this.options.continueOnError) {\n this.cancelled = true;\n }\n } finally {\n this.emitProgress();\n }\n }\n\n /**\n * Resolve the path for a file\n */\n private resolvePath(file: FileSource): string {\n if (this.options.pathResolver) {\n return this.options.pathResolver({ name: file.name, size: file.size });\n }\n\n // Default: basePath/filename\n const basePath = this.options.basePath.replace(/\\/$/, '');\n return basePath ? `${basePath}/${file.name}` : `/${file.name}`;\n }\n\n /**\n * Update speed tracker with delta bytes\n */\n private updateSpeedTracker(): void {\n const progress = this.getProgress();\n const delta = progress.bytesUploaded - this.lastBytesUploaded;\n if (delta > 0) {\n this.speedTracker.addSample(delta);\n this.lastBytesUploaded = progress.bytesUploaded;\n }\n }\n\n /**\n * Emit progress update\n */\n private emitProgress(): void {\n if (this.options.onProgress) {\n this.options.onProgress(this.getProgress());\n }\n }\n\n /**\n * Get final result\n */\n private getResult(): BatchUploadResult {\n const successful: Array<{ file: string; result: UploadResult }> = [];\n const failed: Array<{ file: string; error: Error }> = [];\n\n for (const state of this.fileStates.values()) {\n if (state.status === 'completed' && state.result) {\n successful.push({ file: state.file.name, result: state.result });\n } else if (state.status === 'failed' && state.error) {\n failed.push({ file: state.file.name, error: state.error });\n } else if (state.status === 'cancelled') {\n failed.push({\n file: state.file.name,\n error: new Error('Upload cancelled'),\n });\n }\n }\n\n return { successful, failed };\n }\n}\n","/**\n * Main Upload implementation\n *\n * Provides resumable chunked uploads with progress tracking,\n * pause/resume, and automatic retry support.\n */\n\nimport type { AuthManager } from '../auth';\nimport type {\n Upload,\n UploadOptions,\n UploadProgress,\n UploadResult,\n UploadStatus,\n CreateUploadRequest,\n CreateUploadResponse,\n ChunkUploadResponse,\n CompleteUploadRequest,\n CompleteUploadResponse,\n UploadStatusResponse,\n RetryOptions,\n BatchUpload,\n BatchUploadOptions,\n} from './types';\nimport {\n UploadError,\n UploadErrorCode,\n DEFAULT_CHUNK_SIZE,\n DEFAULT_MAX_RETRIES,\n DEFAULT_NODE_TYPE,\n DEFAULT_BRANCH,\n} from './types';\nimport type { FileSource } from './file-source';\nimport { getContentType, getChunkRange, calculateChunkCount } from './file-source';\nimport { withRetry } from './retry';\nimport { BatchUploader } from './batch';\n\n// ============================================================================\n// Speed Tracker\n// ============================================================================\n\n/**\n * Track upload speed using a sliding window\n */\nclass SpeedTracker {\n private samples: Array<{ bytes: number; timestamp: number }> = [];\n private readonly windowSize: number;\n private readonly maxSamples: number;\n\n constructor(windowSizeMs = 5000, maxSamples = 20) {\n this.windowSize = windowSizeMs;\n this.maxSamples = maxSamples;\n }\n\n /**\n * Add a sample\n */\n addSample(bytes: number): void {\n const now = Date.now();\n this.samples.push({ bytes, timestamp: now });\n\n // Remove old samples\n const cutoff = now - this.windowSize;\n this.samples = this.samples.filter((s) => s.timestamp > cutoff);\n\n // Limit max samples\n if (this.samples.length > this.maxSamples) {\n this.samples = this.samples.slice(-this.maxSamples);\n }\n }\n\n /**\n * Get current speed in bytes/second\n */\n getSpeed(): number {\n if (this.samples.length < 2) {\n return 0;\n }\n\n const first = this.samples[0];\n const last = this.samples[this.samples.length - 1];\n const timeDelta = (last.timestamp - first.timestamp) / 1000; // seconds\n\n if (timeDelta === 0) {\n return 0;\n }\n\n const totalBytes = this.samples.reduce((sum, s) => sum + s.bytes, 0);\n return totalBytes / timeDelta;\n }\n\n /**\n * Calculate ETA in seconds\n */\n getEta(remainingBytes: number): number {\n const speed = this.getSpeed();\n if (speed === 0) {\n return 0;\n }\n return remainingBytes / speed;\n }\n\n /**\n * Reset tracker\n */\n reset(): void {\n this.samples = [];\n }\n}\n\n// ============================================================================\n// Chunk Uploader (Browser vs Node.js)\n// ============================================================================\n\n/**\n * Upload a chunk using XHR (browser) for progress tracking\n */\nasync function uploadChunkXhr(\n url: string,\n chunk: ArrayBuffer,\n headers: Record<string, string>,\n onProgress?: (loaded: number) => void,\n signal?: AbortSignal\n): Promise<Response> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n // Handle abort\n const onAbort = () => {\n xhr.abort();\n reject(UploadError.cancelledError());\n };\n\n if (signal) {\n if (signal.aborted) {\n reject(UploadError.cancelledError());\n return;\n }\n signal.addEventListener('abort', onAbort, { once: true });\n }\n\n // Track upload progress\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable && onProgress) {\n onProgress(event.loaded);\n }\n };\n\n // Handle completion\n xhr.onload = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n\n // Create a Response-like object\n const response = new Response(xhr.responseText, {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: parseXhrHeaders(xhr.getAllResponseHeaders()),\n });\n\n resolve(response);\n };\n\n // Handle errors\n xhr.onerror = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n reject(UploadError.networkError('XHR network error'));\n };\n\n xhr.ontimeout = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n reject(UploadError.timeoutError('XHR timeout'));\n };\n\n xhr.onabort = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n reject(UploadError.cancelledError());\n };\n\n // Open and send\n xhr.open('PATCH', url);\n\n // Set headers\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value);\n }\n\n xhr.send(chunk);\n });\n}\n\n/**\n * Parse XHR response headers into Headers object\n */\nfunction parseXhrHeaders(headerString: string): Headers {\n const headers = new Headers();\n const lines = headerString.trim().split(/[\\r\\n]+/);\n\n for (const line of lines) {\n const parts = line.split(': ');\n const key = parts.shift();\n const value = parts.join(': ');\n if (key) {\n headers.append(key, value);\n }\n }\n\n return headers;\n}\n\n/**\n * Upload a chunk using fetch (Node.js or fallback)\n */\nasync function uploadChunkFetch(\n url: string,\n chunk: ArrayBuffer,\n headers: Record<string, string>,\n signal?: AbortSignal,\n fetchFn: typeof fetch = fetch\n): Promise<Response> {\n try {\n return await fetchFn(url, {\n method: 'PATCH',\n headers,\n body: chunk,\n signal,\n });\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw UploadError.cancelledError();\n }\n throw UploadError.networkError(error.message, error);\n }\n throw error;\n }\n}\n\n/**\n * Detect if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof XMLHttpRequest !== 'undefined';\n}\n\n// ============================================================================\n// Uploader Implementation\n// ============================================================================\n\n/**\n * Configuration for creating an Uploader\n */\nexport interface UploaderConfig {\n /** Base URL for the API */\n baseUrl: string;\n /** Auth manager for authentication */\n authManager: AuthManager;\n /** Custom fetch implementation */\n fetchImpl?: typeof fetch;\n /** Request timeout in milliseconds */\n requestTimeout?: number;\n}\n\n/**\n * Main upload implementation\n */\nexport class Uploader implements Upload {\n readonly id: string;\n\n private readonly baseUrl: string;\n private readonly authManager: AuthManager;\n private readonly fetchImpl: typeof fetch;\n private readonly requestTimeout: number;\n\n private readonly fileSource: FileSource;\n private readonly options: Required<\n Omit<UploadOptions, 'onProgress' | 'signal' | 'metadata' | 'commitMessage' | 'commitActor'>\n > & Pick<UploadOptions, 'onProgress' | 'signal' | 'metadata' | 'commitMessage' | 'commitActor'>;\n\n private session: CreateUploadResponse | null = null;\n private status: UploadStatus = 'pending';\n private bytesUploaded = 0;\n private currentChunk = 0;\n private totalChunks = 0;\n private readonly speedTracker = new SpeedTracker();\n\n private pauseRequested = false;\n private abortController: AbortController | null = null;\n\n /**\n * Create a new Uploader\n */\n constructor(\n config: UploaderConfig,\n fileSource: FileSource,\n options: UploadOptions,\n uploadId?: string\n ) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.authManager = config.authManager;\n this.fetchImpl = config.fetchImpl ?? fetch;\n this.requestTimeout = config.requestTimeout ?? 30000;\n\n this.fileSource = fileSource;\n this.id = uploadId ?? generateUploadId();\n\n // Merge with defaults\n this.options = {\n repository: options.repository,\n branch: options.branch ?? DEFAULT_BRANCH,\n workspace: options.workspace,\n path: options.path,\n nodeType: options.nodeType ?? DEFAULT_NODE_TYPE,\n chunkSize: options.chunkSize ?? DEFAULT_CHUNK_SIZE,\n commitMessage: options.commitMessage,\n commitActor: options.commitActor,\n autoRetry: options.autoRetry ?? true,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n onProgress: options.onProgress,\n signal: options.signal,\n metadata: options.metadata,\n };\n\n // Calculate total chunks\n this.totalChunks = calculateChunkCount(\n this.fileSource.size,\n this.options.chunkSize\n );\n }\n\n /**\n * Start the upload\n */\n async start(): Promise<UploadResult> {\n if (this.status === 'completed') {\n throw new UploadError(\n 'Upload already completed',\n UploadErrorCode.INVALID_FILE,\n false\n );\n }\n\n if (this.status === 'uploading') {\n throw new UploadError(\n 'Upload already in progress',\n UploadErrorCode.INVALID_FILE,\n false\n );\n }\n\n this.pauseRequested = false;\n this.abortController = new AbortController();\n\n // Link external abort signal\n if (this.options.signal) {\n this.options.signal.addEventListener('abort', () => {\n this.abortController?.abort();\n });\n }\n\n try {\n // Create session if not already created\n if (!this.session) {\n await this.createSession();\n }\n\n // Upload chunks\n this.status = 'uploading';\n this.emitProgress();\n\n await this.uploadChunks();\n\n // Complete the upload\n this.status = 'completing';\n this.emitProgress();\n\n const result = await this.completeUpload();\n\n this.status = 'completed';\n this.emitProgress();\n\n return result;\n } catch (error) {\n if (this.status !== 'paused' && this.status !== 'cancelled') {\n this.status = 'failed';\n this.emitProgress();\n }\n throw error;\n }\n }\n\n /**\n * Pause the upload\n */\n pause(): void {\n if (this.status !== 'uploading') {\n return;\n }\n\n this.pauseRequested = true;\n this.status = 'paused';\n this.emitProgress();\n }\n\n /**\n * Resume a paused upload\n */\n async resume(): Promise<UploadResult> {\n if (this.status !== 'paused') {\n throw new UploadError(\n 'Upload is not paused',\n UploadErrorCode.INVALID_FILE,\n false\n );\n }\n\n // Refresh session status\n await this.refreshSessionStatus();\n\n // Continue uploading\n return this.start();\n }\n\n /**\n * Cancel the upload\n */\n async cancel(): Promise<void> {\n this.pauseRequested = true;\n this.abortController?.abort();\n this.status = 'cancelled';\n this.emitProgress();\n\n // Try to cancel server-side\n if (this.session) {\n try {\n await this.deleteSession();\n } catch {\n // Ignore errors during cancel\n }\n }\n }\n\n /**\n * Get current progress\n */\n getProgress(): UploadProgress {\n const bytesTotal = this.fileSource.size;\n const progress = bytesTotal > 0 ? this.bytesUploaded / bytesTotal : 0;\n const speed = this.speedTracker.getSpeed();\n const remainingBytes = bytesTotal - this.bytesUploaded;\n const eta = this.speedTracker.getEta(remainingBytes);\n\n return {\n bytesUploaded: this.bytesUploaded,\n bytesTotal,\n progress,\n speed,\n eta,\n currentChunk: this.currentChunk + 1, // 1-indexed for display\n totalChunks: this.totalChunks,\n status: this.status,\n };\n }\n\n /**\n * Check if upload is active\n */\n isActive(): boolean {\n return this.status === 'uploading' || this.status === 'completing';\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n /**\n * Create upload session\n */\n private async createSession(): Promise<void> {\n const contentType = getContentType(this.fileSource);\n\n const request: CreateUploadRequest = {\n repository: this.options.repository,\n branch: this.options.branch,\n workspace: this.options.workspace,\n path: this.options.path,\n filename: this.fileSource.name,\n file_size: this.fileSource.size,\n content_type: contentType,\n node_type: this.options.nodeType,\n chunk_size: this.options.chunkSize,\n metadata: this.options.metadata,\n };\n\n const response = await this.apiRequest<CreateUploadResponse>(\n '/api/uploads',\n {\n method: 'POST',\n body: request,\n }\n );\n\n this.session = response;\n this.totalChunks = response.total_chunks;\n }\n\n /**\n * Refresh session status from server\n */\n private async refreshSessionStatus(): Promise<void> {\n if (!this.session) {\n return;\n }\n\n const response = await this.apiRequest<UploadStatusResponse>(\n `/api/uploads/${this.session.upload_id}`,\n { method: 'GET' }\n );\n\n // Update local state based on server state\n this.bytesUploaded = response.bytes_received;\n this.currentChunk = response.chunks_completed;\n\n // Check for expiration\n const expiresAt = new Date(response.expires_at);\n if (expiresAt < new Date()) {\n throw UploadError.sessionExpiredError(this.session.upload_id);\n }\n }\n\n /**\n * Upload all remaining chunks\n */\n private async uploadChunks(): Promise<void> {\n const signal = this.abortController?.signal;\n\n while (this.currentChunk < this.totalChunks) {\n // Check for pause/cancel\n if (this.pauseRequested || signal?.aborted) {\n if (signal?.aborted) {\n throw UploadError.cancelledError();\n }\n return; // Paused\n }\n\n // Upload chunk with retry\n if (this.options.autoRetry) {\n const retryOptions: Partial<RetryOptions> = {\n maxRetries: this.options.maxRetries,\n };\n\n await withRetry(\n () => this.uploadChunk(this.currentChunk),\n retryOptions,\n signal\n );\n } else {\n await this.uploadChunk(this.currentChunk);\n }\n\n this.currentChunk++;\n }\n }\n\n /**\n * Upload a single chunk\n */\n private async uploadChunk(chunkIndex: number): Promise<void> {\n if (!this.session) {\n throw new UploadError(\n 'No active session',\n UploadErrorCode.SESSION_NOT_FOUND,\n false\n );\n }\n\n const signal = this.abortController?.signal;\n const { start, end } = getChunkRange(\n chunkIndex,\n this.options.chunkSize,\n this.fileSource.size\n );\n\n // Read chunk data\n const chunk = await this.fileSource.slice(start, end);\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/octet-stream',\n 'Content-Range': `bytes ${start}-${end - 1}/${this.fileSource.size}`,\n };\n\n // Add auth header\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const url = `${this.baseUrl}/api/uploads/${this.session.upload_id}`;\n\n // Upload using XHR (browser) or fetch (Node.js)\n let response: Response;\n\n const chunkStartBytes = this.bytesUploaded;\n\n if (isBrowser()) {\n response = await uploadChunkXhr(\n url,\n chunk,\n headers,\n (loaded) => {\n // Update bytes uploaded with partial progress\n this.bytesUploaded = chunkStartBytes + loaded;\n this.speedTracker.addSample(loaded);\n this.emitProgress();\n },\n signal\n );\n } else {\n response = await uploadChunkFetch(url, chunk, headers, signal, this.fetchImpl);\n }\n\n // Handle response\n if (!response.ok) {\n const body = await response.json().catch(() => ({}));\n throw UploadError.fromResponse(response.status, body);\n }\n\n const result: ChunkUploadResponse = await response.json();\n\n // Update state\n this.bytesUploaded = result.bytes_received;\n this.speedTracker.addSample(end - start);\n this.emitProgress();\n }\n\n /**\n * Complete the upload\n */\n private async completeUpload(): Promise<UploadResult> {\n if (!this.session) {\n throw new UploadError(\n 'No active session',\n UploadErrorCode.SESSION_NOT_FOUND,\n false\n );\n }\n\n const request: CompleteUploadRequest = {\n commit_message: this.options.commitMessage,\n commit_actor: this.options.commitActor,\n };\n\n const response = await this.apiRequest<CompleteUploadResponse>(\n `/api/uploads/${this.session.upload_id}/complete`,\n {\n method: 'POST',\n body: request,\n }\n );\n\n return {\n node: response.node,\n revision: response.revision,\n storageKey: response.storage_key,\n };\n }\n\n /**\n * Delete upload session\n */\n private async deleteSession(): Promise<void> {\n if (!this.session) {\n return;\n }\n\n await this.apiRequest<void>(\n `/api/uploads/${this.session.upload_id}`,\n { method: 'DELETE' }\n );\n }\n\n /**\n * Make an API request\n */\n private async apiRequest<T>(\n path: string,\n options: {\n method: string;\n body?: unknown;\n }\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Add auth header\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.json().catch(() => ({}));\n throw UploadError.fromResponse(response.status, body);\n }\n\n // Handle empty responses\n const text = await response.text();\n if (!text) {\n return undefined as T;\n }\n\n return JSON.parse(text) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw UploadError.timeoutError(`Request timeout after ${this.requestTimeout}ms`);\n }\n\n throw error;\n }\n }\n\n /**\n * Emit progress update\n */\n private emitProgress(): void {\n if (this.options.onProgress) {\n this.options.onProgress(this.getProgress());\n }\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Generate a unique upload ID\n */\nfunction generateUploadId(): string {\n // Use crypto.randomUUID if available\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback to manual UUID generation\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n// ============================================================================\n// Upload Manager\n// ============================================================================\n\n/**\n * Manager for creating and tracking uploads\n */\nexport class UploadManager {\n private readonly config: UploaderConfig;\n private readonly uploads = new Map<string, Uploader>();\n\n /**\n * Create an upload manager\n */\n constructor(config: UploaderConfig) {\n this.config = config;\n }\n\n /**\n * Create a new upload\n */\n createUpload(fileSource: FileSource, options: UploadOptions): Upload {\n const uploader = new Uploader(this.config, fileSource, options);\n this.uploads.set(uploader.id, uploader);\n return uploader;\n }\n\n /**\n * Get an existing upload by ID\n */\n getUpload(id: string): Upload | undefined {\n return this.uploads.get(id);\n }\n\n /**\n * Get all active uploads\n */\n getActiveUploads(): Upload[] {\n return Array.from(this.uploads.values()).filter((u) => u.isActive());\n }\n\n /**\n * Cancel all active uploads\n */\n async cancelAll(): Promise<void> {\n const active = this.getActiveUploads();\n await Promise.all(active.map((u) => u.cancel()));\n }\n\n /**\n * Remove completed/cancelled uploads from tracking\n */\n cleanup(): void {\n for (const [id, upload] of this.uploads) {\n const progress = upload.getProgress();\n if (\n progress.status === 'completed' ||\n progress.status === 'cancelled' ||\n progress.status === 'failed'\n ) {\n this.uploads.delete(id);\n }\n }\n }\n\n /**\n * Create a batch upload for multiple files\n *\n * @param files - Array of FileSource objects to upload\n * @param options - Batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const batch = manager.createBatchUpload(fileSources, {\n * repository: 'media',\n * workspace: 'assets',\n * basePath: '/uploads',\n * concurrency: 3,\n * onProgress: (p) => console.log(`${p.filesCompleted}/${p.filesTotal}`)\n * });\n * const result = await batch.start();\n * ```\n */\n createBatchUpload(files: FileSource[], options: BatchUploadOptions): BatchUpload {\n return new BatchUploader(this.config, files, options);\n }\n}\n","/**\n * HTTP schema-management operations (NodeTypes / Archetypes / ElementTypes)\n *\n * These classes give the HTTP (SSR) client the same schema surface as the\n * WebSocket `Database`, backed by the management REST API\n * (`/api/management/{repo}/{branch}/...`). They mirror the WebSocket SDK\n * method names so call sites can swap clients with minimal changes.\n */\n\nimport type { RaisinHttpClient } from './http-client';\n\n/** Optional commit metadata for write operations. Server-side it is optional\n * (falls back to a default message + the `\"system\"` actor). */\nexport interface SchemaCommit {\n message: string;\n actor?: string;\n}\n\ntype SchemaKind = 'nodetypes' | 'archetypes' | 'elementtypes';\ntype SchemaDefField = 'node_type' | 'archetype' | 'element_type';\n\n/**\n * Shared CRUD/publish/resolve implementation for the three schema kinds.\n */\nabstract class HttpSchemaBase {\n protected abstract readonly kind: SchemaKind;\n protected abstract readonly defField: SchemaDefField;\n\n constructor(\n protected readonly repository: string,\n protected readonly branch: string,\n protected readonly client: RaisinHttpClient\n ) {}\n\n /** Base management URL for this schema kind. */\n protected base(): string {\n return `/api/management/${this.repository}/${this.branch}/${this.kind}`;\n }\n\n /** List all schemas (or only published ones). */\n async list(publishedOnly = false): Promise<unknown[]> {\n const path = publishedOnly ? `${this.base()}/published` : this.base();\n const result = await this.client.managementRequest<unknown>('GET', path);\n return Array.isArray(result) ? result : [];\n }\n\n /** Get a single schema by name. */\n async get(name: string): Promise<unknown> {\n return this.client.managementRequest('GET', `${this.base()}/${encodeURIComponent(name)}`);\n }\n\n /** Get the schema with full inheritance (`extends`) applied. */\n async getResolved(name: string): Promise<unknown> {\n return this.client.managementRequest(\n 'GET',\n `${this.base()}/${encodeURIComponent(name)}/resolved`\n );\n }\n\n /** Create a schema. `name` is folded into the definition body if absent. */\n async create(\n name: string,\n definition: Record<string, unknown>,\n commit?: SchemaCommit\n ): Promise<unknown> {\n return this.client.managementRequest('POST', this.base(), {\n [this.defField]: { name, ...definition },\n commit,\n });\n }\n\n /** Update an existing schema. */\n async update(\n name: string,\n definition: Record<string, unknown>,\n commit?: SchemaCommit\n ): Promise<unknown> {\n return this.client.managementRequest(\n 'PUT',\n `${this.base()}/${encodeURIComponent(name)}`,\n { [this.defField]: { name, ...definition }, commit }\n );\n }\n\n /** Delete a schema. */\n async delete(name: string, commit?: SchemaCommit): Promise<unknown> {\n return this.client.managementRequest(\n 'DELETE',\n `${this.base()}/${encodeURIComponent(name)}`,\n commit\n );\n }\n\n /** Publish a schema. */\n async publish(name: string, commit?: SchemaCommit): Promise<unknown> {\n return this.client.managementRequest(\n 'POST',\n `${this.base()}/${encodeURIComponent(name)}/publish`,\n commit\n );\n }\n\n /** Unpublish a schema. */\n async unpublish(name: string, commit?: SchemaCommit): Promise<unknown> {\n return this.client.managementRequest(\n 'POST',\n `${this.base()}/${encodeURIComponent(name)}/unpublish`,\n commit\n );\n }\n}\n\n/** NodeType management over HTTP REST. */\nexport class HttpNodeTypes extends HttpSchemaBase {\n protected readonly kind: SchemaKind = 'nodetypes';\n protected readonly defField: SchemaDefField = 'node_type';\n\n /**\n * Get the resolved NodeType. Unlike archetypes/element types, NodeType\n * resolution can be workspace-aware (honors workspace NodeType pins).\n */\n async getResolved(name: string, opts?: { workspace?: string }): Promise<unknown> {\n const query = opts?.workspace ? `?workspace=${encodeURIComponent(opts.workspace)}` : '';\n return this.client.managementRequest(\n 'GET',\n `${this.base()}/${encodeURIComponent(name)}/resolved${query}`\n );\n }\n}\n\n/** Archetype management over HTTP REST. */\nexport class HttpArchetypes extends HttpSchemaBase {\n protected readonly kind: SchemaKind = 'archetypes';\n protected readonly defField: SchemaDefField = 'archetype';\n}\n\n/** ElementType management over HTTP REST. */\nexport class HttpElementTypes extends HttpSchemaBase {\n protected readonly kind: SchemaKind = 'elementtypes';\n protected readonly defField: SchemaDefField = 'element_type';\n}\n","/**\n * McpClient — typed wrappers over a RaisinDB MCP server's JSON-RPC endpoint.\n *\n * A `raisin:McpServer` node is exposed over the MCP Streamable HTTP binding at\n * `POST /mcp/{repo}/{branch}/{slug}`, carrying one JSON-RPC 2.0 message per\n * request. This client mirrors the {@link FunctionsApi} shape: it is a thin,\n * transport-injected wrapper so any JS/TS backend (not just AI agents) can talk\n * to a RaisinDB MCP server programmatically, using the exact JSON-RPC method\n * names the engine implements (`tools/list`, `tools/call`, `resources/read`,\n * `resources/subscribe`).\n *\n * The transport is injected (see {@link McpTransport}) so the client stays\n * unit-testable and independent of the concrete HTTP layer — the HTTP client\n * supplies a real transport via its `.mcp(slug)` accessor.\n */\n\n/**\n * A single content block returned by a tool call or resource read.\n *\n * The engine serializes structured results into `text` blocks for spec\n * compliance; machine-readable output is carried separately in\n * {@link McpCallToolResult.structuredContent}.\n */\nexport interface McpContentBlock {\n /** Block discriminator, e.g. `\"text\"`. */\n type: string;\n /** Present on `text` blocks. */\n text?: string;\n /** Allow forward-compatible block variants (`image`, `resource`, …). */\n [key: string]: unknown;\n}\n\n/** A tool descriptor as advertised by `tools/list`. */\nexport interface McpToolDescriptor {\n /** Unique tool name used as the `name` argument to {@link McpClient.callTool}. */\n name: string;\n /** Human-readable description. */\n description?: string;\n /** JSON Schema describing the tool's accepted arguments. */\n inputSchema?: unknown;\n /** JSON Schema describing the tool's structured output, when declared. */\n outputSchema?: unknown;\n /** Forward-compatible extra fields (e.g. `ui`, annotations). */\n [key: string]: unknown;\n}\n\n/** Result of a `tools/call` invocation. */\nexport interface McpCallToolResult {\n /** Result content blocks (typically a single `text` block). */\n content: McpContentBlock[];\n /** `true` when the tool reported a domain-level failure. */\n isError?: boolean;\n /**\n * Machine-readable result conforming to the tool's `outputSchema`, present\n * only for tools that declare one.\n */\n structuredContent?: unknown;\n /** Forward-compatible extra fields. */\n [key: string]: unknown;\n}\n\n/** One entry returned by `resources/read`. */\nexport interface McpResourceContents {\n /** `raisin://` URI of the resource that was read. */\n uri: string;\n /** MIME type of the content, when known. */\n mimeType?: string;\n /** Text payload (JSON-only resources return their properties here). */\n text?: string;\n /** Base64-encoded binary payload, for byte-serving resources. */\n blob?: string;\n /** Forward-compatible extra fields. */\n [key: string]: unknown;\n}\n\n/** Result of `resources/read`. */\nexport interface McpReadResourceResult {\n /** One content entry per URI read. */\n contents: McpResourceContents[];\n}\n\n/**\n * A `notifications/resources/updated` payload pushed over the subscription\n * stream when a watched resource changes.\n */\nexport interface McpResourceUpdate {\n /** URI of the resource that changed. */\n uri: string;\n}\n\n/**\n * A live subscription to resource-change notifications.\n *\n * Iterate it with `for await (const update of subscription) { … }`; call\n * {@link McpResourceSubscription.close} to tear the stream down.\n */\nexport interface McpResourceSubscription extends AsyncIterable<McpResourceUpdate> {\n /** Close the underlying stream and stop receiving updates. */\n close(): void;\n}\n\n/**\n * Transport abstraction the {@link McpClient} is built on.\n *\n * `rpc` performs one request/response JSON-RPC round trip and returns the\n * already-unwrapped `result` (throwing on a JSON-RPC `error`). `subscribe`\n * opens the `resources/subscribe` SSE stream and yields each raw JSON-RPC frame\n * forwarded by the server.\n */\nexport interface McpTransport {\n /**\n * Send one JSON-RPC request and resolve with its `result` payload.\n *\n * @param method - JSON-RPC method name (e.g. `\"tools/list\"`).\n * @param params - Method parameters, shape depends on `method`.\n */\n rpc(method: string, params?: unknown): Promise<unknown>;\n\n /**\n * Open an SSE stream for a subscribing method and yield each JSON-RPC frame\n * the server pushes (the initial ack plus subsequent notifications).\n *\n * @param method - Subscribing JSON-RPC method (`\"resources/subscribe\"`).\n * @param params - Method parameters (`{ uri }`).\n */\n subscribe(method: string, params: unknown): McpFrameStream;\n}\n\n/** A raw JSON-RPC frame as delivered over the subscription SSE stream. */\nexport interface McpJsonRpcFrame {\n jsonrpc?: string;\n id?: unknown;\n method?: string;\n params?: unknown;\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n}\n\n/** A closeable async stream of raw JSON-RPC frames. */\nexport interface McpFrameStream extends AsyncIterable<McpJsonRpcFrame> {\n /** Close the underlying stream. */\n close(): void;\n}\n\n/**\n * Typed client for a single RaisinDB MCP server, addressed by\n * `{repo}/{branch}/{slug}`.\n *\n * @example\n * ```typescript\n * const mcp = client.database('my-repo').mcp('assistant');\n * const { tools } = await mcp.listTools();\n * const result = await mcp.callTool('order_card', { orderId: '42' });\n * const doc = await mcp.readResource('raisin://content/site/home');\n *\n * const sub = mcp.subscribeResource('raisin://content/site/home');\n * for await (const update of sub) {\n * console.log('changed:', update.uri);\n * }\n * ```\n */\nexport class McpClient {\n constructor(private readonly transport: McpTransport) {}\n\n /**\n * List the tools this MCP server advertises to the calling identity.\n *\n * Wraps the `tools/list` JSON-RPC method. The visible set is RLS-scoped to\n * the authenticated caller (or the anonymous role).\n *\n * @returns The advertised tool descriptors.\n */\n async listTools(): Promise<{ tools: McpToolDescriptor[] }> {\n const result = (await this.transport.rpc('tools/list')) as {\n tools?: McpToolDescriptor[];\n };\n return { tools: result?.tools ?? [] };\n }\n\n /**\n * Invoke a tool by name.\n *\n * Wraps the `tools/call` JSON-RPC method. The underlying `raisin:Function`\n * runs RLS-scoped to the calling identity. A domain-level tool failure is\n * reported via {@link McpCallToolResult.isError} (not thrown); transport and\n * protocol errors are thrown.\n *\n * @param name - Tool name from {@link listTools}.\n * @param args - Arguments object matching the tool's `inputSchema`.\n * @returns The tool's content blocks and optional structured content.\n */\n async callTool(\n name: string,\n args?: Record<string, unknown>,\n ): Promise<McpCallToolResult> {\n const result = (await this.transport.rpc('tools/call', {\n name,\n arguments: args ?? {},\n })) as McpCallToolResult;\n return result;\n }\n\n /**\n * Read a resource by its `raisin://` URI.\n *\n * Wraps the `resources/read` JSON-RPC method. JSON-only resources return\n * their properties as a `text` entry; byte-serving resources return base64\n * in `blob`.\n *\n * @param uri - `raisin://{workspace}/{path}` URI to read.\n * @returns One content entry per URI read.\n */\n async readResource(uri: string): Promise<McpReadResourceResult> {\n const result = (await this.transport.rpc('resources/read', {\n uri,\n })) as McpReadResourceResult;\n return { contents: result?.contents ?? [] };\n }\n\n /**\n * Subscribe to change notifications for a resource URI (or URI prefix).\n *\n * Wraps the `resources/subscribe` JSON-RPC method, which upgrades to an SSE\n * stream. The returned {@link McpResourceSubscription} is an async iterable of\n * {@link McpResourceUpdate}; the server's initial subscription ack is consumed\n * internally and not yielded. Call `close()` to end the stream.\n *\n * @param uri - `raisin://` URI (or prefix) to watch.\n * @returns A live, closeable subscription.\n */\n subscribeResource(uri: string): McpResourceSubscription {\n const stream = this.transport.subscribe('resources/subscribe', { uri });\n return {\n close: () => stream.close(),\n async *[Symbol.asyncIterator](): AsyncIterator<McpResourceUpdate> {\n for await (const frame of stream) {\n if (frame.method === 'notifications/resources/updated') {\n const params = (frame.params ?? {}) as Partial<McpResourceUpdate>;\n if (typeof params.uri === 'string') {\n yield { uri: params.uri };\n }\n }\n }\n },\n };\n }\n}\n","/**\n * IdentityAuthApi — passwordless and password sign-in for end users.\n *\n * This is the *identity* half of authentication (the people using an\n * application), distinct from {@link AuthManager}, which is the admin/JWT\n * credential holder the transports authenticate with. The two meet at the\n * token: everything here returns an {@link IdentityAuthResponse}, and\n * `client.setIdentityTokens(...)` hands it to the AuthManager so subsequent\n * SQL, node and function calls run as that person.\n *\n * Every endpoint is repository-scoped (`/auth/{repo}/…`). A repository is not\n * optional: identities, their home nodes and their roles are per repository,\n * so a call that omitted it would have to guess which one, and guessing wrong\n * signs somebody into the wrong data.\n */\n\n/** Transport hook: performs one JSON HTTP call and returns the parsed body. */\nexport type IdentityAuthTransport = <T>(options: {\n method: string;\n path: string;\n body?: unknown;\n /** Send no Authorization header — the point of a sign-in call. */\n skipAuth?: boolean;\n}) => Promise<T>;\n\n/** Identity returned alongside a token pair. */\nexport interface IdentityInfo {\n id: string;\n email: string;\n display_name: string | null;\n avatar_url: string | null;\n email_verified: boolean;\n linked_providers: string[];\n /** The person's home node path in this repository. */\n home: string | null;\n}\n\n/** A successful sign-in: tokens plus who they belong to. */\nexport interface IdentityAuthResult {\n access_token: string;\n refresh_token: string;\n token_type: string;\n /** Unix seconds. */\n expires_at: number;\n identity: IdentityInfo;\n}\n\n/**\n * Acknowledgement that a magic link was *sent*.\n *\n * Deliberately carries no token and no unmasked address: this response is\n * shown to whoever typed the email, who is not yet proven to own it.\n */\nexport interface MagicLinkSent {\n message: string;\n /** e.g. `u***@example.com` — enough to spot a typo, not to harvest. */\n masked_email: string;\n expires_in_minutes: number;\n}\n\nexport interface MagicLinkOptions {\n /**\n * Where RaisinDB sends the browser after it verifies the token.\n *\n * The server checks this against the tenant's redirect allowlist and\n * refuses anything outside it, so an attacker cannot aim a victim's\n * one-time token at their own host. Omit it to use the configured default.\n */\n redirectUrl?: string;\n}\n\n/** Which sign-in methods this repository actually offers. */\nexport interface AuthProviders {\n providers: Array<{\n id: string;\n display_name: string;\n icon: string;\n auth_url: string;\n }>;\n local_enabled: boolean;\n magic_link_enabled: boolean;\n}\n\n/** Who the caller currently is, as this repository sees them. */\nexport interface IdentityMe {\n id: string;\n email: string | null;\n roles: string[];\n anonymous: boolean;\n home: string | null;\n}\n\n/**\n * Identity authentication scoped to one repository.\n *\n * Obtain it from `client.auth(repository)` rather than constructing it.\n */\nexport class IdentityAuthApi {\n constructor(\n private readonly repository: string,\n private readonly transport: IdentityAuthTransport,\n ) {}\n\n private get base(): string {\n return `/auth/${encodeURIComponent(this.repository)}`;\n }\n\n /**\n * Ask RaisinDB to email a sign-in link.\n *\n * The reply is an acknowledgement, never a token — the token only exists in\n * the email. It also resolves for an address that has no account, because a\n * response that differed would turn this endpoint into an account-existence\n * oracle.\n */\n async sendMagicLink(email: string, options?: MagicLinkOptions): Promise<MagicLinkSent> {\n return this.transport<MagicLinkSent>({\n method: 'POST',\n path: `${this.base}/magic-link`,\n body: { email, redirect_url: options?.redirectUrl },\n skipAuth: true,\n });\n }\n\n /**\n * Exchange a magic-link token for a session.\n *\n * Most applications never call this: following the emailed link hits\n * RaisinDB directly, which verifies and 302s to the redirect URL with the\n * tokens in the URL **fragment** (so they stay out of server logs and out\n * of the Referer header) — see {@link readTokensFromFragment}. Call this\n * only when handling the token yourself, and note it is single-use.\n */\n async verifyMagicLink(token: string): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'GET',\n path: `${this.base}/magic-link/verify?token=${encodeURIComponent(token)}`,\n skipAuth: true,\n });\n }\n\n /** Sign in with email and password, where the repository enables it. */\n async login(\n email: string,\n password: string,\n options?: { rememberMe?: boolean },\n ): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'POST',\n path: `${this.base}/login`,\n body: { email, password, remember_me: options?.rememberMe ?? false },\n skipAuth: true,\n });\n }\n\n /** Create an account with email and password. */\n async register(\n email: string,\n password: string,\n options?: { displayName?: string },\n ): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'POST',\n path: `${this.base}/register`,\n body: { email, password, display_name: options?.displayName },\n skipAuth: true,\n });\n }\n\n /** Trade a refresh token for a fresh pair. */\n async refresh(refreshToken: string): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'POST',\n path: `${this.base}/refresh`,\n body: { refresh_token: refreshToken },\n skipAuth: true,\n });\n }\n\n /**\n * Which sign-in methods to render.\n *\n * Ask rather than hard-code: magic link and password are per-repository\n * configuration, and a button for a disabled method is a dead end.\n */\n async providers(): Promise<AuthProviders> {\n return this.transport<AuthProviders>({\n method: 'GET',\n path: `${this.base}/providers`,\n skipAuth: true,\n });\n }\n\n /** Who the current token belongs to in this repository. */\n async me(): Promise<IdentityMe> {\n return this.transport<IdentityMe>({ method: 'GET', path: `${this.base}/me` });\n }\n}\n\n/**\n * Read the tokens a magic-link verify redirect left in the URL fragment.\n *\n * Pass `window.location.hash` (or the whole URL) on the callback route. The\n * fragment never reaches a server, which is why the tokens travel there.\n *\n * Returns `null` when the fragment carries no tokens, so a plain visit to the\n * callback route is distinguishable from an arrival from a link.\n */\nexport function readTokensFromFragment(\n hashOrUrl: string,\n): { accessToken: string; refreshToken: string | null } | null {\n const hash = hashOrUrl.includes('#') ? hashOrUrl.slice(hashOrUrl.indexOf('#') + 1) : hashOrUrl;\n if (!hash) return null;\n const params = new URLSearchParams(hash);\n const accessToken = params.get('access_token');\n if (!accessToken) return null;\n return { accessToken, refreshToken: params.get('refresh_token') };\n}\n","/**\n * NodeBuilder - Ergonomic builder pattern for creating RaisinDB nodes\n *\n * @example\n * ```typescript\n * const node = NodeBuilder.create()\n * .nodeType(\"Page\")\n * .name(\"My Page\")\n * .path(\"/content/my-page\")\n * .property(\"title\", \"Welcome\")\n * .property(\"published\", true)\n * .build();\n * ```\n */\n\nimport { Node, PropertyValue, RelationRef } from './protocol';\n\nexport class NodeBuilder {\n private node: Partial<Node> = {\n properties: {},\n children: [],\n relations: [],\n version: 1,\n };\n\n /**\n * Create a new NodeBuilder instance\n */\n static create(): NodeBuilder {\n return new NodeBuilder();\n }\n\n /**\n * Set the node ID\n */\n id(id: string): this {\n this.node.id = id;\n return this;\n }\n\n /**\n * Set the node name\n */\n name(name: string): this {\n this.node.name = name;\n return this;\n }\n\n /**\n * Set the node path\n */\n path(path: string): this {\n this.node.path = path;\n return this;\n }\n\n /**\n * Set the node type\n */\n nodeType(nodeType: string): this {\n this.node.node_type = nodeType;\n return this;\n }\n\n /**\n * Set the archetype\n */\n archetype(archetype: string): this {\n this.node.archetype = archetype;\n return this;\n }\n\n /**\n * Set a property value\n */\n property(key: string, value: PropertyValue): this {\n if (!this.node.properties) {\n this.node.properties = {};\n }\n this.node.properties[key] = value;\n return this;\n }\n\n /**\n * Set multiple properties at once\n */\n properties(properties: Record<string, PropertyValue>): this {\n this.node.properties = properties;\n return this;\n }\n\n /**\n * Add a child node ID\n */\n child(childId: string): this {\n if (!this.node.children) {\n this.node.children = [];\n }\n this.node.children.push(childId);\n return this;\n }\n\n /**\n * Set the children array\n */\n children(children: string[]): this {\n this.node.children = children;\n return this;\n }\n\n /**\n * Set the order key.\n *\n * @deprecated The server owns editorial ordering: the order key is assigned by\n * the ordering index on write, so any value set here is overwritten. To place a\n * node, create it (it appends to the end of its parent) then call\n * `nodes.reorder()`, `nodes.moveChildBefore()` or `nodes.moveChildAfter()`.\n */\n orderKey(orderKey: string): this {\n this.node.order_key = orderKey;\n return this;\n }\n\n /**\n * Set the parent name\n */\n parent(parent: string): this {\n this.node.parent = parent;\n return this;\n }\n\n /**\n * Set the version\n */\n version(version: number): this {\n this.node.version = version;\n return this;\n }\n\n /**\n * Set the workspace\n */\n workspace(workspace: string): this {\n this.node.workspace = workspace;\n return this;\n }\n\n /**\n * Set the tenant ID\n */\n tenantId(tenantId: string): this {\n this.node.tenant_id = tenantId;\n return this;\n }\n\n /**\n * Add a relation to another node\n */\n relation(relation: RelationRef): this {\n if (!this.node.relations) {\n this.node.relations = [];\n }\n this.node.relations.push(relation);\n return this;\n }\n\n /**\n * Add a relation using individual parameters\n */\n addRelation(\n target: string,\n workspace: string,\n relationType: string,\n targetNodeType?: string,\n weight?: number\n ): this {\n return this.relation({\n target,\n workspace,\n relation_type: relationType,\n target_node_type: targetNodeType || '',\n weight,\n });\n }\n\n /**\n * Set the relations array\n */\n relations(relations: RelationRef[]): this {\n this.node.relations = relations;\n return this;\n }\n\n /**\n * Build and return the Node object\n * @throws {Error} if required fields are missing\n */\n build(): Node {\n // Validate required fields\n if (!this.node.id) {\n throw new Error('Node ID is required');\n }\n if (!this.node.name) {\n throw new Error('Node name is required');\n }\n if (!this.node.path) {\n throw new Error('Node path is required');\n }\n if (!this.node.node_type) {\n throw new Error('Node type is required');\n }\n\n // Ensure required array fields are initialized\n //\n // `order_key` is deliberately left empty: the ordering index assigns it at\n // write time and overwrites whatever arrives, so seeding a value here would\n // only mislead. New children are appended to the end of their parent.\n if (this.node.order_key === undefined) this.node.order_key = '';\n if (!this.node.children) this.node.children = [];\n if (!this.node.relations) this.node.relations = [];\n if (!this.node.properties) this.node.properties = {};\n if (typeof this.node.version !== 'number') this.node.version = 1;\n\n return this.node as Node;\n }\n}\n\n/**\n * Helper functions for working with Node objects\n */\nexport class NodeHelpers {\n /**\n * Get a property value from a node\n */\n static getProperty<T = PropertyValue>(node: Node, key: string): T | undefined {\n return node.properties[key] as T | undefined;\n }\n\n /**\n * Set a property value on a node (mutating)\n */\n static setProperty(node: Node, key: string, value: PropertyValue): void {\n node.properties[key] = value;\n }\n\n /**\n * Get the parent path derived from the node's path\n */\n static getParentPath(node: Node): string | null {\n if (!node.path || node.path === '/') {\n return null;\n }\n const lastSlash = node.path.lastIndexOf('/');\n if (lastSlash <= 0) {\n return '/';\n }\n return node.path.substring(0, lastSlash);\n }\n\n /**\n * Check if the node is published\n */\n static isPublished(node: Node): boolean {\n return node.published_at != null && node.published_at.length > 0;\n }\n\n /**\n * Check if the node has children\n */\n static hasChildren(node: Node): boolean {\n return node.has_children ?? (node.children?.length ?? 0) > 0;\n }\n\n /**\n * Add a relation to a node (mutating)\n */\n static addRelation(\n node: Node,\n target: string,\n workspace: string,\n relationType: string,\n targetNodeType?: string,\n weight?: number\n ): void {\n if (!node.relations) {\n node.relations = [];\n }\n node.relations.push({\n target,\n workspace,\n relation_type: relationType,\n target_node_type: targetNodeType || '',\n weight,\n });\n }\n\n /**\n * Get relations of a specific type\n */\n static getRelationsByType(node: Node, relationType: string): RelationRef[] {\n return (node.relations || []).filter(r => r.relation_type === relationType);\n }\n\n /**\n * Get the name from a path (last segment)\n */\n static getNameFromPath(path: string): string {\n const parts = path.split('/').filter(p => p.length > 0);\n return parts[parts.length - 1] || '';\n }\n\n /**\n * Create a minimal node for testing/mocking\n */\n static createMock(overrides?: Partial<Node>): Node {\n return {\n id: 'mock-id',\n name: 'Mock Node',\n path: '/mock',\n node_type: 'MockType',\n properties: {},\n children: [],\n order_key: '',\n relations: [],\n version: 1,\n ...overrides,\n };\n }\n}\n","/**\n * Event type constants for subscribing to node events\n *\n * @example\n * ```typescript\n * import { RaisinClient, NodeEventType } from '@raisindb/client';\n *\n * client.events.subscribeToTypes([NodeEventType.Created, NodeEventType.Updated], (event) => {\n * console.log('Node changed:', event);\n * });\n * ```\n */\nexport const NodeEventType = {\n /** Node was created */\n Created: 'node:created',\n /** Node was updated */\n Updated: 'node:updated',\n /** Node was deleted */\n Deleted: 'node:deleted',\n /** Node was reordered among siblings */\n Reordered: 'node:reordered',\n /** Node was published */\n Published: 'node:published',\n /** Node was unpublished */\n Unpublished: 'node:unpublished',\n /** A single property was changed */\n PropertyChanged: 'node:property_changed',\n /** A relation was added to the node */\n RelationAdded: 'node:relation_added',\n /** A relation was removed from the node */\n RelationRemoved: 'node:relation_removed',\n} as const;\n\n/** Type for node event type values */\nexport type NodeEventTypeValue = (typeof NodeEventType)[keyof typeof NodeEventType];\n\n/**\n * All node event types as an array (useful for subscribing to all events)\n *\n * @example\n * ```typescript\n * client.events.subscribeToTypes(AllNodeEventTypes, (event) => {\n * console.log('Any node event:', event);\n * });\n * ```\n */\nexport const AllNodeEventTypes: NodeEventTypeValue[] = Object.values(NodeEventType);\n","/**\n * React Router 7 integration for RaisinDB\n *\n * Provides helpers for server-side rendering with React Router 7, including:\n * - Loader utilities for data fetching\n * - Client context management\n * - Hybrid mode support (HTTP on server, WebSocket on client)\n */\n\nimport { RaisinHttpClient, HttpClientOptions } from '../http-client';\nimport { RaisinClient, ClientOptions } from '../client';\nimport { Credentials } from '../auth';\nimport { logger } from '../logger';\n\n/**\n * Configuration for SSR client factory\n */\nexport interface SSRClientConfig {\n /** Base URL for HTTP API (e.g., \"http://localhost:8080\") */\n httpBaseUrl: string;\n /** Base URL for WebSocket (e.g., \"ws://localhost:8080/sys/default\") */\n wsUrl: string;\n /** HTTP client options */\n httpOptions?: HttpClientOptions;\n /** WebSocket client options */\n wsOptions?: ClientOptions;\n /** Default credentials for authentication (optional) */\n credentials?: Credentials;\n}\n\n/**\n * Create an SSR-compatible client for React Router loaders\n *\n * This creates an HTTP client for server-side data fetching.\n * Use in loader functions to fetch data during SSR.\n *\n * @param config - SSR client configuration\n * @returns HTTP client instance\n *\n * @example\n * ```typescript\n * // In a React Router loader\n * export async function loader() {\n * const client = createSSRClient({\n * httpBaseUrl: 'http://localhost:8080',\n * wsUrl: 'ws://localhost:8080/sys/default',\n * credentials: { username: 'admin', password: 'admin' }\n * });\n *\n * await client.authenticate(config.credentials);\n *\n * const posts = await client.database('social')\n * .executeSql('SELECT * FROM social WHERE node_type = \"Post\"');\n *\n * return { posts };\n * }\n * ```\n */\nexport function createSSRClient(config: SSRClientConfig): RaisinHttpClient {\n const client = RaisinClient.forSSR(config.httpBaseUrl, config.httpOptions);\n\n // Auto-authenticate if credentials provided\n if (config.credentials) {\n // Note: This is async, but we return the client immediately\n // Callers should await client.authenticate() if needed\n // Or use the credentials in their loader\n }\n\n return client;\n}\n\n/**\n * Create a loader helper that provides an authenticated client\n *\n * This wraps your loader function and provides an authenticated HTTP client.\n *\n * @param config - SSR client configuration\n * @param loaderFn - Your loader function that receives the authenticated client\n * @returns React Router loader function\n *\n * @example\n * ```typescript\n * export const loader = createLoader(\n * {\n * httpBaseUrl: process.env.RAISIN_HTTP_URL || 'http://localhost:8080',\n * wsUrl: process.env.RAISIN_WS_URL || 'ws://localhost:8080/sys/default',\n * credentials: { username: 'admin', password: 'admin' }\n * },\n * async (client, { request, params }) => {\n * const db = client.database('social');\n * const posts = await db.executeSql('SELECT * FROM social WHERE node_type = \"Post\"');\n * return { posts: posts.rows };\n * }\n * );\n * ```\n */\nexport function createLoader<TData = unknown>(\n config: SSRClientConfig,\n loaderFn: (\n client: RaisinHttpClient,\n args: { request: Request; params: Record<string, string | undefined> }\n ) => Promise<TData>\n): (args: { request: Request; params: Record<string, string | undefined> }) => Promise<TData> {\n return async (args) => {\n const client = createSSRClient(config);\n\n // Authenticate if credentials provided\n if (config.credentials) {\n await client.authenticate(config.credentials);\n }\n\n try {\n return await loaderFn(client, args);\n } catch (error) {\n logger.error('SSR Loader error:', error);\n throw error;\n }\n };\n}\n\n/**\n * Create a request-scoped client for SSR\n *\n * This ensures each SSR request gets its own client instance,\n * preventing state leakage between requests.\n *\n * @param httpBaseUrl - Base HTTP URL\n * @param options - HTTP client options\n * @returns New HTTP client instance\n */\nexport function createRequestScopedClient(\n httpBaseUrl: string,\n options?: HttpClientOptions\n): RaisinHttpClient {\n return new RaisinHttpClient(httpBaseUrl, options);\n}\n\n/**\n * Helper to convert SQL result rows to objects\n *\n * @param columns - Column names from SQL result\n * @param rows - Row data from SQL result\n * @returns Array of objects with column names as keys\n *\n * @example\n * ```typescript\n * const result = await client.database('social')\n * .executeSql('SELECT id, title FROM posts');\n * const posts = rowsToObjects(result.columns, result.rows);\n * // [{ id: '1', title: 'First Post' }, ...]\n * ```\n */\nexport function rowsToObjects<T = Record<string, unknown>>(\n _columns: string[],\n rows: Record<string, unknown>[]\n): T[] {\n return rows as T[];\n}\n\n/**\n * Extract error message from various error types\n *\n * @param error - Error object\n * @returns Error message string\n */\nexport function getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === 'string') {\n return error;\n }\n if (error && typeof error === 'object' && 'message' in error) {\n return String((error as any).message);\n }\n return 'An unknown error occurred';\n}\n\n/**\n * Type for hybrid client that can be either HTTP or WebSocket\n */\nexport type HybridClient = RaisinHttpClient | RaisinClient;\n\n/**\n * Check if client is HTTP-based\n */\nexport function isHttpClient(client: HybridClient): client is RaisinHttpClient {\n return client instanceof RaisinHttpClient;\n}\n\n/**\n * Check if client is WebSocket-based\n */\nexport function isWebSocketClient(client: HybridClient): client is RaisinClient {\n return client instanceof RaisinClient;\n}\n","/**\n * Flow execution types for the RaisinDB JS SDK.\n *\n * These types mirror the backend FlowEvent / FlowExecutionEvent enums\n * used for real-time SSE streaming of flow step-level events.\n */\n\n// ============================================================================\n// Flow Instance\n// ============================================================================\n\n/** Response returned when a flow is started via the run endpoint. */\nexport interface FlowRunResponse {\n /** The created flow instance ID */\n instance_id: string;\n /** Job ID for tracking execution */\n job_id: string;\n /** Status (always \"queued\" for async execution) */\n status: string;\n}\n\n/** Flow instance status values */\nexport type FlowInstanceStatus =\n | 'queued'\n | 'pending'\n | 'running'\n | 'completed'\n | 'failed'\n | 'waiting'\n | 'cancelled';\n\n/** Response from GET flow instance status endpoint. */\nexport interface FlowInstanceStatusResponse {\n /** Flow instance ID */\n id: string;\n /** Current status */\n status: FlowInstanceStatus;\n /** Flow-scoped variables */\n variables: Record<string, unknown>;\n /** Path to the flow definition */\n flow_path: string;\n /** ISO 8601 timestamp of when the flow started */\n started_at: string;\n /** Error message (if status is failed) */\n error?: string;\n}\n\n// ============================================================================\n// Flow Execution Events (matching backend FlowEvent enum)\n// ============================================================================\n\n/** Base properties shared by all events */\ninterface BaseFlowEvent {\n timestamp: string;\n}\n\n/** A step has started execution */\nexport interface StepStartedEvent extends BaseFlowEvent {\n type: 'step_started';\n node_id: string;\n step_name?: string;\n step_type: string;\n}\n\n/** A step has completed successfully */\nexport interface StepCompletedEvent extends BaseFlowEvent {\n type: 'step_completed';\n node_id: string;\n output: unknown;\n duration_ms: number;\n}\n\n/** A step has failed */\nexport interface StepFailedEvent extends BaseFlowEvent {\n type: 'step_failed';\n node_id: string;\n error: string;\n duration_ms: number;\n}\n\n/** Flow is waiting for external input (human task, approval, etc.) */\nexport interface FlowWaitingEvent extends BaseFlowEvent {\n type: 'flow_waiting';\n node_id: string;\n wait_type: string;\n reason: string;\n}\n\n/** Flow has resumed after waiting */\nexport interface FlowResumedEvent extends BaseFlowEvent {\n type: 'flow_resumed';\n node_id: string;\n wait_duration_ms: number;\n}\n\n/** Flow has completed successfully */\nexport interface FlowCompletedEvent extends BaseFlowEvent {\n type: 'flow_completed';\n output: unknown;\n total_duration_ms: number;\n}\n\n/** Flow has failed */\nexport interface FlowFailedEvent extends BaseFlowEvent {\n type: 'flow_failed';\n error: string;\n failed_at_node?: string;\n total_duration_ms: number;\n}\n\n/** Partial text content from AI streaming */\nexport interface TextChunkEvent extends BaseFlowEvent {\n type: 'text_chunk';\n text: string;\n}\n\n/** AI tool call started */\nexport interface ToolCallStartedEvent extends BaseFlowEvent {\n type: 'tool_call_started';\n tool_call_id: string;\n function_name: string;\n arguments: unknown;\n}\n\n/** AI tool call completed */\nexport interface ToolCallCompletedEvent extends BaseFlowEvent {\n type: 'tool_call_completed';\n tool_call_id: string;\n result: unknown;\n /** Error message if the tool call failed */\n error?: string;\n /** Execution duration in milliseconds */\n duration_ms?: number;\n}\n\n/** Partial thinking/reasoning content from AI streaming */\nexport interface ThoughtChunkEvent extends BaseFlowEvent {\n type: 'thought_chunk';\n text: string;\n}\n\n/** AI conversation node was created or resolved */\nexport interface ConversationCreatedEvent extends BaseFlowEvent {\n type: 'conversation_created';\n conversation_path: string;\n workspace: string;\n}\n\n/** An AI message was persisted to the node tree */\nexport interface MessageSavedEvent extends BaseFlowEvent {\n type: 'message_saved';\n message_path: string;\n role: string;\n conversation_path: string;\n}\n\n/** Log message from flow execution */\nexport interface LogEvent extends BaseFlowEvent {\n type: 'log';\n level: string;\n message: string;\n node_id?: string;\n}\n\n/** Union of all flow execution events streamed via SSE */\nexport type FlowExecutionEvent =\n | StepStartedEvent\n | StepCompletedEvent\n | StepFailedEvent\n | FlowWaitingEvent\n | FlowResumedEvent\n | FlowCompletedEvent\n | FlowFailedEvent\n | TextChunkEvent\n | ToolCallStartedEvent\n | ToolCallCompletedEvent\n | ThoughtChunkEvent\n | ConversationCreatedEvent\n | MessageSavedEvent\n | LogEvent;\n\n/** Type guard: is this a terminal event (flow_completed or flow_failed)? */\nexport function isTerminalEvent(\n event: FlowExecutionEvent,\n): event is FlowCompletedEvent | FlowFailedEvent {\n return event.type === 'flow_completed' || event.type === 'flow_failed';\n}\n","/**\n * Workflow definition types for RaisinDB flows.\n *\n * This is the canonical, shared data model for `raisin:Flow` definitions\n * (the `workflow_data` property of a flow node). The visual designer\n * (@raisindb/flow-designer), the admin console, and SDK consumers all\n * describe flows with these shapes.\n *\n * A flow definition is a tree of steps and containers:\n * - `FlowStep` - a single unit of work: function call, AI agent call,\n * human task (approval/input/review/action), or chat session\n * - `FlowContainer` - groups children: and / or / parallel / ai_sequence\n *\n * Functions, AI agents, and humans are uniform step concepts: a human task\n * whose `assignee` resolves to an AI agent is decided by the agent (with\n * confidence-threshold escalation back to a human).\n */\n\n// ============================================================================\n// References\n// ============================================================================\n\n/**\n * RaisinDB reference (PropertyValue::Reference) - cross-node reference\n * with workspace context.\n */\nexport interface RaisinReference {\n /** Node ID or path (raisin:ref) */\n 'raisin:ref': string;\n /** Workspace context */\n 'raisin:workspace': string;\n /** Optional resolved path */\n 'raisin:path'?: string;\n}\n\n/** Extract a display name from a reference path. */\nexport function getRefDisplayName(ref: RaisinReference): string {\n const path = ref['raisin:path'] || ref['raisin:ref'];\n const segments = path.split('/').filter(Boolean);\n return segments[segments.length - 1] || path;\n}\n\n/** Get the full path from a reference. */\nexport function getRefPath(ref: RaisinReference): string {\n return ref['raisin:path'] || ref['raisin:ref'];\n}\n\n// ============================================================================\n// Core enums\n// ============================================================================\n\n/** Container types */\nexport type ContainerType = 'and' | 'or' | 'parallel' | 'ai_sequence';\n\n/** Step error behavior */\nexport type StepErrorBehavior = 'stop' | 'skip' | 'continue';\n\n/** Flow-level error strategy */\nexport type FlowErrorStrategy = 'fail_fast' | 'continue';\n\n// ============================================================================\n// Retry\n// ============================================================================\n\n/** Retry configuration for a step */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (0 = no retries) */\n max_retries: number;\n /** Base delay in milliseconds for exponential backoff */\n base_delay_ms: number;\n /** Maximum delay cap in milliseconds */\n max_delay_ms: number;\n}\n\n/** Predefined retry strategies */\nexport const RETRY_STRATEGIES = {\n none: { max_retries: 0, base_delay_ms: 0, max_delay_ms: 0 },\n quick: { max_retries: 3, base_delay_ms: 1000, max_delay_ms: 10000 },\n standard: { max_retries: 5, base_delay_ms: 2000, max_delay_ms: 60000 },\n aggressive: { max_retries: 10, base_delay_ms: 5000, max_delay_ms: 120000 },\n llm: { max_retries: 5, base_delay_ms: 10000, max_delay_ms: 120000 },\n} as const;\n\nexport type RetryStrategy = keyof typeof RETRY_STRATEGIES;\n\n// ============================================================================\n// Human tasks\n// ============================================================================\n\n/** The human task types the flow runtime understands semantically */\nexport const CANONICAL_TASK_TYPES = ['approval', 'input', 'review', 'action'] as const;\n\n/** A canonical human task type */\nexport type CanonicalTaskType = (typeof CANONICAL_TASK_TYPES)[number];\n\n/**\n * Human task type.\n *\n * The canonical types are suggestions, not a closed set: an application may\n * define its own task vocabulary, and any slug matching\n * `[a-z][a-z0-9_-]{0,63}` is carried through to the task node verbatim for\n * a task UI to dispatch on. Spelled this way so the canonical values still\n * autocomplete.\n */\nexport type HumanTaskType = CanonicalTaskType | (string & {});\n\n/** Human task option for approval tasks */\nexport interface TaskOption {\n /** Option value returned when selected */\n value: string;\n /** Display label */\n label: string;\n /** Visual style */\n style?: 'default' | 'success' | 'danger' | 'warning';\n}\n\n// ============================================================================\n// Chat steps\n// ============================================================================\n\n/** Handoff target for chat steps */\nexport interface HandoffTarget {\n /** Target agent reference */\n agent_ref: RaisinReference;\n /** Trigger phrase patterns */\n trigger_phrases?: string[];\n /** When to trigger handoff */\n trigger_condition?: string;\n}\n\n/** Chat termination mode */\nexport type ChatTerminationMode =\n | 'user_request'\n | 'max_turns'\n | 'inactivity'\n | 'ai_decision';\n\n/** Chat termination configuration */\nexport interface ChatTerminationConfig {\n /** Termination modes that end the chat */\n modes: ChatTerminationMode[];\n /** Inactivity timeout in milliseconds */\n inactivity_timeout_ms?: number;\n /** Termination phrases to detect */\n termination_phrases?: string[];\n}\n\n/** Chat step configuration */\nexport interface ChatStepConfig {\n /** Reference to the agent node */\n agent_ref?: RaisinReference;\n /** System prompt override */\n system_prompt?: string;\n /** Agents to hand off to */\n handoff_targets: HandoffTarget[];\n /** Session timeout in milliseconds */\n session_timeout_ms?: number;\n /** Maximum number of conversation turns */\n max_turns: number;\n /** Termination configuration */\n termination: ChatTerminationConfig;\n}\n\n// ============================================================================\n// AI containers\n// ============================================================================\n\n/** Tool execution mode for AI container */\nexport type AiToolMode = 'auto' | 'explicit' | 'hybrid';\n\n/** AI error handling behavior */\nexport type AiErrorBehavior = 'stop' | 'continue' | 'retry';\n\n/** AI Container configuration (for ai_sequence containers) */\nexport interface AiContainerConfig {\n /** Reference to the agent node */\n agent_ref?: RaisinReference;\n /** Tool execution mode */\n tool_mode: AiToolMode;\n /** Tools to expose as explicit steps (for hybrid mode) */\n explicit_tools: string[];\n /** Maximum iterations for tool call loops */\n max_iterations: number;\n /** Enable AI thinking/reasoning display */\n thinking_enabled: boolean;\n /** Reference to existing conversation to continue */\n conversation_ref?: RaisinReference;\n /** Error handling behavior */\n on_error: AiErrorBehavior;\n /** Maximum retries on transient AI failures (default: 2) */\n max_retries?: number;\n /** Base delay between retries in milliseconds (default: 1000) */\n retry_delay_ms?: number;\n /** Timeout for entire container execution in milliseconds */\n timeout_ms?: number;\n /** Response format: \"text\", \"json_object\", or \"json_schema\" */\n response_format?: string;\n /** JSON schema for structured output (when response_format = \"json_schema\") */\n output_schema?: unknown;\n}\n\n// ============================================================================\n// Steps and containers\n// ============================================================================\n\n/** Base flow node interface */\nexport interface FlowDefinitionNodeBase {\n id: string;\n node_type: 'raisin:FlowStep' | 'raisin:FlowContainer';\n}\n\n/** Step properties */\nexport interface FlowStepProperties {\n /** Action name/label */\n action?: string;\n /** Function reference */\n function_ref?: RaisinReference;\n /** Agent reference */\n agent_ref?: RaisinReference;\n /** Function arguments - values support template expressions like\n * `{{ input.value }}` or `${steps.prev.id}` */\n arguments?: Record<string, unknown>;\n /** Lua script for evaluation */\n lua_script?: string;\n /** Condition expression (REL) - same namespaces as templates:\n * `input.*`, `steps.<id>.*`, `trigger.*`, flow variables */\n condition?: string;\n /** Key for payload data */\n payload_key?: string;\n /** Whether step is disabled */\n disabled?: boolean;\n /** Step type - distinguishes AI agent, chat, and human task steps */\n step_type?: 'default' | 'ai_agent' | 'human_task' | 'chat' | 'wait' | 'sub_flow' | 'decision';\n /** Prompt for ai_agent steps (template expressions supported) */\n prompt?: string;\n /** Retry configuration for this step */\n retry?: RetryConfig;\n /** Retry strategy preset (alternative to custom retry config) */\n retry_strategy?: RetryStrategy;\n /** Step timeout in milliseconds */\n timeout_ms?: number;\n\n // Error handling\n\n /** Target node ID for error flow (error edge) */\n error_edge?: string;\n /** Target node ID when a wait deadline expires */\n timeout_edge?: string;\n /** Reference to compensation function for saga rollback */\n compensation_ref?: RaisinReference;\n /** Mapping for the compensation input - values support template\n * expressions; the forward step's output is available as `output.*` */\n compensation_input_mapping?: Record<string, unknown>;\n /** Continue workflow on step failure */\n continue_on_fail?: boolean;\n /** Execute step in isolated branch for safety */\n isolated_branch?: boolean;\n /** Execution identity mode for permission handling */\n execution_identity?: 'agent' | 'caller' | 'function';\n\n // Human task (step_type = 'human_task')\n\n /** Type of human task */\n task_type?: HumanTaskType;\n /** Assignee path - a user (\"/users/alice\") or an AI agent\n * (\"/agents/support\"); agents decide tasks automatically */\n assignee?: string;\n /** Task description */\n task_description?: string;\n /** Options for approval tasks */\n options?: TaskOption[];\n /** JSON schema for input tasks */\n input_schema?: object;\n /**\n * Task due time in seconds from creation (doubles as the wait deadline).\n * A template expression (e.g. \"${input.due_seconds}\") is allowed, so a\n * deadline can come from data instead of being authored into the flow.\n */\n due_in_seconds?: number | string;\n /** Task priority (1-5, where 5 is highest); a template expression is allowed */\n priority?: number | string;\n /** Minimum confidence (0-1) for an agent assignee's decision to be\n * accepted; below it the task escalates (default 0.7) */\n min_confidence?: number;\n /** Human assignee to escalate to when an agent assignee fails or is\n * not confident enough */\n escalation_assignee?: string;\n\n // Wait step (step_type = 'wait')\n\n /** What to wait for (defaults to 'delay') */\n wait_type?: 'delay' | 'until' | 'event' | 'cron';\n /** Duration for a 'delay' wait, e.g. \"30m\" (templates allowed) */\n duration?: string;\n /** Absolute timestamp for an 'until' wait (templates allowed) */\n until?: string;\n /** Event type for an 'event' wait */\n event_type?: string;\n /** Optional deadline for an 'event' wait */\n timeout?: string;\n /** Cron expression for a 'cron' wait */\n cron?: string;\n\n // Sub-flow step (step_type = 'sub_flow')\n\n /** The flow to invoke */\n flow_ref?: RaisinReference;\n /** Input mapping for the child flow (template expressions) */\n input_mapping?: object;\n /** Run the child flow asynchronously */\n async?: boolean;\n\n // Decision step (step_type = 'decision', or any step with a condition)\n\n /** Node id to run when the condition is true (defaults to the next sibling) */\n yes_branch?: string;\n /** Node id to run when the condition is false (defaults to the next sibling) */\n no_branch?: string;\n\n // Chat step (step_type = 'chat')\n\n /** Chat step configuration */\n chat_config?: ChatStepConfig;\n}\n\n/** Basic workflow step */\nexport interface FlowDefinitionStep extends FlowDefinitionNodeBase {\n node_type: 'raisin:FlowStep';\n properties: FlowStepProperties;\n on_error?: StepErrorBehavior;\n /** Target node ID for error flow (error edge at node level) */\n error_edge?: string;\n}\n\n/** Container rule for conditional execution */\nexport interface ContainerRule {\n /** Condition expression */\n condition: string;\n /** ID of next step if condition matches */\n next_step: string;\n}\n\n/**\n * Fan-out configuration for parallel containers.\n *\n * Without it, a parallel container's children ARE its branches - a fixed\n * set, all running at once. With it, the children form ONE branch subgraph\n * that runs once per item of a runtime collection, and the container joins\n * every one of those runs. That is what a per-item human task needs: one\n * task per row, then a real join.\n */\nexport interface FanOutConfig {\n /** Collection expression to fan out over, e.g. \"${steps.plan.items}\" */\n over: string;\n /** Safety cap on branches created (fan-out width comes from runtime data) */\n max_branches?: number;\n}\n\n/** How a parallel container joins its branches */\nexport type MergeStrategy = 'merge_all' | 'first_success' | 'all_success';\n\n/** Container node with children (AND/OR/Parallel/AI) */\nexport interface FlowDefinitionContainer extends FlowDefinitionNodeBase {\n node_type: 'raisin:FlowContainer';\n container_type: ContainerType;\n rules?: ContainerRule[];\n children: FlowDefinitionNode[];\n /** AI container configuration (only for ai_sequence type) */\n ai_config?: AiContainerConfig;\n /** Fan-out configuration (only for parallel type): one branch per collection item */\n fan_out?: FanOutConfig;\n /** How branches are joined (only for parallel type; default \"merge_all\") */\n merge_strategy?: MergeStrategy;\n /** Container timeout in milliseconds */\n timeout_ms?: number;\n}\n\n/** Union type for all flow definition nodes */\nexport type FlowDefinitionNode = FlowDefinitionStep | FlowDefinitionContainer;\n\n/** Complete flow definition (the `workflow_data` of a raisin:Flow node) */\nexport interface FlowDefinition {\n /** Schema version */\n version: number;\n /** Error handling strategy */\n error_strategy: FlowErrorStrategy;\n /** Global timeout in milliseconds */\n timeout_ms?: number;\n /** Root workflow nodes */\n nodes: FlowDefinitionNode[];\n}\n\n/** Type guard for FlowDefinitionStep */\nexport function isFlowDefinitionStep(\n node: FlowDefinitionNode,\n): node is FlowDefinitionStep {\n return node.node_type === 'raisin:FlowStep';\n}\n\n/** Type guard for FlowDefinitionContainer */\nexport function isFlowDefinitionContainer(\n node: FlowDefinitionNode,\n): node is FlowDefinitionContainer {\n return node.node_type === 'raisin:FlowContainer';\n}\n\n// ============================================================================\n// Inbox tasks (human-in-the-loop primitive)\n// ============================================================================\n\n/** Status of an inbox task */\nexport type InboxTaskStatus = 'pending' | 'completed' | 'expired' | 'cancelled';\n\n/**\n * An inbox task (`raisin:InboxTask` node) - created by human_task steps\n * (or `raisin.tasks.create` in functions) and completed by users or agents.\n */\nexport interface InboxTask {\n /** Node ID */\n id: string;\n /** Node path (under the assignee's inbox) */\n path: string;\n /** Task type */\n task_type: HumanTaskType;\n /** Task title */\n title: string;\n /** Task description */\n description?: string;\n /** Assignee path (user or agent) */\n assignee: string;\n /** Current status */\n status: InboxTaskStatus;\n /** Priority (1-5, where 5 is highest) */\n priority?: number;\n /** Options for approval tasks */\n options?: TaskOption[];\n /** JSON schema for input tasks */\n input_schema?: object;\n /** Owning flow instance (absent for standalone tasks) */\n flow_instance_id?: string;\n /** Step that created the task */\n step_id?: string;\n /** Creation timestamp (ISO 8601) */\n created_at?: string;\n /** Due timestamp (ISO 8601) */\n due_at?: string;\n /** The submitted response (when completed) */\n response?: Record<string, unknown>;\n /** Who completed the task (user id or agent path) */\n completed_by?: string;\n /** Completion timestamp (ISO 8601) */\n responded_at?: string;\n /** Set when an agent assignee escalated the task */\n escalated_from?: string;\n /** Why the task was escalated */\n escalation_reason?: string;\n}\n\n/** Result of completing an inbox task */\nexport interface TaskCompletionResult {\n task_id: string;\n task_path: string;\n status: string;\n /** Present when the completion resumed a waiting flow */\n flow?: {\n instance_id: string;\n job_id: string;\n };\n}\n","/**\n * Plan projection utility.\n *\n * Builds deterministic plan/task state from persisted chat messages.\n */\n\nimport type { ChatMessage } from '../types/chat';\n\nexport interface PlanProjectionTask {\n taskId?: string;\n title: string;\n status: string;\n description?: string;\n priority?: string;\n}\n\nexport interface PlanProjection {\n key: string;\n planPath?: string;\n planId?: string;\n title: string;\n status: string;\n requiresApproval: boolean;\n tasks: PlanProjectionTask[];\n sourceMessagePath?: string;\n updatedAt?: string;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nexport function parsePlanTasks(rawTasks: unknown): PlanProjectionTask[] {\n if (!Array.isArray(rawTasks)) return [];\n return rawTasks\n .map((rawTask, index) => {\n if (typeof rawTask === 'string') {\n return {\n title: rawTask,\n status: 'pending',\n } satisfies PlanProjectionTask;\n }\n const task = asRecord(rawTask);\n if (!task) return null;\n return {\n taskId: asString(task.task_id) ?? asString(task.id),\n title: asString(task.title) ?? `Task ${index + 1}`,\n status: asString(task.status) ?? 'pending',\n description: asString(task.description),\n priority: asString(task.priority),\n } satisfies PlanProjectionTask;\n })\n .filter((task): task is PlanProjectionTask => task !== null);\n}\n\nconst TERMINAL_TASK_STATUSES = new Set(['completed', 'cancelled']);\nconst TERMINAL_PLAN_STATUSES = new Set(['completed', 'failed', 'cancelled']);\n\n/**\n * Same race as upsertTask: an ai_task_update message carrying a stale\n * plan_status (e.g. \"in_progress\", computed before the final task's\n * completion count caught up) can be persisted and thus replayed here after\n * the message that actually reflects the terminal plan status. Guard it the\n * same way - never regress out of a terminal plan status.\n */\nfunction setPlanStatus(plan: PlanProjection, nextStatus: string | undefined): void {\n if (!nextStatus) return;\n if (TERMINAL_PLAN_STATUSES.has(plan.status) && !TERMINAL_PLAN_STATUSES.has(nextStatus)) {\n return;\n }\n plan.status = nextStatus;\n}\n\nexport function upsertTask(plan: PlanProjection, nextTask: PlanProjectionTask): void {\n const existingIndex = plan.tasks.findIndex((task) =>\n (nextTask.taskId && task.taskId === nextTask.taskId) ||\n (!nextTask.taskId && task.title === nextTask.title)\n );\n if (existingIndex === -1) {\n plan.tasks.push(nextTask);\n return;\n }\n const existing = plan.tasks[existingIndex];\n // Mirrors the server-side monotonic guard in update-task/index.js: tool\n // calls from one model turn can execute in parallel, so an ai_task_update\n // message for an earlier \"in_progress\" transition can be persisted (and\n // thus replayed here) after the \"completed\" message for the same task.\n // Never let that regress an already-terminal status.\n if (TERMINAL_TASK_STATUSES.has(existing.status) && !TERMINAL_TASK_STATUSES.has(nextTask.status)) {\n return;\n }\n plan.tasks[existingIndex] = {\n ...existing,\n ...nextTask,\n };\n}\n\nexport function ensurePlan(\n plans: Map<string, PlanProjection>,\n key: string,\n fallbackTitle: string,\n timestamp: string | undefined,\n): PlanProjection {\n const existing = plans.get(key);\n if (existing) {\n if (timestamp) existing.updatedAt = timestamp;\n return existing;\n }\n const created: PlanProjection = {\n key,\n title: fallbackTitle,\n status: 'pending_approval',\n requiresApproval: true,\n tasks: [],\n updatedAt: timestamp,\n };\n plans.set(key, created);\n return created;\n}\n\n/**\n * Build deterministic plan/task state from persisted chat messages.\n * Uses ai_plan as canonical plan source and ai_task_update for incremental task status changes.\n */\nexport function projectPlansFromMessages(messages: ChatMessage[]): PlanProjection[] {\n const ordered = [...messages].sort((a, b) => {\n const aTime = Date.parse(a.timestamp || '');\n const bTime = Date.parse(b.timestamp || '');\n return (Number.isNaN(aTime) ? 0 : aTime) - (Number.isNaN(bTime) ? 0 : bTime);\n });\n\n const plans = new Map<string, PlanProjection>();\n\n for (const message of ordered) {\n const timestamp = message.timestamp;\n const data = asRecord(message.data);\n\n if (message.messageType === 'ai_plan' && data) {\n const planPath = asString(data.plan_path);\n const planId = asString(data.plan_id);\n const key = planPath || planId || message.path || message.id || `plan:${timestamp}`;\n const plan = ensurePlan(\n plans,\n key,\n asString(data.title) || message.content || 'Plan',\n timestamp\n );\n\n plan.planPath = planPath ?? plan.planPath;\n plan.planId = planId ?? plan.planId;\n plan.title = asString(data.title) || plan.title;\n setPlanStatus(plan, asString(data.status));\n plan.requiresApproval = Boolean(data.requires_approval) || plan.status === 'pending_approval';\n plan.sourceMessagePath = message.path ?? plan.sourceMessagePath;\n\n const parsedTasks = parsePlanTasks(data.tasks);\n if (parsedTasks.length > 0) {\n plan.tasks = parsedTasks;\n }\n }\n\n if (message.messageType === 'ai_task_update' && data) {\n const planPath = asString(data.plan_path);\n const planId = asString(data.plan_id);\n const key = planPath || planId;\n if (!key) continue;\n\n const plan = ensurePlan(plans, key, 'Plan', timestamp);\n plan.planPath = planPath ?? plan.planPath;\n plan.planId = planId ?? plan.planId;\n setPlanStatus(plan, asString(data.plan_status));\n plan.requiresApproval = plan.status === 'pending_approval';\n\n const taskUpdate: PlanProjectionTask = {\n taskId: asString(data.task_id),\n title: asString(data.task_title) || asString(data.title) || 'Task',\n status: asString(data.status) || 'pending',\n };\n upsertTask(plan, taskUpdate);\n }\n\n if (Array.isArray(message.children)) {\n for (const child of message.children) {\n if (child.type !== 'plan') continue;\n const key = child.path || message.path || message.id || `plan-child:${child.id}:${timestamp}`;\n const plan = ensurePlan(plans, key, child.planTitle || message.content || 'Plan', timestamp);\n plan.title = child.planTitle || plan.title;\n plan.status = child.status || plan.status;\n plan.requiresApproval = plan.status === 'pending_approval';\n if (Array.isArray(child.tasks) && child.tasks.length > 0) {\n plan.tasks = child.tasks.map((task) => ({\n taskId: task.id,\n title: task.title,\n status: task.status,\n }));\n }\n }\n }\n }\n\n // Belt-and-suspenders: if every task landed in a terminal state but the\n // plan's own status field is stuck non-terminal (the same message-race\n // that setPlanStatus guards against can also leave it simply never\n // updated), derive completion from the tasks - mirrors the server's\n // auto-complete check in update-task/index.js's updatePlanProgress.\n for (const plan of plans.values()) {\n if (\n !TERMINAL_PLAN_STATUSES.has(plan.status) &&\n plan.tasks.length > 0 &&\n plan.tasks.every((task) => TERMINAL_TASK_STATUSES.has(task.status))\n ) {\n plan.status = 'completed';\n plan.requiresApproval = false;\n }\n }\n\n return [...plans.values()].sort((a, b) => {\n const aTime = Date.parse(a.updatedAt || '');\n const bTime = Date.parse(b.updatedAt || '');\n return (Number.isNaN(bTime) ? 0 : bTime) - (Number.isNaN(aTime) ? 0 : aTime);\n });\n}\n","/**\n * Framework-agnostic conversation store for RaisinDB.\n *\n * Manages the full conversation lifecycle: creating conversations, sending\n * messages, streaming responses, persistent SSE subscriptions, message\n * history, tool call tracking, and plan projection. Notifies subscribers\n * on every state change so UI frameworks (React, Svelte, Vue) can bind.\n *\n * @example Svelte 5:\n * ```typescript\n * const store = new ConversationStore({ database: db, conversationPath: '/...' });\n * let snapshot = $state(store.getSnapshot());\n * store.subscribe(s => { snapshot = s; });\n * ```\n *\n * @example React (via useConversation hook):\n * ```tsx\n * const chat = useConversation(React, { database: db, conversationPath: '/...' });\n * ```\n */\n\nimport type { ConversationManager, ConversationSubscription } from '../conversations';\nimport type { Database } from '../database';\nimport type { ChatMessage, ChatEvent, ChatLogEvent } from '../types/chat';\nimport { logger, getLogLevel, LogLevel } from '../logger';\nimport { projectPlansFromMessages, type PlanProjection } from '../utils/plan-projection';\nimport { isRecoveredDoneEvent } from '../utils/chat-events';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Info about an in-flight tool call */\nexport interface ToolCallInfo {\n id: string;\n functionName: string;\n arguments: unknown;\n status: 'running' | 'completed' | 'failed';\n result?: unknown;\n durationMs?: number;\n}\n\n/** Snapshot of the conversation store state */\nexport interface ConversationStoreSnapshot {\n /** The conversation object, if loaded */\n conversation: { conversationPath: string; type: string } | null;\n /** All messages in the conversation */\n messages: ChatMessage[];\n /** Whether the AI is currently generating a response */\n isStreaming: boolean;\n /** Whether the chat is waiting for user input */\n isWaiting: boolean;\n /** Accumulated text from the current streaming response */\n streamingText: string;\n /** Current error, if any */\n error: string | null;\n /** Tracks in-flight tool executions */\n activeToolCalls: ToolCallInfo[];\n /** Deterministic plan/task projection from persisted messages */\n plans: PlanProjection[];\n /** Whether messages are being loaded */\n isLoading: boolean;\n /** Path to the conversation node */\n conversationPath: string | null;\n}\n\n/** Options for creating a ConversationStore */\nexport interface ConversationStoreOptions {\n /** Pre-configured Database instance */\n database: Database;\n /** Resume an existing conversation */\n conversationPath?: string;\n /** Create a new conversation on first message */\n createOptions?: {\n participant: string;\n input?: Record<string, unknown>;\n };\n /** Callback for individual chat events */\n onEvent?: (event: ChatEvent) => void;\n /** Streaming inactivity timeout in ms (default: 120000). Auto-recovers when no SSE event arrives within this window. */\n streamingTimeoutMs?: number;\n /** Activity watchdog polling interval in ms (default: 30000). Periodically checks backend turn health while streaming. */\n watchdogIntervalMs?: number;\n}\n\ntype Subscriber = (snapshot: ConversationStoreSnapshot) => void;\n\n// ---------------------------------------------------------------------------\n// ConversationStore\n// ---------------------------------------------------------------------------\n\n/**\n * Framework-agnostic store managing a single conversation's state.\n *\n * Handles the full lifecycle: creating conversations, sending messages,\n * streaming responses, tool call tracking, plan projection, and deferred\n * message reload on turn completion.\n */\nexport class ConversationStore {\n private manager: ConversationManager;\n private subscribers = new Set<Subscriber>();\n private onEvent?: (event: ChatEvent) => void;\n private createOptions?: { participant: string; input?: Record<string, unknown> };\n\n // Persistent SSE subscription\n private subscription: ConversationSubscription | null = null;\n\n // Internal mutable state\n private _conversationPath: string | null;\n private _messages: ChatMessage[] = [];\n private _isStreaming = false;\n private _isWaiting = false;\n private _streamingText = '';\n private _error: string | null = null;\n private _activeToolCalls: ToolCallInfo[] = [];\n private _isLoading = false;\n private _conversationType: string | null = null;\n\n // Streaming timeout (Fix A)\n private _streamingTimeoutMs: number;\n private _streamingTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Activity watchdog (Fix B)\n private _watchdogIntervalMs: number;\n private _watchdogTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(options: ConversationStoreOptions) {\n this.manager = options.database.conversations;\n this._conversationPath = options.conversationPath ?? null;\n this.createOptions = options.createOptions;\n this.onEvent = options.onEvent;\n this._streamingTimeoutMs = options.streamingTimeoutMs ?? 120_000;\n this._watchdogIntervalMs = options.watchdogIntervalMs ?? 30_000;\n\n // Auto-subscribe to existing conversation\n if (this._conversationPath) {\n this.ensureSubscription();\n }\n }\n\n // ==========================================================================\n // Subscription\n // ==========================================================================\n\n /**\n * Subscribe to state changes.\n * Returns an unsubscribe function.\n */\n subscribe(callback: Subscriber): () => void {\n this.subscribers.add(callback);\n callback(this.getSnapshot());\n return () => { this.subscribers.delete(callback); };\n }\n\n /**\n * Get the current state snapshot.\n */\n getSnapshot(): ConversationStoreSnapshot {\n return {\n conversation: this._conversationPath\n ? { conversationPath: this._conversationPath, type: this._conversationType || 'ai_chat' }\n : null,\n messages: [...this._messages],\n isStreaming: this._isStreaming,\n isWaiting: this._isWaiting,\n streamingText: this._streamingText,\n error: this._error,\n activeToolCalls: [...this._activeToolCalls],\n plans: projectPlansFromMessages(this._messages),\n isLoading: this._isLoading,\n conversationPath: this._conversationPath,\n };\n }\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Send a user message and stream the AI response.\n *\n * If no conversation exists yet and `createOptions` was provided,\n * the conversation is created automatically on the first call.\n */\n async sendMessage(content: string): Promise<void> {\n if (this._isStreaming) {\n logger.warn('[ConversationStore] Cannot send message while streaming');\n return;\n }\n\n logger.info('[ConversationStore] Sending message', { path: this._conversationPath });\n this._error = null;\n\n // Create conversation if needed\n if (!this._conversationPath) {\n if (!this.createOptions) {\n throw new Error('No conversationPath and no createOptions provided');\n }\n try {\n const convo = await this.manager.create({\n participant: this.createOptions.participant,\n input: this.createOptions.input,\n });\n this._conversationPath = convo.conversationPath;\n this._conversationType = convo.type;\n\n for (const event of convo.initialEvents ?? []) {\n this.onEvent?.(event);\n this.handleEvent(event);\n }\n\n this.notify();\n } catch (err) {\n this._error = err instanceof Error ? err.message : String(err);\n this.notify();\n return;\n }\n }\n\n // Add user message optimistically\n const userMessage: ChatMessage = {\n role: 'user',\n content,\n timestamp: new Date().toISOString(),\n };\n this._messages.push(userMessage);\n\n // Start streaming\n this._isStreaming = true;\n this._isWaiting = false;\n this._streamingText = '';\n this._activeToolCalls = [];\n this.resetStreamingTimer();\n this.startWatchdog();\n this.notify();\n\n // Use persistent SSE subscription + create message node\n try {\n this.ensureSubscription();\n await this.subscription!.waitUntilConnected();\n await this.manager.createUserMessage(this._conversationPath!, content);\n // Events arrive via the persistent subscription → handleEvent\n } catch (err) {\n logger.error('[ConversationStore] Send failed', err);\n this._error = err instanceof Error ? err.message : String(err);\n this._isStreaming = false;\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n }\n }\n\n /**\n * Load messages from the persisted node tree.\n * Useful for loading history on page reload.\n */\n async loadMessages(): Promise<ChatMessage[]> {\n if (!this._conversationPath) return [];\n this._isLoading = true;\n this.notify();\n try {\n const messages = await this.manager.getMessages(this._conversationPath);\n logger.debug(`[ConversationStore] Loaded ${messages.length} messages`);\n if (messages.length > 0) {\n this._messages = messages;\n // Rebuild tool call state from messages\n this._activeToolCalls = [];\n }\n return messages;\n } finally {\n this._isLoading = false;\n this.notify();\n }\n }\n\n /**\n * Approve a pending plan.\n */\n async approvePlan(planPath: string): Promise<void> {\n await this.manager.approvePlan(planPath);\n }\n\n /**\n * Reject a pending plan.\n */\n async rejectPlan(planPath: string, feedback?: string): Promise<void> {\n await this.manager.rejectPlan(planPath, feedback);\n }\n\n /**\n * Mark a single message as read.\n */\n async markMessageAsRead(messagePath: string): Promise<void> {\n await this.manager.markMessageAsRead(messagePath);\n }\n\n /**\n * Stop the current streaming response.\n */\n stop(): void {\n this._isStreaming = false;\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n }\n\n /**\n * Clean up the store and release resources.\n */\n destroy(): void {\n this.stop();\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.subscription?.unsubscribe();\n this.subscription = null;\n this.subscribers.clear();\n }\n\n /**\n * Get the conversation path.\n */\n getConversationPath(): string | null {\n return this._conversationPath;\n }\n\n // ==========================================================================\n // Internal\n // ==========================================================================\n\n private ensureSubscription(): void {\n if (this.subscription) return;\n if (!this._conversationPath) return;\n\n this.subscription = this.manager.subscribe(\n this._conversationPath,\n (event) => {\n this.onEvent?.(event);\n this.handleEvent(event);\n },\n );\n }\n\n private handleEvent(event: ChatEvent): void {\n logger.debug('[ConversationStore] SSE:', event.type);\n // Every SSE event resets the streaming inactivity timer\n if (this._isStreaming) {\n this.resetStreamingTimer();\n }\n switch (event.type) {\n case 'text_chunk':\n this.markStreamingActivity();\n this._streamingText += event.text;\n this.notify();\n break;\n\n case 'thought_chunk':\n this.markStreamingActivity();\n this.notify();\n break;\n\n case 'assistant_message':\n this._messages.push(event.message);\n this._streamingText = '';\n this.notify();\n break;\n\n case 'tool_call_started': {\n this.markStreamingActivity();\n logger.debug('[ConversationStore] Tool started:', event.functionName);\n const info: ToolCallInfo = {\n id: event.toolCallId,\n functionName: event.functionName,\n arguments: event.arguments,\n status: 'running',\n };\n this._activeToolCalls.push(info);\n this.notify();\n break;\n }\n\n case 'tool_call_completed': {\n this.markStreamingActivity();\n logger.debug('[ConversationStore] Tool completed:', event.toolCallId);\n const idx = this._activeToolCalls.findIndex(tc => tc.id === event.toolCallId);\n if (idx >= 0) {\n this._activeToolCalls[idx] = {\n ...this._activeToolCalls[idx],\n status: event.error ? 'failed' : 'completed',\n result: event.result,\n durationMs: event.durationMs,\n };\n }\n this.notify();\n break;\n }\n\n case 'waiting': {\n logger.info('[ConversationStore] Waiting for input');\n this.flushStreamingText(event.timestamp);\n this._isStreaming = false;\n this._isWaiting = true;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n // Deferred reload: pick up canonical messages from node tree\n this.deferredReload();\n break;\n }\n\n case 'done': {\n if (isRecoveredDoneEvent(event)) {\n logger.debug('[ConversationStore] Ignoring recovered done event');\n this.reconcileRecoveredDone();\n break;\n }\n const doneEvent = event as import('../types/chat').ChatDoneEvent;\n if (doneEvent.dispatchPhase && doneEvent.dispatchPhase !== 'terminal') {\n logger.debug('[ConversationStore] Ignoring non-terminal done event');\n break;\n }\n logger.info('[ConversationStore] Turn done');\n this.flushStreamingText(event.timestamp);\n // Safety net: if streaming missed chunks, use the complete response from the event\n if (doneEvent.content && !this.lastMessageIsAssistant()) {\n this._messages.push({\n role: (doneEvent.role as ChatMessage['role']) || 'assistant',\n content: doneEvent.content,\n timestamp: event.timestamp,\n senderDisplayName: doneEvent.senderDisplayName,\n finishReason: doneEvent.finishReason,\n });\n }\n this._isStreaming = false;\n this._isWaiting = true;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n this.deferredReload();\n break;\n }\n\n case 'completed': {\n this.flushStreamingText(event.timestamp);\n if (event.messages && event.messages.length > 0) {\n this._messages = event.messages;\n }\n this._isStreaming = false;\n this._isWaiting = false;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n this.deferredReload();\n break;\n }\n\n case 'failed':\n logger.error('[ConversationStore] Turn failed', event.error);\n this._error = event.error;\n this._isStreaming = false;\n // A failed turn ends any waiting state too - otherwise UIs keyed on\n // isWaiting show a thinking indicator forever after a failure.\n this._isWaiting = false;\n this._streamingText = '';\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n break;\n\n case 'conversation_created':\n this._conversationPath = event.conversationPath;\n this.notify();\n break;\n\n case 'message_saved':\n // A message was persisted — reload to pick it up, then notify\n this.silentReload().catch(() => {});\n this.notify();\n break;\n\n case 'message_delivered':\n this._messages.push(event.message);\n this.notify();\n break;\n\n case 'log': {\n const logEvent = event as ChatLogEvent;\n const currentLevel = getLogLevel();\n const levelMap: Record<string, LogLevel> = {\n debug: LogLevel.Debug,\n info: LogLevel.Info,\n warn: LogLevel.Warn,\n error: LogLevel.Error,\n };\n const eventLevel = levelMap[logEvent.level] ?? LogLevel.Debug;\n if (currentLevel >= eventLevel) {\n const fn = logEvent.level === 'error' ? console.error\n : logEvent.level === 'warn' ? console.warn\n : logEvent.level === 'debug' ? console.debug\n : console.info;\n fn('[server]', logEvent.message);\n }\n break;\n }\n }\n }\n\n /**\n * Agent activity observed while the store thought the turn was over.\n *\n * This happens when execution continues WITHOUT a user message — plan\n * approval in approve_then_auto / step_by_step (approvePlan() returns an\n * enqueue receipt and the agent starts executing), or agent-initiated\n * follow-ups. The events arrive over the persistent live subscription\n * (no history replay), so activity is always \"now\": re-enter streaming\n * state so UIs show progress and the end-of-turn handling (done/waiting\n * → deferred reload) runs again for this continuation.\n */\n private markStreamingActivity(): void {\n if (this._isStreaming) return;\n logger.debug('[ConversationStore] Agent activity while idle — re-entering streaming state');\n this._isStreaming = true;\n this._isWaiting = false;\n this._streamingText = '';\n this.resetStreamingTimer();\n this.startWatchdog();\n }\n\n /**\n * If accumulated streaming text hasn't been captured in an assistant_message,\n * synthesize one.\n */\n private flushStreamingText(timestamp: string): void {\n if (this._streamingText && !this.lastMessageIsAssistant()) {\n this._messages.push({\n role: 'assistant',\n content: this._streamingText,\n timestamp,\n });\n }\n this._streamingText = '';\n }\n\n private lastMessageIsAssistant(): boolean {\n const last = this._messages[this._messages.length - 1];\n return last?.role === 'assistant';\n }\n\n /**\n * After a turn completes, reload canonical messages from the node tree\n * to catch any events missed during SSE gaps.\n */\n private deferredReload(): void {\n if (!this._conversationPath) return;\n logger.debug('[ConversationStore] Scheduling deferred reload');\n const attemptReload = (delay: number, retriesLeft: number) => {\n setTimeout(async () => {\n try {\n const prevCount = this._messages.length;\n await this.silentReload();\n // If no new messages appeared and retries remain, try again with exponential backoff\n if (this._messages.length === prevCount && retriesLeft > 0) {\n attemptReload(delay * 2, retriesLeft - 1);\n }\n } catch {}\n }, delay);\n };\n attemptReload(500, 2); // 500ms, 1000ms, 2000ms\n }\n\n private async silentReload(): Promise<void> {\n if (!this._conversationPath) return;\n try {\n const fresh = await this.manager.getMessages(this._conversationPath);\n if (fresh.length === 0) return;\n\n // Try incremental merge: match existing messages by role+content\n // to preserve object references (prevents Svelte DOM recreation)\n let matchCount = 0;\n const limit = Math.min(this._messages.length, fresh.length);\n for (let i = 0; i < limit; i++) {\n if (this._messages[i].role !== fresh[i].role ||\n this._messages[i].content !== fresh[i].content) break;\n matchCount++;\n }\n\n if (matchCount === this._messages.length && fresh.length === matchCount) {\n // Same content, possibly different metadata — update silently\n for (let i = 0; i < matchCount; i++) {\n const f = fresh[i];\n const e = this._messages[i];\n if (f.id) e.id = f.id;\n if (f.path) e.path = f.path;\n if (f.messageType) e.messageType = f.messageType;\n if (f.data) e.data = f.data;\n if (f.children) e.children = f.children;\n if (f.finishReason) e.finishReason = f.finishReason;\n }\n await this.rebuildToolCallState();\n return; // No visible change — don't notify\n }\n\n if (matchCount === this._messages.length && fresh.length > matchCount) {\n // Existing messages match prefix — append new ones\n for (let i = matchCount; i < fresh.length; i++) {\n this._messages.push(fresh[i]);\n }\n // Also update metadata on matched messages\n for (let i = 0; i < matchCount; i++) {\n const f = fresh[i];\n const e = this._messages[i];\n if (f.id) e.id = f.id;\n if (f.path) e.path = f.path;\n if (f.messageType) e.messageType = f.messageType;\n if (f.data) e.data = f.data;\n if (f.children) e.children = f.children;\n }\n await this.rebuildToolCallState();\n this.notify(); // New messages to show\n return;\n }\n\n // Fresh is a prefix subset — outbox delivery pending, keep extras\n if (matchCount === fresh.length && fresh.length < this._messages.length) {\n for (let i = 0; i < matchCount; i++) {\n const f = fresh[i];\n const e = this._messages[i];\n if (f.id) e.id = f.id;\n if (f.path) e.path = f.path;\n if (f.messageType) e.messageType = f.messageType;\n if (f.data) e.data = f.data;\n if (f.children) e.children = f.children;\n }\n await this.rebuildToolCallState();\n return; // Keep streaming-flushed extras — message_saved will trigger next reload\n }\n\n // Content mismatch — full replace\n this._messages = fresh;\n await this.rebuildToolCallState();\n this.notify();\n } catch (err) {\n logger.debug('[ConversationStore] Silent reload failed:', err);\n }\n }\n\n // ==========================================================================\n // Streaming timeout (Fix A) — auto-recover on SSE inactivity\n // ==========================================================================\n\n private resetStreamingTimer(): void {\n this.clearStreamingTimer();\n if (!this._isStreaming) return;\n this._streamingTimer = setTimeout(() => {\n if (this._isStreaming) {\n logger.warn('[ConversationStore] Streaming timeout — no SSE activity for', this._streamingTimeoutMs, 'ms');\n this.recoverFromHang();\n }\n }, this._streamingTimeoutMs);\n }\n\n private clearStreamingTimer(): void {\n if (this._streamingTimer) {\n clearTimeout(this._streamingTimer);\n this._streamingTimer = null;\n }\n }\n\n // ==========================================================================\n // Activity watchdog (Fix B) — periodic backend health check\n // ==========================================================================\n\n private startWatchdog(): void {\n this.stopWatchdog();\n if (!this._conversationPath) return;\n this._watchdogTimer = setInterval(async () => {\n if (!this._isStreaming || !this._conversationPath) {\n this.stopWatchdog();\n return;\n }\n try {\n const health = await this.manager.checkTurnHealth(this._conversationPath);\n if (health === 'done' && this._isStreaming) {\n logger.warn('[ConversationStore] Watchdog detected completed turn while still streaming — recovering');\n this.recoverFromHang();\n }\n } catch {\n // Ignore watchdog errors — it's a best-effort check\n }\n }, this._watchdogIntervalMs);\n }\n\n private stopWatchdog(): void {\n if (this._watchdogTimer) {\n clearInterval(this._watchdogTimer);\n this._watchdogTimer = null;\n }\n }\n\n // ==========================================================================\n // Hang recovery (shared by timeout + watchdog)\n // ==========================================================================\n\n private recoverFromHang(): void {\n logger.info('[ConversationStore] Recovering from hang');\n this.clearStreamingTimer();\n this.stopWatchdog();\n this._isStreaming = false;\n this._isWaiting = true;\n this._streamingText = '';\n this.notify();\n // Reload to pick up any persisted state we missed\n this.silentReload().catch(() => {});\n }\n\n /**\n * Reconcile a recovered done event against persisted state.\n * If the backend turn is actually complete, finalize the local state.\n * Otherwise keep streaming active and let normal events continue.\n */\n private reconcileRecoveredDone(): void {\n if (!this._conversationPath) return;\n void this.manager.checkTurnHealth(this._conversationPath).then((health) => {\n if (health !== 'done') return;\n if (!this._isStreaming) return;\n this._isStreaming = false;\n this._isWaiting = true;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n this.deferredReload();\n }).catch(() => {\n // Best effort only; streaming watchdog still protects against hangs.\n });\n }\n\n // ==========================================================================\n // Tool call state rebuild (Fix C) — reconstruct from node tree on reload\n // ==========================================================================\n\n private async rebuildToolCallState(): Promise<void> {\n if (!this._conversationPath) {\n this._activeToolCalls = [];\n return;\n }\n try {\n const pendingCalls = await this.manager.getActiveToolCalls(this._conversationPath);\n if (pendingCalls.length > 0) {\n this._activeToolCalls = pendingCalls.map(tc => ({\n id: tc.id,\n functionName: tc.name,\n arguments: undefined,\n status: 'running' as const,\n }));\n // Keep streaming active if there are pending tool calls\n if (!this._isStreaming) {\n this._isStreaming = true;\n this.resetStreamingTimer();\n this.startWatchdog();\n }\n } else {\n this._activeToolCalls = [];\n // No pending tools — check if we should clear streaming\n if (this._isStreaming) {\n const lastMsg = this._messages[this._messages.length - 1];\n const isLastAssistantDone = lastMsg?.role === 'assistant' &&\n (lastMsg.dispatchPhase\n ? lastMsg.dispatchPhase === 'terminal'\n : (!!lastMsg.finishReason && lastMsg.finishReason !== 'tool_calls'));\n if (isLastAssistantDone) {\n this._isStreaming = false;\n this._isWaiting = true;\n this.clearStreamingTimer();\n this.stopWatchdog();\n }\n }\n }\n } catch {\n this._activeToolCalls = [];\n }\n }\n\n private notify(): void {\n const snapshot = this.getSnapshot();\n for (const sub of this.subscribers) {\n try { sub(snapshot); }\n catch (err) { logger.error('Error in conversation store subscriber:', err); }\n }\n }\n}\n","/**\n * Multi-conversation list store for RaisinDB.\n *\n * Manages the list of conversations: loading, creating, deleting, marking\n * as read, and optional real-time updates via WebSocket events.\n *\n * Provides a factory (`getConversationStore`) that returns cached\n * per-conversation `ConversationStore` instances.\n *\n * @example Svelte 5:\n * ```typescript\n * const listStore = new ConversationListStore({ database: db, realtime: true });\n * let snapshot = $state(listStore.getSnapshot());\n * listStore.subscribe(s => { snapshot = s; });\n * await listStore.load();\n * ```\n */\n\nimport type { Database } from '../database';\nimport type { ConversationType, ConversationListItem } from '../types/chat';\nimport { ConversationStore, type ConversationStoreOptions } from './conversation-store';\nimport { logger } from '../logger';\nimport { normalizeHomePath } from '../utils/home-path';\n\n/**\n * Build the realtime subscription filters for a user's chats folder.\n *\n * The server matches subscription paths literally with glob semantics:\n * `*` matches exactly one path segment, `**` matches recursively, and there\n * is NO implicit prefix matching — a plain path only matches that exact\n * node. To observe conversations created/updated under the chats folder we\n * therefore need the recursive `/**` suffix.\n *\n * Exported for testing.\n * @internal\n */\nexport function buildChatsSubscriptionFilters(userHome: string): {\n workspace: string;\n path: string;\n event_types: string[];\n} {\n const home = normalizeHomePath(userHome) ?? userHome;\n return {\n workspace: 'raisin:access_control',\n path: `${home}/inbox/chats/**`,\n event_types: ['node:created', 'node:updated'],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Snapshot of the conversation list state */\nexport interface ConversationListSnapshot {\n conversations: ConversationListItem[];\n totalUnreadCount: number;\n isLoading: boolean;\n error: string | null;\n}\n\n/** Options for creating a ConversationListStore */\nexport interface ConversationListStoreOptions {\n database: Database;\n /** Filter by conversation type */\n type?: ConversationType;\n /** Subscribe to WebSocket events for new conversations */\n realtime?: boolean;\n}\n\ntype Subscriber = (snapshot: ConversationListSnapshot) => void;\n\n// ---------------------------------------------------------------------------\n// ConversationListStore\n// ---------------------------------------------------------------------------\n\nexport class ConversationListStore {\n private database: Database;\n private type?: ConversationType;\n private realtime: boolean;\n private subscribers = new Set<Subscriber>();\n\n // Internal state\n private _conversations: ConversationListItem[] = [];\n private _isLoading = false;\n private _error: string | null = null;\n\n // Cached ConversationStore instances\n private _stores = new Map<string, ConversationStore>();\n\n // Real-time subscription\n private _realtimeSubscription: { unsubscribe: () => void } | null = null;\n\n constructor(options: ConversationListStoreOptions) {\n this.database = options.database;\n this.type = options.type;\n this.realtime = options.realtime ?? false;\n }\n\n // ==========================================================================\n // Subscription\n // ==========================================================================\n\n subscribe(callback: Subscriber): () => void {\n this.subscribers.add(callback);\n callback(this.getSnapshot());\n return () => { this.subscribers.delete(callback); };\n }\n\n getSnapshot(): ConversationListSnapshot {\n return {\n conversations: [...this._conversations],\n totalUnreadCount: this._conversations.reduce((sum, c) => sum + (c.unreadCount ?? 0), 0),\n isLoading: this._isLoading,\n error: this._error,\n };\n }\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Load conversations from the server.\n */\n async load(): Promise<void> {\n this._isLoading = true;\n this._error = null;\n this.notify();\n\n try {\n const conversations = await this.database.conversations.list({\n type: this.type,\n });\n logger.debug(`[ConversationListStore] Loaded ${conversations.length} conversations`);\n this._conversations = conversations;\n\n if (this.realtime) {\n this.startRealtimeSubscription();\n }\n } catch (err) {\n logger.error('[ConversationListStore] Failed to load conversations', err);\n this._error = err instanceof Error ? err.message : String(err);\n } finally {\n this._isLoading = false;\n this.notify();\n }\n }\n\n /**\n * Create a new conversation.\n */\n async createConversation(options: {\n participant: string;\n subject?: string;\n input?: Record<string, unknown>;\n }): Promise<ConversationListItem> {\n const convo = await this.database.conversations.create(options);\n\n const listItem: ConversationListItem = {\n id: convo.id,\n type: convo.type,\n conversationPath: convo.conversationPath,\n conversationWorkspace: convo.conversationWorkspace,\n agentRef: convo.agentRef,\n participants: convo.participants,\n unreadCount: 0,\n updatedAt: new Date().toISOString(),\n };\n\n this._conversations = [listItem, ...this._conversations];\n this.notify();\n return listItem;\n }\n\n /**\n * Delete a conversation.\n */\n async deleteConversation(conversationPath: string): Promise<void> {\n // Destroy cached store\n const store = this._stores.get(conversationPath);\n if (store) {\n store.destroy();\n this._stores.delete(conversationPath);\n }\n\n await this.database.conversations.delete(conversationPath);\n this._conversations = this._conversations.filter(c => c.conversationPath !== conversationPath);\n this.notify();\n }\n\n /**\n * Mark a conversation as read.\n */\n async markAsRead(conversationPath: string): Promise<void> {\n await this.database.conversations.markAsRead(conversationPath);\n this._conversations = this._conversations.map(c =>\n c.conversationPath === conversationPath ? { ...c, unreadCount: 0 } : c\n );\n this.notify();\n }\n\n /**\n * Get or create a ConversationStore for a specific conversation.\n * Caches instances so repeated calls return the same store.\n */\n getConversationStore(\n conversationPath: string,\n overrides?: Partial<ConversationStoreOptions>,\n ): ConversationStore {\n let store = this._stores.get(conversationPath);\n if (!store) {\n store = new ConversationStore({\n database: this.database,\n conversationPath,\n ...overrides,\n });\n this._stores.set(conversationPath, store);\n }\n return store;\n }\n\n /**\n * Clean up all resources.\n */\n destroy(): void {\n this._realtimeSubscription?.unsubscribe();\n this._realtimeSubscription = null;\n\n for (const store of this._stores.values()) {\n store.destroy();\n }\n this._stores.clear();\n this.subscribers.clear();\n }\n\n // ==========================================================================\n // Internal\n // ==========================================================================\n\n private async startRealtimeSubscription(): Promise<void> {\n if (this._realtimeSubscription) return;\n logger.debug('[ConversationListStore] Starting realtime subscription');\n\n try {\n const workspace = this.database.workspace('raisin:access_control');\n const events = workspace.events();\n\n // We need the user home path to subscribe to the right folder\n const result = await this.database.executeSql(\n `SELECT RAISIN_CURRENT_USER()->>'path'::String as home`,\n );\n const rows = result.rows as unknown as Record<string, unknown>[];\n const userHome = rows?.[0]?.home as string;\n if (!userHome) return;\n\n this._realtimeSubscription = await events.subscribe(\n buildChatsSubscriptionFilters(userHome),\n async (event) => {\n const eventData = event as any;\n const nodeId = eventData.payload?.node_id;\n if (!nodeId) return;\n\n try {\n const nodeResult = await this.database.executeSql(\n `SELECT id, path, node_type, properties, created_at, updated_at FROM 'raisin:access_control' WHERE id = $1 LIMIT 1`,\n [nodeId],\n );\n const row = (nodeResult.rows as unknown as Record<string, unknown>[])?.[0];\n if (!row || row.node_type !== 'raisin:Conversation') return;\n\n const convPath = row.path as string;\n const props = (row.properties ?? {}) as Record<string, unknown>;\n const item: ConversationListItem = {\n id: row.id as string,\n type: (props.conversation_type as ConversationType) ?? 'ai_chat',\n conversationPath: convPath,\n conversationWorkspace: 'raisin:access_control',\n agentRef: props.agent_ref as string | undefined,\n participants: props.participants as string[] | undefined,\n unreadCount: (props.unread_count as number) ?? 0,\n lastMessage: props.last_message as { content: string; sender_id: string; created_at: string } | undefined,\n updatedAt: (row.updated_at ?? row.created_at) as string,\n };\n\n const existingIdx = this._conversations.findIndex(c => c.conversationPath === convPath);\n if (existingIdx >= 0) {\n // Update existing conversation and move to top\n this._conversations.splice(existingIdx, 1);\n }\n this._conversations = [item, ...this._conversations];\n this.notify();\n } catch (err) {\n logger.debug('Failed to process conversation event:', err);\n }\n },\n );\n } catch (err) {\n logger.debug('Failed to start realtime subscription:', err);\n }\n }\n\n private notify(): void {\n const snapshot = this.getSnapshot();\n for (const sub of this.subscribers) {\n try { sub(snapshot); }\n catch (err) { logger.error('Error in conversation list store subscriber:', err); }\n }\n }\n}\n","/**\n * React adapters for the RaisinDB conversation stores.\n *\n * Since the SDK does not depend on React, the hooks accept React as a\n * parameter to avoid a hard dependency while providing full type safety.\n *\n * @example\n * ```tsx\n * import React from 'react';\n * import { useConversation, useConversationList } from '@raisindb/client';\n *\n * function Chat() {\n * const chat = useConversation(React, {\n * database: db,\n * conversationPath: '/...',\n * });\n * return (\n * <div>\n * {chat.messages.map((m, i) => <div key={i}>{m.content}</div>)}\n * {chat.isStreaming && <p>{chat.streamingText}</p>}\n * </div>\n * );\n * }\n * ```\n */\n\nimport {\n ConversationStore,\n type ConversationStoreOptions,\n type ConversationStoreSnapshot,\n} from '../stores/conversation-store';\nimport {\n ConversationListStore,\n type ConversationListStoreOptions,\n type ConversationListSnapshot,\n} from '../stores/conversation-list-store';\nimport type { ChatMessage, ConversationListItem } from '../types/chat';\n\n/** Minimal subset of the React API needed by the hooks */\nexport interface ReactLike {\n useState<T>(initial: T | (() => T)): [T, (value: T | ((prev: T) => T)) => void];\n useEffect(effect: () => void | (() => void), deps?: unknown[]): void;\n useRef<T>(initial: T): { current: T };\n useCallback<T extends (...args: never[]) => unknown>(fn: T, deps: unknown[]): T;\n}\n\n// ---------------------------------------------------------------------------\n// useConversation\n// ---------------------------------------------------------------------------\n\nconst INITIAL_SNAPSHOT: ConversationStoreSnapshot = {\n conversation: null,\n messages: [],\n isStreaming: false,\n isWaiting: false,\n streamingText: '',\n error: null,\n activeToolCalls: [],\n plans: [],\n isLoading: false,\n conversationPath: null,\n};\n\nexport interface UseConversationReturn extends ConversationStoreSnapshot {\n sendMessage: (content: string) => Promise<void>;\n approvePlan: (planPath: string) => Promise<void>;\n rejectPlan: (planPath: string, feedback?: string) => Promise<void>;\n stop: () => void;\n loadMessages: () => Promise<ChatMessage[]>;\n}\n\nexport function useConversation(\n react: ReactLike,\n options: ConversationStoreOptions,\n): UseConversationReturn {\n const { useState, useEffect, useRef, useCallback } = react;\n\n const [snapshot, setSnapshot] = useState<ConversationStoreSnapshot>(INITIAL_SNAPSHOT);\n const storeRef = useRef<ConversationStore | null>(null);\n\n useEffect(() => {\n const store = new ConversationStore(options);\n storeRef.current = store;\n\n const unsubscribe = store.subscribe((next) => setSnapshot(next));\n\n return () => {\n unsubscribe();\n store.destroy();\n storeRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.conversationPath]);\n\n const sendMessage = useCallback(async (content: string) => {\n await storeRef.current?.sendMessage(content);\n }, []);\n\n const approvePlan = useCallback(async (planPath: string) => {\n await storeRef.current?.approvePlan(planPath);\n }, []);\n\n const rejectPlan = useCallback(async (planPath: string, feedback?: string) => {\n await storeRef.current?.rejectPlan(planPath, feedback);\n }, []);\n\n const stop = useCallback(() => { storeRef.current?.stop(); }, []);\n\n const loadMessages = useCallback(async () => {\n return (await storeRef.current?.loadMessages()) ?? [];\n }, []);\n\n return {\n ...snapshot,\n sendMessage,\n approvePlan,\n rejectPlan,\n stop,\n loadMessages,\n };\n}\n\n// ---------------------------------------------------------------------------\n// useConversationList\n// ---------------------------------------------------------------------------\n\n// isLoading starts TRUE: the hook always calls store.load() in its mount\n// effect, but the first render happens before that effect runs — reporting\n// \"not loading\" there makes consumers mis-resolve an empty list as \"loaded,\n// no conversations\" (e.g. failing to resume the latest conversation).\nconst INITIAL_LIST_SNAPSHOT: ConversationListSnapshot = {\n conversations: [],\n totalUnreadCount: 0,\n isLoading: true,\n error: null,\n};\n\nexport interface UseConversationListReturn extends ConversationListSnapshot {\n createConversation: (options: { participant: string; subject?: string }) => Promise<ConversationListItem>;\n deleteConversation: (conversationPath: string) => Promise<void>;\n markAsRead: (conversationPath: string) => Promise<void>;\n}\n\nexport function useConversationList(\n react: ReactLike,\n options: ConversationListStoreOptions,\n): UseConversationListReturn {\n const { useState, useEffect, useRef, useCallback } = react;\n\n const [snapshot, setSnapshot] = useState<ConversationListSnapshot>(INITIAL_LIST_SNAPSHOT);\n const storeRef = useRef<ConversationListStore | null>(null);\n\n useEffect(() => {\n const store = new ConversationListStore(options);\n storeRef.current = store;\n\n const unsubscribe = store.subscribe((next) => setSnapshot(next));\n store.load();\n\n return () => {\n unsubscribe();\n store.destroy();\n storeRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.type, options.realtime]);\n\n const createConversation = useCallback(async (opts: { participant: string; subject?: string }) => {\n return storeRef.current!.createConversation(opts);\n }, []);\n\n const deleteConversation = useCallback(async (conversationPath: string) => {\n await storeRef.current?.deleteConversation(conversationPath);\n }, []);\n\n const markAsRead = useCallback(async (conversationPath: string) => {\n await storeRef.current?.markAsRead(conversationPath);\n }, []);\n\n return {\n ...snapshot,\n createConversation,\n deleteConversation,\n markAsRead,\n };\n}\n","/**\n * Svelte 5 helpers for RaisinDB conversation stores.\n *\n * Unlike the React integration which provides hooks, the Svelte 5 integration\n * provides factory functions that return objects designed to work seamlessly\n * with Svelte 5 runes. Use these in `.svelte.ts` files with `$state`.\n *\n * The SDK stores (ConversationStore, ConversationListStore) already have a\n * `.subscribe(callback)` API compatible with Svelte's reactivity. These\n * helpers simplify the most common patterns.\n *\n * @example Svelte 5 runes (in .svelte.ts file):\n * ```typescript\n * // stores/chat.svelte.ts\n * import { ConversationStore, type ConversationStoreSnapshot, type Database } from '@raisindb/client';\n *\n * class ChatState {\n * snapshot = $state<ConversationStoreSnapshot | null>(null);\n * #store: ConversationStore | null = null;\n * #unsub: (() => void) | null = null;\n *\n * get messages() { return this.snapshot?.messages ?? []; }\n * get isStreaming() { return this.snapshot?.isStreaming ?? false; }\n * get streamingText() { return this.snapshot?.streamingText ?? ''; }\n * get plans() { return this.snapshot?.plans ?? []; }\n * get error() { return this.snapshot?.error ?? null; }\n *\n * async open(db: Database, path: string) {\n * this.close();\n * this.#store = new ConversationStore({ database: db, conversationPath: path });\n * this.#unsub = this.#store.subscribe(s => { this.snapshot = s; });\n * await this.#store.loadMessages();\n * }\n *\n * sendMessage = async (content: string) => {\n * await this.#store?.sendMessage(content);\n * };\n *\n * close() {\n * this.#unsub?.();\n * this.#store?.destroy();\n * this.#store = null;\n * this.snapshot = null;\n * }\n * }\n *\n * export const chat = new ChatState();\n * ```\n *\n * @example In a .svelte component:\n * ```svelte\n * <script>\n * import { chat } from '$lib/stores/chat.svelte';\n *\n * // Properties are reactive — no $ prefix needed\n * const messages = $derived(chat.messages);\n * </script>\n *\n * {#each messages as msg}\n * <div>{msg.content}</div>\n * {/each}\n * {#if chat.isStreaming}\n * <p class=\"streaming\">{chat.streamingText}</p>\n * {/if}\n * ```\n *\n * @module\n */\n\nimport {\n ConversationStore,\n type ConversationStoreOptions,\n type ConversationStoreSnapshot,\n} from '../stores/conversation-store';\nimport {\n ConversationListStore,\n type ConversationListStoreOptions,\n type ConversationListSnapshot,\n} from '../stores/conversation-list-store';\n\n/**\n * Create a conversation store adapter for Svelte 5.\n *\n * Returns an object with the store, a snapshot getter, actions, and a\n * destroy function. In a `.svelte.ts` file, bind `snapshot` to `$state`\n * to get fine-grained reactivity.\n *\n * @example\n * ```typescript\n * const adapter = createConversationAdapter({ database: db, conversationPath: path });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n * // ...later\n * adapter.destroy();\n * ```\n */\nexport function createConversationAdapter(options: ConversationStoreOptions) {\n const store = new ConversationStore(options);\n\n return {\n /** The underlying ConversationStore instance */\n store,\n\n /** Get the current snapshot */\n getSnapshot: (): ConversationStoreSnapshot => store.getSnapshot(),\n\n /** Subscribe to snapshot changes. Returns unsubscribe function. */\n subscribe: (cb: (s: ConversationStoreSnapshot) => void) => store.subscribe(cb),\n\n /** Send a user message */\n sendMessage: (content: string) => store.sendMessage(content),\n\n /** Load persisted messages */\n loadMessages: () => store.loadMessages(),\n\n /** Approve a pending plan */\n approvePlan: (planPath: string) => store.approvePlan(planPath),\n\n /** Reject a pending plan */\n rejectPlan: (planPath: string, feedback?: string) => store.rejectPlan(planPath, feedback),\n\n /** Mark a message as read */\n markMessageAsRead: (messagePath: string) => store.markMessageAsRead(messagePath),\n\n /** Stop streaming */\n stop: () => store.stop(),\n\n /** Get the conversation path */\n getConversationPath: () => store.getConversationPath(),\n\n /** Destroy the store and release resources */\n destroy: () => store.destroy(),\n };\n}\n\n/**\n * Create a conversation list store adapter for Svelte 5.\n *\n * @example\n * ```typescript\n * const adapter = createConversationListAdapter({ database: db, realtime: true });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n * await adapter.load();\n * ```\n */\nexport function createConversationListAdapter(options: ConversationListStoreOptions) {\n const store = new ConversationListStore(options);\n\n return {\n /** The underlying ConversationListStore instance */\n store,\n\n /** Get the current snapshot */\n getSnapshot: (): ConversationListSnapshot => store.getSnapshot(),\n\n /** Subscribe to snapshot changes. Returns unsubscribe function. */\n subscribe: (cb: (s: ConversationListSnapshot) => void) => store.subscribe(cb),\n\n /** Load conversations from the server */\n load: () => store.load(),\n\n /** Create a new conversation */\n createConversation: (opts: { participant: string; subject?: string; input?: Record<string, unknown> }) =>\n store.createConversation(opts),\n\n /** Delete a conversation */\n deleteConversation: (path: string) => store.deleteConversation(path),\n\n /** Mark a conversation as read */\n markAsRead: (path: string) => store.markAsRead(path),\n\n /** Get or create a ConversationStore for a specific path */\n getConversationStore: (path: string) => store.getConversationStore(path),\n\n /** Destroy the store and release resources */\n destroy: () => store.destroy(),\n };\n}\n","import type { RaisinClient } from '../../client';\nimport type { IdentityUser } from '../../auth';\n\nexport interface AuthSnapshot {\n user: IdentityUser | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n}\n\nexport interface AuthAdapter {\n subscribe: (cb: (snapshot: AuthSnapshot) => void) => () => void;\n getSnapshot: () => AuthSnapshot;\n login: (email: string, password: string, repository: string) => Promise<IdentityUser>;\n register: (email: string, password: string, repository: string, displayName?: string) => Promise<IdentityUser>;\n logout: (options?: { disconnect?: boolean; reconnect?: boolean }) => Promise<void>;\n initSession: (repository: string) => Promise<IdentityUser | null>;\n destroy: () => void;\n}\n\n/**\n * Create an auth adapter for Svelte 5.\n *\n * Returns a plain object with `subscribe`, `getSnapshot`, auth actions, and `destroy`.\n * Bind `getSnapshot()` to `$state` in a `.svelte.ts` file for reactivity.\n *\n * @example\n * ```typescript\n * // lib/auth.svelte.ts\n * import { createAuthAdapter } from '@raisindb/client/svelte';\n * import { client } from '$lib/raisin';\n *\n * const adapter = createAuthAdapter(client);\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const auth = {\n * get user() { return snapshot.user; },\n * get isAuthenticated() { return snapshot.isAuthenticated; },\n * get isLoading() { return snapshot.isLoading; },\n * login: adapter.login,\n * register: adapter.register,\n * logout: adapter.logout,\n * initSession: adapter.initSession,\n * };\n * ```\n */\nexport function createAuthAdapter(client: RaisinClient): AuthAdapter {\n let snapshot: AuthSnapshot = {\n user: client.getStoredUser(),\n isAuthenticated: client.getStoredUser() !== null,\n isLoading: false,\n };\n\n const listeners = new Set<(s: AuthSnapshot) => void>();\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n function update(partial: Partial<AuthSnapshot>) {\n snapshot = { ...snapshot, ...partial };\n emit();\n }\n\n const unsubAuth = client.onAuthStateChange(({ event, session }) => {\n if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED' || event === 'USER_UPDATED') {\n update({ user: session.user, isAuthenticated: true });\n } else if (event === 'SIGNED_OUT' || event === 'SESSION_EXPIRED') {\n update({ user: null, isAuthenticated: false });\n }\n });\n\n const unsubUser = client.onUserChange(({ node }) => {\n if (!snapshot.user) return;\n update({\n user: {\n ...snapshot.user,\n home: node.path,\n displayName: (node.properties.display_name as string) ?? snapshot.user.displayName,\n avatarUrl: (node.properties.avatar_url as string) ?? snapshot.user.avatarUrl,\n },\n });\n });\n\n return {\n subscribe(cb: (s: AuthSnapshot) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n\n async login(email: string, password: string, repository: string) {\n update({ isLoading: true });\n try {\n return await client.loginWithEmail(email, password, repository);\n } finally {\n update({ isLoading: false });\n }\n },\n\n async register(email: string, password: string, repository: string, displayName?: string) {\n update({ isLoading: true });\n try {\n return await client.registerWithEmail(email, password, repository, displayName);\n } finally {\n update({ isLoading: false });\n }\n },\n\n async logout(options?: { disconnect?: boolean; reconnect?: boolean }) {\n update({ isLoading: true });\n try {\n await client.logout(options);\n } finally {\n update({ isLoading: false });\n }\n },\n\n async initSession(repository: string) {\n update({ isLoading: true });\n try {\n return await client.initSession(repository);\n } finally {\n update({ isLoading: false });\n }\n },\n\n destroy() {\n unsubAuth();\n unsubUser();\n listeners.clear();\n },\n };\n}\n","import type { RaisinClient } from '../../client';\nimport { ConnectionState } from '../../connection';\n\nexport interface ConnectionSnapshot {\n state: ConnectionState;\n isConnected: boolean;\n isReady: boolean;\n}\n\nexport interface ConnectionAdapter {\n subscribe: (cb: (snapshot: ConnectionSnapshot) => void) => () => void;\n getSnapshot: () => ConnectionSnapshot;\n connect: () => Promise<void>;\n disconnect: () => void;\n destroy: () => void;\n}\n\n/**\n * Create a connection adapter for Svelte 5.\n *\n * Tracks WebSocket connection state and ready state. Bind to `$state` in\n * a `.svelte.ts` file for reactivity.\n *\n * @example\n * ```typescript\n * // lib/connection.svelte.ts\n * import { createConnectionAdapter } from '@raisindb/client/svelte';\n * import { client } from '$lib/raisin';\n *\n * const adapter = createConnectionAdapter(client);\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const connection = {\n * get state() { return snapshot.state; },\n * get isConnected() { return snapshot.isConnected; },\n * get isReady() { return snapshot.isReady; },\n * connect: adapter.connect,\n * disconnect: adapter.disconnect,\n * };\n * ```\n */\nexport function createConnectionAdapter(client: RaisinClient): ConnectionAdapter {\n let snapshot: ConnectionSnapshot = {\n state: client.getConnectionState(),\n isConnected: client.getConnectionState() === ConnectionState.Connected,\n isReady: client.isReady(),\n };\n\n const listeners = new Set<(s: ConnectionSnapshot) => void>();\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n const unsubConn = client.onConnectionStateChange((newState) => {\n snapshot = {\n state: newState,\n isConnected: newState === ConnectionState.Connected,\n isReady: snapshot.isReady,\n };\n emit();\n });\n\n const unsubReady = client.onReadyStateChange((ready) => {\n snapshot = { ...snapshot, isReady: ready };\n emit();\n });\n\n return {\n subscribe(cb: (s: ConnectionSnapshot) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n\n async connect() {\n await client.connect();\n },\n\n disconnect() {\n client.disconnect();\n },\n\n destroy() {\n unsubConn();\n unsubReady();\n listeners.clear();\n },\n };\n}\n","import type { Database } from '../../database';\nimport type { SqlResult } from '../../protocol';\n\nexport interface SqlAdapterOptions {\n enabled?: boolean;\n refetchOnReconnect?: boolean;\n realtime?: {\n workspace: string;\n eventTypes?: string[];\n path?: string;\n nodeType?: string;\n };\n}\n\nexport interface SqlSnapshot<T> {\n data: T[] | null;\n isLoading: boolean;\n error: Error | null;\n}\n\nexport interface SqlAdapter<T> {\n subscribe: (cb: (snapshot: SqlSnapshot<T>) => void) => () => void;\n getSnapshot: () => SqlSnapshot<T>;\n refetch: () => Promise<void>;\n destroy: () => void;\n}\n\nfunction rowsToObjects<T>(result: SqlResult): T[] {\n return result.rows as T[];\n}\n\n/**\n * Create a SQL query adapter for Svelte 5.\n *\n * Executes a SQL query and maintains reactive snapshot state. Supports\n * realtime subscriptions and automatic refetch on reconnect.\n *\n * @example\n * ```typescript\n * // lib/posts.svelte.ts\n * import { createSqlAdapter } from '@raisindb/client/svelte';\n * import { db } from '$lib/raisin';\n *\n * const adapter = createSqlAdapter<{ title: string }>(db, \"SELECT * FROM 'content'\", [], {\n * realtime: { workspace: 'content' },\n * });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const posts = {\n * get data() { return snapshot.data; },\n * get isLoading() { return snapshot.isLoading; },\n * get error() { return snapshot.error; },\n * refetch: adapter.refetch,\n * };\n * ```\n */\nexport function createSqlAdapter<T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n): SqlAdapter<T> {\n let snapshot: SqlSnapshot<T> = {\n data: null,\n isLoading: false,\n error: null,\n };\n\n const listeners = new Set<(s: SqlSnapshot<T>) => void>();\n let destroyed = false;\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n function update(partial: Partial<SqlSnapshot<T>>) {\n snapshot = { ...snapshot, ...partial };\n emit();\n }\n\n async function fetchData() {\n if (destroyed) return;\n update({ isLoading: true, error: null });\n try {\n const result = await database.executeSql(sql, params);\n if (!destroyed) {\n update({ data: rowsToObjects<T>(result), isLoading: false });\n }\n } catch (err) {\n if (!destroyed) {\n update({\n error: err instanceof Error ? err : new Error(String(err)),\n isLoading: false,\n });\n }\n }\n }\n\n // Cleanup handles\n const cleanups: (() => void)[] = [];\n\n // Initial fetch\n const enabled = options?.enabled !== false;\n if (enabled) {\n fetchData();\n }\n\n // Refetch on reconnect\n const refetchOnReconnect = options?.refetchOnReconnect !== false;\n if (enabled && refetchOnReconnect) {\n const client = (database as any)._client;\n if (client?.onReconnected) {\n const unsub = client.onReconnected(() => { fetchData(); });\n cleanups.push(unsub);\n }\n }\n\n // Realtime subscription\n const realtime = options?.realtime;\n if (enabled && realtime) {\n let unsubscribe: (() => Promise<void>) | undefined;\n let cancelled = false;\n\n database.events().subscribe(\n {\n workspace: realtime.workspace,\n event_types: realtime.eventTypes,\n path: realtime.path,\n node_type: realtime.nodeType,\n },\n () => { fetchData(); },\n ).then((sub) => {\n if (cancelled) {\n sub.unsubscribe();\n } else {\n unsubscribe = () => sub.unsubscribe();\n }\n });\n\n cleanups.push(() => {\n cancelled = true;\n unsubscribe?.();\n });\n }\n\n return {\n subscribe(cb: (s: SqlSnapshot<T>) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n refetch: fetchData,\n\n destroy() {\n destroyed = true;\n for (const cleanup of cleanups) cleanup();\n listeners.clear();\n },\n };\n}\n","import type { Database } from '../../database';\nimport type { EventMessage, SubscriptionFilters } from '../../protocol';\n\nexport interface SubscriptionAdapter {\n destroy: () => void;\n}\n\n/**\n * Create an event subscription adapter for Svelte 5.\n *\n * Pure side-effect adapter — subscribes to database events and invokes the\n * callback on each matching event. Call `destroy()` to unsubscribe.\n *\n * @example\n * ```typescript\n * // In a .svelte component's script block or .svelte.ts file\n * import { createSubscriptionAdapter } from '@raisindb/client/svelte';\n * import { db } from '$lib/raisin';\n *\n * const sub = createSubscriptionAdapter(\n * db,\n * { workspace: 'content', node_type: 'Post' },\n * (event) => { console.log('Post changed:', event); },\n * );\n *\n * // In onDestroy or $effect cleanup:\n * sub.destroy();\n * ```\n */\nexport function createSubscriptionAdapter(\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n): SubscriptionAdapter {\n let unsubscribe: (() => Promise<void>) | undefined;\n let cancelled = false;\n\n database.events().subscribe(filters, (event) => {\n if (!cancelled) callback(event);\n }).then((sub) => {\n if (cancelled) {\n sub.unsubscribe();\n } else {\n unsubscribe = () => sub.unsubscribe();\n }\n });\n\n return {\n destroy() {\n cancelled = true;\n unsubscribe?.();\n },\n };\n}\n","import { FlowClient } from '../../flow-client';\nimport type { FlowClientOptions } from '../../flow-client';\nimport type { AuthManager } from '../../auth';\nimport type { FlowsApi } from '../../flows';\nimport type { Database } from '../../database';\nimport type { FlowExecutionEvent } from '../../types/flow';\n\nexport type FlowStatus = 'idle' | 'running' | 'waiting' | 'completed' | 'failed';\n\nexport interface FlowSnapshot {\n events: FlowExecutionEvent[];\n status: FlowStatus;\n isRunning: boolean;\n error: string | null;\n output: unknown | null;\n instanceId: string | null;\n}\n\nexport interface FlowAdapterOptions {\n database?: Database;\n baseUrl?: string;\n repository?: string;\n authManager?: AuthManager;\n clientOptions?: FlowClientOptions;\n flowsApi?: FlowsApi;\n}\n\nexport interface FlowAdapter {\n subscribe: (cb: (snapshot: FlowSnapshot) => void) => () => void;\n getSnapshot: () => FlowSnapshot;\n run: (flowPath: string, input?: Record<string, unknown>) => Promise<void>;\n resume: (data: unknown) => Promise<void>;\n reset: () => void;\n destroy: () => void;\n}\n\n/**\n * Create a flow execution adapter for Svelte 5.\n *\n * Manages the full flow lifecycle: starting, streaming events, resuming\n * waiting flows, and tracking completion. Bind snapshot to `$state` for reactivity.\n *\n * @example\n * ```typescript\n * // lib/flow.svelte.ts\n * import { createFlowAdapter } from '@raisindb/client/svelte';\n * import { db } from '$lib/raisin';\n *\n * const adapter = createFlowAdapter({ database: db });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const flow = {\n * get events() { return snapshot.events; },\n * get status() { return snapshot.status; },\n * get isRunning() { return snapshot.isRunning; },\n * get error() { return snapshot.error; },\n * get output() { return snapshot.output; },\n * run: adapter.run,\n * resume: adapter.resume,\n * reset: adapter.reset,\n * };\n * ```\n */\nexport function createFlowAdapter(options: FlowAdapterOptions): FlowAdapter {\n let snapshot: FlowSnapshot = {\n events: [],\n status: 'idle',\n isRunning: false,\n error: null,\n output: null,\n instanceId: null,\n };\n\n const listeners = new Set<(s: FlowSnapshot) => void>();\n let aborted = false;\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n function update(partial: Partial<FlowSnapshot>) {\n snapshot = { ...snapshot, ...partial };\n if ('status' in partial) {\n snapshot.isRunning = snapshot.status === 'running';\n }\n emit();\n }\n\n // Resolve FlowClient\n let flowClient: FlowClient | null = null;\n if (options.database) {\n flowClient = options.database.flow;\n } else if (options.baseUrl && options.repository && options.authManager) {\n flowClient = new FlowClient(\n options.baseUrl,\n options.repository,\n options.authManager,\n options.clientOptions,\n options.flowsApi,\n );\n }\n\n return {\n subscribe(cb: (s: FlowSnapshot) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n\n async run(flowPath: string, input: Record<string, unknown> = {}) {\n if (!flowClient) return;\n\n aborted = false;\n update({\n events: [],\n error: null,\n output: null,\n status: 'running',\n });\n\n try {\n const result = await flowClient.run(flowPath, input);\n update({ instanceId: result.instance_id });\n\n for await (const event of flowClient.streamEvents(result.instance_id)) {\n if (aborted) break;\n\n update({ events: [...snapshot.events, event] });\n\n if (event.type === 'flow_waiting') {\n update({ status: 'waiting' });\n } else if (event.type === 'flow_completed') {\n update({ output: event.output, status: 'completed' });\n } else if (event.type === 'flow_failed') {\n update({ error: event.error, status: 'failed' });\n }\n }\n } catch (err) {\n update({\n error: err instanceof Error ? err.message : String(err),\n status: 'failed',\n });\n }\n },\n\n async resume(data: unknown) {\n if (!flowClient || !snapshot.instanceId) return;\n\n update({ status: 'running', error: null });\n\n try {\n const stream = await flowClient.createEventStream(snapshot.instanceId);\n await flowClient.resume(snapshot.instanceId, data);\n\n for await (const event of stream.events) {\n if (aborted) break;\n\n update({ events: [...snapshot.events, event] });\n\n if (event.type === 'flow_waiting') {\n update({ status: 'waiting' });\n stream.close();\n return;\n } else if (event.type === 'flow_completed') {\n update({ output: event.output, status: 'completed' });\n stream.close();\n return;\n } else if (event.type === 'flow_failed') {\n update({ error: event.error, status: 'failed' });\n stream.close();\n return;\n }\n }\n\n stream.close();\n } catch (err) {\n update({\n error: err instanceof Error ? err.message : String(err),\n status: 'failed',\n });\n }\n },\n\n reset() {\n aborted = true;\n update({\n events: [],\n status: 'idle',\n error: null,\n output: null,\n instanceId: null,\n });\n },\n\n destroy() {\n aborted = true;\n listeners.clear();\n },\n };\n}\n","import type { RaisinClient } from '../../client';\n\n/**\n * Context value for the RaisinDB Svelte integration.\n *\n * Use with Svelte's `setContext`/`getContext` in `.svelte` files.\n *\n * @example Setup in `+layout.svelte`:\n * ```svelte\n * <script>\n * import { setContext } from 'svelte';\n * import { RAISIN_CONTEXT_KEY, type RaisinContext } from '@raisindb/client/svelte';\n * import { client } from '$lib/raisin';\n *\n * setContext<RaisinContext>(RAISIN_CONTEXT_KEY, { client, repository: 'myrepo' });\n * </script>\n *\n * {@render children()}\n * ```\n *\n * @example Usage in a child component:\n * ```svelte\n * <script>\n * import { getContext } from 'svelte';\n * import { RAISIN_CONTEXT_KEY, type RaisinContext } from '@raisindb/client/svelte';\n *\n * const { client, repository } = getContext<RaisinContext>(RAISIN_CONTEXT_KEY);\n * const db = client.database(repository!);\n * </script>\n * ```\n */\nexport interface RaisinContext {\n client: RaisinClient;\n repository?: string;\n}\n\n/**\n * Shared context key for RaisinDB. Use this with `setContext` and `getContext`\n * to ensure consistent key usage across your application.\n */\nexport const RAISIN_CONTEXT_KEY: unique symbol = Symbol('raisin');\n","/**\n * React flow adapter for RaisinDB.\n *\n * Provides a `useFlow` hook that wraps the FlowClient for executing\n * and monitoring RaisinDB flows in React applications. Returns reactive\n * state tracking flow events, status, and providing control actions.\n *\n * Since this SDK package does not depend on React, the hook accepts\n * React as a parameter via the `ReactLike` interface.\n *\n * @example\n * ```tsx\n * import React from 'react';\n * import { useFlow } from '@raisindb/client';\n *\n * function OrderProcessor() {\n * const flow = useFlow(React, {\n * baseUrl: 'http://localhost:8081',\n * repository: 'my-repo',\n * authManager,\n * });\n *\n * const handleRun = async () => {\n * await flow.run('/flows/process-order', { orderId: 'ord-123' });\n * };\n *\n * return (\n * <div>\n * <button onClick={handleRun} disabled={flow.isRunning}>Run</button>\n * <p>Status: {flow.status}</p>\n * {flow.events.map((e, i) => <div key={i}>{e.type}</div>)}\n * {flow.error && <p className=\"error\">{flow.error}</p>}\n * </div>\n * );\n * }\n * ```\n */\n\nimport { FlowClient } from '../flow-client';\nimport type { FlowClientOptions } from '../flow-client';\nimport type { AuthManager } from '../auth';\nimport type { FlowsApi } from '../flows';\nimport type { Database } from '../database';\nimport type { FlowExecutionEvent } from '../types/flow';\nimport type { ReactLike } from './react-conversation';\n\n/** Options for creating the FlowClient within useFlow */\nexport interface UseFlowOptions {\n /**\n * Pre-configured Database instance (from `client.database()`).\n * When provided, `baseUrl`, `repository`, `authManager`, and `flowsApi` are derived\n * automatically — no manual wiring needed.\n */\n database?: Database;\n /** Base HTTP URL of the RaisinDB server */\n baseUrl?: string;\n /** Repository name */\n repository?: string;\n /** Auth manager for token access */\n authManager?: AuthManager;\n /** Additional FlowClient options */\n clientOptions?: FlowClientOptions;\n /** Optional FlowsApi for WebSocket-based flow operations */\n flowsApi?: FlowsApi;\n}\n\n/** Flow execution status */\nexport type FlowStatus = 'idle' | 'running' | 'waiting' | 'completed' | 'failed';\n\n/** Return value from the useFlow hook */\nexport interface UseFlowReturn {\n /** Collected flow execution events */\n events: FlowExecutionEvent[];\n /** Current flow status */\n status: FlowStatus;\n /** Whether a flow is currently running */\n isRunning: boolean;\n /** Current error, if any */\n error: string | null;\n /** Output from the completed flow */\n output: unknown | null;\n /** Current flow instance ID, if running */\n instanceId: string | null;\n /** Run a flow by path with optional input data */\n run: (flowPath: string, input?: Record<string, unknown>) => Promise<void>;\n /** Resume a waiting flow with data */\n resume: (data: unknown) => Promise<void>;\n /** Reset the hook state (clear events, status, error) */\n reset: () => void;\n}\n\n/**\n * React hook for executing and monitoring RaisinDB flows.\n *\n * Manages the full lifecycle: starting a flow, streaming events,\n * resuming waiting flows, and tracking completion status.\n * Auto-cleans up on component unmount.\n *\n * @param react - The React instance (pass `React` or `{ useState, useEffect, useRef, useCallback }`)\n * @param options - Flow client options (baseUrl, repository, authManager, etc.)\n * @returns Reactive flow state and action functions\n *\n * @example\n * ```tsx\n * import React from 'react';\n * import { useFlow } from '@raisindb/client';\n *\n * function DataPipeline() {\n * const flow = useFlow(React, {\n * baseUrl: 'http://localhost:8081',\n * repository: 'my-repo',\n * authManager,\n * });\n *\n * return (\n * <div>\n * <button onClick={() => flow.run('/flows/etl', { source: 'api' })}>\n * Start Pipeline\n * </button>\n * <p>Status: {flow.status}</p>\n * <p>Events: {flow.events.length}</p>\n * {flow.status === 'waiting' && (\n * <button onClick={() => flow.resume({ approved: true })}>\n * Approve\n * </button>\n * )}\n * {flow.output && <pre>{JSON.stringify(flow.output, null, 2)}</pre>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useFlow(react: ReactLike, options: UseFlowOptions): UseFlowReturn {\n const { useState, useEffect, useRef, useCallback } = react;\n\n const [events, setEvents] = useState<FlowExecutionEvent[]>([]);\n const [status, setStatus] = useState<FlowStatus>('idle');\n const [error, setError] = useState<string | null>(null);\n const [output, setOutput] = useState<unknown | null>(null);\n const [instanceId, setInstanceId] = useState<string | null>(null);\n\n const clientRef = useRef<FlowClient | null>(null);\n const abortRef = useRef(false);\n\n // Create the FlowClient once\n useEffect(() => {\n if (options.database) {\n clientRef.current = options.database.flow;\n } else if (options.baseUrl && options.repository && options.authManager) {\n clientRef.current = new FlowClient(\n options.baseUrl,\n options.repository,\n options.authManager,\n options.clientOptions,\n options.flowsApi,\n );\n }\n\n return () => {\n abortRef.current = true;\n clientRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.database, options.baseUrl, options.repository]);\n\n const run = useCallback(async (flowPath: string, input: Record<string, unknown> = {}) => {\n const client = clientRef.current;\n if (!client) return;\n\n // Reset state\n abortRef.current = false;\n setEvents([]);\n setError(null);\n setOutput(null);\n setStatus('running');\n\n try {\n const result = await client.run(flowPath, input);\n setInstanceId(result.instance_id);\n\n for await (const event of client.streamEvents(result.instance_id)) {\n if (abortRef.current) break;\n\n setEvents((prev) => [...prev, event]);\n\n if (event.type === 'flow_waiting') {\n setStatus('waiting');\n } else if (event.type === 'flow_completed') {\n setOutput(event.output);\n setStatus('completed');\n } else if (event.type === 'flow_failed') {\n setError(event.error);\n setStatus('failed');\n }\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setStatus('failed');\n }\n }, []);\n\n const resume = useCallback(async (data: unknown) => {\n const client = clientRef.current;\n if (!client || !instanceId) return;\n\n setStatus('running');\n setError(null);\n\n try {\n // Open event stream before resuming to avoid missing events\n const stream = await client.createEventStream(instanceId);\n await client.resume(instanceId, data);\n\n for await (const event of stream.events) {\n if (abortRef.current) break;\n\n setEvents((prev) => [...prev, event]);\n\n if (event.type === 'flow_waiting') {\n setStatus('waiting');\n stream.close();\n return;\n } else if (event.type === 'flow_completed') {\n setOutput(event.output);\n setStatus('completed');\n stream.close();\n return;\n } else if (event.type === 'flow_failed') {\n setError(event.error);\n setStatus('failed');\n stream.close();\n return;\n }\n }\n\n stream.close();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setStatus('failed');\n }\n }, [instanceId]);\n\n const reset = useCallback(() => {\n abortRef.current = true;\n setEvents([]);\n setStatus('idle');\n setError(null);\n setOutput(null);\n setInstanceId(null);\n }, []);\n\n return {\n events,\n status,\n isRunning: status === 'running',\n error,\n output,\n instanceId,\n run,\n resume,\n reset,\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseAuthReturn } from './types';\nimport type { IdentityUser } from '../../auth';\n\nexport function createUseAuth(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): () => UseAuthReturn {\n return function useAuth(): UseAuthReturn {\n const { useState, useEffect, useRef, useCallback, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useAuth must be used within a <RaisinProvider>');\n }\n const { client } = ctx;\n\n const [user, setUser] = useState<IdentityUser | null>(client.getStoredUser());\n const [isLoading, setIsLoading] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n\n const unsubAuth = client.onAuthStateChange(({ event, session }) => {\n if (!mountedRef.current) return;\n if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED' || event === 'USER_UPDATED') {\n setUser(session.user);\n } else if (event === 'SIGNED_OUT' || event === 'SESSION_EXPIRED') {\n setUser(null);\n }\n });\n\n const unsubUser = client.onUserChange(({ node }) => {\n if (!mountedRef.current) return;\n // Update user with the latest node properties\n setUser((prev) => {\n if (!prev) return prev;\n return {\n ...prev,\n home: node.path,\n displayName: (node.properties.display_name as string) ?? prev.displayName,\n avatarUrl: (node.properties.avatar_url as string) ?? prev.avatarUrl,\n };\n });\n });\n\n return () => {\n mountedRef.current = false;\n unsubAuth();\n unsubUser();\n };\n }, [client]);\n\n const login = useCallback(async (email: string, password: string, repository: string) => {\n setIsLoading(true);\n try {\n const result = await client.loginWithEmail(email, password, repository);\n return result;\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n const register = useCallback(async (email: string, password: string, repository: string, displayName?: string) => {\n setIsLoading(true);\n try {\n const result = await client.registerWithEmail(email, password, repository, displayName);\n return result;\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n const logout = useCallback(async (options?: { disconnect?: boolean; reconnect?: boolean }) => {\n setIsLoading(true);\n try {\n await client.logout(options);\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n const initSession = useCallback(async (repository: string) => {\n setIsLoading(true);\n try {\n const result = await client.initSession(repository);\n return result;\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n return {\n user,\n isAuthenticated: user !== null,\n isLoading,\n login,\n register,\n logout,\n initSession,\n };\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseConnectionReturn } from './types';\nimport { ConnectionState } from '../../connection';\n\nexport function createUseConnection(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): () => UseConnectionReturn {\n return function useConnection(): UseConnectionReturn {\n const { useState, useEffect, useCallback, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useConnection must be used within a <RaisinProvider>');\n }\n const { client } = ctx;\n\n const [state, setState] = useState<ConnectionState>(client.getConnectionState());\n const [isReady, setIsReady] = useState(client.isReady());\n\n useEffect(() => {\n const unsubConn = client.onConnectionStateChange((newState) => {\n setState(newState);\n });\n\n const unsubReady = client.onReadyStateChange((ready) => {\n setIsReady(ready);\n });\n\n return () => {\n unsubConn();\n unsubReady();\n };\n }, [client]);\n\n const connect = useCallback(async () => {\n await client.connect();\n }, [client]);\n\n const disconnect = useCallback(() => {\n client.disconnect();\n }, [client]);\n\n return {\n state,\n isConnected: state === ConnectionState.Connected,\n isReady,\n connect,\n disconnect,\n };\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseSqlOptions, UseSqlReturn } from './types';\nimport type { SqlResult } from '../../protocol';\n\nfunction rowsToObjects<T>(result: SqlResult): T[] {\n return result.rows as T[];\n}\n\nexport function createUseSql(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): <T = Record<string, unknown>>(sql: string, params?: unknown[], options?: UseSqlOptions) => UseSqlReturn<T> {\n return function useSql<T = Record<string, unknown>>(\n sql: string,\n params?: unknown[],\n options?: UseSqlOptions,\n ): UseSqlReturn<T> {\n const { useState, useEffect, useRef, useCallback, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useSql must be used within a <RaisinProvider>');\n }\n const { client, repository: defaultRepo } = ctx;\n\n const [data, setData] = useState<T[] | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const mountedRef = useRef(true);\n\n const enabled = options?.enabled !== false;\n const repo = options?.repository ?? defaultRepo;\n const refetchOnReconnect = options?.refetchOnReconnect !== false;\n const realtime = options?.realtime;\n\n // Serialize params for dependency comparison\n const paramsKey = params ? JSON.stringify(params) : '';\n\n const fetchData = useCallback(async () => {\n if (!repo) return;\n setIsLoading(true);\n setError(null);\n try {\n const db = client.database(repo);\n const result = await db.executeSql(sql, params);\n if (mountedRef.current) {\n setData(rowsToObjects<T>(result));\n }\n } catch (err) {\n if (mountedRef.current) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n if (mountedRef.current) {\n setIsLoading(false);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, repo, sql, paramsKey]);\n\n // Initial fetch and re-fetch on query/params change\n useEffect(() => {\n mountedRef.current = true;\n if (enabled) {\n fetchData();\n }\n return () => {\n mountedRef.current = false;\n };\n }, [enabled, fetchData]);\n\n // Refetch on reconnect\n useEffect(() => {\n if (!enabled || !refetchOnReconnect) return;\n\n const unsub = client.onReconnected(() => {\n fetchData();\n });\n return unsub;\n }, [client, enabled, refetchOnReconnect, fetchData]);\n\n // Realtime subscription: refetch on matching events\n useEffect(() => {\n if (!enabled || !realtime || !repo) return;\n\n const db = client.database(repo);\n let unsubscribe: (() => Promise<void>) | undefined;\n\n db.events().subscribe(\n {\n workspace: realtime.workspace,\n event_types: realtime.eventTypes,\n path: realtime.path,\n node_type: realtime.nodeType,\n },\n () => {\n fetchData();\n },\n ).then((sub) => {\n unsubscribe = () => sub.unsubscribe();\n });\n\n return () => {\n unsubscribe?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, enabled, repo, realtime?.workspace, realtime?.path, realtime?.nodeType, fetchData]);\n\n return {\n data,\n isLoading,\n error,\n refetch: fetchData,\n };\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseSubscriptionOptions } from './types';\nimport type { EventMessage } from '../../protocol';\n\nexport function createUseSubscription(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): (options: UseSubscriptionOptions, callback: (event: EventMessage) => void) => void {\n return function useSubscription(\n options: UseSubscriptionOptions,\n callback: (event: EventMessage) => void,\n ): void {\n const { useEffect, useRef, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useSubscription must be used within a <RaisinProvider>');\n }\n const { client, repository } = ctx;\n\n // callbackRef pattern: avoid re-subscribing when callback identity changes\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n const enabled = options.enabled !== false;\n\n useEffect(() => {\n if (!enabled || !repository || !options.workspace) return;\n\n const db = client.database(repository);\n let unsubscribe: (() => Promise<void>) | undefined;\n let cancelled = false;\n\n db.events().subscribe(\n {\n workspace: options.workspace,\n event_types: options.event_types,\n path: options.path,\n node_type: options.node_type,\n include_node: options.include_node,\n },\n (event) => {\n if (!cancelled) {\n callbackRef.current(event);\n }\n },\n ).then((sub) => {\n if (cancelled) {\n sub.unsubscribe();\n } else {\n unsubscribe = () => sub.unsubscribe();\n }\n });\n\n return () => {\n cancelled = true;\n unsubscribe?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, repository, enabled, options.workspace, options.path, options.node_type, options.include_node]);\n };\n}\n","/**\n * React integration layer for RaisinDB.\n *\n * Provides a `createRaisinReact(React)` factory that returns a Provider\n * component and hooks for auth, connection, queries, and subscriptions.\n *\n * Uses the \"bring your own React\" pattern to avoid a peer dependency.\n *\n * @example\n * ```ts\n * import React from 'react';\n * import { RaisinClient, LocalStorageTokenStorage, createRaisinReact } from '@raisindb/client';\n *\n * const client = new RaisinClient('wss://localhost:8443/sys/default/myrepo', {\n * tokenStorage: new LocalStorageTokenStorage('myrepo'),\n * });\n *\n * export const {\n * RaisinProvider, useAuth, useConnection, useDatabase,\n * useSql, useSubscription, useConversation, useFlow,\n * } = createRaisinReact(React);\n * ```\n */\n\nimport type {\n ReactLikeWithContext,\n RaisinProviderProps,\n RaisinContextValue,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlOptions,\n UseSqlReturn,\n UseSubscriptionOptions,\n} from './types';\n\nimport type { RaisinClient } from '../../client';\nimport type { Database } from '../../database';\nimport type { EventMessage } from '../../protocol';\nimport type {\n ConversationStoreOptions,\n} from '../../stores/conversation-store';\nimport type { ConversationListStoreOptions } from '../../stores/conversation-list-store';\n\nimport { createUseAuth } from './use-auth';\nimport { createUseConnection } from './use-connection';\nimport { createUseSql } from './use-sql';\nimport { createUseSubscription } from './use-subscription';\n\nimport {\n useConversation as rawUseConversation,\n useConversationList as rawUseConversationList,\n type UseConversationReturn,\n type UseConversationListReturn,\n} from '../react-conversation';\nimport {\n useFlow as rawUseFlow,\n type UseFlowOptions,\n type UseFlowReturn,\n} from '../react-flow';\n\nexport interface RaisinReact {\n RaisinProvider: (props: RaisinProviderProps) => any;\n useRaisinClient: () => RaisinClient;\n useDatabase: (repository?: string) => Database;\n useAuth: () => UseAuthReturn;\n useConnection: () => UseConnectionReturn;\n useSql: <T = Record<string, unknown>>(sql: string, params?: unknown[], options?: UseSqlOptions) => UseSqlReturn<T>;\n useSubscription: (options: UseSubscriptionOptions, callback: (event: EventMessage) => void) => void;\n useConversation: (options: ConversationStoreOptions) => UseConversationReturn;\n useConversationList: (options: ConversationListStoreOptions) => UseConversationListReturn;\n useFlow: (options: UseFlowOptions) => UseFlowReturn;\n}\n\n/**\n * Create the full React integration for RaisinDB.\n *\n * Accepts a React instance and returns a Provider component plus hooks.\n * The React instance must include `createContext`, `useContext`, `useMemo`,\n * and `createElement` in addition to the base `ReactLike` interface.\n *\n * @param react - The React instance\n * @returns Provider component and hooks\n */\nexport function createRaisinReact(react: ReactLikeWithContext): RaisinReact {\n const RaisinContext = react.createContext<RaisinContextValue | null>(null);\n\n // --- Provider ---\n function RaisinProvider(props: RaisinProviderProps): any {\n const { client, repository, children } = props;\n\n const value = react.useMemo(\n () => ({ client, repository }),\n [client, repository],\n );\n\n return react.createElement(\n RaisinContext.Provider as unknown,\n { value },\n children,\n );\n }\n\n // --- Context accessors ---\n function useRaisinClient(): RaisinClient {\n const ctx = react.useContext(RaisinContext);\n if (!ctx) {\n throw new Error('useRaisinClient must be used within a <RaisinProvider>');\n }\n return ctx.client;\n }\n\n function useDatabase(repository?: string): Database {\n const ctx = react.useContext(RaisinContext);\n if (!ctx) {\n throw new Error('useDatabase must be used within a <RaisinProvider>');\n }\n const repo = repository ?? ctx.repository;\n if (!repo) {\n throw new Error('useDatabase requires a repository — pass it as an argument or set it on <RaisinProvider>');\n }\n return react.useMemo(() => ctx.client.database(repo), [ctx.client, repo]);\n }\n\n // --- Core hooks ---\n const useAuth = createUseAuth(react, RaisinContext);\n const useConnection = createUseConnection(react, RaisinContext);\n const useSql = createUseSql(react, RaisinContext);\n const useSubscription = createUseSubscription(react, RaisinContext);\n\n // --- Pre-bound existing hooks ---\n function useConversation(options: ConversationStoreOptions): UseConversationReturn {\n return rawUseConversation(react, options);\n }\n\n function useConversationList(options: ConversationListStoreOptions): UseConversationListReturn {\n return rawUseConversationList(react, options);\n }\n\n function useFlow(options: UseFlowOptions): UseFlowReturn {\n return rawUseFlow(react, options);\n }\n\n return {\n RaisinProvider,\n useRaisinClient,\n useDatabase,\n useAuth,\n useConnection,\n useSql,\n useSubscription,\n useConversation,\n useConversationList,\n useFlow,\n };\n}\n\n// Re-export types\nexport type {\n ReactLikeWithContext,\n RaisinProviderProps,\n RaisinContextValue,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlOptions,\n UseSqlReturn,\n UseSubscriptionOptions,\n} from './types';\n\n// Hook return/option types (parity with the @raisindb/client/vue subpath):\n// apps need these to type props that carry a hook's return value around.\nexport type {\n ReactLike,\n UseConversationReturn,\n UseConversationListReturn,\n} from '../react-conversation';\nexport type { UseFlowOptions, UseFlowReturn, FlowStatus } from '../react-flow';\nexport type {\n ConversationStoreOptions,\n ConversationStoreSnapshot,\n ToolCallInfo,\n} from '../../stores/conversation-store';\nexport type {\n ConversationListStoreOptions,\n ConversationListSnapshot,\n} from '../../stores/conversation-list-store';\nexport type { PlanProjection, PlanProjectionTask } from '../../utils/plan-projection';\nexport type { ChatMessage, ConversationListItem } from '../../types/chat';\n","import type { VueLike, VueRef, UseAuthReturn } from './types';\nimport type { RaisinClient } from '../../client';\n// Framework-free snapshot adapter shared with the Svelte integration.\nimport { createAuthAdapter, type AuthSnapshot } from '../svelte/svelte-auth';\n\nexport function createUseAuth(vue: VueLike): (client: RaisinClient) => UseAuthReturn {\n return function useAuth(client: RaisinClient): UseAuthReturn {\n const adapter = createAuthAdapter(client);\n const snapshot = vue.ref(adapter.getSnapshot()) as VueRef<AuthSnapshot>;\n const unsubscribe = adapter.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n adapter.destroy();\n });\n\n return {\n user: vue.computed(() => snapshot.value.user),\n isAuthenticated: vue.computed(() => snapshot.value.isAuthenticated),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n login: adapter.login,\n register: adapter.register,\n logout: adapter.logout,\n initSession: adapter.initSession,\n };\n };\n}\n","import type { VueLike, VueRef, UseConnectionReturn } from './types';\nimport type { RaisinClient } from '../../client';\n// Framework-free snapshot adapter shared with the Svelte integration.\nimport { createConnectionAdapter, type ConnectionSnapshot } from '../svelte/svelte-connection';\n\nexport function createUseConnection(vue: VueLike): (client: RaisinClient) => UseConnectionReturn {\n return function useConnection(client: RaisinClient): UseConnectionReturn {\n const adapter = createConnectionAdapter(client);\n const snapshot = vue.ref(adapter.getSnapshot()) as VueRef<ConnectionSnapshot>;\n const unsubscribe = adapter.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n adapter.destroy();\n });\n\n return {\n state: vue.computed(() => snapshot.value.state),\n isConnected: vue.computed(() => snapshot.value.isConnected),\n isReady: vue.computed(() => snapshot.value.isReady),\n connect: adapter.connect,\n disconnect: adapter.disconnect,\n };\n };\n}\n","import type { VueLike, VueRef, UseSqlReturn } from './types';\nimport type { Database } from '../../database';\n// Framework-free snapshot adapter shared with the Svelte integration.\nimport {\n createSqlAdapter,\n type SqlAdapterOptions,\n type SqlSnapshot,\n} from '../svelte/svelte-sql';\n\nexport function createUseSql(\n vue: VueLike,\n): <T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n) => UseSqlReturn<T> {\n return function useSql<T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n ): UseSqlReturn<T> {\n const adapter = createSqlAdapter<T>(database, sql, params, options);\n const snapshot = vue.ref(adapter.getSnapshot()) as VueRef<SqlSnapshot<T>>;\n const unsubscribe = adapter.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n adapter.destroy();\n });\n\n return {\n data: vue.computed(() => snapshot.value.data),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n error: vue.computed(() => snapshot.value.error),\n refetch: adapter.refetch,\n };\n };\n}\n","import type { VueLike, UseSubscriptionReturn } from './types';\nimport type { Database } from '../../database';\nimport type { EventMessage, SubscriptionFilters } from '../../protocol';\n// Framework-free side-effect adapter shared with the Svelte integration.\nimport { createSubscriptionAdapter } from '../svelte/svelte-subscription';\n\nexport function createUseSubscription(\n vue: VueLike,\n): (\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n) => UseSubscriptionReturn {\n return function useSubscription(\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n ): UseSubscriptionReturn {\n const adapter = createSubscriptionAdapter(database, filters, callback);\n\n // Automatic cleanup when the component unmounts.\n vue.onUnmounted(() => adapter.destroy());\n\n return {\n unsubscribe: () => adapter.destroy(),\n };\n };\n}\n","import type {\n VueLike,\n VueRef,\n UseConversationReturn,\n UseConversationListReturn,\n} from './types';\nimport {\n ConversationStore,\n type ConversationStoreOptions,\n type ConversationStoreSnapshot,\n} from '../../stores/conversation-store';\nimport {\n ConversationListStore,\n type ConversationListStoreOptions,\n type ConversationListSnapshot,\n} from '../../stores/conversation-list-store';\nimport { logger } from '../../logger';\n\nexport function createUseConversation(\n vue: VueLike,\n): (options: ConversationStoreOptions) => UseConversationReturn {\n return function useConversation(options: ConversationStoreOptions): UseConversationReturn {\n const store = new ConversationStore(options);\n const snapshot = vue.ref(store.getSnapshot()) as VueRef<ConversationStoreSnapshot>;\n const unsubscribe = store.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n store.destroy();\n });\n\n return {\n conversation: vue.computed(() => snapshot.value.conversation),\n messages: vue.computed(() => snapshot.value.messages),\n isStreaming: vue.computed(() => snapshot.value.isStreaming),\n isWaiting: vue.computed(() => snapshot.value.isWaiting),\n streamingText: vue.computed(() => snapshot.value.streamingText),\n error: vue.computed(() => snapshot.value.error),\n activeToolCalls: vue.computed(() => snapshot.value.activeToolCalls),\n plans: vue.computed(() => snapshot.value.plans),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n conversationPath: vue.computed(() => snapshot.value.conversationPath),\n sendMessage: (content: string) => store.sendMessage(content),\n approvePlan: async (planPath: string) => { await store.approvePlan(planPath); },\n rejectPlan: async (planPath: string, feedback?: string) => { await store.rejectPlan(planPath, feedback); },\n stop: () => store.stop(),\n loadMessages: () => store.loadMessages(),\n store,\n };\n };\n}\n\nexport function createUseConversationList(\n vue: VueLike,\n): (options: ConversationListStoreOptions) => UseConversationListReturn {\n return function useConversationList(options: ConversationListStoreOptions): UseConversationListReturn {\n const store = new ConversationListStore(options);\n const snapshot = vue.ref(store.getSnapshot()) as VueRef<ConversationListSnapshot>;\n const unsubscribe = store.subscribe((s) => { snapshot.value = s; });\n\n // Initial load (same behavior as the React useConversationList hook).\n store.load().catch((err) => {\n logger.error('[useConversationList] Initial load failed:', err);\n });\n\n vue.onUnmounted(() => {\n unsubscribe();\n store.destroy();\n });\n\n return {\n conversations: vue.computed(() => snapshot.value.conversations),\n totalUnreadCount: vue.computed(() => snapshot.value.totalUnreadCount),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n error: vue.computed(() => snapshot.value.error),\n createConversation: (opts) => store.createConversation(opts),\n deleteConversation: (conversationPath: string) => store.deleteConversation(conversationPath),\n markAsRead: (conversationPath: string) => store.markAsRead(conversationPath),\n refresh: () => store.load(),\n store,\n };\n };\n}\n","/**\n * Vue 3 integration layer for RaisinDB.\n *\n * Provides a `createRaisinVue(vue)` factory that returns composables for\n * auth, connection, SQL queries, node-event subscriptions, and the\n * conversation stores.\n *\n * Uses the same \"bring your own framework\" pattern as the React integration\n * (`createRaisinReact(React)`): the SDK never imports `vue`, so Vue stays\n * out of the SDK's dependency graph and the main `.` bundle. You pass the\n * Vue module (its `ref`, `computed`, and `onUnmounted` are all that is\n * needed) once at setup time.\n *\n * Each composable creates its underlying store/adapter when called and\n * destroys it automatically in `onUnmounted`, so call them from\n * `setup()` / `<script setup>`.\n *\n * @example\n * ```ts\n * // lib/raisin-vue.ts\n * import * as vue from 'vue';\n * import { RaisinClient, LocalStorageTokenStorage } from '@raisindb/client';\n * import { createRaisinVue } from '@raisindb/client/vue';\n *\n * export const client = new RaisinClient('ws://localhost:8081/sys/default/myrepo', {\n * tokenStorage: new LocalStorageTokenStorage('myapp'),\n * });\n * export const db = client.database('myrepo');\n *\n * export const {\n * useAuth, useConnection, useSql, useSubscription,\n * useConversation, useConversationList,\n * } = createRaisinVue(vue);\n * ```\n *\n * @example In a component:\n * ```vue\n * <script setup lang=\"ts\">\n * import { client, db, useConversation } from '@/lib/raisin-vue';\n *\n * const chat = useConversation({\n * database: db,\n * createOptions: { participant: '/agents/support' },\n * });\n * </script>\n *\n * <template>\n * <div v-for=\"(m, i) in chat.messages.value\" :key=\"i\">{{ m.content }}</div>\n * <p v-if=\"chat.isStreaming.value\">{{ chat.streamingText.value }}</p>\n * </template>\n * ```\n */\n\nimport type {\n VueLike,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlReturn,\n UseSubscriptionReturn,\n UseConversationReturn,\n UseConversationListReturn,\n} from './types';\nimport type { RaisinClient } from '../../client';\nimport type { Database } from '../../database';\nimport type { EventMessage, SubscriptionFilters } from '../../protocol';\nimport type { ConversationStoreOptions } from '../../stores/conversation-store';\nimport type { ConversationListStoreOptions } from '../../stores/conversation-list-store';\nimport type { SqlAdapterOptions } from '../svelte/svelte-sql';\n\nimport { createUseAuth } from './vue-auth';\nimport { createUseConnection } from './vue-connection';\nimport { createUseSql } from './vue-sql';\nimport { createUseSubscription } from './vue-subscription';\nimport { createUseConversation, createUseConversationList } from './vue-conversation';\n\nexport interface RaisinVue {\n /** Reactive auth state + login/register/logout/initSession actions */\n useAuth: (client: RaisinClient) => UseAuthReturn;\n /** Reactive connection state (state / isConnected / isReady) */\n useConnection: (client: RaisinClient) => UseConnectionReturn;\n /** Run a SQL query with reactive data/isLoading/error + optional realtime refetch */\n useSql: <T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n ) => UseSqlReturn<T>;\n /** Subscribe to node events; unsubscribes automatically on unmount */\n useSubscription: (\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n ) => UseSubscriptionReturn;\n /** Bind a ConversationStore (chat: messages, streaming, tool calls, plans) */\n useConversation: (options: ConversationStoreOptions) => UseConversationReturn;\n /** Bind a ConversationListStore (inbox-style conversation list) */\n useConversationList: (options: ConversationListStoreOptions) => UseConversationListReturn;\n}\n\n/**\n * Create the full Vue 3 integration for RaisinDB.\n *\n * @param vue - The Vue module (or any object providing `ref`, `computed`, `onUnmounted`)\n * @returns The set of composables\n */\nexport function createRaisinVue(vue: VueLike): RaisinVue {\n return {\n useAuth: createUseAuth(vue),\n useConnection: createUseConnection(vue),\n useSql: createUseSql(vue),\n useSubscription: createUseSubscription(vue),\n useConversation: createUseConversation(vue),\n useConversationList: createUseConversationList(vue),\n };\n}\n\n// Re-export types\nexport type {\n VueLike,\n VueRef,\n VueComputedRef,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlReturn,\n UseSubscriptionReturn,\n UseConversationReturn,\n UseConversationListReturn,\n} from './types';\nexport type { SqlAdapterOptions as UseSqlOptions } from '../svelte/svelte-sql';\n"],"mappings":"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","names":["import_events","LogLevel","ConnectionState","uuidv4","RequestType","ResponseStatus","payload","payload","scheduled","conversationId","import_events","UploadErrorCode","config","config","config","currentToken","config","config","rowsToObjects","rowsToObjects","useConversation","useConversationList","useFlow","createUseAuth","createUseConnection","createUseSql","createUseSubscription","useConversation","useConversationList","createUseAuth","createUseConnection","createUseSql","createUseSubscription"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/connection.ts","../src/utils/reconnect.ts","../src/logger.ts","../src/utils/request-tracker.ts","../src/auth.ts","../src/protocol.ts","../src/events.ts","../src/nodes.ts","../src/transactions.ts","../src/upload/file-source.ts","../src/workspace.ts","../src/sql.ts","../src/node-types.ts","../src/archetypes.ts","../src/element-types.ts","../src/branches.ts","../src/scheduler.ts","../src/tags.ts","../src/flows.ts","../src/functions-api.ts","../src/errors.ts","../src/streaming/sse-client.ts","../src/utils/chat-events.ts","../src/utils/home-path.ts","../src/conversations.ts","../src/flow-client.ts","../src/inbox.ts","../src/database.ts","../src/http-client.ts","../src/upload/types.ts","../src/upload/retry.ts","../src/upload/batch.ts","../src/upload/uploader.ts","../src/http-schema.ts","../src/mcp.ts","../src/identity-auth.ts","../src/node-builder.ts","../src/constants.ts","../src/integrations/react-router.ts","../src/types/flow.ts","../src/types/flow-definition.ts","../src/utils/plan-projection.ts","../src/stores/conversation-store.ts","../src/stores/conversation-list-store.ts","../src/integrations/react-conversation.ts","../src/integrations/svelte-conversation.ts","../src/integrations/svelte/svelte-auth.ts","../src/integrations/svelte/svelte-connection.ts","../src/integrations/svelte/svelte-sql.ts","../src/integrations/svelte/svelte-subscription.ts","../src/integrations/svelte/svelte-flow.ts","../src/integrations/svelte/svelte-context.ts","../src/integrations/react-flow.ts","../src/integrations/react/use-auth.ts","../src/integrations/react/use-connection.ts","../src/integrations/react/use-sql.ts","../src/integrations/react/use-subscription.ts","../src/integrations/react/index.ts","../src/integrations/vue/vue-auth.ts","../src/integrations/vue/vue-connection.ts","../src/integrations/vue/vue-sql.ts","../src/integrations/vue/vue-subscription.ts","../src/integrations/vue/vue-conversation.ts","../src/integrations/vue/index.ts"],"sourcesContent":["/**\n * RaisinDB JavaScript/TypeScript Client SDK\n *\n * A universal WebSocket client for RaisinDB that works in browser, Node.js, and serverless environments.\n *\n * @example\n * ```typescript\n * import { RaisinClient } from '@raisindb/client';\n *\n * const client = new RaisinClient('raisin://localhost:8080/sys/default');\n * await client.connect();\n * await client.authenticate({ username: 'admin', password: 'password' });\n *\n * const db = client.database('my_repo');\n * const ws = db.workspace('content');\n *\n * const node = await ws.nodes().create({\n * type: 'Page',\n * path: '/home',\n * properties: { title: 'Home Page' }\n * });\n * ```\n */\n\n// Main client\nexport { RaisinClient } from './client';\nexport type {\n ClientOptions,\n ClientMode,\n CurrentUser,\n UserNode,\n // Auth state change types (Firebase/Supabase-compatible)\n AuthEvent,\n AuthStateChange,\n AuthStateChangeCallback,\n UserChangeEvent,\n UserChangeCallback,\n} from './client';\n\n// HTTP client for SSR\nexport { RaisinHttpClient, HttpDatabase, HttpWorkspaceClient } from './http-client';\nexport type {\n HttpClientOptions,\n CurrentUser as HttpCurrentUser,\n UserNode as HttpUserNode,\n SignAssetOptions,\n SignedAssetUrl,\n} from './http-client';\n\n// Database and workspace\nexport { Database } from './database';\nexport type { DatabaseHttpOptions } from './database';\nexport { WorkspaceClient, WorkspaceManager } from './workspace';\nexport type { WorkspaceCreateOptions, WorkspaceUpdateOptions } from './workspace';\n\n// Node operations\nexport { NodeOperations } from './nodes';\nexport type {\n NodeCreateOptions,\n NodeCreateDeepOptions,\n NodeUpdateOptions,\n NodeQueryOptions,\n} from './nodes';\n\n// Transactions\nexport { Transaction } from './transactions';\nexport type { TransactionOptions } from './transactions';\n\n// Node builder and helpers\nexport { NodeBuilder, NodeHelpers } from './node-builder';\n\n// Management operations\nexport { NodeTypes } from './node-types';\nexport { Archetypes } from './archetypes';\nexport { ElementTypes } from './element-types';\nexport { Branches } from './branches';\nexport type {\n BranchDiff,\n BranchDivergence,\n CrossBranchCopySummary,\n CrossBranchNodeChange,\n NodeDiffInfo\n} from './branches';\nexport { Tags } from './tags';\nexport { SchedulerApi } from './scheduler';\nexport type {\n ListInvocationsFilter,\n ScheduleInvocationOptions,\n ScheduledInvocation,\n ScheduledInvocationRef,\n ScheduledInvocationTargetKind\n} from './scheduler';\n\n// HTTP (SSR) schema management\nexport { HttpNodeTypes, HttpArchetypes, HttpElementTypes } from './http-schema';\nexport type { SchemaCommit } from './http-schema';\n\n// SQL queries\nexport { SqlQuery, createSqlHandler } from './sql';\n\n// Events\nexport { EventHandler, EventSubscriptions } from './events';\nexport type { EventCallback, Subscription } from './events';\n\n// Event type constants\nexport { NodeEventType, AllNodeEventTypes } from './constants';\nexport type { NodeEventTypeValue } from './constants';\n\n// Connection\nexport { Connection, ConnectionState } from './connection';\nexport type { ConnectionOptions } from './connection';\n\n// Authentication\nexport { AuthManager, MemoryTokenStorage, LocalStorageTokenStorage } from './auth';\nexport type {\n Credentials,\n TokenStorage,\n IdentityUser,\n IdentityAuthResponse,\n IdentityAuthError,\n} from './auth';\n\n// Protocol types\nexport type {\n RequestEnvelope,\n ResponseEnvelope,\n EventMessage,\n NodeEventPayload,\n RequestContext,\n ErrorInfo,\n ResponseMetadata,\n Node,\n RelationRef,\n IncomingRelation,\n NodeRelationships,\n PropertyValue,\n NodeCreatePayload,\n NodeCreateDeepPayload,\n NodeUpdatePayload,\n NodeDeletePayload,\n NodeGetPayload,\n NodeHistoryPayload,\n RevisionEntry,\n AuditQueryPayload,\n AuditLogEntry,\n NodeQueryPayload,\n RelationAddPayload,\n RelationRemovePayload,\n RelationsGetPayload,\n SqlQueryPayload,\n SqlResult,\n Workspace,\n WorkspaceCreatePayload,\n WorkspaceGetPayload,\n WorkspaceDeletePayload,\n WorkspaceUpdatePayload,\n SubscribePayload,\n SubscriptionFilters,\n UnsubscribePayload,\n SubscriptionResponse,\n AuthenticatePayload,\n AuthenticateResponse,\n RefreshTokenPayload,\n TransactionBeginPayload,\n TransactionBeginResponse,\n TransactionCommitPayload,\n TransactionCommitResponse,\n TransactionRollbackPayload,\n} from './protocol';\n\nexport {\n RequestType,\n ResponseStatus,\n encodeMessage,\n decodeMessage,\n isEventMessage,\n isResponseEnvelope,\n} from './protocol';\n\n// Utilities\nexport { RequestTracker } from './utils/request-tracker';\nexport type { RequestTrackerOptions } from './utils/request-tracker';\nexport { ReconnectManager } from './utils/reconnect';\nexport type { ReconnectOptions } from './utils/reconnect';\nexport { normalizeHomePath } from './utils/home-path';\n\n// Logger\nexport { LogLevel, logger, configureLogger, setLogLevel, getLogLevel, getLoggerConfig } from './logger';\nexport type { LoggerConfig } from './logger';\n\n// React Router 7 integration\nexport {\n createSSRClient,\n createLoader,\n createRequestScopedClient,\n rowsToObjects,\n getErrorMessage,\n isHttpClient,\n isWebSocketClient,\n} from './integrations/react-router';\nexport type {\n SSRClientConfig,\n HybridClient,\n} from './integrations/react-router';\n\n// Upload module\nexport type {\n UploadStatus,\n UploadOptions,\n UploadProgress,\n UploadResult,\n Upload,\n CreateUploadRequest,\n CreateUploadResponse,\n ChunkUploadResponse,\n UploadStatusResponse,\n CompleteUploadRequest,\n CompleteUploadResponse,\n RetryOptions,\n FileSource,\n RetryContext,\n RetryCallback,\n UploaderConfig,\n // Batch upload types\n BatchFileProgress,\n BatchProgress,\n BatchUploadResult,\n BatchUploadOptions,\n BatchUpload,\n} from './upload';\nexport {\n UploadError,\n UploadErrorCode,\n DEFAULT_CHUNK_SIZE,\n DEFAULT_MAX_RETRIES,\n DEFAULT_RETRY_BASE_DELAY,\n DEFAULT_RETRY_MAX_DELAY,\n DEFAULT_NODE_TYPE,\n DEFAULT_BRANCH,\n DEFAULT_BATCH_CONCURRENCY,\n BrowserFileSource,\n NodeFileSource,\n createFileSource,\n getContentType,\n calculateChunkCount,\n getChunkRange,\n DEFAULT_RETRY_OPTIONS,\n calculateDelay,\n sleep,\n isRetryableError,\n withRetry,\n RetryBuilder,\n classifyError,\n Uploader,\n UploadManager,\n BatchUploader,\n} from './upload';\n\n// Errors\nexport {\n RaisinError,\n RaisinConnectionError,\n RaisinAuthError,\n RaisinFlowError,\n RaisinTimeoutError,\n RaisinAbortError,\n} from './errors';\nexport type {\n RaisinErrorCode,\n ConnectionErrorCode,\n AuthErrorCode,\n FlowErrorCode,\n TimeoutErrorCode,\n AbortErrorCode,\n} from './errors';\n\n// Flow execution\nexport { FlowClient } from './flow-client';\nexport type { FlowClientOptions, FlowRunResult, FlowCollectResult } from './flow-client';\n\n// Function invocation\nexport { FunctionsApi, HttpFunctionsApi } from './functions-api';\nexport { IdentityAuthApi, readTokensFromFragment } from './identity-auth';\nexport type {\n IdentityAuthResult,\n IdentityAuthTransport,\n IdentityInfo,\n IdentityMe,\n MagicLinkSent,\n MagicLinkOptions,\n AuthProviders,\n} from './identity-auth';\nexport type {\n FunctionInvokeOptions,\n FunctionInvokeResponse,\n FunctionInvokeSyncResponse\n} from './functions-api';\n\n// MCP client (talk to a raisin:McpServer over JSON-RPC)\nexport { McpClient } from './mcp';\nexport type {\n McpTransport,\n McpFrameStream,\n McpJsonRpcFrame,\n McpToolDescriptor,\n McpContentBlock,\n McpCallToolResult,\n McpResourceContents,\n McpReadResourceResult,\n McpResourceUpdate,\n McpResourceSubscription,\n} from './mcp';\n\n// Flow execution (WebSocket)\nexport { FlowsApi } from './flows';\nexport type {\n FlowRunResponse,\n FlowInstanceStatus,\n FlowInstanceStatusResponse,\n FlowMetrics,\n FlowExecutionEvent,\n StepStartedEvent,\n StepCompletedEvent,\n StepUsage,\n StepFailedEvent,\n FlowWaitingEvent,\n FlowResumedEvent,\n FlowCompletedEvent,\n FlowFailedEvent,\n TextChunkEvent,\n ToolCallStartedEvent,\n ToolCallCompletedEvent,\n ThoughtChunkEvent,\n ConversationCreatedEvent,\n MessageSavedEvent,\n LogEvent,\n} from './types/flow';\nexport { isTerminalEvent } from './types/flow';\n\n// Workflow definition types (canonical, shared with the flow designer)\nexport type {\n RaisinReference,\n ContainerType,\n StepErrorBehavior,\n FlowErrorStrategy,\n RetryConfig,\n RetryStrategy,\n HumanTaskType,\n CanonicalTaskType,\n TaskOption,\n HandoffTarget,\n ChatTerminationMode,\n ChatTerminationConfig,\n ChatStepConfig,\n AiToolMode,\n AiErrorBehavior,\n AiContainerConfig,\n FlowDefinitionNodeBase,\n FlowStepProperties,\n FlowDefinitionStep,\n ContainerRule,\n FanOutConfig,\n MergeStrategy,\n FlowDefinitionContainer,\n LoopConfig,\n FlowDefinitionNode,\n FlowDefinition,\n InboxTask,\n InboxTaskStatus,\n TaskCompletionResult,\n} from './types/flow-definition';\nexport {\n RETRY_STRATEGIES,\n getRefDisplayName,\n getRefPath,\n isFlowDefinitionStep,\n isFlowDefinitionContainer,\n} from './types/flow-definition';\n\n// Inbox tasks (human-in-the-loop)\nexport { InboxApi } from './inbox';\nexport type {\n InboxApiOptions,\n ListTasksOptions,\n ListTasksResponse,\n} from './inbox';\n\n// Chat types\nexport type {\n ChatMessage,\n ChatEvent,\n Conversation,\n ConversationType,\n ConversationListItem,\n ConversationStatus,\n MessageBody,\n ChatTextChunkEvent,\n ChatAssistantMessageEvent,\n ChatWaitingEvent,\n ChatCompletedEvent,\n ChatFailedEvent,\n ChatDoneEvent,\n ChatToolCallStartedEvent,\n ChatToolCallCompletedEvent,\n ChatThoughtChunkEvent,\n ToolCallRecord,\n MessageChild,\n PlanTask,\n ChatConversationCreatedEvent,\n ChatMessageSavedEvent,\n ChatMessageDeliveredEvent,\n ChatLogEvent,\n} from './types/chat';\n\n// Conversation management (unified API)\nexport { ConversationManager, DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS } from './conversations';\nexport type {\n ListConversationsOptions,\n CreateConversationOptions as CreateConvoOptions,\n SendMessageOptions,\n ConversationSubscription,\n PlanActionReceipt,\n PlanActionOptions,\n ConversationManagerOptions,\n} from './conversations';\n\n// Conversation stores (framework-agnostic)\nexport { ConversationStore } from './stores/conversation-store';\nexport type {\n ConversationStoreSnapshot,\n ConversationStoreOptions,\n ToolCallInfo,\n} from './stores/conversation-store';\nexport { ConversationListStore } from './stores/conversation-list-store';\nexport type {\n ConversationListSnapshot,\n ConversationListStoreOptions,\n} from './stores/conversation-list-store';\n\n// Plan projection utility\nexport { projectPlansFromMessages } from './utils/plan-projection';\nexport type { PlanProjection, PlanProjectionTask } from './utils/plan-projection';\n\n// React conversation adapters\nexport { useConversation, useConversationList } from './integrations/react-conversation';\nexport type {\n ReactLike,\n UseConversationReturn,\n UseConversationListReturn,\n} from './integrations/react-conversation';\n\n// Svelte 5 conversation adapters (legacy path — prefer @raisindb/client/svelte)\nexport { createConversationAdapter, createConversationListAdapter } from './integrations/svelte-conversation';\n\n// Svelte 5 integration (full)\nexport {\n createAuthAdapter,\n createConnectionAdapter,\n createSqlAdapter,\n createSubscriptionAdapter,\n createFlowAdapter,\n RAISIN_CONTEXT_KEY,\n} from './integrations/svelte';\nexport type {\n AuthSnapshot,\n AuthAdapter,\n ConnectionSnapshot,\n ConnectionAdapter,\n SqlAdapterOptions,\n SqlSnapshot,\n SqlAdapter,\n SubscriptionAdapter,\n FlowSnapshot,\n FlowAdapterOptions,\n FlowAdapter,\n FlowStatus as SvelteFlowStatus,\n RaisinContext,\n} from './integrations/svelte';\n\n// React flow adapter\nexport { useFlow } from './integrations/react-flow';\nexport type {\n UseFlowOptions,\n UseFlowReturn,\n FlowStatus,\n} from './integrations/react-flow';\n\n// React integration (Provider + hooks factory)\nexport { createRaisinReact } from './integrations/react';\nexport type {\n RaisinReact,\n ReactLikeWithContext,\n RaisinProviderProps,\n RaisinContextValue,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlOptions,\n UseSqlReturn,\n UseSubscriptionOptions,\n} from './integrations/react';\n\n// Vue 3 integration (composables factory — also available as @raisindb/client/vue)\nexport { createRaisinVue } from './integrations/vue';\nexport type {\n RaisinVue,\n VueLike,\n VueRef,\n VueComputedRef,\n} from './integrations/vue';\n\n// Streaming (SSE)\nexport { SSEClient } from './streaming/sse-client';\nexport type {\n SSEEvent,\n SSEClientOptions,\n SSEConnectionState,\n SSEStateCallback,\n} from './streaming/sse-client';\n","/**\n * RaisinDB WebSocket client\n */\n\nimport { EventEmitter } from 'events';\nimport { Connection, ConnectionState, ConnectionOptions } from './connection';\nimport { RequestTracker } from './utils/request-tracker';\nimport {\n AuthManager,\n Credentials,\n AdminCredentials,\n isJwtCredentials,\n TokenStorage,\n LocalStorageTokenStorage,\n IdentityUser,\n IdentityAuthResponse,\n} from './auth';\nimport { EventHandler } from './events';\nimport { Database } from './database';\nimport {\n RequestEnvelope,\n ResponseEnvelope,\n RequestContext,\n RequestType,\n ResponseStatus,\n AuthenticatePayload,\n AuthenticateResponse,\n AuthenticateJwtPayload,\n AuthenticateJwtResponse,\n ConnectedMessage,\n encodeMessage,\n decodeMessage,\n isEventMessage,\n isResponseEnvelope,\n isConnectedMessage,\n} from './protocol';\nimport { RaisinHttpClient, HttpClientOptions, SignAssetOptions, SignedAssetUrl } from './http-client';\nimport { RaisinAuthError, RaisinTimeoutError } from './errors';\nimport { logger, LogLevel, setLogLevel } from './logger';\nimport { normalizeHomePath } from './utils/home-path';\nimport type { Upload, UploadOptions, BatchUpload, BatchUploadOptions } from './upload/types';\nimport { createFileSource } from './upload/file-source';\nimport { UploadManager } from './upload/uploader';\n\n/**\n * Client mode\n */\nexport type ClientMode = 'websocket' | 'http' | 'hybrid';\n\n// ============================================================================\n// Auth State Change Types (Firebase/Supabase-compatible pattern)\n// ============================================================================\n\n/**\n * Auth event types emitted by onAuthStateChange\n */\nexport type AuthEvent =\n | 'SIGNED_IN'\n | 'SIGNED_OUT'\n | 'TOKEN_REFRESHED'\n | 'SESSION_EXPIRED'\n | 'USER_UPDATED';\n\n/**\n * Auth state change payload\n */\nexport interface AuthStateChange {\n /** The auth event that occurred */\n event: AuthEvent;\n /** Current session state */\n session: {\n /** Current identity user or null if signed out */\n user: IdentityUser | null;\n /** Current access token or null if signed out */\n accessToken: string | null;\n /**\n * Current EFFECTIVE roles (direct + group + inherited) for the connected\n * user, or null/undefined when signed out. Populated from the WS auth\n * handshake so role-gated consumers can read roles from the event without a\n * separate call. Updated on SIGNED_IN, USER_UPDATED (incl. after a\n * server-pushed permission change), and reconnect.\n */\n roles?: string[] | null;\n };\n}\n\n/**\n * Callback for auth state changes\n */\nexport type AuthStateChangeCallback = (change: AuthStateChange) => void;\n\n/**\n * User change event payload (for user home node updates)\n */\nexport interface UserChangeEvent {\n /** The user's home node with updated data */\n node: UserNode;\n /** Type of change (e.g., 'node:updated') */\n changeType: string;\n}\n\n/**\n * Callback for user home node changes\n */\nexport type UserChangeCallback = (event: UserChangeEvent) => void;\n\n/**\n * Client options\n */\nexport interface ClientOptions {\n /** Connection options */\n connection?: ConnectionOptions;\n /** Token storage (default: in-memory) */\n tokenStorage?: TokenStorage;\n /** Request timeout in milliseconds (default: 30000) */\n requestTimeout?: number;\n /** Tenant ID (extracted from URL if not provided; default: \"default\") */\n tenantId?: string;\n /**\n * Repository name. When the URL has no path (e.g. `ws://host:8081`),\n * the client connects to the tenant-less `/ws/{repository}` route.\n * When the URL already carries a path, this overrides the repository\n * extracted from the URL (used for repo-scoped auth endpoints).\n */\n repository?: string;\n /** Default branch (default: \"main\") */\n defaultBranch?: string;\n /** Client mode (default: \"websocket\") */\n mode?: ClientMode;\n /** Log level (default: Info - minimal logging) */\n logLevel?: LogLevel;\n /** HTTP base URL for identity auth (derived from WS URL if not provided) */\n httpBaseUrl?: string;\n}\n\n/**\n * RaisinDB client\n */\n/**\n * Current user info\n */\nexport interface CurrentUser {\n /** User ID (identity UUID) */\n userId: string;\n /** Roles assigned to the user */\n roles?: string[];\n /** Whether this is an anonymous user */\n anonymous: boolean;\n /** The full user node from the repository (from CURRENT_USER()) */\n node?: UserNode;\n}\n\n/**\n * User node from the repository\n */\nexport interface UserNode {\n /** Node ID */\n id: string;\n /** Node path (e.g., '/users/internal/john-at-example-com') */\n path: string;\n /** Node name */\n name: string;\n /** Node type (e.g., 'raisin:User') */\n node_type: string;\n /** Node properties */\n properties: Record<string, unknown>;\n}\n\nexport class RaisinClient extends EventEmitter {\n private connection: Connection;\n private requestTracker: RequestTracker;\n private authManager: AuthManager;\n private eventHandler: EventHandler;\n private _context: RequestContext;\n private options: Required<Omit<ClientOptions, 'connection' | 'tokenStorage' | 'mode' | 'logLevel' | 'httpBaseUrl' | 'repository'>>;\n private _currentUser: CurrentUser | null = null;\n /** In-flight role re-resolve, used to coalesce concurrent refreshCurrentUser() calls. */\n #refreshingUser: Promise<void> | null = null;\n private _httpBaseUrl: string;\n private _repository: string;\n\n // Auth state change listeners (Firebase/Supabase pattern)\n private _authListeners: Set<AuthStateChangeCallback> = new Set();\n private _userChangeListeners: Set<UserChangeCallback> = new Set();\n private _userHomeSubscription: { unsubscribe: () => Promise<void> } | null = null;\n\n // Ready state: connected AND (authenticated OR no stored token)\n private _ready: boolean = false;\n private _readyListeners: Set<(ready: boolean) => void> = new Set();\n\n // Reconnection tracking\n private _previousConnectionState: ConnectionState = ConnectionState.Disconnected;\n private _reconnectedListeners: Set<() => void> = new Set();\n private _everConnected = false;\n\n // Requests queued while the connection is re-establishing.\n // Flushed after reconnect + re-auth; bounded by MAX_QUEUED_REQUESTS.\n private _queuedRequests: Array<{ requestId: string; encoded: Uint8Array }> = [];\n /** Hard cap on requests held while reconnecting; overflow rejects immediately. */\n private static readonly MAX_QUEUED_REQUESTS = 100;\n\n /**\n * Backoff delays (ms) between subscription-restore retries after reconnect.\n * @internal - overridable in tests\n */\n private _restoreRetryDelaysMs: number[] = [1000, 3000, 9000];\n\n // Upload manager (uses HTTP under the hood)\n private _uploadManager: UploadManager | null = null;\n\n constructor(url: string, options: ClientOptions = {}) {\n super();\n\n // Configure log level if provided\n if (options.logLevel !== undefined) {\n setLogLevel(options.logLevel);\n }\n\n // When a repository option is given and the URL has no path, build the\n // tenant-less /ws/{repository} URL internally.\n const connectionUrl = this.buildConnectionUrl(url, options.repository);\n\n this.options = {\n requestTimeout: options.requestTimeout ?? 30000,\n tenantId: options.tenantId ?? this.extractTenantFromUrl(connectionUrl),\n defaultBranch: options.defaultBranch ?? 'main',\n };\n\n // Derive HTTP base URL from WebSocket URL if not provided\n this._httpBaseUrl = options.httpBaseUrl ?? this.deriveHttpUrl(connectionUrl);\n\n // Extract repository from URL for repo-scoped auth endpoints\n this._repository = options.repository ?? this.extractRepositoryFromUrl(connectionUrl);\n\n // Initialize context\n this._context = {\n tenant_id: this.options.tenantId,\n branch: this.options.defaultBranch,\n };\n\n // Send the tenant on the WebSocket upgrade request so tenant-less /ws\n // URLs resolve to the right tenant - but ONLY when the caller explicitly\n // provided one (or the URL carries one). Header ABSENCE is the protocol's\n // \"use your default resolution\" signal; always asserting 'default' would\n // fight proxies that inject the real tenant header. Only effective where\n // the WebSocket implementation supports custom headers (Node.js `ws`);\n // browsers ignore it and rely on the server-side resolution.\n const explicitTenant =\n options.tenantId ?? (this.extractTenantFromUrl(url) !== 'default' ? this.options.tenantId : undefined);\n const connectionOptions: ConnectionOptions = {\n ...options.connection,\n headers: {\n ...(explicitTenant ? { 'x-tenant-id': explicitTenant } : {}),\n ...options.connection?.headers,\n },\n };\n\n // Initialize components\n this.connection = this.createConnection(connectionUrl, connectionOptions);\n this.requestTracker = new RequestTracker({\n defaultTimeout: this.options.requestTimeout,\n });\n this.authManager = new AuthManager(options.tokenStorage);\n this.eventHandler = new EventHandler((payload, requestType) =>\n this.sendRequestInternal(payload, requestType)\n );\n\n // Set up event handlers\n this.setupConnectionHandlers();\n }\n\n /**\n * Create the underlying WebSocket connection.\n * Seam for tests to inject a fake connection.\n * @internal\n */\n protected createConnection(url: string, options?: ConnectionOptions): Connection {\n return new Connection(url, options);\n }\n\n /**\n * Derive HTTP URL from WebSocket URL\n * ws://host:port/path -> http://host:port\n * wss://host:port/path -> https://host:port\n */\n private deriveHttpUrl(wsUrl: string): string {\n try {\n const url = wsUrl\n .replace(/^raisin:\\/\\//, 'ws://')\n .replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(url);\n const protocol = parsed.protocol === 'wss:' ? 'https:' : 'http:';\n return `${protocol}//${parsed.host}`;\n } catch {\n return 'http://localhost:8081';\n }\n }\n\n /**\n * Build the WebSocket connection URL.\n *\n * When a repository option is provided and the URL carries no path\n * (e.g. `ws://host:8081`), build the tenant-less `/ws/{repository}`\n * route internally. URLs that already carry a path are used as-is.\n */\n private buildConnectionUrl(url: string, repository?: string): string {\n if (!repository) {\n return url;\n }\n try {\n const wsUrl = url.replace(/^raisin:\\/\\//, 'ws://').replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(wsUrl);\n const hasPath = parsed.pathname.split('/').some((p) => p.length > 0);\n if (hasPath) {\n return url;\n }\n return `${url.replace(/\\/+$/, '')}/ws/${repository}`;\n } catch {\n return url;\n }\n }\n\n /**\n * Extract repository from URL\n * URL forms: /ws/{repo} (tenant-less, preferred), /sys/{tenant}/{repo}\n * (operator/multi-tenant), /{tenant}/{repo} (legacy).\n */\n private extractRepositoryFromUrl(url: string): string {\n try {\n const wsUrl = url.replace(/^raisin:\\/\\//, 'ws://').replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(wsUrl);\n const parts = parsed.pathname.split('/').filter((p) => p.length > 0);\n if (parts[0] === 'ws') {\n // /ws/{repo}\n return parts.length > 1 ? parts[1] : '';\n }\n if (parts[0] === 'sys') {\n // /sys/{tenant}/{repo}\n return parts.length > 2 ? parts[2] : '';\n }\n // Legacy /{tenant}/{repo}\n return parts.length > 1 ? parts[1] : '';\n } catch {\n return '';\n }\n }\n\n /**\n * Extract tenant ID from URL\n * URL forms: /ws/{repo} (tenant-less — no tenant in URL),\n * /sys/{tenant}/{repo} (canonical), /{tenant}/{repo} (legacy).\n * When the URL doesn't carry a tenant, fall back to 'default' — the\n * server's tenant middleware resolves it anyway (production derives the\n * tenant from the request itself), so an explicit tenantId is optional.\n */\n private extractTenantFromUrl(url: string): string {\n try {\n // Convert raisin:// to ws:// for URL parsing\n const wsUrl = url.replace(/^raisin:\\/\\//, 'ws://').replace(/^raisins:\\/\\//, 'wss://');\n const parsed = new URL(wsUrl);\n const parts = parsed.pathname.split('/').filter((p) => p.length > 0);\n if (parts[0] === 'ws') {\n // Tenant-less route: the server resolves the tenant from the\n // upgrade request (x-tenant-id header, falling back to 'default').\n return 'default';\n }\n if (parts[0] === 'sys') {\n return parts.length > 1 ? parts[1] : 'default';\n }\n return parts.length >= 2 ? parts[0] : 'default';\n } catch (error) {\n return 'default';\n }\n }\n\n /**\n * Set up connection event handlers\n */\n private setupConnectionHandlers(): void {\n this.connection.on('message', (data: ArrayBuffer) => {\n this.handleMessage(data);\n });\n\n this.connection.on('stateChange', (state: ConnectionState) => {\n const wasDisconnected =\n this._previousConnectionState === ConnectionState.Disconnected ||\n this._previousConnectionState === ConnectionState.Reconnecting;\n\n if (state === ConnectionState.Connected) {\n this._everConnected = true;\n }\n\n if (state === ConnectionState.Disconnected || state === ConnectionState.Closed) {\n // The connection is down for good (manual close, max reconnect\n // attempts reached, ...): cancel all pending requests, including\n // any held in the reconnect queue.\n this._queuedRequests = [];\n this.requestTracker.cancelAll();\n }\n\n // Handle reconnection: restore subscriptions after connection is re-established\n // Note: handleConnectedMessage() handles re-auth, then we restore subscriptions\n if (state === ConnectionState.Connected && wasDisconnected && this._previousConnectionState !== ConnectionState.Disconnected) {\n // This is a reconnection (not initial connection)\n // Subscription restoration happens after auth in handleConnectedMessage\n logger.info('[setupConnectionHandlers] Reconnection detected, will restore subscriptions after auth');\n }\n\n this._previousConnectionState = state;\n\n // Update ready state on all connection changes\n this._updateReadyState();\n });\n\n this.connection.on('error', (error: Error) => {\n logger.error('Connection error:', error);\n });\n }\n\n /**\n * Handle incoming message\n */\n private handleMessage(data: ArrayBuffer): void {\n logger.debug(`handleMessage() called - data size: ${data.byteLength} bytes`);\n try {\n logger.debug(`Attempting to decode MessagePack message...`);\n const message = decodeMessage(data);\n logger.debug(`Successfully decoded message`);\n logger.debug(`Message keys:`, Object.keys(message));\n logger.debug(`Message structure:`, JSON.stringify(message, null, 2));\n logger.debug(`Type check: isEvent=${isEventMessage(message)}, isResponse=${isResponseEnvelope(message)}, isConnected=${isConnectedMessage(message)}`);\n logger.debug(`Has 'status' property:`, 'status' in message);\n logger.debug(`Has 'subscription_id' property:`, 'subscription_id' in message);\n logger.debug(`Status value:`, (message as any).status);\n\n if (isConnectedMessage(message)) {\n // Handle connected message from server\n this.handleConnectedMessage(message);\n } else if (isEventMessage(message)) {\n // Out-of-band \"your permissions may have changed\" push (reserved\n // subscription id / event type, sent by the server after an\n // access-control write). Re-resolve roles instead of routing it to a\n // normal subscription callback. Keep in sync with the server\n // (raisin-transport-ws event_handler PERMISSIONS_EVENT_TYPE).\n if ((message as { event_type?: string }).event_type === 'permissions:changed') {\n logger.info('[permissions:changed] server signaled a role/permission change; re-resolving');\n void this.refreshCurrentUser();\n } else {\n // Handle event message\n logger.debug(`Routing to event handler`);\n this.eventHandler.handleEvent(message);\n }\n } else if (isResponseEnvelope(message)) {\n // Handle response message\n logger.debug(`Routing to response handler - request_id: ${(message as any).request_id}, status: ${(message as any).status}`);\n this.handleResponse(message);\n } else {\n logger.warn(`Unknown message type - not event or response`);\n }\n } catch (error) {\n logger.error('Error decoding message:', error);\n logger.error('Message data (first 100 bytes):', new Uint8Array(data.slice(0, 100)));\n }\n }\n\n /**\n * Handle connected message from server\n * Stores current user info for anonymous users\n *\n * NOTE: We do NOT store the anonymous token here because it would overwrite\n * any existing user JWT in localStorage. The anonymous token is only needed\n * for HTTP API calls when there's no existing session.\n */\n private handleConnectedMessage(message: ConnectedMessage): void {\n logger.info(`Connected to server - connection_id: ${message.connection_id}, anonymous: ${message.anonymous}`);\n\n // Check if this is a reconnection (we had subscriptions before)\n const hasActiveSubscriptions = this.eventHandler.getActiveSubscriptions().length > 0 ||\n this.eventHandler.hasStoredFilters();\n\n // Store current user info for anonymous users (but don't overwrite stored tokens!)\n if (message.anonymous && message.user_id) {\n // Only set anonymous user if we don't already have a stored token\n // (otherwise we're about to authenticate with the stored token)\n const hasStoredToken = this.authManager.storage.getAccessToken() !== null;\n if (!hasStoredToken) {\n this._currentUser = {\n userId: message.user_id,\n anonymous: true,\n // Anonymous users don't have a node in the repository\n };\n logger.debug(`Anonymous user info stored: ${message.user_id}`);\n // Anonymous user is ready immediately\n this._updateReadyState();\n this._flushQueuedRequests();\n\n // Restore subscriptions for anonymous users on reconnect\n if (hasActiveSubscriptions) {\n this._restoreSubscriptionsAndNotify();\n }\n } else {\n // Auto-authenticate with stored token on reconnect\n logger.info(`[handleConnectedMessage] Stored token found, auto-authenticating...`);\n this.autoReauthenticate()\n .then(async (authenticated) => {\n if (authenticated) {\n // After successful re-auth, deliver requests queued while down\n this._flushQueuedRequests();\n } else {\n this._rejectQueuedRequests(\n new RaisinAuthError(\n 'Re-authentication failed after reconnect',\n 'AUTH_TOKEN_EXPIRED',\n 401\n )\n );\n }\n // Restore subscriptions regardless (they may be readable anonymously)\n if (hasActiveSubscriptions) {\n await this._restoreSubscriptionsAndNotify();\n }\n })\n .catch((err) => {\n logger.error(`[handleConnectedMessage] Auto-authenticate failed:`, err);\n this._rejectQueuedRequests(\n err instanceof Error ? err : new Error('Re-authentication failed after reconnect')\n );\n });\n }\n } else {\n // Non-anonymous connection message: nothing to re-authenticate here\n this._flushQueuedRequests();\n }\n\n // Emit connected event\n this.emit('connected', {\n connectionId: message.connection_id,\n anonymous: message.anonymous,\n userId: message.user_id,\n });\n }\n\n /**\n * Restore subscriptions after reconnection and notify listeners.\n *\n * Retries with backoff (see `_restoreRetryDelaysMs`); on final failure a\n * `subscription_restore_failed` event is emitted so applications can\n * resync their state (e.g. reload lists and re-subscribe manually).\n * @internal\n */\n private async _restoreSubscriptionsAndNotify(): Promise<void> {\n const delays = this._restoreRetryDelaysMs;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n try {\n logger.info(\n `[_restoreSubscriptionsAndNotify] Restoring subscriptions (attempt ${attempt + 1}/${delays.length + 1})...`\n );\n await this.eventHandler.restoreSubscriptions({ retry: attempt > 0 });\n logger.info('[_restoreSubscriptionsAndNotify] Subscriptions restored successfully');\n\n // Notify reconnected listeners\n this._emitReconnected();\n return;\n } catch (error) {\n lastError = error;\n logger.error(\n `[_restoreSubscriptionsAndNotify] Restore attempt ${attempt + 1} failed:`,\n error\n );\n if (attempt < delays.length) {\n await new Promise((resolve) => setTimeout(resolve, delays[attempt]));\n }\n }\n }\n\n logger.error('[_restoreSubscriptionsAndNotify] Giving up after retries; events may be stale');\n this.emit(\n 'subscription_restore_failed',\n lastError instanceof Error ? lastError : new Error(String(lastError))\n );\n }\n\n /**\n * Emit reconnected event to all listeners\n * @internal\n */\n private _emitReconnected(): void {\n logger.info('[_emitReconnected] Emitting reconnected event');\n for (const callback of this._reconnectedListeners) {\n try {\n callback();\n } catch (err) {\n logger.error('[_emitReconnected] Listener error:', err);\n }\n }\n this.emit('reconnected');\n }\n\n /**\n * Auto-reauthenticate with stored JWT on reconnection\n *\n * @returns true if the session was re-authenticated, false otherwise\n * @internal\n */\n private async autoReauthenticate(): Promise<boolean> {\n const token = this.authManager.storage.getAccessToken();\n if (!token) {\n logger.warn('[autoReauthenticate] No stored token');\n return false;\n }\n\n // Check if token is expired\n const payload = AuthManager.parseToken(token);\n if (payload?.exp && typeof payload.exp === 'number') {\n if (payload.exp * 1000 < Date.now()) {\n logger.warn('[autoReauthenticate] Token expired, attempting refresh...');\n const refreshed = await this.refreshToken();\n if (!refreshed) {\n logger.error('[autoReauthenticate] Token refresh failed, clearing session');\n this.authManager.clear();\n this._currentUser = null;\n this._emitAuthEvent('SESSION_EXPIRED');\n return false;\n }\n // Use the new token\n const newToken = this.authManager.storage.getAccessToken();\n if (newToken) {\n await this.authenticate({ type: 'jwt', token: newToken });\n return true;\n }\n return false;\n }\n }\n\n // Authenticate with the stored token\n try {\n await this.authenticate({ type: 'jwt', token });\n logger.info('[autoReauthenticate] Successfully re-authenticated');\n return true;\n } catch (err) {\n logger.error('[autoReauthenticate] Failed to authenticate:', err);\n // Try to refresh token\n const refreshed = await this.refreshToken();\n if (refreshed) {\n const newToken = this.authManager.storage.getAccessToken();\n if (newToken) {\n await this.authenticate({ type: 'jwt', token: newToken });\n return true;\n }\n return false;\n } else {\n this.authManager.clear();\n this._currentUser = null;\n this._emitAuthEvent('SESSION_EXPIRED');\n return false;\n }\n }\n }\n\n /**\n * Handle response message\n */\n private handleResponse(response: ResponseEnvelope): void {\n const requestId = response.request_id;\n logger.debug(`handleResponse() called - request_id: ${requestId}, status: ${response.status}`);\n\n if (response.status === ResponseStatus.Success || response.status === ResponseStatus.Complete) {\n logger.debug(`Resolving request ${requestId} with success result`);\n this.requestTracker.resolveRequest(requestId, response.result);\n logger.debug(`Request ${requestId} resolved successfully`);\n } else if (response.status === ResponseStatus.Error) {\n logger.debug(`Rejecting request ${requestId} with error: ${response.error?.message}`);\n const error = new Error(\n response.error?.message ?? 'Unknown error'\n );\n (error as any).code = response.error?.code;\n (error as any).details = response.error?.details;\n this.requestTracker.rejectRequest(requestId, error);\n logger.debug(`Request ${requestId} rejected with error`);\n } else if (response.status === ResponseStatus.Streaming) {\n // Handle streaming responses (could be enhanced later)\n // For now, just resolve with the current chunk\n logger.debug(`Resolving streaming response for request ${requestId}`);\n this.requestTracker.resolveRequest(requestId, response.result);\n } else if (response.status === ResponseStatus.Acknowledged) {\n // Request acknowledged, continue waiting\n logger.debug(`Request ${requestId} acknowledged, waiting for completion`);\n } else {\n logger.warn(`Unknown response status: ${response.status} for request ${requestId}`);\n }\n }\n\n /**\n * Connect to the server\n */\n async connect(): Promise<void> {\n await this.connection.connect();\n }\n\n /**\n * Authenticate with credentials\n *\n * Supports two authentication modes:\n * - Admin auth: { username: string, password: string }\n * - JWT auth: { type: 'jwt', token: string }\n *\n * @param credentials - User credentials\n */\n async authenticate(credentials: Credentials): Promise<void> {\n if (isJwtCredentials(credentials)) {\n // JWT authentication for identity users\n logger.info('[authenticate] Starting JWT authentication...');\n const payload: AuthenticateJwtPayload = { token: credentials.token };\n const response = await this.sendRequestInternal(\n payload,\n RequestType.AuthenticateJwt\n ) as AuthenticateJwtResponse;\n\n // Store current user info from auth response\n // Note: User node can be fetched separately via fetchUserNode() if needed\n this._currentUser = {\n userId: response.user_id,\n roles: response.roles,\n anonymous: false,\n };\n logger.info(`[authenticate] JWT auth successful: user_id=${response.user_id}, roles=${JSON.stringify(response.roles)}`);\n\n // Emit authenticated event with JWT response\n this.emit('authenticated', response);\n } else {\n // Admin authentication with username/password\n const payload: AuthenticatePayload = AuthManager.createAuthPayload(credentials as AdminCredentials);\n const response = await this.sendRequestInternal(\n payload,\n RequestType.Authenticate\n ) as AuthenticateResponse;\n\n this.authManager.setTokens(response);\n\n // For admin auth, we don't have user_id in response, use 'admin' as placeholder\n this._currentUser = {\n userId: 'admin',\n anonymous: false,\n // Admin users don't have a node in the repository\n };\n\n // Emit authenticated event\n this.emit('authenticated', response);\n }\n }\n\n /**\n * Disconnect from the server\n */\n disconnect(): void {\n this.connection.disconnect();\n this.requestTracker.clear();\n this.eventHandler.clearAll();\n this.eventHandler.destroy();\n this.authManager.clear();\n this._currentUser = null;\n }\n\n // ============================================================================\n // Identity Authentication (Email/Password via HTTP)\n // ============================================================================\n\n /**\n * Login with email and password (identity auth)\n *\n * This uses HTTP /auth/{repo}/login endpoint, stores tokens, connects WebSocket,\n * authenticates the WebSocket, and fetches the user node via SQL.\n *\n * @param email - User's email address\n * @param password - User's password\n * @param repository - Repository name (used for auth endpoint)\n * @returns The authenticated user info\n *\n * @example\n * ```typescript\n * const client = new RaisinClient('ws://localhost:8081/sys/default/myrepo');\n * const user = await client.loginWithEmail('user@example.com', 'password', 'myrepo');\n * console.log('Logged in as:', user.email, 'home:', user.home);\n * ```\n */\n async loginWithEmail(\n email: string,\n password: string,\n repository: string\n ): Promise<IdentityUser> {\n logger.info('[loginWithEmail] Starting login...');\n\n // Override _repository with the explicitly provided value (URL extraction\n // can return the wrong segment for 3-segment paths like /sys/default/repo)\n if (repository) {\n this._repository = repository;\n }\n\n // 1. Call HTTP login endpoint\n const url = `${this._httpBaseUrl}/auth/${repository}/login`;\n logger.debug('[loginWithEmail] POST', url);\n\n const response = await this._fetchWithTimeout(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }));\n // Real Error instance; keeps `{ code, message }` fields for\n // backwards-compatible destructuring (IdentityAuthError shape).\n throw new RaisinAuthError(\n error.message || 'Login failed',\n error.code || 'LOGIN_FAILED',\n response.status\n );\n }\n\n const tokens: IdentityAuthResponse = await response.json();\n logger.info('[loginWithEmail] HTTP login successful, user_id:', tokens.identity.id);\n\n // 2. Store tokens\n this.authManager.storage.setAccessToken(tokens.access_token);\n this.authManager.storage.setRefreshToken(tokens.refresh_token);\n\n // 3. Connect WebSocket if not connected\n if (!this.connection.isConnected()) {\n logger.debug('[loginWithEmail] Connecting WebSocket...');\n await this.connect();\n }\n\n // 4. Authenticate WebSocket with JWT\n logger.debug('[loginWithEmail] Authenticating WebSocket with JWT...');\n await this.authenticate({ type: 'jwt', token: tokens.access_token });\n\n // 5. Fetch user node via SQL to get the correct path (fallback if HTTP response has no home)\n logger.debug('[loginWithEmail] Fetching user node via SQL RAISIN_CURRENT_USER()...');\n const userNode = await this.fetchUserNode(repository);\n\n // 6. Build user object (HTTP response takes precedence, SQL is fallback)\n logger.info('[loginWithEmail] HTTP response identity.home:', tokens.identity.home);\n logger.info('[loginWithEmail] SQL userNode?.path:', userNode?.path);\n const user: IdentityUser = {\n id: tokens.identity.id,\n email: tokens.identity.email,\n displayName: tokens.identity.display_name,\n avatarUrl: tokens.identity.avatar_url,\n emailVerified: tokens.identity.email_verified,\n home: tokens.identity.home ?? userNode?.path ?? null,\n };\n\n // 7. Store user in localStorage if using LocalStorageTokenStorage\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // 8. Update current user.\n // Preserve the roles that authenticate({type:'jwt'}) just resolved from the\n // server (client.ts authenticate() sets _currentUser.roles = response.roles).\n // This overwrite exists to attach the fetched user node; it must NOT discard\n // the effective roles, or getCurrentUser().roles would always be [].\n this._currentUser = {\n userId: user.id,\n roles: this._currentUser?.roles ?? [],\n anonymous: false,\n node: userNode ?? undefined,\n };\n\n // 9. Schedule auto-refresh (expires_at minus 5 minutes)\n const expiresInMs = RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n\n // 10. Subscribe to user home changes if available\n if (user.home) {\n await this._subscribeToUserHome(repository, user.home);\n }\n\n // 11. Emit auth events\n logger.info('[loginWithEmail] Login complete, user home:', user.home);\n this._emitAuthEvent('SIGNED_IN');\n this.emit('login', user);\n return user;\n }\n\n /**\n * Register a new user with email and password\n *\n * @param email - User's email address\n * @param password - User's password\n * @param repository - Repository name\n * @param displayName - Optional display name\n * @returns The registered user info\n */\n async registerWithEmail(\n email: string,\n password: string,\n repository: string,\n displayName?: string\n ): Promise<IdentityUser> {\n logger.info('[registerWithEmail] Starting registration...');\n\n // 1. Call HTTP register endpoint\n const url = `${this._httpBaseUrl}/auth/${repository}/register`;\n const response = await this._fetchWithTimeout(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password, display_name: displayName }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }));\n // Real Error instance; keeps `{ code, message }` fields for\n // backwards-compatible destructuring (IdentityAuthError shape).\n throw new RaisinAuthError(\n error.message || 'Registration failed',\n error.code || 'REGISTRATION_FAILED',\n response.status\n );\n }\n\n const tokens: IdentityAuthResponse = await response.json();\n logger.info('[registerWithEmail] Registration successful, user_id:', tokens.identity.id);\n\n // 2. Store tokens\n this.authManager.storage.setAccessToken(tokens.access_token);\n this.authManager.storage.setRefreshToken(tokens.refresh_token);\n\n // 3. Connect WebSocket if not connected\n if (!this.connection.isConnected()) {\n await this.connect();\n }\n\n // 4. Authenticate WebSocket with JWT\n await this.authenticate({ type: 'jwt', token: tokens.access_token });\n\n // 5. Fetch user node - note: might be null initially until job completes\n // Wait a bit for the user node creation job to complete\n await new Promise(resolve => setTimeout(resolve, 500));\n const userNode = await this.fetchUserNode(repository);\n\n // 6. Build user object (HTTP response takes precedence, SQL is fallback)\n logger.info('[registerWithEmail] HTTP response identity.home:', tokens.identity.home);\n logger.info('[registerWithEmail] SQL userNode?.path:', userNode?.path);\n const user: IdentityUser = {\n id: tokens.identity.id,\n email: tokens.identity.email,\n displayName: tokens.identity.display_name,\n avatarUrl: tokens.identity.avatar_url,\n emailVerified: tokens.identity.email_verified,\n home: tokens.identity.home ?? userNode?.path ?? null,\n };\n\n // 7. Store user in localStorage if using LocalStorageTokenStorage\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // 8. Update current user.\n // Preserve the roles that authenticate({type:'jwt'}) just resolved from the\n // server (client.ts authenticate() sets _currentUser.roles = response.roles).\n // This overwrite exists to attach the fetched user node; it must NOT discard\n // the effective roles, or getCurrentUser().roles would always be [].\n this._currentUser = {\n userId: user.id,\n roles: this._currentUser?.roles ?? [],\n anonymous: false,\n node: userNode ?? undefined,\n };\n\n // 9. Schedule auto-refresh (expires_at minus 5 minutes)\n const expiresInMs = RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n\n // 10. Subscribe to user home changes if available\n if (user.home) {\n await this._subscribeToUserHome(repository, user.home);\n }\n\n // 11. Emit auth events\n logger.info('[registerWithEmail] Registration complete, user home:', user.home);\n this._emitAuthEvent('SIGNED_IN');\n this.emit('register', user);\n return user;\n }\n\n /**\n * Logout - clear tokens and handle reconnection\n *\n * For SPAs, use `reconnect: true` (default) to stay connected as anonymous.\n * This allows the app to continue functioning without auth.\n *\n * @param options.reconnect - Reconnect as anonymous after logout (default: true for SPAs)\n * @param options.disconnect - Fully disconnect without reconnecting (default: false)\n *\n * @example\n * ```typescript\n * // SPA: logout and reconnect as anonymous (default)\n * await client.logout();\n *\n * // Fully disconnect (e.g., closing app)\n * await client.logout({ disconnect: true });\n * ```\n */\n async logout(options: { disconnect?: boolean; reconnect?: boolean } = {}): Promise<void> {\n logger.info('[logout] Logging out...');\n\n // Clear auto-refresh timer\n if (this._refreshTimer) {\n clearTimeout(this._refreshTimer);\n this._refreshTimer = undefined;\n }\n\n // Unsubscribe from user home\n await this._unsubscribeFromUserHome();\n\n // Clear tokens and user state\n this.authManager.clear();\n this._currentUser = null;\n\n // Determine behavior: reconnect by default unless disconnect is explicitly true\n const shouldDisconnect = options.disconnect === true;\n const shouldReconnect = !shouldDisconnect && (options.reconnect !== false);\n\n if (shouldReconnect) {\n // Disconnect and reconnect as anonymous (SPA flow)\n logger.info('[logout] Reconnecting as anonymous...');\n this.connection.disconnect();\n await this.connect();\n logger.info('[logout] Reconnected as anonymous');\n } else if (shouldDisconnect) {\n // Fully disconnect\n this.disconnect();\n }\n\n // Emit auth event\n this._emitAuthEvent('SIGNED_OUT');\n this.emit('logout');\n }\n\n /**\n * Initialize session from stored tokens\n *\n * This checks localStorage for existing tokens, connects WebSocket,\n * authenticates, and fetches the current user node. Call this on app startup.\n *\n * @param repository - Repository name for user node lookup\n * @returns The current user if session is valid, null otherwise\n *\n * @example\n * ```typescript\n * const client = new RaisinClient('ws://localhost:8081/sys/default/myrepo', {\n * tokenStorage: new LocalStorageTokenStorage('myapp')\n * });\n * const user = await client.initSession('myrepo');\n * if (user) {\n * console.log('Restored session for:', user.email);\n * } else {\n * // Redirect to login\n * }\n * ```\n */\n async initSession(repository: string): Promise<IdentityUser | null> {\n logger.info('[initSession] Initializing session from storage...');\n\n // Override _repository with the explicitly provided value (URL extraction\n // can return the wrong segment for 3-segment paths like /sys/default/repo)\n if (repository) {\n this._repository = repository;\n }\n\n const token = this.authManager.storage.getAccessToken();\n\n // Always connect WebSocket first (even for anonymous)\n if (!this.connection.isConnected()) {\n logger.debug('[initSession] Connecting WebSocket...');\n await this.connect();\n }\n\n if (!token) {\n logger.info('[initSession] No stored token found, connected as anonymous');\n return null;\n }\n\n // Check if token is expired (basic check)\n const payload = AuthManager.parseToken(token);\n if (payload && payload.exp && typeof payload.exp === 'number') {\n if (payload.exp * 1000 < Date.now()) {\n logger.info('[initSession] Token expired, attempting refresh...');\n\n // Delegate to refreshToken() rather than issuing our own refresh POST.\n // Refresh tokens are single-use (the server rotates them and revokes the\n // session on reuse), and connect() above can already have started a\n // refresh via autoReauthenticate(). Two refreshes racing on the same\n // stored token trip the server's reuse detection and kill the session.\n // refreshToken() is single-flighted, so both callers share one request.\n if (!this.authManager.storage.getRefreshToken()) {\n logger.warn('[initSession] No refresh token, clearing session');\n this.authManager.clear();\n return null;\n }\n\n const refreshed = await this.refreshToken();\n if (!refreshed) {\n logger.warn('[initSession] Token refresh failed, clearing session');\n this.authManager.clear();\n return null;\n }\n logger.info('[initSession] Token refreshed successfully');\n }\n }\n\n try {\n\n // Authenticate with stored token\n const currentToken = this.authManager.storage.getAccessToken();\n if (!currentToken) {\n return null;\n }\n\n logger.debug('[initSession] Authenticating WebSocket...');\n await this.authenticate({ type: 'jwt', token: currentToken });\n\n // Fetch user node via SQL\n logger.debug('[initSession] Fetching user node...');\n const userNode = await this.fetchUserNode(repository);\n\n // Get stored user or build from token\n let user: IdentityUser | null = null;\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n user = this.authManager.storage.getUser();\n }\n\n if (!user && payload) {\n // Build user from JWT payload (home is encoded in the token)\n user = {\n id: payload.sub as string,\n email: payload.email as string || '',\n displayName: payload.display_name as string || null,\n avatarUrl: null,\n emailVerified: false,\n home: (payload.home as string) ?? null,\n };\n }\n\n if (user) {\n // Update user home: SQL result > JWT payload > stored value\n const jwtHome = (payload?.home as string) ?? null;\n user.home = userNode?.path ?? jwtHome ?? user.home;\n\n // Update stored user\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // Preserve roles resolved by authenticate({type:'jwt'}) above — do not\n // clobber them with [] (that made getCurrentUser().roles empty after a\n // localStorage session restore).\n this._currentUser = {\n userId: user.id,\n roles: this._currentUser?.roles ?? [],\n anonymous: false,\n node: userNode ?? undefined,\n };\n\n // Schedule auto-refresh based on token expiration\n const currentToken = this.authManager.storage.getAccessToken();\n if (currentToken) {\n const tokenPayload = AuthManager.parseToken(currentToken);\n if (tokenPayload?.exp && typeof tokenPayload.exp === 'number') {\n const expiresInMs = (tokenPayload.exp * 1000) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n }\n }\n\n // Subscribe to user home changes if available\n if (user.home) {\n await this._subscribeToUserHome(repository, user.home);\n }\n\n logger.info('[initSession] Session restored for user:', user.email, 'home:', user.home);\n this._emitAuthEvent('SIGNED_IN');\n this.emit('session_restored', user);\n return user;\n }\n\n return null;\n } catch (err) {\n logger.warn('[initSession] Failed to restore session:', err);\n return null;\n }\n }\n\n /**\n * Get the stored identity user (from localStorage)\n */\n getStoredUser(): IdentityUser | null {\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n return this.authManager.storage.getUser();\n }\n return null;\n }\n\n /**\n * Check if there's a stored token (may or may not be valid)\n */\n hasStoredToken(): boolean {\n return this.authManager.storage.getAccessToken() !== null;\n }\n\n /**\n * Refresh the access token using the stored refresh token.\n *\n * This method:\n * 1. Gets the stored refresh token\n * 2. Calls the /auth/refresh endpoint\n * 3. Stores the new access and refresh tokens\n * 4. Returns the updated user info\n *\n * @returns The identity user if refresh was successful, null otherwise\n * @throws Error if no refresh token is stored or refresh fails\n */\n async refreshToken(): Promise<IdentityUser | null> {\n // Single-flight: refresh tokens are single-use. The server rotates the\n // token on every refresh and revokes the whole session if it ever sees a\n // stale generation (TOKEN_REUSE_DETECTED), since that is indistinguishable\n // from a stolen token being replayed. Several call sites can want a refresh\n // at once on startup — initSession(), connect() -> autoReauthenticate(),\n // the auto-refresh timer, and any 401 retry — so without this guard they\n // each POST the same stored token and we revoke our own session.\n if (this._refreshInFlight) {\n logger.debug('[refreshToken] Refresh already in flight, awaiting it');\n return this._refreshInFlight;\n }\n this._refreshInFlight = this._refreshToken().finally(() => {\n this._refreshInFlight = null;\n });\n return this._refreshInFlight;\n }\n\n /** In-flight refresh shared by concurrent refreshToken() callers. */\n private _refreshInFlight: Promise<IdentityUser | null> | null = null;\n\n private async _refreshToken(): Promise<IdentityUser | null> {\n const refreshToken = this.authManager.storage.getRefreshToken();\n if (!refreshToken) {\n logger.warn('[refreshToken] No refresh token available');\n return null;\n }\n\n try {\n logger.info('[refreshToken] Refreshing access token...');\n const url = this._repository\n ? `${this._httpBaseUrl}/auth/${this._repository}/refresh`\n : `${this._httpBaseUrl}/auth/refresh`;\n const response = await this._fetchWithTimeout(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refresh_token: refreshToken }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n logger.error('[refreshToken] Refresh failed:', response.status, errorText);\n\n // A revoked-for-security response means the token was presented twice.\n // With single-flighting in place that should no longer be us, so treat\n // it as a real signal (either a genuine replay, or a second client\n // instance sharing this storage) rather than a routine expiry.\n if (/TOKEN_REUSE_DETECTED|TOKEN_FAMILY_MISMATCH/.test(errorText)) {\n logger.error(\n '[refreshToken] Session revoked by the server as a suspected token replay. ' +\n 'If this happened on a normal page load, two refreshes raced on the same token.',\n );\n }\n\n // Clear tokens on auth failure (401/403)\n if (response.status === 401 || response.status === 403) {\n this.authManager.clear();\n this._currentUser = null;\n this.emit('auth_error', new Error('Token refresh failed - session expired'));\n }\n return null;\n }\n\n const tokens: IdentityAuthResponse = await response.json();\n\n // Store new tokens\n this.authManager.storage.setAccessToken(tokens.access_token);\n this.authManager.storage.setRefreshToken(tokens.refresh_token);\n\n // Update user info\n const user: IdentityUser = {\n id: tokens.identity.id,\n email: tokens.identity.email,\n displayName: tokens.identity.display_name,\n avatarUrl: tokens.identity.avatar_url,\n emailVerified: tokens.identity.email_verified,\n home: null, // Will be updated on next query\n };\n\n if (this.authManager.storage instanceof LocalStorageTokenStorage) {\n this.authManager.storage.setUser(user);\n }\n\n // Schedule next refresh (token expires_at minus 5 minutes)\n const expiresInMs = RaisinClient.expiresAtToMs(tokens.expires_at) - Date.now() - (5 * 60 * 1000);\n if (expiresInMs > 0) {\n this.scheduleAutoRefresh(expiresInMs);\n }\n\n logger.info('[refreshToken] Token refreshed successfully');\n this._emitAuthEvent('TOKEN_REFRESHED');\n this.emit('token_refreshed', user);\n return user;\n } catch (err) {\n logger.error('[refreshToken] Error during token refresh:', err);\n return null;\n }\n }\n\n /**\n * Fetch with a timeout derived from `requestTimeout`.\n *\n * Aborts the request after `requestTimeout` ms and rejects with a\n * `RaisinTimeoutError`. If the caller provides its own AbortSignal in\n * `init.signal`, it is respected: an external abort rejects with the\n * original AbortError instead of a timeout error.\n * @internal\n */\n private async _fetchWithTimeout(url: string, init: RequestInit = {}): Promise<Response> {\n const timeoutMs = this.options.requestTimeout;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n const externalSignal = init.signal ?? undefined;\n if (externalSignal) {\n if (externalSignal.aborted) {\n controller.abort();\n } else {\n externalSignal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n }\n\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (error) {\n if (\n error instanceof Error &&\n error.name === 'AbortError' &&\n !externalSignal?.aborted\n ) {\n throw new RaisinTimeoutError(\n `Request to ${url} timed out after ${timeoutMs}ms`,\n 'REQUEST_TIMEOUT',\n timeoutMs\n );\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n\n /**\n * Normalize a token `expires_at` value to epoch milliseconds.\n *\n * Server endpoints are inconsistent: some return seconds, others\n * milliseconds. Anything above 1e11 can't be a seconds-epoch (year 5138),\n * so treat it as milliseconds.\n * @internal\n */\n private static expiresAtToMs(expiresAt: number): number {\n return expiresAt > 100_000_000_000 ? expiresAt : expiresAt * 1000;\n }\n\n /**\n * Schedule automatic token refresh\n * @internal\n */\n private scheduleAutoRefresh(delayMs: number): void {\n // Clear any existing timer\n if (this._refreshTimer) {\n clearTimeout(this._refreshTimer);\n }\n\n // Clamp to a sane window: at least 30s out (avoid refresh storms on\n // skewed clocks), at most ~24 days (setTimeout 32-bit overflow fires\n // immediately otherwise).\n const clamped = Math.min(Math.max(delayMs, 30_000), 0x7fffffff);\n\n logger.debug(`[scheduleAutoRefresh] Scheduling refresh in ${Math.round(clamped / 1000 / 60)} minutes`);\n\n this._refreshTimer = setTimeout(async () => {\n logger.info('[autoRefresh] Auto-refreshing token...');\n await this.refreshToken();\n }, clamped);\n }\n\n /** Timer for automatic token refresh */\n private _refreshTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Get a database/repository interface\n *\n * @param name - Repository name\n * @returns Database interface\n */\n database(name: string): Database {\n // Set repository in client context for this database\n this._context.repository = name;\n return new Database(\n name,\n this._context,\n (payload, requestType, contextOverride, requestOptions) =>\n this.sendRequestInternal(payload, requestType as RequestType, contextOverride, requestOptions),\n this.eventHandler,\n undefined,\n undefined,\n () => this.getUploadManager(),\n (options) => this.signAssetUrl(options),\n { httpBaseUrl: this._httpBaseUrl, authManager: this.authManager },\n );\n }\n\n /**\n * Send a request to the server\n *\n * If the connection is temporarily down (connecting/reconnecting, or\n * disconnected with auto-reconnect enabled), the request is queued and\n * flushed once the connection is re-established and re-authenticated.\n * Queued requests are still subject to their own request timeout, and the\n * queue is bounded (overflow rejects immediately).\n */\n private async sendRequestInternal(\n payload: unknown,\n requestType: RequestType | string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ): Promise<unknown> {\n const connected = this.connection.isConnected();\n if (!connected) {\n const state = this.connection.getState();\n const willReconnect =\n state === ConnectionState.Connecting ||\n state === ConnectionState.Reconnecting ||\n (state === ConnectionState.Disconnected &&\n this._everConnected &&\n this.connection.isAutoReconnectEnabled());\n\n if (!willReconnect) {\n throw new Error('Not connected to server');\n }\n\n if (this._queuedRequests.length >= RaisinClient.MAX_QUEUED_REQUESTS) {\n throw new Error(\n `Request queue is full (${RaisinClient.MAX_QUEUED_REQUESTS} requests pending while reconnecting)`\n );\n }\n }\n\n const requestId = this.requestTracker.generateRequestId();\n\n // Use provided context or default to this._context\n const context = contextOverride || this._context;\n\n logger.debug(`sendRequestInternal - request_id: ${requestId}, type: ${requestType}`);\n logger.debug(`Context:`, JSON.stringify(context, null, 2));\n\n // Create request envelope\n const request: RequestEnvelope = {\n request_id: requestId,\n type: requestType as RequestType,\n context,\n payload,\n };\n\n // Create promise for response\n const responsePromise = this.requestTracker.createRequest(\n requestId,\n requestOptions?.timeoutMs,\n );\n\n // Send request (or queue it while the connection is re-establishing)\n try {\n const encoded = encodeMessage(request);\n logger.debug(`Encoded request - ID: ${requestId}, type: ${requestType}, size: ${encoded.length} bytes`);\n if (connected) {\n this.connection.send(encoded);\n logger.debug(`Request sent - ID: ${requestId}`);\n } else {\n this._queuedRequests.push({ requestId, encoded });\n logger.debug(\n `Request queued while reconnecting - ID: ${requestId}, queue size: ${this._queuedRequests.length}`\n );\n }\n } catch (error) {\n logger.error(`Failed to send request - ID: ${requestId}:`, error);\n this.requestTracker.rejectRequest(\n requestId,\n error instanceof Error ? error : new Error('Failed to send request')\n );\n throw error;\n }\n\n return responsePromise;\n }\n\n /**\n * Flush requests queued while the connection was re-establishing.\n * Called after the connection is connected and (re-)authenticated.\n * @internal\n */\n private _flushQueuedRequests(): void {\n if (this._queuedRequests.length === 0) return;\n\n const queued = this._queuedRequests;\n this._queuedRequests = [];\n logger.info(`[_flushQueuedRequests] Flushing ${queued.length} queued request(s)`);\n\n for (const { requestId, encoded } of queued) {\n // Skip requests that already timed out while queued\n if (!this.requestTracker.hasPendingRequest(requestId)) continue;\n try {\n this.connection.send(encoded);\n } catch (error) {\n this.requestTracker.rejectRequest(\n requestId,\n error instanceof Error ? error : new Error('Failed to send queued request')\n );\n }\n }\n }\n\n /**\n * Reject all requests queued while the connection was re-establishing\n * (e.g. re-authentication failed after reconnect).\n * @internal\n */\n private _rejectQueuedRequests(error: Error): void {\n if (this._queuedRequests.length === 0) return;\n\n const queued = this._queuedRequests;\n this._queuedRequests = [];\n logger.warn(`[_rejectQueuedRequests] Rejecting ${queued.length} queued request(s): ${error.message}`);\n\n for (const { requestId } of queued) {\n this.requestTracker.rejectRequest(requestId, error);\n }\n }\n\n /**\n * Get the HTTP base URL derived from the WebSocket URL\n */\n get httpBaseUrl(): string {\n return this._httpBaseUrl;\n }\n\n /**\n * Get current connection state\n */\n getConnectionState(): ConnectionState {\n return this.connection.getState();\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connection.isConnected();\n }\n\n /**\n * Check if ready (connected AND authenticated)\n *\n * Returns true when the client is fully ready to make requests:\n * - WebSocket is connected AND\n * - Either authenticated (signed in) OR no stored token (anonymous is ok)\n *\n * Use this for UI indicators that should show \"connected\" only when\n * the client is actually ready to process requests.\n */\n isReady(): boolean {\n return this._ready;\n }\n\n /**\n * Subscribe to ready state changes\n *\n * The callback is invoked whenever the ready state changes.\n * Ready = connected AND (authenticated OR no stored token)\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onReadyStateChange((ready) => {\n * if (ready) {\n * console.log('Client is ready');\n * showGreenIndicator();\n * } else {\n * console.log('Client is not ready');\n * showRedIndicator();\n * }\n * });\n * ```\n *\n * @param callback - Function called when ready state changes\n * @returns Unsubscribe function\n */\n onReadyStateChange(callback: (ready: boolean) => void): () => void {\n this._readyListeners.add(callback);\n // Immediately call with current state\n callback(this._ready);\n return () => {\n this._readyListeners.delete(callback);\n };\n }\n\n /**\n * Check if authenticated\n */\n isAuthenticated(): boolean {\n return this.authManager.isAuthenticated();\n }\n\n /**\n * Get current user info\n *\n * Returns the current authenticated user's information including\n * their ID, node path in the repository, and roles.\n *\n * @returns Current user info or null if not connected/authenticated\n */\n getCurrentUser(): CurrentUser | null {\n return this._currentUser;\n }\n\n /**\n * Re-resolve the current user's EFFECTIVE roles from the server and refresh\n * `getCurrentUser()`.\n *\n * Roles are deliberately not embedded in the JWT (they are resolved live\n * server-side), so when an admin changes a user's roles/groups the token does\n * not change — the client must re-ask. This re-runs the WS JWT auth handshake\n * (which returns freshly resolved effective roles), updates `_currentUser`, and\n * emits `USER_UPDATED` so role-gated UI can react without a reload.\n *\n * Called automatically when the server pushes `permissions:changed` after an\n * access-control write, and exposed for on-demand refresh. Safe no-op when not\n * authenticated.\n */\n async refreshCurrentUser(): Promise<void> {\n // Coalesce concurrent re-resolves: a burst of `permissions:changed` pushes\n // (e.g. during package/role seeding) collapses into a single in-flight\n // handshake instead of a storm.\n if (this.#refreshingUser) return this.#refreshingUser;\n const token = this.authManager.storage.getAccessToken();\n if (!token) return;\n this.#refreshingUser = (async () => {\n const before = JSON.stringify(this._currentUser?.roles ?? null);\n const prevNode = this._currentUser?.node;\n try {\n // authenticate({type:'jwt'}) re-resolves roles and rebuilds _currentUser\n // (without the node); preserve the previously-fetched node.\n await this.authenticate({ type: 'jwt', token });\n if (this._currentUser && prevNode && !this._currentUser.node) {\n this._currentUser.node = prevNode;\n }\n // Only notify when the effective roles actually changed — avoids\n // redundant USER_UPDATED churn when a push carried no role change.\n const after = JSON.stringify(this._currentUser?.roles ?? null);\n if (after !== before) {\n this._emitAuthEvent('USER_UPDATED');\n }\n } catch (err) {\n logger.warn('[refreshCurrentUser] role re-resolve failed:', err);\n } finally {\n this.#refreshingUser = null;\n }\n })();\n return this.#refreshingUser;\n }\n\n /**\n * Get current user ID\n *\n * @returns User ID or null if not connected/authenticated\n */\n getCurrentUserId(): string | null {\n return this._currentUser?.userId ?? null;\n }\n\n /**\n * Get current user's node path in the repository\n *\n * @returns User's node path (e.g., '/users/internal/john-at-example-com') or null if not connected\n */\n getCurrentUserPath(): string | null {\n return this._currentUser?.node?.path ?? null;\n }\n\n /**\n * Fetch user node using SQL RAISIN_CURRENT_USER() function\n *\n * @param repository - Repository name to query\n * @returns User's full node from the repository, or null if query fails\n */\n async fetchUserNode(repository: string): Promise<UserNode | null> {\n logger.info('[fetchUserNode] Fetching user node for repository:', repository);\n try {\n // Use SQL to get the current user node (RAISIN_CURRENT_USER() returns the node as JSON)\n const db = this.database(repository);\n logger.info('[fetchUserNode] Executing SQL: SELECT RAISIN_CURRENT_USER() as user_node');\n const result = await db.executeSql('SELECT RAISIN_CURRENT_USER() as user_node');\n logger.info('[fetchUserNode] SQL result:', JSON.stringify(result));\n\n if (result.rows && result.rows.length > 0) {\n const row = result.rows[0] as unknown as { user_node: UserNode | null };\n logger.info('[fetchUserNode] User node:', row.user_node ? `path=${row.user_node.path}` : 'null');\n return row.user_node ?? null;\n }\n logger.info('[fetchUserNode] No rows returned');\n return null;\n } catch (err) {\n logger.warn('[fetchUserNode] Error fetching user node via SQL:', err);\n return null;\n }\n }\n\n /**\n * Get current tenant ID\n */\n getTenantId(): string {\n return this._context.tenant_id;\n }\n\n /**\n * Set branch for subsequent requests\n *\n * @param branch - Branch name\n */\n setBranch(branch: string): void {\n this._context.branch = branch;\n }\n\n /**\n * Get current branch\n */\n getBranch(): string {\n return this._context.branch ?? this.options.defaultBranch;\n }\n\n // ============================================================================\n // Auth State Change API (Firebase/Supabase-compatible)\n // ============================================================================\n\n /**\n * Listen for authentication state changes (Firebase/Supabase-compatible pattern)\n *\n * This method provides a reactive way to respond to auth events:\n * - SIGNED_IN: User logged in or session restored\n * - SIGNED_OUT: User logged out\n * - TOKEN_REFRESHED: Access token was refreshed\n * - SESSION_EXPIRED: Session expired (auto-logout triggered)\n * - USER_UPDATED: User's home node was updated\n *\n * @param callback - Function called on each auth state change\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onAuthStateChange(({ event, session }) => {\n * if (event === 'SIGNED_IN') {\n * console.log('User signed in:', session.user?.email);\n * } else if (event === 'SIGNED_OUT') {\n * console.log('User signed out');\n * }\n * });\n *\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n onAuthStateChange(callback: AuthStateChangeCallback): () => void {\n this._authListeners.add(callback);\n return () => {\n this._authListeners.delete(callback);\n };\n }\n\n /**\n * Listen for connection state changes\n *\n * @param callback - Function called on each connection state change\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onConnectionStateChange((state) => {\n * console.log('Connection state:', state);\n * if (state === ConnectionState.Disconnected) {\n * showOfflineIndicator();\n * }\n * });\n * ```\n */\n onConnectionStateChange(callback: (state: ConnectionState) => void): () => void {\n const handler = (state: ConnectionState) => callback(state);\n this.connection.on('stateChange', handler);\n return () => {\n this.connection.off('stateChange', handler);\n };\n }\n\n /**\n * Listen for reconnection events\n *\n * This callback fires after a successful reconnection when:\n * 1. The WebSocket connection is re-established\n * 2. Re-authentication (if needed) is complete\n * 3. Event subscriptions have been restored\n *\n * Use this to refresh application data after a server restart or network recovery.\n *\n * @param callback - Function called after successful reconnection\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onReconnected(() => {\n * console.log('Reconnected! Refreshing data...');\n * // Refresh conversations, sync state, etc.\n * await refreshData();\n * });\n * ```\n */\n onReconnected(callback: () => void): () => void {\n this._reconnectedListeners.add(callback);\n return () => {\n this._reconnectedListeners.delete(callback);\n };\n }\n\n /**\n * Listen for changes to the current user's home node\n *\n * This automatically subscribes to real-time updates on the user's home node\n * (e.g., /users/internal/john-at-example-com) when the user logs in.\n *\n * @param callback - Function called when user's home node is updated\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const unsubscribe = client.onUserChange(({ node, changeType }) => {\n * console.log('User home updated:', changeType);\n * console.log('New properties:', node.properties);\n * // Update UI with new avatar, displayName, preferences, etc.\n * });\n * ```\n */\n onUserChange(callback: UserChangeCallback): () => void {\n this._userChangeListeners.add(callback);\n return () => {\n this._userChangeListeners.delete(callback);\n };\n }\n\n /**\n * Get current session (sync getter)\n *\n * @returns Current session with user and access token, or null if not authenticated\n *\n * @example\n * ```typescript\n * const session = client.getSession();\n * if (session) {\n * console.log('Logged in as:', session.user?.email);\n * }\n * ```\n */\n getSession(): { user: IdentityUser | null; accessToken: string | null } | null {\n const accessToken = this.authManager.storage.getAccessToken();\n if (!accessToken) return null;\n return {\n user: this.getStoredUser(),\n accessToken,\n };\n }\n\n /**\n * Get current user (alias for getStoredUser, Supabase-compatible)\n *\n * @returns Current identity user or null\n */\n getUser(): IdentityUser | null {\n return this.getStoredUser();\n }\n\n /**\n * Emit auth event to all listeners\n * @internal\n */\n private _emitAuthEvent(event: AuthEvent): void {\n const session = {\n user: this.getStoredUser(),\n accessToken: this.authManager.storage.getAccessToken(),\n // Surface effective roles so role-gated consumers can react to\n // SIGNED_IN / USER_UPDATED without calling getCurrentUser() themselves.\n roles: this._currentUser?.roles ?? null,\n };\n const change: AuthStateChange = { event, session };\n\n for (const callback of this._authListeners) {\n try {\n callback(change);\n } catch (err) {\n logger.error('[_emitAuthEvent] Listener error:', err);\n }\n }\n\n // Update ready state after auth events\n this._updateReadyState();\n }\n\n /**\n * Update and emit ready state\n * Ready = connected AND (authenticated OR no stored token)\n * @internal\n */\n private _updateReadyState(): void {\n const connected = this.connection.isConnected();\n const hasToken = this.hasStoredToken();\n const user = this.getStoredUser();\n // Ready if: connected AND (no stored token OR user is signed in)\n const ready = connected && (!hasToken || user !== null);\n\n if (this._ready !== ready) {\n this._ready = ready;\n logger.debug('[_updateReadyState] Ready state changed:', ready, { connected, hasToken, user: user?.email });\n for (const callback of this._readyListeners) {\n try {\n callback(ready);\n } catch (err) {\n logger.error('[_updateReadyState] Listener error:', err);\n }\n }\n }\n }\n\n /**\n * Subscribe to user's home node for real-time updates\n * @internal\n */\n private async _subscribeToUserHome(repository: string, userHome: string): Promise<void> {\n // Unsubscribe from previous subscription if any\n await this._unsubscribeFromUserHome();\n\n // Strip a possible workspace prefix (e.g. \"/raisin:access_control/users/...\")\n userHome = normalizeHomePath(userHome) ?? userHome;\n\n try {\n const db = this.database(repository);\n // Extract workspace from path (e.g., \"/users/internal/john\" -> \"users\")\n const pathParts = userHome.split('/').filter(p => p.length > 0);\n if (pathParts.length === 0) {\n logger.warn('[_subscribeToUserHome] Invalid user home path:', userHome);\n return;\n }\n\n const workspace = pathParts[0];\n const events = db.workspace(workspace).events();\n\n logger.debug('[_subscribeToUserHome] Subscribing to user home:', userHome);\n const subscription = await events.subscribeToPath(userHome, (event) => {\n logger.debug('[_subscribeToUserHome] User home event:', event.event_type);\n\n // Emit to onUserChange listeners\n for (const callback of this._userChangeListeners) {\n try {\n callback({\n node: event.payload as unknown as UserNode,\n changeType: event.event_type,\n });\n } catch (err) {\n logger.error('[_subscribeToUserHome] Listener error:', err);\n }\n }\n\n // Also emit USER_UPDATED auth event\n this._emitAuthEvent('USER_UPDATED');\n });\n\n this._userHomeSubscription = subscription;\n logger.info('[_subscribeToUserHome] Subscribed to user home:', userHome);\n } catch (err) {\n logger.error('[_subscribeToUserHome] Failed to subscribe:', err);\n }\n }\n\n /**\n * Unsubscribe from user's home node\n * @internal\n */\n private async _unsubscribeFromUserHome(): Promise<void> {\n if (this._userHomeSubscription) {\n try {\n await this._userHomeSubscription.unsubscribe();\n } catch (err) {\n logger.warn('[_unsubscribeFromUserHome] Error during unsubscribe:', err);\n }\n this._userHomeSubscription = null;\n }\n }\n\n /**\n * Create a new repository\n *\n * @param repositoryId - Repository identifier\n * @param description - Repository description\n * @param config - Repository configuration\n * @returns Repository creation result\n */\n async createRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n description,\n config,\n },\n RequestType.RepositoryCreate\n );\n }\n\n /**\n * Get a repository by ID\n *\n * @param repositoryId - Repository identifier\n * @returns Repository information\n */\n async getRepository(repositoryId: string): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n },\n RequestType.RepositoryGet\n );\n }\n\n /**\n * List all repositories\n *\n * @returns Array of repository information\n */\n async listRepositories(): Promise<unknown[]> {\n const result = await this.sendRequestInternal(\n {},\n RequestType.RepositoryList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update a repository\n *\n * @param repositoryId - Repository identifier\n * @param description - New repository description\n * @param config - New repository configuration\n * @returns Repository update result\n */\n async updateRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n description,\n config,\n },\n RequestType.RepositoryUpdate\n );\n }\n\n /**\n * Delete a repository\n *\n * @param repositoryId - Repository identifier\n * @returns Repository deletion result\n */\n async deleteRepository(repositoryId: string): Promise<unknown> {\n return this.sendRequestInternal(\n {\n repository_id: repositoryId,\n },\n RequestType.RepositoryDelete\n );\n }\n\n // ============================================================================\n // Upload Methods (use HTTP under the hood)\n // ============================================================================\n\n /**\n * Get or create the upload manager\n * @internal\n */\n private getUploadManager(): UploadManager {\n if (!this._uploadManager) {\n this._uploadManager = new UploadManager({\n baseUrl: this._httpBaseUrl,\n authManager: this.authManager,\n fetchImpl: fetch,\n requestTimeout: this.options.requestTimeout,\n });\n }\n return this._uploadManager;\n }\n\n /**\n * Create a resumable upload from a File or Blob (Browser)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support. Uses HTTP under the hood.\n *\n * @param file - File or Blob to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const client = new RaisinClient('raisin://localhost:8080/sys/default');\n * await client.connect();\n *\n * const file = document.querySelector('input').files[0];\n * const upload = await client.upload(file, {\n * repository: 'media',\n * workspace: 'assets',\n * path: '/videos/my-video.mp4',\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * const result = await upload.start();\n * ```\n */\n async upload(file: File | Blob, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(file);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Create a resumable upload from a file path (Node.js)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support. Uses HTTP under the hood.\n *\n * @param filePath - Path to the file to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const upload = await client.uploadFile('/path/to/file.zip', {\n * repository: 'data',\n * workspace: 'backups',\n * path: '/backup.zip'\n * });\n * await upload.start();\n * ```\n */\n async uploadFile(filePath: string, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(filePath);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Upload multiple files as a batch\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n * Uses HTTP under the hood.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param options - Batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await client.uploadFiles(files, {\n * repository: 'media',\n * workspace: 'assets',\n * basePath: '/uploads',\n * concurrency: 3,\n * onProgress: (p) => {\n * console.log(`${p.filesCompleted}/${p.filesTotal} files`);\n * console.log(`${Math.round(p.progress * 100)}% complete`);\n * },\n * onFileComplete: (file, result) => console.log(`Uploaded: ${file}`),\n * onFileError: (file, err) => console.error(`Failed: ${file}`, err),\n * });\n *\n * const result = await batch.start();\n * console.log(`Success: ${result.successful.length}, Failed: ${result.failed.length}`);\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n options: BatchUploadOptions\n ): Promise<BatchUpload> {\n const sources = await Promise.all(\n Array.from(files).map((f) => createFileSource(f))\n );\n const manager = this.getUploadManager();\n return manager.createBatchUpload(sources, options);\n }\n\n /**\n * Get an existing upload by ID\n *\n * @param uploadId - ID of the upload to retrieve\n * @returns Upload controller or undefined if not found\n */\n getUpload(uploadId: string): Upload | undefined {\n const manager = this.getUploadManager();\n return manager.getUpload(uploadId);\n }\n\n /**\n * Get all active uploads\n *\n * @returns Array of active upload controllers\n */\n getActiveUploads(): Upload[] {\n const manager = this.getUploadManager();\n return manager.getActiveUploads();\n }\n\n /**\n * Cancel all active uploads\n */\n async cancelAllUploads(): Promise<void> {\n const manager = this.getUploadManager();\n await manager.cancelAll();\n }\n\n // ============================================================================\n // Asset Signed URL Methods\n // ============================================================================\n\n /**\n * Get a signed URL for accessing an asset's binary content.\n *\n * Server validates user access before generating URL. The returned URL\n * can be used without authentication (signature provides access).\n *\n * @param options - Sign URL options\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const { url, expiresAt } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/image.jpeg',\n * command: 'display',\n * });\n *\n * // Use in <img> tag\n * document.querySelector('img').src = url;\n *\n * // Or force download\n * const { url: downloadUrl } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/document.pdf',\n * command: 'download',\n * });\n * ```\n */\n async signAssetUrl(options: SignAssetOptions): Promise<SignedAssetUrl> {\n const branch = options.branch ?? this._context.branch ?? 'main';\n // Add @propertyPath suffix if specified (for thumbnails, etc.)\n // Only add suffix when propertyPath is provided - maintains backward compatibility\n const pathWithProperty = options.propertyPath\n ? `${options.path}@${options.propertyPath}`\n : options.path;\n const endpoint = `/api/repository/${options.repository}/${branch}/head/${options.workspace}${pathWithProperty}/raisin:sign`;\n\n const response = await this._fetchWithTimeout(`${this._httpBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(this.authManager.isAuthenticated()\n ? { Authorization: `Bearer ${this.authManager.getAccessToken()}` }\n : {}),\n },\n body: JSON.stringify({\n command: options.command,\n expires_in: options.expiresIn ?? 300,\n }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: 'Unknown error' }));\n throw new Error(error.message || `Failed to sign asset URL: ${response.status}`);\n }\n\n const data = await response.json();\n return {\n url: `${this._httpBaseUrl}${data.url}`,\n expiresAt: data.expiresAt ?? data.expires_at,\n };\n }\n\n /**\n * Create an HTTP-only client for server-side rendering\n *\n * This client uses HTTP REST API instead of WebSocket, making it suitable\n * for server-side rendering where WebSocket connections are not available.\n *\n * @param baseUrl - Base HTTP URL (e.g., \"http://localhost:8080\")\n * @param options - HTTP client options\n * @returns HTTP client instance\n *\n * @example\n * ```typescript\n * // In a React Router loader (server-side)\n * const client = RaisinClient.forSSR('http://localhost:8080', {\n * tenantId: 'default'\n * });\n * await client.authenticate({ username: 'admin', password: 'admin' });\n * const result = await client.database('social').executeSql('SELECT * FROM nodes');\n * ```\n */\n static forSSR(baseUrl: string, options?: HttpClientOptions): RaisinHttpClient {\n return new RaisinHttpClient(baseUrl, options);\n }\n\n /**\n * Create an HTTP client (alias for forSSR)\n *\n * @param baseUrl - Base HTTP URL\n * @param options - HTTP client options\n * @returns HTTP client instance\n */\n static createHttpClient(baseUrl: string, options?: HttpClientOptions): RaisinHttpClient {\n return RaisinClient.forSSR(baseUrl, options);\n }\n}\n","/**\n * Universal WebSocket connection manager\n *\n * Detects environment (browser vs Node.js) and uses appropriate WebSocket implementation.\n * Handles auto-reconnect, heartbeat, and connection state management.\n */\n\nimport { EventEmitter } from 'events';\nimport { ReconnectManager, ReconnectOptions } from './utils/reconnect';\nimport { logger } from './logger';\n\n/**\n * Connection state\n */\nexport enum ConnectionState {\n Disconnected = 'disconnected',\n Connecting = 'connecting',\n Connected = 'connected',\n Reconnecting = 'reconnecting',\n Closed = 'closed',\n}\n\n/**\n * Connection options\n */\nexport interface ConnectionOptions {\n /** Auto-reconnect on disconnect (default: true) */\n autoReconnect?: boolean;\n /** Reconnection options */\n reconnectOptions?: ReconnectOptions;\n /** Heartbeat interval in milliseconds (default: 30000, 0 to disable) */\n heartbeatInterval?: number;\n /** Heartbeat timeout in milliseconds (default: 5000) */\n heartbeatTimeout?: number;\n /** WebSocket protocols */\n protocols?: string | string[];\n /**\n * Extra headers to send on the WebSocket upgrade request\n * (e.g. `x-tenant-id` for tenant-less `/ws` URLs).\n *\n * Only honored by WebSocket implementations that support custom headers\n * (Node.js `ws` package). Browser WebSockets silently ignore them — the\n * server then resolves the tenant from the request (default: \"default\").\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Connection events\n */\nexport interface ConnectionEvents {\n stateChange: (state: ConnectionState) => void;\n message: (data: ArrayBuffer) => void;\n error: (error: Error) => void;\n close: (event: CloseEvent) => void;\n}\n\n/**\n * Type for WebSocket implementation (browser or Node.js)\n */\ntype WebSocketImpl = typeof WebSocket | typeof import('ws').WebSocket;\n\n/**\n * Get the appropriate WebSocket implementation for the current environment\n */\nfunction getWebSocketImpl(): WebSocketImpl {\n // Browser environment\n if (typeof WebSocket !== 'undefined') {\n return WebSocket as WebSocketImpl;\n }\n\n // Node.js environment\n try {\n // Use dynamic import to avoid bundler issues\n const ws = require('ws');\n return ws.WebSocket || ws.default || ws;\n } catch (error) {\n throw new Error(\n 'WebSocket implementation not found. In Node.js, please install the \"ws\" package: npm install ws'\n );\n }\n}\n\n/**\n * Universal WebSocket connection manager\n */\nexport class Connection extends EventEmitter {\n private ws?: WebSocket;\n private url: string;\n private state: ConnectionState = ConnectionState.Disconnected;\n private reconnectManager: ReconnectManager;\n private heartbeatTimer?: NodeJS.Timeout;\n private heartbeatTimeoutTimer?: NodeJS.Timeout;\n private options: Required<Omit<ConnectionOptions, 'reconnectOptions' | 'protocols' | 'headers'>> & {\n protocols?: string | string[];\n headers?: Record<string, string>;\n };\n private WebSocketImpl: WebSocketImpl;\n private manualClose = false;\n\n constructor(url: string, options: ConnectionOptions = {}) {\n super();\n // Convert raisin:// / raisins:// to ws:// / wss:// for the WebSocket layer\n this.url = url\n .replace(/^raisin:\\/\\//, 'ws://')\n .replace(/^raisins:\\/\\//, 'wss://');\n this.options = {\n autoReconnect: options.autoReconnect ?? true,\n heartbeatInterval: options.heartbeatInterval ?? 30000,\n heartbeatTimeout: options.heartbeatTimeout ?? 5000,\n protocols: options.protocols,\n headers: options.headers,\n };\n this.reconnectManager = new ReconnectManager(options.reconnectOptions);\n this.WebSocketImpl = getWebSocketImpl();\n }\n\n /**\n * Connect to the WebSocket server\n */\n async connect(): Promise<void> {\n if (this.state === ConnectionState.Connected || this.state === ConnectionState.Connecting) {\n return;\n }\n\n this.manualClose = false;\n this.setState(ConnectionState.Connecting);\n\n return new Promise((resolve, reject) => {\n try {\n // Create WebSocket instance.\n // The third argument (upgrade headers) is only understood by the\n // Node.js `ws` package. Browsers do NOT simply ignore it - Chromium\n // fails the handshake when a third argument is passed - so only pass\n // it to non-browser implementations. Browser connections rely on the\n // server-side tenant resolution instead of upgrade headers.\n const isBrowserWebSocket =\n typeof WebSocket !== 'undefined' && this.WebSocketImpl === WebSocket;\n this.ws = (\n isBrowserWebSocket || !this.options.headers\n ? new (this.WebSocketImpl as any)(this.url, this.options.protocols)\n : new (this.WebSocketImpl as any)(this.url, this.options.protocols, {\n headers: this.options.headers,\n })\n ) as WebSocket;\n\n // Set binary type for MessagePack\n this.ws.binaryType = 'arraybuffer';\n\n // Handle open event\n this.ws.onopen = () => {\n this.setState(ConnectionState.Connected);\n this.reconnectManager.reset();\n this.startHeartbeat();\n resolve();\n };\n\n // Handle message event\n this.ws.onmessage = (event: MessageEvent) => {\n logger.debug(`WebSocket onmessage fired - data type: ${typeof event.data}, is ArrayBuffer: ${event.data instanceof ArrayBuffer}`);\n this.resetHeartbeat();\n const data = event.data as ArrayBuffer;\n logger.debug(`Received binary message - size: ${data.byteLength} bytes`);\n logger.debug(`Emitting 'message' event to client handlers`);\n this.emit('message', data);\n };\n\n // Handle error event\n this.ws.onerror = () => {\n const error = new Error('WebSocket error occurred');\n this.emit('error', error);\n if (this.state === ConnectionState.Connecting) {\n reject(error);\n }\n };\n\n // Handle close event\n this.ws.onclose = (event: CloseEvent) => {\n this.stopHeartbeat();\n this.emit('close', event);\n\n if (!this.manualClose && this.options.autoReconnect) {\n this.setState(ConnectionState.Reconnecting);\n this.reconnect();\n } else {\n this.setState(ConnectionState.Disconnected);\n }\n\n if (this.state === ConnectionState.Connecting) {\n reject(new Error(`Connection closed: ${event.reason || 'Unknown reason'}`));\n }\n };\n } catch (error) {\n this.setState(ConnectionState.Disconnected);\n reject(error);\n }\n });\n }\n\n /**\n * Disconnect from the WebSocket server\n */\n disconnect(): void {\n this.manualClose = true;\n this.reconnectManager.cancelReconnect();\n this.stopHeartbeat();\n\n if (this.ws) {\n this.ws.close(1000, 'Client disconnect');\n this.ws = undefined;\n }\n\n this.setState(ConnectionState.Closed);\n }\n\n /**\n * Send data through the WebSocket\n *\n * @param data - Data to send (Uint8Array for MessagePack)\n */\n send(data: Uint8Array): void {\n if (this.state !== ConnectionState.Connected || !this.ws) {\n throw new Error('Cannot send data: not connected');\n }\n\n // Check actual WebSocket readyState\n if (this.ws.readyState !== 1) { // WebSocket.OPEN = 1\n logger.error(`WebSocket not open - readyState: ${this.ws.readyState} (0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED)`);\n throw new Error(`Cannot send data: WebSocket not open (readyState: ${this.ws.readyState})`);\n }\n\n logger.debug(`Sending message - size: ${data.length} bytes, readyState: ${this.ws.readyState}`);\n\n try {\n this.ws.send(data);\n logger.debug(`Message sent successfully`);\n } catch (error) {\n logger.error(`Failed to send message:`, error);\n throw new Error(`Failed to send data: ${error}`);\n }\n }\n\n /**\n * Get current connection state\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.state === ConnectionState.Connected;\n }\n\n /**\n * Whether auto-reconnect is enabled for this connection.\n *\n * Used by the client to decide whether requests issued while the\n * connection is down can be queued (the connection will come back) or\n * should fail immediately.\n */\n isAutoReconnectEnabled(): boolean {\n return this.options.autoReconnect;\n }\n\n /**\n * Reconnect to the server\n */\n private reconnect(): void {\n const success = this.reconnectManager.scheduleReconnect(async () => {\n try {\n await this.connect();\n } catch (error) {\n // Error is already handled by connect()\n // Reconnection will be scheduled again if autoReconnect is enabled\n }\n });\n\n if (!success) {\n this.setState(ConnectionState.Disconnected);\n this.emit('error', new Error('Max reconnection attempts reached'));\n }\n }\n\n /**\n * Set connection state and emit event\n */\n private setState(state: ConnectionState): void {\n if (this.state !== state) {\n this.state = state;\n this.emit('stateChange', state);\n }\n }\n\n /**\n * Start heartbeat mechanism\n */\n private startHeartbeat(): void {\n if (this.options.heartbeatInterval <= 0) {\n return;\n }\n\n this.stopHeartbeat();\n\n // Note: WebSocket implementations (browser and ws library) automatically handle\n // ping/pong frames at the protocol level, so we don't need application-level heartbeat\n // that sends empty binary messages. The underlying WebSocket will keep the connection alive.\n }\n\n /**\n * Stop heartbeat mechanism\n */\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n }\n\n /**\n * Reset heartbeat timeout (called when message received)\n */\n private resetHeartbeat(): void {\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n }\n}\n","/**\n * Reconnection manager with exponential backoff\n */\n\n/**\n * Reconnection strategy options\n */\nexport interface ReconnectOptions {\n /** Initial delay in milliseconds (default: 1000) */\n initialDelay?: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelay?: number;\n /** Backoff multiplier (default: 2) */\n backoffMultiplier?: number;\n /** Maximum number of reconnection attempts (default: Infinity) */\n maxAttempts?: number;\n /** Add random jitter to delay (default: true). Jitter is +/- 25% of the computed delay. */\n jitter?: boolean;\n}\n\n/**\n * Reconnection manager with exponential backoff\n */\nexport class ReconnectManager {\n private currentDelay: number;\n private attempts = 0;\n private reconnectTimeout?: NodeJS.Timeout;\n private isReconnecting = false;\n\n private readonly initialDelay: number;\n private readonly maxDelay: number;\n private readonly backoffMultiplier: number;\n private readonly maxAttempts: number;\n private readonly jitter: boolean;\n\n constructor(options: ReconnectOptions = {}) {\n this.initialDelay = options.initialDelay ?? 1000;\n this.maxDelay = options.maxDelay ?? 30000;\n this.backoffMultiplier = options.backoffMultiplier ?? 2;\n this.maxAttempts = options.maxAttempts ?? Infinity;\n this.jitter = options.jitter ?? true;\n this.currentDelay = this.initialDelay;\n }\n\n /**\n * Schedule a reconnection attempt\n *\n * @param callback - Function to call when it's time to reconnect\n * @returns true if reconnection was scheduled, false if max attempts reached\n */\n scheduleReconnect(callback: () => void | Promise<void>): boolean {\n // Check if we've exceeded max attempts\n if (this.attempts >= this.maxAttempts) {\n return false;\n }\n\n // Clear any existing timeout\n this.cancelReconnect();\n\n this.isReconnecting = true;\n this.attempts++;\n\n // Apply jitter: +/- 25% of the computed delay\n let delay = this.currentDelay;\n if (this.jitter) {\n const jitterRange = delay * 0.25;\n delay += (Math.random() * 2 - 1) * jitterRange;\n delay = Math.max(0, Math.round(delay));\n }\n\n this.reconnectTimeout = setTimeout(async () => {\n try {\n await callback();\n // If successful, reset the delay\n this.reset();\n } catch (error) {\n // Increase delay for next attempt\n this.currentDelay = Math.min(\n this.currentDelay * this.backoffMultiplier,\n this.maxDelay\n );\n }\n }, delay);\n\n return true;\n }\n\n /**\n * Cancel any pending reconnection attempt\n */\n cancelReconnect(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = undefined;\n }\n this.isReconnecting = false;\n }\n\n /**\n * Reset the reconnection state (call after successful connection)\n */\n reset(): void {\n this.cancelReconnect();\n this.currentDelay = this.initialDelay;\n this.attempts = 0;\n }\n\n /**\n * Check if currently in reconnection mode\n */\n isActive(): boolean {\n return this.isReconnecting;\n }\n\n /**\n * Get the current number of reconnection attempts\n */\n getAttempts(): number {\n return this.attempts;\n }\n\n /**\n * Get the current delay in milliseconds\n */\n getCurrentDelay(): number {\n return this.currentDelay;\n }\n\n /**\n * Check if max attempts have been reached\n */\n hasReachedMaxAttempts(): boolean {\n return this.attempts >= this.maxAttempts;\n }\n}\n","/**\n * Configurable logger for RaisinDB client\n */\n\n/**\n * Log levels in order of verbosity (lower = less verbose)\n */\nexport enum LogLevel {\n Silent = 0,\n Error = 1,\n Warn = 2,\n Info = 3,\n Debug = 4,\n}\n\n/**\n * Logger configuration\n */\nexport interface LoggerConfig {\n /** Current log level (default: Error) */\n level: LogLevel;\n /** Prefix for all log messages (default: \"[RaisinDB]\") */\n prefix: string;\n}\n\n/**\n * Global logger configuration\n */\nlet config: LoggerConfig = {\n level: LogLevel.Error,\n prefix: '[RaisinDB]',\n};\n\n/**\n * Configure the logger\n *\n * @param options - Logger configuration options\n *\n * @example\n * ```typescript\n * import { configureLogger, LogLevel } from '@raisindb/client';\n *\n * // Enable debug logging\n * configureLogger({ level: LogLevel.Debug });\n *\n * // Disable all logging\n * configureLogger({ level: LogLevel.Silent });\n * ```\n */\nexport function configureLogger(options: Partial<LoggerConfig>): void {\n config = { ...config, ...options };\n}\n\n/**\n * Get current logger configuration\n */\nexport function getLoggerConfig(): LoggerConfig {\n return { ...config };\n}\n\n/**\n * Set log level\n *\n * @param level - Log level to set\n */\nexport function setLogLevel(level: LogLevel): void {\n config.level = level;\n}\n\n/**\n * Get current log level\n */\nexport function getLogLevel(): LogLevel {\n return config.level;\n}\n\n/**\n * Logger instance with level-aware logging methods\n */\nexport const logger = {\n /**\n * Log debug message (only shown when level >= Debug)\n */\n debug(...args: unknown[]): void {\n if (config.level >= LogLevel.Debug) {\n console.log(config.prefix, ...args);\n }\n },\n\n /**\n * Log info message (only shown when level >= Info)\n */\n info(...args: unknown[]): void {\n if (config.level >= LogLevel.Info) {\n console.log(config.prefix, ...args);\n }\n },\n\n /**\n * Log warning message (only shown when level >= Warn)\n */\n warn(...args: unknown[]): void {\n if (config.level >= LogLevel.Warn) {\n console.warn(config.prefix, ...args);\n }\n },\n\n /**\n * Log error message (only shown when level >= Error)\n */\n error(...args: unknown[]): void {\n if (config.level >= LogLevel.Error) {\n console.error(config.prefix, ...args);\n }\n },\n};\n\nif (typeof globalThis !== 'undefined') {\n (globalThis as any).__raisinDebug = (enable = true) => {\n setLogLevel(enable ? LogLevel.Debug : LogLevel.Error);\n console.log(`[RaisinDB] Debug logging ${enable ? 'ENABLED' : 'DISABLED'} (includes server handler logs)`);\n };\n}\n","/**\n * Request tracker for managing pending requests and their promises\n */\n\nimport { v4 as uuidv4 } from 'uuid';\n\n/**\n * Pending request information\n */\ninterface PendingRequest<T = unknown> {\n resolve: (value: T) => void;\n reject: (error: Error) => void;\n timeout?: NodeJS.Timeout;\n}\n\n/**\n * Request tracker options\n */\nexport interface RequestTrackerOptions {\n /** Default timeout in milliseconds (default: 30000) */\n defaultTimeout?: number;\n}\n\n/**\n * RequestTracker manages pending requests and their promises\n */\nexport class RequestTracker {\n private pendingRequests = new Map<string, PendingRequest>();\n private defaultTimeout: number;\n\n constructor(options: RequestTrackerOptions = {}) {\n this.defaultTimeout = options.defaultTimeout ?? 30000;\n }\n\n /**\n * Generate a new unique request ID\n */\n generateRequestId(): string {\n return uuidv4();\n }\n\n /**\n * Create a new tracked request\n *\n * @param requestId - Unique request ID\n * @param timeout - Timeout in milliseconds (uses default if not specified)\n * @returns Promise that resolves when response is received\n */\n createRequest<T = unknown>(requestId: string, timeout?: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timeoutMs = timeout ?? this.defaultTimeout;\n\n // Set up timeout\n const timeoutHandle = setTimeout(() => {\n this.rejectRequest(\n requestId,\n new Error(`Request ${requestId} timed out after ${timeoutMs}ms`)\n );\n }, timeoutMs);\n\n // Store pending request\n this.pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: timeoutHandle,\n });\n });\n }\n\n /**\n * Resolve a pending request\n *\n * @param requestId - Request ID to resolve\n * @param value - Value to resolve with\n */\n resolveRequest<T = unknown>(requestId: string, value: T): void {\n const pending = this.pendingRequests.get(requestId);\n if (pending) {\n if (pending.timeout) {\n clearTimeout(pending.timeout);\n }\n pending.resolve(value);\n this.pendingRequests.delete(requestId);\n }\n }\n\n /**\n * Reject a pending request\n *\n * @param requestId - Request ID to reject\n * @param error - Error to reject with\n */\n rejectRequest(requestId: string, error: Error): void {\n const pending = this.pendingRequests.get(requestId);\n if (pending) {\n if (pending.timeout) {\n clearTimeout(pending.timeout);\n }\n pending.reject(error);\n this.pendingRequests.delete(requestId);\n }\n }\n\n /**\n * Cancel a pending request\n *\n * @param requestId - Request ID to cancel\n */\n cancelRequest(requestId: string): void {\n this.rejectRequest(requestId, new Error(`Request ${requestId} was cancelled`));\n }\n\n /**\n * Check if a request is pending\n *\n * @param requestId - Request ID to check\n */\n hasPendingRequest(requestId: string): boolean {\n return this.pendingRequests.has(requestId);\n }\n\n /**\n * Get the number of pending requests\n */\n getPendingCount(): number {\n return this.pendingRequests.size;\n }\n\n /**\n * Cancel all pending requests\n */\n cancelAll(): void {\n const requestIds = Array.from(this.pendingRequests.keys());\n for (const requestId of requestIds) {\n this.cancelRequest(requestId);\n }\n }\n\n /**\n * Clear all pending requests without rejecting them\n * (useful during cleanup)\n */\n clear(): void {\n for (const pending of this.pendingRequests.values()) {\n if (pending.timeout) {\n clearTimeout(pending.timeout);\n }\n }\n this.pendingRequests.clear();\n }\n}\n","/**\n * JWT authentication manager\n */\n\nimport {\n AuthenticatePayload,\n AuthenticateResponse,\n RefreshTokenPayload,\n} from './protocol';\n\n/**\n * Token storage interface\n */\nexport interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string): void;\n getRefreshToken(): string | null;\n setRefreshToken(token: string): void;\n clear(): void;\n}\n\n/**\n * In-memory token storage (default)\n */\nexport class MemoryTokenStorage implements TokenStorage {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getRefreshToken(): string | null {\n return this.refreshToken;\n }\n\n setRefreshToken(token: string): void {\n this.refreshToken = token;\n }\n\n clear(): void {\n this.accessToken = null;\n this.refreshToken = null;\n }\n}\n\n/**\n * LocalStorage-based token storage for browser\n */\nexport class LocalStorageTokenStorage implements TokenStorage {\n private prefix: string;\n\n constructor(prefix: string = 'raisindb') {\n this.prefix = prefix;\n }\n\n getAccessToken(): string | null {\n if (typeof localStorage === 'undefined') return null;\n return localStorage.getItem(`${this.prefix}_access_token`);\n }\n\n setAccessToken(token: string): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(`${this.prefix}_access_token`, token);\n }\n\n getRefreshToken(): string | null {\n if (typeof localStorage === 'undefined') return null;\n return localStorage.getItem(`${this.prefix}_refresh_token`);\n }\n\n setRefreshToken(token: string): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(`${this.prefix}_refresh_token`, token);\n }\n\n clear(): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.removeItem(`${this.prefix}_access_token`);\n localStorage.removeItem(`${this.prefix}_refresh_token`);\n localStorage.removeItem(`${this.prefix}_user`);\n }\n\n /**\n * Store user data in localStorage\n */\n setUser(user: IdentityUser): void {\n if (typeof localStorage === 'undefined') return;\n localStorage.setItem(`${this.prefix}_user`, JSON.stringify(user));\n }\n\n /**\n * Get stored user data from localStorage\n */\n getUser(): IdentityUser | null {\n if (typeof localStorage === 'undefined') return null;\n const userJson = localStorage.getItem(`${this.prefix}_user`);\n if (!userJson) return null;\n try {\n return JSON.parse(userJson);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Identity user information (from JWT/login response)\n */\nexport interface IdentityUser {\n /** Identity UUID */\n id: string;\n /** Email address */\n email: string;\n /** Display name */\n displayName: string | null;\n /** Avatar URL */\n avatarUrl: string | null;\n /** Whether email is verified */\n emailVerified: boolean;\n /** User's home node path in the repository (from JWT or RAISIN_CURRENT_USER) */\n home: string | null;\n}\n\n/**\n * Identity auth tokens response (from HTTP login/register)\n */\nexport interface IdentityAuthResponse {\n access_token: string;\n refresh_token: string;\n token_type: string;\n expires_at: number;\n identity: {\n id: string;\n email: string;\n display_name: string | null;\n avatar_url: string | null;\n email_verified: boolean;\n linked_providers: string[];\n /** User's home node path in the repository */\n home: string | null;\n };\n}\n\n/**\n * Identity auth error\n */\nexport interface IdentityAuthError {\n code: string;\n message: string;\n}\n\n/**\n * Admin authentication credentials (username/password)\n */\nexport interface AdminCredentials {\n username: string;\n password: string;\n}\n\n/**\n * JWT authentication credentials (identity users)\n * Used by SPAs that have obtained a JWT via HTTP API\n */\nexport interface JwtCredentials {\n type: 'jwt';\n token: string;\n}\n\n/**\n * Authentication credentials - either admin or JWT\n */\nexport type Credentials = AdminCredentials | JwtCredentials;\n\n/**\n * Type guard to check if credentials are JWT-based\n */\nexport function isJwtCredentials(credentials: Credentials): credentials is JwtCredentials {\n return 'type' in credentials && credentials.type === 'jwt';\n}\n\n/**\n * Authentication manager\n */\nexport class AuthManager {\n private _storage: TokenStorage;\n private expiresAt: number | null = null;\n private refreshTimer?: NodeJS.Timeout;\n\n constructor(storage?: TokenStorage) {\n this._storage = storage ?? new MemoryTokenStorage();\n }\n\n /**\n * Get storage (for direct token manipulation)\n */\n get storage(): TokenStorage {\n return this._storage;\n }\n\n /**\n * Store authentication response\n *\n * @param response - Authentication response from server\n */\n setTokens(response: AuthenticateResponse): void {\n this._storage.setAccessToken(response.access_token);\n this._storage.setRefreshToken(response.refresh_token);\n\n // Calculate expiration time (subtract 60 seconds for safety margin)\n const expiresInMs = (response.expires_in - 60) * 1000;\n this.expiresAt = Date.now() + expiresInMs;\n\n // Schedule automatic refresh\n this.scheduleTokenRefresh(expiresInMs);\n }\n\n /**\n * Get current access token\n */\n getAccessToken(): string | null {\n return this._storage.getAccessToken();\n }\n\n /**\n * Get current refresh token\n */\n getRefreshToken(): string | null {\n return this._storage.getRefreshToken();\n }\n\n /**\n * Check if authenticated\n */\n isAuthenticated(): boolean {\n const token = this._storage.getAccessToken();\n return token !== null && !this.isTokenExpired();\n }\n\n /**\n * Check if token is expired\n */\n isTokenExpired(): boolean {\n if (this.expiresAt === null) {\n return true;\n }\n return Date.now() >= this.expiresAt;\n }\n\n /**\n * Check if token needs refresh (within 5 minutes of expiration)\n */\n needsRefresh(): boolean {\n if (this.expiresAt === null) {\n return false;\n }\n const fiveMinutes = 5 * 60 * 1000;\n return Date.now() >= this.expiresAt - fiveMinutes;\n }\n\n /**\n * Clear authentication state\n */\n clear(): void {\n this._storage.clear();\n this.expiresAt = null;\n this.cancelTokenRefresh();\n }\n\n /**\n * Schedule automatic token refresh\n *\n * @param delayMs - Delay in milliseconds\n */\n private scheduleTokenRefresh(delayMs: number): void {\n this.cancelTokenRefresh();\n\n this.refreshTimer = setTimeout(() => {\n // Emit event that refresh is needed\n // The client should handle this by calling the refresh endpoint\n }, delayMs);\n }\n\n /**\n * Cancel scheduled token refresh\n */\n private cancelTokenRefresh(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = undefined;\n }\n }\n\n /**\n * Create authentication payload for admin auth\n *\n * @param credentials - Admin credentials\n */\n static createAuthPayload(credentials: AdminCredentials): AuthenticatePayload {\n return {\n username: credentials.username,\n password: credentials.password,\n };\n }\n\n /**\n * Create refresh token payload\n *\n * @param refreshToken - Refresh token\n */\n static createRefreshPayload(refreshToken: string): RefreshTokenPayload {\n return {\n refresh_token: refreshToken,\n };\n }\n\n /**\n * Parse JWT token (without verification)\n * This is just for extracting expiration time, not for security\n *\n * @param token - JWT token\n * @returns Parsed token payload or null if invalid\n */\n static parseToken(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(decoded);\n } catch (error) {\n return null;\n }\n }\n}\n","/**\n * WebSocket protocol definitions for RaisinDB\n *\n * This module defines TypeScript interfaces matching the Rust protocol.\n * All messages are serialized using MessagePack for efficiency.\n */\n\nimport { encode, decode } from '@msgpack/msgpack';\n\n// ============================================================================\n// Core Envelope Types\n// ============================================================================\n\n/**\n * Request envelope wrapping all client-to-server messages\n */\nexport interface RequestEnvelope {\n /** Unique identifier for this request (generated by client) */\n request_id: string;\n /** Type of request */\n type: RequestType;\n /** Request context (tenant, repository, workspace) */\n context: RequestContext;\n /** Request-specific payload */\n payload: unknown;\n}\n\n/**\n * Response envelope wrapping all server-to-client messages\n */\nexport interface ResponseEnvelope {\n /** Request ID this response corresponds to */\n request_id: string;\n /** Response status */\n status: ResponseStatus;\n /** Response data (if successful) */\n result?: unknown;\n /** Error information (if failed) */\n error?: ErrorInfo;\n /** Metadata for streaming responses */\n metadata?: ResponseMetadata;\n}\n\n/**\n * Payload of node events (`node:created`, `node:updated`, `node:deleted`, ...)\n * as emitted by the server's WebSocket event forwarder.\n *\n * All fields except `kind` are optional because the exact shape depends on\n * the event kind and subscription options (e.g. `node` is only present when\n * the subscription was created with `include_node: true`). Unknown extra\n * fields are accessible via the index signature.\n */\nexport interface NodeEventPayload {\n /** Event kind (e.g. \"Created\", \"Updated\", \"Deleted\", \"PropertyChanged { .. }\") */\n kind: string;\n /** Tenant the event originated from */\n tenant_id?: string;\n /** Repository the event originated from */\n repository_id?: string;\n /** Branch the event originated from */\n branch?: string;\n /** Workspace containing the node */\n workspace_id?: string;\n /** ID of the affected node */\n node_id?: string;\n /** Node type of the affected node */\n node_type?: string | null;\n /** Revision (HLC timestamp) of the change */\n revision?: string;\n /** Path of the affected node */\n path?: string | null;\n /** Full node data (only when subscribed with `include_node: true`) */\n node?: Node;\n /** Event metadata (source, related nodes, ...) */\n metadata?: Record<string, unknown> | null;\n /** Relation type (for `node:relation_added` / `node:relation_removed`) */\n relation_type?: string;\n /** Target node ID (for relation events) */\n target_node_id?: string;\n /** Changed property name (for `node:property_changed`) */\n property?: string;\n /** Related node ID, if provided in event metadata */\n related_node_id?: string;\n /** Related workspace, if provided in event metadata */\n related_workspace?: string;\n /** Relation direction, if provided in event metadata */\n relation_direction?: string;\n /** Additional event-specific fields */\n [key: string]: unknown;\n}\n\n/**\n * Event message for server-initiated events (subscriptions)\n *\n * Defaults the payload type to {@link NodeEventPayload} (the most common\n * case). Pass a type parameter for other event families\n * (e.g. `EventMessage<MyRepositoryEventPayload>`).\n */\nexport interface EventMessage<TPayload = NodeEventPayload> {\n /** Unique event ID */\n event_id: string;\n /** Subscription ID this event belongs to */\n subscription_id: string;\n /** Event type */\n event_type: string;\n /** Event payload */\n payload: TPayload;\n /** Timestamp of the event (ISO 8601 string) */\n timestamp: string;\n}\n\n/**\n * Connected message sent by server on WebSocket connection\n * Includes anonymous token for HTTP API calls when anonymous access is enabled\n */\nexport interface ConnectedMessage {\n /** Message type identifier */\n type: 'connected';\n /** Connection ID assigned by server */\n connection_id: string;\n /** Whether this is an anonymous connection */\n anonymous: boolean;\n /** JWT token for HTTP API calls (only for anonymous connections) */\n token?: string;\n /** User ID (for anonymous connections, a generated UUID) */\n user_id?: string;\n}\n\n/**\n * Request context containing scope information\n */\nexport interface RequestContext {\n /** Tenant ID */\n tenant_id: string;\n /** Repository ID (optional for some operations) */\n repository?: string;\n /** Branch name (optional, defaults to \"main\") */\n branch?: string;\n /** Workspace ID (optional for some operations) */\n workspace?: string;\n /** Revision/commit ID for time-travel queries (optional) */\n revision?: string;\n /** Transaction ID for transactional operations (optional) */\n transaction_id?: string;\n}\n\n// ============================================================================\n// Enums\n// ============================================================================\n\n/**\n * Type of request\n */\nexport enum RequestType {\n // Authentication\n Authenticate = 'authenticate',\n AuthenticateJwt = 'authenticate_jwt',\n RefreshToken = 'refresh_token',\n\n // Node operations\n NodeCreate = 'node_create',\n NodeUpdate = 'node_update',\n NodeDelete = 'node_delete',\n NodeGet = 'node_get',\n NodeQuery = 'node_query',\n NodeQueryByPath = 'node_query_by_path',\n NodeQueryByProperty = 'node_query_by_property',\n\n // Tree operations\n NodeListChildren = 'node_list_children',\n NodeGetTree = 'node_get_tree',\n NodeGetTreeFlat = 'node_get_tree_flat',\n\n // Node manipulation operations\n NodeMove = 'node_move',\n NodeRename = 'node_rename',\n NodeCopy = 'node_copy',\n NodeCopyTree = 'node_copy_tree',\n NodeReorder = 'node_reorder',\n NodeMoveChildBefore = 'node_move_child_before',\n NodeMoveChildAfter = 'node_move_child_after',\n NodeApplyChildOrder = 'node_apply_child_order',\n\n // Property path operations\n PropertyGet = 'property_get',\n PropertyUpdate = 'property_update',\n\n // Relationship operations\n RelationAdd = 'relation_add',\n RelationRemove = 'relation_remove',\n RelationsGet = 'relations_get',\n\n // SQL queries\n SqlQuery = 'sql_query',\n\n // Workspace operations\n WorkspaceCreate = 'workspace_create',\n WorkspaceGet = 'workspace_get',\n WorkspaceList = 'workspace_list',\n WorkspaceDelete = 'workspace_delete',\n WorkspaceUpdate = 'workspace_update',\n\n // Branch operations\n BranchCreate = 'branch_create',\n BranchGet = 'branch_get',\n BranchList = 'branch_list',\n BranchDelete = 'branch_delete',\n BranchGetHead = 'branch_get_head',\n BranchUpdateHead = 'branch_update_head',\n BranchMerge = 'branch_merge',\n BranchCompare = 'branch_compare',\n BranchDiff = 'branch_diff',\n BranchCopyNodes = 'branch_copy_nodes',\n\n // Tag operations\n TagCreate = 'tag_create',\n TagGet = 'tag_get',\n TagList = 'tag_list',\n TagDelete = 'tag_delete',\n\n // NodeType operations\n NodeTypeCreate = 'node_type_create',\n NodeTypeGet = 'node_type_get',\n NodeTypeList = 'node_type_list',\n NodeTypeUpdate = 'node_type_update',\n NodeTypeDelete = 'node_type_delete',\n NodeTypePublish = 'node_type_publish',\n NodeTypeUnpublish = 'node_type_unpublish',\n NodeTypeValidate = 'node_type_validate',\n NodeTypeGetResolved = 'node_type_get_resolved',\n\n // Archetype operations\n ArchetypeCreate = 'archetype_create',\n ArchetypeGet = 'archetype_get',\n ArchetypeList = 'archetype_list',\n ArchetypeUpdate = 'archetype_update',\n ArchetypeDelete = 'archetype_delete',\n ArchetypePublish = 'archetype_publish',\n ArchetypeUnpublish = 'archetype_unpublish',\n ArchetypeGetResolved = 'archetype_get_resolved',\n\n // ElementType operations\n ElementTypeCreate = 'element_type_create',\n ElementTypeGet = 'element_type_get',\n ElementTypeList = 'element_type_list',\n ElementTypeUpdate = 'element_type_update',\n ElementTypeDelete = 'element_type_delete',\n ElementTypePublish = 'element_type_publish',\n ElementTypeUnpublish = 'element_type_unpublish',\n ElementTypeGetResolved = 'element_type_get_resolved',\n\n // Search operations\n FullTextSearch = 'full_text_search',\n VectorSearch = 'vector_search',\n\n // Event subscriptions\n Subscribe = 'subscribe',\n Unsubscribe = 'unsubscribe',\n\n // Repository management\n RepositoryCreate = 'repository_create',\n RepositoryGet = 'repository_get',\n RepositoryList = 'repository_list',\n RepositoryUpdate = 'repository_update',\n RepositoryDelete = 'repository_delete',\n\n // Audit operations\n AuditQuery = 'audit_query',\n\n // Binary operations\n BinaryUpload = 'binary_upload',\n BinaryDownload = 'binary_download',\n\n // Batch operations\n Batch = 'batch',\n\n // Transaction operations\n TransactionBegin = 'transaction_begin',\n TransactionCommit = 'transaction_commit',\n TransactionRollback = 'transaction_rollback',\n\n // Flow operations\n FlowRun = 'flow_run',\n FlowResume = 'flow_resume',\n FlowGetInstanceStatus = 'flow_get_instance_status',\n FlowCancel = 'flow_cancel',\n FlowSubscribeEvents = 'flow_subscribe_events',\n FlowUnsubscribeEvents = 'flow_unsubscribe_events',\n\n // Function operations\n FunctionInvoke = 'function_invoke',\n FunctionInvokeSync = 'function_invoke_sync',\n\n // Scheduled invocation operations (one-shot, time-based function/flow runs)\n ScheduledInvocationCreate = 'scheduled_invocation_create',\n ScheduledInvocationCancel = 'scheduled_invocation_cancel',\n ScheduledInvocationList = 'scheduled_invocation_list',\n ScheduledInvocationGet = 'scheduled_invocation_get',\n}\n\n/**\n * Response status\n */\nexport enum ResponseStatus {\n /** Request succeeded, complete result included */\n Success = 'success',\n /** Request failed, error information included */\n Error = 'error',\n /** Streaming response, more chunks to come */\n Streaming = 'streaming',\n /** Final chunk of a streaming response */\n Complete = 'complete',\n /** Request acknowledged, processing asynchronously */\n Acknowledged = 'acknowledged',\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Error information\n */\nexport interface ErrorInfo {\n /** Error code */\n code: string;\n /** Human-readable error message */\n message: string;\n /** Additional error details */\n details?: unknown;\n}\n\n/**\n * Response metadata for streaming and pagination\n */\nexport interface ResponseMetadata {\n /** Current chunk number (for streaming) */\n chunk?: number;\n /** Total number of chunks (if known) */\n total_chunks?: number;\n /** Total number of results (for pagination) */\n total?: number;\n /** Has more results available */\n has_more?: boolean;\n /** Credits consumed (for backpressure) */\n credits_consumed?: number;\n}\n\n// ============================================================================\n// Node Operation Types\n// ============================================================================\n\n/**\n * Node data structure\n */\n/**\n * A reference to a related node in the graph database\n */\nexport interface RelationRef {\n /** ID of the target node */\n target: string;\n /** Workspace containing the target node */\n workspace: string;\n /** Node type of the target (for filtering) */\n target_node_type: string;\n /** Semantic relationship type (e.g., \"references\", \"links_to\") */\n relation_type: string;\n /** Optional weight for graph algorithms */\n weight?: number;\n}\n\n/**\n * An incoming relationship record including the source node metadata\n */\nexport interface IncomingRelation {\n /** Workspace containing the source node */\n source_workspace: string;\n /** ID of the source node */\n source_node_id: string;\n /** Relationship details pointing to the current node */\n relation: RelationRef;\n}\n\n/**\n * Complete incoming/outgoing relationship information for a node\n */\nexport interface NodeRelationships {\n /** Relationships originating from this node */\n outgoing: RelationRef[];\n /** Relationships targeting this node */\n incoming: IncomingRelation[];\n}\n\n/**\n * A content node in RaisinDB's hierarchical structure\n */\nexport interface Node {\n /** Unique identifier for this node */\n id: string;\n /** Display name of the node (used in URLs and hierarchical paths) */\n name: string;\n /** Full path to this node in the tree (e.g., \"/content/my-page\") */\n path: string;\n /** The NodeType name that defines this node's schema */\n node_type: string;\n /** Optional archetype for specialized rendering */\n archetype?: string;\n /** Key-value map of properties, validated against the NodeType schema */\n properties: Record<string, PropertyValue>;\n /** Ordered list of child node IDs */\n children: string[];\n /** Fractional index for ordering among siblings (Base62 string) */\n order_key: string;\n /** Whether this node has children (computed field) */\n has_children?: boolean;\n /**\n * Name of the parent node (not the full path, just the name).\n * Example: If path is \"/content/docs/page1\", parent should be \"docs\"\n */\n parent?: string;\n /** Version number for this node (incremented on updates) */\n version: number;\n /** Timestamp when this node was created (ISO 8601 string) */\n created_at?: string;\n /** Timestamp when this node was last updated (ISO 8601 string) */\n updated_at?: string;\n /** Timestamp when this node was published (ISO 8601 string, null if unpublished) */\n published_at?: string;\n /** User ID who published this node */\n published_by?: string;\n /** User ID who last updated this node */\n updated_by?: string;\n /** User ID who created this node */\n created_by?: string;\n /** Translations for multi-language support */\n translations?: Record<string, PropertyValue>;\n /** Tenant ID for multi-tenant deployments */\n tenant_id?: string;\n /** Workspace this node belongs to */\n workspace?: string;\n /** Owner user ID (for access control) */\n owner_id?: string;\n /** Relations to other nodes */\n relations: RelationRef[];\n}\n\n/**\n * Property value types\n */\nexport type PropertyValue =\n | string\n | number\n | boolean\n | null\n | PropertyValue[]\n | { [key: string]: PropertyValue };\n\n/**\n * Node create payload\n */\nexport interface NodeCreatePayload {\n node_type: string;\n path: string;\n properties: Record<string, PropertyValue>;\n content?: unknown;\n}\n\n/**\n * Deep create/upsert payload. `path` is the full node path; missing ancestor\n * folders are auto-created as `parent_node_type` (defaults to `raisin:Folder`).\n */\nexport interface NodeCreateDeepPayload {\n node_type: string;\n path: string;\n properties: Record<string, PropertyValue>;\n content?: unknown;\n parent_node_type?: string;\n}\n\n/**\n * Node update payload\n */\nexport interface NodeUpdatePayload {\n node_id: string;\n properties: Record<string, PropertyValue>;\n content?: unknown;\n}\n\n/**\n * Node delete payload\n */\nexport interface NodeDeletePayload {\n node_id: string;\n}\n\n/**\n * Node get payload\n */\nexport interface NodeGetPayload {\n node_id: string;\n}\n\n/**\n * Node history payload (git-style \"file history\").\n * Identify the node by either `node_id` or `path`.\n */\nexport interface NodeHistoryPayload {\n node_id?: string;\n path?: string;\n /** Maximum number of revisions to return (newest first). Unbounded if omitted. */\n limit?: number;\n}\n\n/**\n * A single entry in a node's revision history (newest first).\n *\n * Use `revision` with `atRevision(revision)` reads to fetch the full snapshot\n * of that historical version.\n */\nexport interface RevisionEntry {\n /** HLC revision string (\"timestamp-counter\"), usable with atRevision(). */\n revision: string;\n /** When this revision was written (ISO 8601 string). */\n updated_at?: string;\n /** User ID who authored this revision. */\n updated_by?: string;\n /** True when the node was deleted at this revision (tombstone). */\n deleted: boolean;\n}\n\n/**\n * Audit-log query payload. Identify the node by either `node_id` or `path`.\n * Audit logs are only produced for NodeTypes marked `auditable`.\n */\nexport interface AuditQueryPayload {\n node_id?: string;\n path?: string;\n}\n\n/**\n * A single audit-log entry for a node.\n *\n * Only produced for NodeTypes marked `auditable`. Distinct from a\n * {@link RevisionEntry} (the always-on structural MVCC history).\n */\nexport interface AuditLogEntry {\n id: string;\n node_id: string;\n path: string;\n workspace: string;\n /** User ID that performed the action (the node's `updated_by` at write time). */\n user_id?: string;\n /** Action performed, e.g. \"Create\" | \"Update\" | \"Delete\" | \"Publish\" | … */\n action: string;\n /** ISO 8601 timestamp. */\n timestamp: string;\n details?: string;\n}\n\n/**\n * Node query payload\n */\nexport interface NodeQueryPayload {\n query: unknown;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Relationship add payload\n */\nexport interface RelationAddPayload {\n source_path: string;\n target_workspace: string;\n target_path: string;\n weight?: number;\n relation_type?: string;\n}\n\n/**\n * Relationship remove payload\n */\nexport interface RelationRemovePayload {\n source_path: string;\n target_workspace: string;\n target_path: string;\n}\n\n/**\n * Relationship list payload\n */\nexport interface RelationsGetPayload {\n node_path: string;\n}\n\n/**\n * SQL query payload\n */\nexport interface SqlQueryPayload {\n /** SQL query string */\n query: string;\n /** Parameters for the query (for injection protection) */\n params?: unknown[];\n}\n\n/**\n * SQL query result\n */\nexport interface SqlResult {\n columns: string[];\n rows: Record<string, unknown>[];\n row_count: number;\n}\n\n// ============================================================================\n// Workspace Operation Types\n// ============================================================================\n\n/**\n * Workspace data structure\n */\nexport interface Workspace {\n id: string;\n name: string;\n description?: string;\n allowed_node_types?: string[];\n allowed_root_node_types?: string[];\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Workspace create payload\n */\nexport interface WorkspaceCreatePayload {\n name: string;\n description?: string;\n}\n\n/**\n * Workspace get payload\n */\nexport interface WorkspaceGetPayload {\n name: string;\n}\n\n/**\n * Workspace delete payload\n */\nexport interface WorkspaceDeletePayload {\n name: string;\n}\n\n/**\n * Workspace update payload\n */\nexport interface WorkspaceUpdatePayload {\n name: string;\n description?: string;\n allowed_node_types?: string[];\n allowed_root_node_types?: string[];\n}\n\n// ============================================================================\n// Transaction Operation Types\n// ============================================================================\n\n/**\n * Transaction begin payload\n */\nexport interface TransactionBeginPayload {\n /** Optional commit message */\n message?: string;\n /** Optional actor identifier */\n actor?: string;\n}\n\n/**\n * Transaction begin response\n */\nexport interface TransactionBeginResponse {\n /** Unique transaction ID */\n transaction_id: string;\n}\n\n/**\n * Transaction commit payload\n */\nexport interface TransactionCommitPayload {}\n\n/**\n * Transaction commit response\n */\nexport interface TransactionCommitResponse {\n /** Revision (HLC timestamp) assigned to this commit in format \"timestamp-counter\" (e.g., \"1762780281515-0\") */\n revision: string;\n /** Unique commit ID */\n commit_id: string;\n}\n\n/**\n * Transaction rollback payload\n */\nexport interface TransactionRollbackPayload {}\n\n// ============================================================================\n// Event Subscription Types\n// ============================================================================\n\n/**\n * Subscribe payload\n */\nexport interface SubscribePayload {\n /** Filters for this subscription */\n filters: SubscriptionFilters;\n}\n\n/**\n * Subscription filters\n */\nexport interface SubscriptionFilters {\n /** Filter by workspace */\n workspace?: string;\n /**\n * Filter by path pattern.\n *\n * Semantics: a plain path matches only that exact node (no implicit\n * prefix matching), `*` matches exactly one path segment, `**` matches\n * recursively (e.g. \"/folder/**\" for all descendants of \"/folder\").\n */\n path?: string;\n /** Filter by event types */\n event_types?: string[];\n /** Filter by node type */\n node_type?: string;\n /** Include full node data in event payload (default: false) */\n include_node?: boolean;\n}\n\n/**\n * Unsubscribe payload\n */\nexport interface UnsubscribePayload {\n /** Subscription ID to cancel */\n subscription_id: string;\n}\n\n/**\n * Subscription response\n */\nexport interface SubscriptionResponse {\n /** Unique subscription ID */\n subscription_id: string;\n}\n\n// ============================================================================\n// Authentication Types\n// ============================================================================\n\n/**\n * Authenticate payload (admin user with username/password)\n */\nexport interface AuthenticatePayload {\n username: string;\n password: string;\n}\n\n/**\n * Authenticate with JWT token (identity user)\n *\n * Used by SPAs and clients that have already obtained a JWT token\n * via HTTP API (e.g., /auth/{repo}/login)\n */\nexport interface AuthenticateJwtPayload {\n /** JWT access token from identity provider */\n token: string;\n}\n\n/**\n * Authenticate response (admin auth)\n */\nexport interface AuthenticateResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n}\n\n/**\n * Authenticate JWT response (identity auth)\n */\nexport interface AuthenticateJwtResponse {\n /** User ID from the JWT */\n user_id: string;\n /** Effective roles assigned to the user */\n roles: string[];\n}\n\n/**\n * Refresh token payload\n */\nexport interface RefreshTokenPayload {\n refresh_token: string;\n}\n\n// ============================================================================\n// MessagePack Utilities\n// ============================================================================\n\n/**\n * Encode a message to MessagePack binary format\n */\nexport function encodeMessage(message: RequestEnvelope): Uint8Array {\n return encode(message);\n}\n\n/**\n * Decode a MessagePack binary message\n */\nexport function decodeMessage(data: ArrayBuffer | Uint8Array): ResponseEnvelope | EventMessage {\n const decoded = decode(data) as ResponseEnvelope | EventMessage;\n\n // Type guard: check if it's an event message\n if ('subscription_id' in decoded && 'event_type' in decoded) {\n return decoded as EventMessage;\n }\n\n return decoded as ResponseEnvelope;\n}\n\n/**\n * Type guard to check if a message is an event\n */\nexport function isEventMessage(message: ResponseEnvelope | EventMessage): message is EventMessage {\n return 'subscription_id' in message && 'event_type' in message;\n}\n\n/**\n * Type guard to check if a message is a response\n */\nexport function isResponseEnvelope(message: ResponseEnvelope | EventMessage): message is ResponseEnvelope {\n return 'status' in message && !('subscription_id' in message);\n}\n\n/**\n * Type guard to check if a message is a connected message\n */\nexport function isConnectedMessage(message: unknown): message is ConnectedMessage {\n return (\n typeof message === 'object' &&\n message !== null &&\n 'type' in message &&\n (message as ConnectedMessage).type === 'connected'\n );\n}\n","/**\n * Event subscription system\n */\n\nimport {\n EventMessage,\n SubscriptionFilters,\n SubscribePayload,\n UnsubscribePayload,\n SubscriptionResponse,\n RequestType,\n} from './protocol';\nimport { logger } from './logger';\n\n/**\n * Event callback function\n */\nexport type EventCallback = (event: EventMessage) => void;\n\n/**\n * Subscription interface\n */\nexport interface Subscription {\n /** Unique subscription ID */\n id: string;\n /** Unsubscribe from events */\n unsubscribe(): Promise<void>;\n /** Check if subscription is active */\n isActive(): boolean;\n}\n\n/**\n * Internal tracking for deduplicated subscriptions\n */\ninterface FilterSubscriptionEntry {\n /** Server-side subscription ID */\n serverId: string;\n /** Original filters (for reconnection) */\n filters: SubscriptionFilters;\n /** All callbacks registered for this filter combination */\n callbacks: Set<EventCallback>;\n /** Set while the entry still needs to be re-subscribed after a reconnect */\n restorePending?: boolean;\n}\n\n/** Default deduplication window in milliseconds (5 seconds) */\nconst DEFAULT_DEDUP_WINDOW_MS = 5000;\n\n/**\n * Event handler for managing subscriptions with deduplication\n *\n * Multiple subscribe() calls with identical filters will share a single\n * server-side subscription, reducing network overhead and server load.\n *\n * Event deduplication is enabled by default to prevent duplicate event\n * delivery during rapid reconnection scenarios.\n */\nexport class EventHandler {\n /** Map: server subscription ID -> filter hash (for event routing) */\n private subscriptions = new Map<string, string>();\n\n /** Map: filter hash -> subscription entry (for deduplication) */\n private filterSubscriptions = new Map<string, FilterSubscriptionEntry>();\n\n /** Map: callback -> filter hash (for unsubscribe lookup) */\n private callbackToHash = new Map<EventCallback, string>();\n\n /** Map: event_id -> expiration timestamp (for event deduplication) */\n private recentEventIds = new Map<string, number>();\n\n /** Deduplication window in milliseconds */\n private dedupWindowMs: number;\n\n /** Cleanup timer for expired event IDs */\n private dedupCleanupTimer?: ReturnType<typeof setInterval>;\n\n private sendRequest: (\n payload: SubscribePayload | UnsubscribePayload,\n requestType: RequestType\n ) => Promise<unknown>;\n\n constructor(\n sendRequest: (\n payload: SubscribePayload | UnsubscribePayload,\n requestType: RequestType\n ) => Promise<unknown>,\n options?: { dedupWindowMs?: number }\n ) {\n this.sendRequest = sendRequest;\n this.dedupWindowMs = options?.dedupWindowMs ?? DEFAULT_DEDUP_WINDOW_MS;\n\n // Start cleanup timer for expired event IDs (runs every 10 seconds)\n this.dedupCleanupTimer = setInterval(() => {\n this.cleanupExpiredEventIds();\n }, 10000);\n }\n\n /**\n * Cleanup resources (call when client is disconnected)\n */\n destroy(): void {\n if (this.dedupCleanupTimer) {\n clearInterval(this.dedupCleanupTimer);\n this.dedupCleanupTimer = undefined;\n }\n this.recentEventIds.clear();\n }\n\n /**\n * Remove expired event IDs from the deduplication cache\n * @internal\n */\n private cleanupExpiredEventIds(): void {\n const now = Date.now();\n for (const [eventId, expiration] of this.recentEventIds) {\n if (expiration <= now) {\n this.recentEventIds.delete(eventId);\n }\n }\n }\n\n /**\n * Track an event ID for deduplication\n * @internal\n */\n private trackEventId(eventId: string): void {\n const expiration = Date.now() + this.dedupWindowMs;\n this.recentEventIds.set(eventId, expiration);\n }\n\n /**\n * Check if an event ID has been seen recently\n * @internal\n */\n private isEventDuplicate(eventId: string): boolean {\n const expiration = this.recentEventIds.get(eventId);\n if (!expiration) return false;\n return expiration > Date.now();\n }\n\n /**\n * Create a deterministic hash of subscription filters\n *\n * Two subscriptions with identical filters will produce the same hash,\n * allowing deduplication.\n */\n private hashFilters(filters: SubscriptionFilters): string {\n // Sort event_types for consistent hashing\n const sortedEventTypes = filters.event_types\n ? [...filters.event_types].sort()\n : undefined;\n\n // Create deterministic JSON string\n return JSON.stringify({\n workspace: filters.workspace ?? null,\n path: filters.path ?? null,\n event_types: sortedEventTypes ?? null,\n node_type: filters.node_type ?? null,\n include_node: filters.include_node ?? false,\n });\n }\n\n /**\n * Subscribe to events with filters\n *\n * If a subscription with identical filters already exists, the callback\n * is added to the existing subscription instead of creating a new one.\n *\n * Path filter semantics (matched server-side):\n * - A plain path matches **only that exact node** — there is no implicit\n * prefix matching.\n * - `*` matches exactly one path segment (e.g. `/inbox/*` matches\n * `/inbox/a` but not `/inbox/a/b`).\n * - `**` matches recursively (e.g. `/inbox/**` matches all descendants\n * of `/inbox`, but not `/inbox` itself).\n *\n * @param filters - Event filters\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribe(\n filters: SubscriptionFilters,\n callback: EventCallback\n ): Promise<Subscription> {\n const hash = this.hashFilters(filters);\n\n // Check for existing subscription with same filters\n const existing = this.filterSubscriptions.get(hash);\n if (existing) {\n logger.debug('Reusing existing subscription with identical filters');\n existing.callbacks.add(callback);\n this.callbackToHash.set(callback, hash);\n\n return this.createSubscriptionHandle(existing.serverId, callback, hash);\n }\n\n // Create new server subscription\n const payload: SubscribePayload = { filters };\n const response = (await this.sendRequest(\n payload,\n RequestType.Subscribe\n )) as SubscriptionResponse;\n\n const serverId = response.subscription_id;\n\n // Track the new subscription\n this.filterSubscriptions.set(hash, {\n serverId,\n filters,\n callbacks: new Set([callback]),\n });\n this.subscriptions.set(serverId, hash);\n this.callbackToHash.set(callback, hash);\n\n return this.createSubscriptionHandle(serverId, callback, hash);\n }\n\n /**\n * Create a subscription handle for the callback\n */\n private createSubscriptionHandle(\n serverId: string,\n callback: EventCallback,\n hash: string\n ): Subscription {\n return {\n id: serverId,\n unsubscribe: async () => {\n await this.unsubscribeCallback(callback);\n },\n isActive: () => {\n const entry = this.filterSubscriptions.get(hash);\n return entry?.callbacks.has(callback) ?? false;\n },\n };\n }\n\n /**\n * Unsubscribe a specific callback\n *\n * Only sends unsubscribe to server when the last callback is removed.\n */\n private async unsubscribeCallback(callback: EventCallback): Promise<void> {\n const hash = this.callbackToHash.get(callback);\n if (!hash) {\n logger.warn('Callback not found in subscription map');\n return;\n }\n\n const entry = this.filterSubscriptions.get(hash);\n if (!entry) {\n logger.warn('Subscription entry not found for hash');\n return;\n }\n\n // Remove this callback\n entry.callbacks.delete(callback);\n this.callbackToHash.delete(callback);\n\n // If no more callbacks, unsubscribe from server\n if (entry.callbacks.size === 0) {\n const payload: UnsubscribePayload = { subscription_id: entry.serverId };\n await this.sendRequest(payload, RequestType.Unsubscribe);\n\n this.filterSubscriptions.delete(hash);\n this.subscriptions.delete(entry.serverId);\n }\n }\n\n /**\n * Unsubscribe from events by subscription ID\n *\n * @param subscriptionId - Subscription ID to cancel\n * @deprecated Use subscription.unsubscribe() instead\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const hash = this.subscriptions.get(subscriptionId);\n if (!hash) {\n // Fall back to direct unsubscribe for backwards compatibility\n const payload: UnsubscribePayload = { subscription_id: subscriptionId };\n await this.sendRequest(payload, RequestType.Unsubscribe);\n return;\n }\n\n const entry = this.filterSubscriptions.get(hash);\n if (!entry) {\n return;\n }\n\n // Remove all callbacks and unsubscribe from server\n for (const callback of entry.callbacks) {\n this.callbackToHash.delete(callback);\n }\n entry.callbacks.clear();\n\n const payload: UnsubscribePayload = { subscription_id: subscriptionId };\n await this.sendRequest(payload, RequestType.Unsubscribe);\n\n this.filterSubscriptions.delete(hash);\n this.subscriptions.delete(subscriptionId);\n }\n\n /**\n * Handle incoming event message\n *\n * Routes event to all callbacks registered for the subscription.\n * Automatically deduplicates events using event_id within a 5-second window.\n *\n * @param event - Event message from server\n */\n handleEvent(event: EventMessage): void {\n // Deduplicate events using event_id\n if (event.event_id && this.isEventDuplicate(event.event_id)) {\n logger.debug('Skipping duplicate event:', event.event_id);\n return;\n }\n\n // Track this event for deduplication\n if (event.event_id) {\n this.trackEventId(event.event_id);\n }\n\n const hash = this.subscriptions.get(event.subscription_id);\n if (!hash) {\n logger.warn('Received event for unknown subscription:', event.subscription_id);\n return;\n }\n\n const entry = this.filterSubscriptions.get(hash);\n if (!entry) {\n logger.warn('No entry found for subscription hash');\n return;\n }\n\n // Call all registered callbacks\n for (const callback of entry.callbacks) {\n try {\n callback(event);\n } catch (error) {\n logger.error('Error in event callback:', error);\n }\n }\n }\n\n /**\n * Get all active subscription IDs\n */\n getActiveSubscriptions(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Check if a subscription is active\n *\n * @param subscriptionId - Subscription ID to check\n */\n hasSubscription(subscriptionId: string): boolean {\n return this.subscriptions.has(subscriptionId);\n }\n\n /**\n * Clear all subscriptions (used during disconnect)\n */\n clearAll(): void {\n this.subscriptions.clear();\n this.filterSubscriptions.clear();\n this.callbackToHash.clear();\n }\n\n /**\n * Check if there are stored filters that need restoration\n * Used to detect if we need to restore subscriptions on reconnect\n */\n hasStoredFilters(): boolean {\n return this.filterSubscriptions.size > 0 || this.callbackToHash.size > 0;\n }\n\n /**\n * Register a direct listener for flow events by subscription ID.\n * Used by FlowsApi to receive flow execution events via WS.\n */\n addFlowEventListener(subscriptionId: string, callback: EventCallback): void {\n // Create a synthetic entry so handleEvent routes events to this callback\n const hash = `__flow__${subscriptionId}`;\n this.filterSubscriptions.set(hash, {\n serverId: subscriptionId,\n filters: {} as SubscriptionFilters,\n callbacks: new Set([callback]),\n });\n this.subscriptions.set(subscriptionId, hash);\n this.callbackToHash.set(callback, hash);\n }\n\n /**\n * Remove a flow event listener by subscription ID.\n */\n removeFlowEventListener(subscriptionId: string): void {\n const hash = this.subscriptions.get(subscriptionId);\n if (!hash) return;\n\n const entry = this.filterSubscriptions.get(hash);\n if (entry) {\n for (const callback of entry.callbacks) {\n this.callbackToHash.delete(callback);\n }\n this.filterSubscriptions.delete(hash);\n }\n this.subscriptions.delete(subscriptionId);\n }\n\n /**\n * Restore subscriptions after reconnect\n *\n * Re-subscribes to the server with the original filters for all active\n * subscription entries. Failed entries are kept (with their callbacks)\n * and marked pending so a retry call can re-attempt them without\n * duplicating already-restored subscriptions.\n *\n * @param options.retry - When true, only re-attempts entries that failed\n * in a previous call (instead of re-subscribing everything)\n * @throws Error if any subscription could not be restored\n */\n async restoreSubscriptions(options?: { retry?: boolean }): Promise<void> {\n if (!options?.retry) {\n // Fresh restore session: every entry needs a new server-side\n // subscription; drop stale routing IDs from the old connection.\n for (const entry of this.filterSubscriptions.values()) {\n this.subscriptions.delete(entry.serverId);\n entry.restorePending = true;\n }\n }\n\n // Collect entries to restore (can't modify map while iterating)\n const entriesToRestore = Array.from(this.filterSubscriptions.entries())\n .filter(([, entry]) => entry.restorePending);\n\n let failureCount = 0;\n let lastError: unknown;\n\n // Re-subscribe each pending entry\n for (const [hash, entry] of entriesToRestore) {\n if (entry.callbacks.size === 0) {\n entry.restorePending = false;\n continue;\n }\n\n try {\n const payload: SubscribePayload = { filters: entry.filters };\n const response = (await this.sendRequest(\n payload,\n RequestType.Subscribe\n )) as SubscriptionResponse;\n\n const newServerId = response.subscription_id;\n\n // Update mappings with new server ID\n entry.serverId = newServerId;\n entry.restorePending = false;\n this.subscriptions.set(newServerId, hash);\n\n // Update callbackToHash (hash stays the same, just verify it's set)\n for (const callback of entry.callbacks) {\n this.callbackToHash.set(callback, hash);\n }\n } catch (error) {\n logger.error('Failed to restore subscription:', error);\n failureCount++;\n lastError = error;\n // Keep the entry pending so a retry can re-attempt it\n }\n }\n\n if (failureCount > 0) {\n const message = lastError instanceof Error ? lastError.message : String(lastError);\n throw new Error(\n `Failed to restore ${failureCount} subscription(s) after reconnect: ${message}`\n );\n }\n }\n}\n\n/**\n * Event subscriptions interface for workspace\n */\nexport class EventSubscriptions {\n private eventHandler: EventHandler;\n private filters: Partial<SubscriptionFilters>;\n\n constructor(eventHandler: EventHandler, filters: Partial<SubscriptionFilters> = {}) {\n this.eventHandler = eventHandler;\n this.filters = filters;\n }\n\n /**\n * Subscribe to events\n *\n * @param filters - Additional filters (merged with workspace filters)\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribe(\n filters: Partial<SubscriptionFilters>,\n callback: EventCallback\n ): Promise<Subscription> {\n // Merge workspace filters with provided filters\n const mergedFilters: SubscriptionFilters = {\n ...this.filters,\n ...filters,\n } as SubscriptionFilters;\n\n return this.eventHandler.subscribe(mergedFilters, callback);\n }\n\n /**\n * Subscribe to specific event types\n *\n * @param eventTypes - Event types to subscribe to\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribeToTypes(eventTypes: string[], callback: EventCallback): Promise<Subscription> {\n return this.subscribe({ event_types: eventTypes }, callback);\n }\n\n /**\n * Subscribe to events for a specific path\n *\n * Path pattern semantics (matched server-side):\n * - A plain path matches **only that exact node** — there is no implicit\n * prefix matching, so `/folder` does NOT match `/folder/child`.\n * - `*` matches exactly one path segment: `/folder/*` matches\n * `/folder/child` but not `/folder/child/grandchild`.\n * - `**` matches recursively: `/folder/**` matches every descendant of\n * `/folder` (but not `/folder` itself).\n *\n * @param path - Path pattern (e.g. \"/folder\", \"/folder/*\", \"/folder/**\")\n * @param callback - Callback function for events\n * @param options - Optional subscription options\n * @param options.includeNode - Include full node data in event payload (default: false)\n * @returns Subscription object\n */\n async subscribeToPath(\n path: string,\n callback: EventCallback,\n options?: { includeNode?: boolean }\n ): Promise<Subscription> {\n const filters: Partial<SubscriptionFilters> = { path };\n if (options?.includeNode) {\n filters.include_node = true;\n }\n return this.subscribe(filters, callback);\n }\n\n /**\n * Subscribe to events for a specific node type\n *\n * @param nodeType - Node type to filter by\n * @param callback - Callback function for events\n * @returns Subscription object\n */\n async subscribeToNodeType(nodeType: string, callback: EventCallback): Promise<Subscription> {\n return this.subscribe({ node_type: nodeType }, callback);\n }\n}\n","/**\n * Node operations interface\n */\n\nimport {\n Node,\n PropertyValue,\n NodeCreatePayload,\n NodeCreateDeepPayload,\n NodeUpdatePayload,\n NodeDeletePayload,\n NodeGetPayload,\n NodeHistoryPayload,\n NodeQueryPayload,\n RelationAddPayload,\n RelationRemovePayload,\n RelationsGetPayload,\n NodeRelationships,\n RevisionEntry,\n AuditQueryPayload,\n AuditLogEntry,\n} from './protocol';\n\n/**\n * Options for creating a node\n */\nexport interface NodeCreateOptions {\n /** Node type */\n type: string;\n /** Node path */\n path: string;\n /** Node properties */\n properties?: Record<string, PropertyValue>;\n /** Node content (optional) */\n content?: unknown;\n}\n\n/**\n * Options for creating/upserting a node with auto-created ancestor folders\n */\nexport interface NodeCreateDeepOptions extends NodeCreateOptions {\n /** NodeType used for auto-created ancestor folders (defaults to `raisin:Folder`) */\n parentNodeType?: string;\n}\n\n/**\n * Options for updating a node\n */\nexport interface NodeUpdateOptions {\n /** Properties to update */\n properties?: Record<string, PropertyValue>;\n /** Content to update (optional) */\n content?: unknown;\n}\n\n/**\n * Options for querying nodes\n */\nexport interface NodeQueryOptions {\n /** Query object */\n query: unknown;\n /** Maximum number of results */\n limit?: number;\n /** Offset for pagination */\n offset?: number;\n}\n\n/**\n * Node operations interface\n */\nexport class NodeOperations {\n private sendRequest: (payload: unknown, requestType?: string) => Promise<unknown>;\n private workspace?: string;\n\n constructor(\n sendRequest: (payload: unknown, requestType?: string) => Promise<unknown>,\n workspace?: string\n ) {\n this.sendRequest = sendRequest;\n this.workspace = workspace;\n }\n\n /**\n * Create a new node\n *\n * @param options - Node creation options\n * @returns Created node\n */\n async create(options: NodeCreateOptions): Promise<Node> {\n const payload: NodeCreatePayload = {\n node_type: options.type,\n path: options.path,\n properties: options.properties ?? {},\n content: options.content,\n };\n\n const result = await this.sendRequest(payload);\n return result as Node;\n }\n\n /**\n * Create a node, auto-creating any missing ancestor folders.\n *\n * @param options - Node creation options (with optional `parentNodeType`)\n * @returns Created node\n */\n async createDeep(options: NodeCreateDeepOptions): Promise<Node> {\n const payload: NodeCreateDeepPayload = {\n node_type: options.type,\n path: options.path,\n properties: options.properties ?? {},\n content: options.content,\n parent_node_type: options.parentNodeType,\n };\n\n const result = await this.sendRequest(payload, 'node_create_deep');\n return result as Node;\n }\n\n /**\n * Upsert a node by path (create-or-update), auto-creating any missing ancestor folders.\n *\n * @param options - Node creation options (with optional `parentNodeType`)\n * @returns Upserted node\n */\n async upsertDeep(options: NodeCreateDeepOptions): Promise<Node> {\n const payload: NodeCreateDeepPayload = {\n node_type: options.type,\n path: options.path,\n properties: options.properties ?? {},\n content: options.content,\n parent_node_type: options.parentNodeType,\n };\n\n const result = await this.sendRequest(payload, 'node_upsert_deep');\n return result as Node;\n }\n\n /**\n * Update an existing node\n *\n * @param id - Node ID\n * @param options - Node update options\n * @returns Updated node\n */\n async update(id: string, options: NodeUpdateOptions): Promise<Node> {\n const payload: NodeUpdatePayload = {\n node_id: id,\n properties: options.properties ?? {},\n content: options.content,\n };\n\n const result = await this.sendRequest(payload);\n return result as Node;\n }\n\n /**\n * Delete a node\n *\n * @param id - Node ID\n * @returns true if deleted successfully\n */\n async delete(id: string): Promise<boolean> {\n const payload: NodeDeletePayload = {\n node_id: id,\n };\n\n await this.sendRequest(payload);\n return true;\n }\n\n /**\n * Get a node by ID\n *\n * @param id - Node ID\n * @returns Node or null if not found\n */\n async get(id: string): Promise<Node | null> {\n const payload: NodeGetPayload = {\n node_id: id,\n };\n\n try {\n const result = await this.sendRequest(payload);\n return result as Node;\n } catch (error) {\n // If node not found, return null\n if (error instanceof Error && error.message.includes('not found')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * List a node's revision history (git-style \"file history\"), newest first.\n *\n * Each entry carries the `revision` (usable with `atRevision()` reads to\n * fetch the full snapshot), plus when/who and whether the node was deleted\n * at that revision. Always available regardless of the NodeType `auditable`\n * flag — it reflects the structural MVCC version history.\n *\n * @param id - Node ID\n * @param options - Optional `{ limit }` to cap the number of revisions\n * @returns Array of revision entries (newest first)\n *\n * @example\n * ```typescript\n * const history = await ws.nodes().history(nodeId, { limit: 50 });\n * for (const rev of history) {\n * const snapshot = await ws.atRevision(rev.revision).nodes().get(nodeId);\n * }\n * ```\n */\n async history(id: string, options?: { limit?: number }): Promise<RevisionEntry[]> {\n const payload: NodeHistoryPayload = {\n node_id: id,\n limit: options?.limit,\n };\n const result = await this.sendRequest(payload, 'node_history');\n return (result as RevisionEntry[]) ?? [];\n }\n\n /**\n * List a node's revision history by path (newest first).\n *\n * @param path - Node path\n * @param options - Optional `{ limit }` to cap the number of revisions\n * @returns Array of revision entries (newest first)\n */\n async historyByPath(path: string, options?: { limit?: number }): Promise<RevisionEntry[]> {\n const payload: NodeHistoryPayload = {\n path,\n limit: options?.limit,\n };\n const result = await this.sendRequest(payload, 'node_history');\n return (result as RevisionEntry[]) ?? [];\n }\n\n /**\n * Query a node's audit-log entries by ID.\n *\n * Audit logs are only produced for NodeTypes marked `auditable`. This is\n * distinct from {@link history}, which is the always-on structural revision\n * history available for every node.\n *\n * @param id - Node ID\n * @returns Array of audit-log entries\n */\n async auditLog(id: string): Promise<AuditLogEntry[]> {\n const payload: AuditQueryPayload = { node_id: id };\n const result = await this.sendRequest(payload, 'audit_query');\n return (result as AuditLogEntry[]) ?? [];\n }\n\n /**\n * Query a node's audit-log entries by path.\n *\n * @param path - Node path\n * @returns Array of audit-log entries\n */\n async auditLogByPath(path: string): Promise<AuditLogEntry[]> {\n const payload: AuditQueryPayload = { path };\n const result = await this.sendRequest(payload, 'audit_query');\n return (result as AuditLogEntry[]) ?? [];\n }\n\n /**\n * Query nodes\n *\n * @param options - Query options\n * @returns Array of nodes\n */\n async query(options: NodeQueryOptions): Promise<Node[]> {\n const payload: NodeQueryPayload = {\n query: options.query,\n limit: options.limit,\n offset: options.offset,\n };\n\n const result = await this.sendRequest(payload);\n return result as Node[];\n }\n\n /**\n * Get a node by path\n *\n * @param path - Node path\n * @returns Node or null if not found\n */\n async getByPath(path: string): Promise<Node | null> {\n try {\n const result = await this.query({\n query: { path },\n limit: 1,\n });\n return result.length > 0 ? result[0] : null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Query nodes by property\n *\n * @param propertyName - Property name\n * @param propertyValue - Property value\n * @param limit - Maximum number of results\n * @returns Array of nodes\n */\n async queryByProperty(\n propertyName: string,\n propertyValue: PropertyValue,\n limit?: number\n ): Promise<Node[]> {\n return this.query({\n query: {\n properties: {\n [propertyName]: propertyValue,\n },\n },\n limit,\n });\n }\n\n /**\n * Query nodes by type\n *\n * @param nodeType - Node type\n * @param limit - Maximum number of results\n * @returns Array of nodes\n */\n async queryByType(nodeType: string, limit?: number): Promise<Node[]> {\n return this.query({\n query: { node_type: nodeType },\n limit,\n });\n }\n\n /**\n * Get children of a node\n *\n * @param parentId - Parent node ID\n * @param limit - Maximum number of results\n * @returns Array of child nodes\n */\n async getChildren(parentId: string, limit?: number): Promise<Node[]> {\n return this.query({\n query: { parent: parentId },\n limit,\n });\n }\n\n /**\n * Get children by path\n *\n * @param parentPath - Parent node path\n * @param limit - Maximum number of results\n * @returns Array of child nodes\n */\n async getChildrenByPath(parentPath: string, limit?: number): Promise<Node[]> {\n const parent = await this.getByPath(parentPath);\n if (!parent) {\n return [];\n }\n return this.getChildren(parent.id, limit);\n }\n\n // ========================================================================\n // Tree Operations\n // ========================================================================\n\n /**\n * List children of a parent node, in editorial (drag-and-drop) order.\n *\n * @param parentPath - Path of the parent node\n * @returns Array of child nodes\n */\n async listChildren(parentPath: string): Promise<Node[]> {\n const { items } = await this.listChildrenPage(parentPath);\n return items;\n }\n\n /**\n * List one page of a parent's children, in editorial order.\n *\n * Pagination is keyset-based: pass the previous response's `nextCursor` back as\n * `cursor` to get the following page. `nextCursor` is `null` on the last page.\n * Treat the cursor as opaque — do not parse or construct it.\n *\n * @param parentPath - Path of the parent node\n * @param options - `cursor` from a previous page, and page `limit`\n */\n async listChildrenPage(\n parentPath: string,\n options: { cursor?: string; limit?: number } = {},\n ): Promise<{ items: Node[]; nextCursor: string | null }> {\n const payload: Record<string, unknown> = {\n parent_path: parentPath,\n };\n if (options.cursor !== undefined) payload.cursor = options.cursor;\n if (options.limit !== undefined) payload.limit = options.limit;\n\n const result = await this.sendRequest(payload, 'node_list_children');\n\n // The paginated shape is `{ nodes, next_cursor }`; a bare array means an\n // older server that ignored the cursor arguments.\n if (Array.isArray(result)) {\n return { items: result as Node[], nextCursor: null };\n }\n const page = result as { nodes?: Node[]; next_cursor?: unknown };\n return {\n items: page.nodes ?? [],\n nextCursor:\n page.next_cursor == null ? null : JSON.stringify(page.next_cursor),\n };\n }\n\n /**\n * Get a node tree starting from a root node\n *\n * @param rootPath - Path of the root node\n * @param maxDepth - Maximum depth to traverse (optional)\n * @returns Root node with nested children\n */\n async getTree(rootPath: string, maxDepth?: number): Promise<Node> {\n const payload: { root_path: string; max_depth?: number } = {\n root_path: rootPath,\n };\n\n if (maxDepth !== undefined) {\n payload.max_depth = maxDepth;\n }\n\n const result = await this.sendRequest(payload, 'node_get_tree');\n return result as Node;\n }\n\n /**\n * Get a flattened node tree starting from a root node\n *\n * @param rootPath - Path of the root node\n * @param maxDepth - Maximum depth to traverse (optional)\n * @returns Array of nodes in tree order\n */\n async getTreeFlat(rootPath: string, maxDepth?: number): Promise<Node[]> {\n const payload: { root_path: string; max_depth?: number } = {\n root_path: rootPath,\n };\n\n if (maxDepth !== undefined) {\n payload.max_depth = maxDepth;\n }\n\n const result = await this.sendRequest(payload, 'node_get_tree_flat');\n return result as Node[];\n }\n\n // ========================================================================\n // Node Manipulation Operations\n // ========================================================================\n\n /**\n * Move a node to a new parent\n *\n * @param fromPath - Source node path\n * @param toParentPath - Destination parent path\n * @returns Moved node\n */\n async move(fromPath: string, toParentPath: string): Promise<Node> {\n const payload = {\n from_path: fromPath,\n to_parent_path: toParentPath,\n };\n\n const result = await this.sendRequest(payload, 'node_move');\n return result as Node;\n }\n\n /**\n * Rename a node\n *\n * @param nodePath - Node path\n * @param newName - New name for the node\n * @returns Renamed node\n */\n async rename(nodePath: string, newName: string): Promise<Node> {\n // Server NodeRenamePayload expects `old_path` (not `node_path`).\n const payload = {\n old_path: nodePath,\n new_name: newName,\n };\n\n const result = await this.sendRequest(payload, 'node_rename');\n return result as Node;\n }\n\n /**\n * Copy a node to a new parent (shallow copy)\n *\n * @param fromPath - Source node path\n * @param toParentPath - Destination parent path\n * @param newName - New name for the copied node (optional)\n * @returns Copied node\n */\n async copy(fromPath: string, toParentPath: string, newName?: string): Promise<Node> {\n // Server NodeCopyPayload expects `source_path` / `target_parent`.\n const payload: { source_path: string; target_parent: string; new_name?: string } = {\n source_path: fromPath,\n target_parent: toParentPath,\n };\n\n if (newName !== undefined) {\n payload.new_name = newName;\n }\n\n const result = await this.sendRequest(payload, 'node_copy');\n return result as Node;\n }\n\n /**\n * Copy a node tree to a new parent (deep copy with all children)\n *\n * @param fromPath - Source node path\n * @param toParentPath - Destination parent path\n * @param newName - New name for the copied node (optional)\n * @returns Copied node tree\n */\n async copyTree(fromPath: string, toParentPath: string, newName?: string): Promise<Node> {\n // Server NodeCopyTreePayload expects `source_path` / `target_parent`.\n const payload: { source_path: string; target_parent: string; new_name?: string } = {\n source_path: fromPath,\n target_parent: toParentPath,\n };\n\n if (newName !== undefined) {\n payload.new_name = newName;\n }\n\n const result = await this.sendRequest(payload, 'node_copy_tree');\n return result as Node;\n }\n\n /**\n * Move a child to a specific position among its siblings.\n *\n * Positions are 0-based; a position past the end appends. The server owns the\n * fractional order key — you name a position, it mints the key.\n *\n * @param parentPath - Parent node path\n * @param childName - Name of the child to move (not a full path)\n * @param position - Target 0-based position among the parent's children\n * @returns The reordered node, carrying its newly assigned `order_key`\n */\n async reorder(parentPath: string, childName: string, position: number): Promise<Node> {\n const payload = {\n parent_path: parentPath,\n child_name: childName,\n position,\n };\n\n const result = await this.sendRequest(payload, 'node_reorder');\n return result as Node;\n }\n\n /**\n * Move a child so it sits immediately before one of its siblings.\n *\n * @param parentPath - Parent node path\n * @param childName - Name of the child to move (not a full path)\n * @param beforeChildName - Name of the sibling to sit before\n */\n async moveChildBefore(\n parentPath: string,\n childName: string,\n beforeChildName: string,\n ): Promise<void> {\n const payload = {\n parent_path: parentPath,\n child_name: childName,\n before_child_name: beforeChildName,\n };\n\n await this.sendRequest(payload, 'node_move_child_before');\n }\n\n /**\n * Move a child so it sits immediately after one of its siblings.\n *\n * @param parentPath - Parent node path\n * @param childName - Name of the child to move (not a full path)\n * @param afterChildName - Name of the sibling to sit after\n */\n async moveChildAfter(\n parentPath: string,\n childName: string,\n afterChildName: string,\n ): Promise<void> {\n const payload = {\n parent_path: parentPath,\n child_name: childName,\n after_child_name: afterChildName,\n };\n\n await this.sendRequest(payload, 'node_move_child_after');\n }\n\n /**\n * Replay a parent's child order from another branch onto the current branch.\n *\n * Carries node sibling-order across branches — useful for selective publish\n * flows, where copying node content (e.g. via SQL) does not move the ordering\n * index. Only children that exist under the parent on both branches are\n * reordered. The target branch is the connection's current branch.\n *\n * @param parentPath - Parent node path\n * @param sourceBranch - Branch to copy the child order FROM\n */\n async applyChildOrder(parentPath: string, sourceBranch: string): Promise<void> {\n const payload = {\n parent_path: parentPath,\n source_branch: sourceBranch,\n };\n\n await this.sendRequest(payload, 'node_apply_child_order');\n }\n\n // ========================================================================\n // Relationship Operations\n // ========================================================================\n\n /**\n * Add a relationship between two nodes\n *\n * @param nodePath - Source node path\n * @param relationType - Type of relationship\n * @param targetNodePath - Target node path\n * @param weight - Optional relationship weight (legacy signature)\n * @returns True if the relation exists after the call\n */\n async addRelation(\n nodePath: string,\n relationType: string,\n targetNodePath: string,\n weightOrOptions?: number | RelationAddOptions\n ): Promise<boolean> {\n const options =\n typeof weightOrOptions === 'number'\n ? { weight: weightOrOptions }\n : weightOrOptions;\n\n const payload: RelationAddPayload = {\n source_path: nodePath,\n target_workspace: this.resolveTargetWorkspace(options),\n target_path: targetNodePath,\n relation_type: relationType,\n };\n\n if (options?.weight !== undefined) {\n payload.weight = options.weight;\n }\n\n const result = await this.sendRequest(payload, 'relation_add');\n return this.parseSuccess(result);\n }\n\n /**\n * Remove a relationship between two nodes\n *\n * @param nodePath - Source node path\n * @param targetPathOrRelationType - Target node path (preferred) or legacy relation type\n * @param targetPathOrOptions - Target path for the legacy signature or mutation options\n * @param options - Relationship options when using the legacy signature\n * @returns True if the relation was removed or no longer exists\n */\n async removeRelation(\n nodePath: string,\n targetPathOrRelationType: string,\n targetPathOrOptions?: string | RelationRemoveOptions,\n options?: RelationRemoveOptions\n ): Promise<boolean> {\n let targetPath: string;\n let resolvedOptions: RelationRemoveOptions | undefined;\n\n if (typeof targetPathOrOptions === 'string') {\n // Legacy signature: removeRelation(source, relationType, targetPath)\n targetPath = targetPathOrOptions;\n resolvedOptions = options;\n } else {\n // Preferred signature: removeRelation(source, targetPath, options?)\n targetPath = targetPathOrRelationType;\n resolvedOptions = targetPathOrOptions;\n }\n\n const payload: RelationRemovePayload = {\n source_path: nodePath,\n target_workspace: this.resolveTargetWorkspace(resolvedOptions),\n target_path: targetPath,\n };\n\n const result = await this.sendRequest(payload, 'relation_remove');\n return this.parseSuccess(result);\n }\n\n /**\n * Get all incoming and outgoing relationships for a node\n *\n * @param nodePath - Node path\n * @returns Relationship summary including incoming/outgoing edges\n */\n async getRelationships(nodePath: string): Promise<NodeRelationships> {\n const payload: RelationsGetPayload = {\n node_path: nodePath,\n };\n\n const result = await this.sendRequest(payload, 'relations_get');\n return result as NodeRelationships;\n }\n\n /**\n * Determine which workspace to target for relationship operations\n */\n private resolveTargetWorkspace(options?: RelationTargetOptions): string {\n const workspace = options?.targetWorkspace ?? this.workspace;\n if (!workspace) {\n throw new Error(\n 'targetWorkspace is required when workspace context is not set'\n );\n }\n return workspace;\n }\n\n /**\n * Normalize success responses from relationship mutations\n */\n private parseSuccess(result: unknown): boolean {\n if (typeof result === 'boolean') {\n return result;\n }\n if (\n result &&\n typeof result === 'object' &&\n 'success' in result &&\n typeof (result as { success?: unknown }).success !== 'undefined'\n ) {\n return Boolean((result as { success?: boolean }).success);\n }\n return true;\n }\n}\n\ninterface RelationTargetOptions {\n targetWorkspace?: string;\n}\n\ninterface RelationAddOptions extends RelationTargetOptions {\n weight?: number;\n}\n\ntype RelationRemoveOptions = RelationTargetOptions;\n","/**\n * Transaction support for RaisinDB\n */\n\nimport {\n RequestContext,\n RequestType,\n TransactionBeginPayload,\n TransactionBeginResponse,\n TransactionCommitPayload,\n TransactionCommitResponse,\n TransactionRollbackPayload,\n} from './protocol';\nimport { NodeOperations } from './nodes';\n\n/**\n * Transaction options\n */\nexport interface TransactionOptions {\n /** Optional commit message */\n message?: string;\n /** Optional actor identifier */\n actor?: string;\n}\n\n/**\n * Transaction class for executing multiple operations atomically\n */\nexport class Transaction {\n private sendRequest: (payload: unknown, requestType: string, contextOverride?: RequestContext) => Promise<unknown>;\n private context: RequestContext;\n private transactionId?: string;\n private isActive: boolean = false;\n private nodeOps?: NodeOperations;\n\n constructor(\n context: RequestContext,\n sendRequest: (payload: unknown, requestType: string, contextOverride?: RequestContext) => Promise<unknown>\n ) {\n this.context = context;\n this.sendRequest = sendRequest;\n }\n\n /**\n * Begin the transaction\n *\n * @param options - Transaction options\n * @returns This transaction instance for chaining\n */\n async begin(options?: TransactionOptions): Promise<Transaction> {\n if (this.isActive) {\n throw new Error('Transaction already active');\n }\n\n const payload: TransactionBeginPayload = {\n message: options?.message,\n actor: options?.actor,\n };\n\n const response = await this.sendRequest(\n payload,\n RequestType.TransactionBegin,\n this.context\n ) as TransactionBeginResponse;\n\n this.transactionId = response.transaction_id;\n this.isActive = true;\n\n // Create NodeOperations with transaction context\n const txContext: RequestContext = {\n ...this.context,\n transaction_id: this.transactionId,\n };\n\n this.nodeOps = new NodeOperations(\n (payload: unknown, requestType?: string) =>\n this.sendRequest(payload, requestType || 'node_create', txContext),\n txContext.workspace\n );\n\n return this;\n }\n\n /**\n * Get node operations scoped to this transaction\n *\n * @returns NodeOperations instance\n */\n nodes(): NodeOperations {\n if (!this.isActive || !this.nodeOps) {\n throw new Error('Transaction not active. Call begin() first.');\n }\n return this.nodeOps;\n }\n\n /**\n * Commit the transaction\n *\n * @returns Transaction commit response\n */\n async commit(): Promise<TransactionCommitResponse> {\n if (!this.isActive) {\n throw new Error('Transaction not active');\n }\n\n const payload: TransactionCommitPayload = {};\n\n const txContext: RequestContext = {\n ...this.context,\n transaction_id: this.transactionId,\n };\n\n try {\n const response = await this.sendRequest(\n payload,\n RequestType.TransactionCommit,\n txContext\n ) as TransactionCommitResponse;\n\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n\n return response;\n } catch (error) {\n // Transaction failed, mark as inactive\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n throw error;\n }\n }\n\n /**\n * Rollback the transaction\n */\n async rollback(): Promise<void> {\n if (!this.isActive) {\n throw new Error('Transaction not active');\n }\n\n const payload: TransactionRollbackPayload = {};\n\n const txContext: RequestContext = {\n ...this.context,\n transaction_id: this.transactionId,\n };\n\n try {\n await this.sendRequest(\n payload,\n RequestType.TransactionRollback,\n txContext\n );\n\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n } catch (error) {\n // Even if rollback fails, mark as inactive\n this.isActive = false;\n this.transactionId = undefined;\n this.nodeOps = undefined;\n throw error;\n }\n }\n\n /**\n * Get transaction ID\n */\n getTransactionId(): string | undefined {\n return this.transactionId;\n }\n\n /**\n * Check if transaction is active\n */\n isTransactionActive(): boolean {\n return this.isActive;\n }\n}\n","/**\n * File source abstraction for Browser and Node.js environments\n *\n * Provides a unified interface for reading file data in chunks,\n * supporting both browser File/Blob APIs and Node.js filesystem.\n */\n\n// ============================================================================\n// FileSource Interface\n// ============================================================================\n\n/**\n * Abstract interface for reading file data in chunks\n */\nexport interface FileSource {\n /** Total size of the file in bytes */\n readonly size: number;\n /** Name of the file */\n readonly name: string;\n /** MIME type of the file (optional) */\n readonly type?: string;\n /**\n * Read a slice of the file\n *\n * @param start - Start byte offset (inclusive)\n * @param end - End byte offset (exclusive)\n * @returns ArrayBuffer containing the slice data\n */\n slice(start: number, end: number): Promise<ArrayBuffer>;\n}\n\n// ============================================================================\n// Browser Implementation\n// ============================================================================\n\n/**\n * FileSource implementation for browser File/Blob objects\n */\nexport class BrowserFileSource implements FileSource {\n private readonly _file: File | Blob;\n\n /**\n * Create a browser file source\n *\n * @param file - File or Blob object\n */\n constructor(file: File | Blob) {\n this._file = file;\n }\n\n /**\n * Total size in bytes\n */\n get size(): number {\n return this._file.size;\n }\n\n /**\n * File name (or \"blob\" for Blob objects)\n */\n get name(): string {\n return 'name' in this._file ? this._file.name : 'blob';\n }\n\n /**\n * MIME type\n */\n get type(): string | undefined {\n return this._file.type || undefined;\n }\n\n /**\n * Read a slice of the file\n */\n async slice(start: number, end: number): Promise<ArrayBuffer> {\n const blob = this._file.slice(start, end);\n return blob.arrayBuffer();\n }\n}\n\n// ============================================================================\n// Node.js Implementation\n// ============================================================================\n\n/**\n * FileSource implementation for Node.js file paths\n *\n * Uses lazy initialization to avoid blocking on construction.\n * The fs module is dynamically imported to support browser bundling.\n */\nexport class NodeFileSource implements FileSource {\n private _size = 0;\n private readonly _name: string;\n private readonly _filePath: string;\n private _initialized = false;\n private _fsPromises: typeof import('fs/promises') | null = null;\n\n /**\n * Create a Node.js file source\n *\n * @param filePath - Path to the file\n * @param fsPromises - Optional fs/promises module (for testing)\n */\n constructor(\n filePath: string,\n fsPromises?: typeof import('fs/promises')\n ) {\n this._filePath = filePath;\n this._fsPromises = fsPromises ?? null;\n // Extract filename from path\n const parts = filePath.split(/[/\\\\]/);\n this._name = parts[parts.length - 1] || 'file';\n }\n\n /**\n * Initialize the file source (load fs module and get file stats)\n */\n private async init(): Promise<void> {\n if (this._initialized) {\n return;\n }\n\n // Dynamically import fs/promises if not provided\n if (!this._fsPromises) {\n if (!isNodeEnvironment()) {\n throw new Error(\n 'NodeFileSource requires Node.js (fs/promises is not available in browsers). ' +\n 'In the browser, use a File or Blob object instead.'\n );\n }\n // Dynamic import with a computed specifier so bundlers (Vite, etc.)\n // don't try to resolve \"fs/promises\" into browser bundles.\n const specifier = 'fs/promises';\n this._fsPromises = (await import(\n /* @vite-ignore */ /* webpackIgnore: true */ specifier\n )) as typeof import('fs/promises');\n }\n\n // Get file stats to determine size\n const stats = await this._fsPromises.stat(this._filePath);\n this._size = stats.size;\n this._initialized = true;\n }\n\n /**\n * Total size in bytes\n *\n * Note: Returns 0 until initialized via slice() call\n */\n get size(): number {\n return this._size;\n }\n\n /**\n * File name\n */\n get name(): string {\n return this._name;\n }\n\n /**\n * MIME type (not available for Node.js files)\n */\n get type(): string | undefined {\n return undefined;\n }\n\n /**\n * Read a slice of the file\n */\n async slice(start: number, end: number): Promise<ArrayBuffer> {\n await this.init();\n\n // Open file for reading\n const fd = await this._fsPromises!.open(this._filePath, 'r');\n\n try {\n const length = end - start;\n const buffer = Buffer.alloc(length);\n await fd.read(buffer, 0, length, start);\n\n // Convert Buffer to ArrayBuffer\n return buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength\n );\n } finally {\n await fd.close();\n }\n }\n\n /**\n * Ensure the file source is initialized\n *\n * Call this before accessing size to ensure it's populated.\n */\n async ensureInitialized(): Promise<void> {\n await this.init();\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Detect the runtime environment\n */\nfunction isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Create a FileSource from various inputs\n *\n * Automatically detects the input type and environment:\n * - File/Blob objects use BrowserFileSource\n * - String paths use NodeFileSource (Node.js only)\n *\n * @param input - File, Blob, or file path string\n * @returns Promise resolving to a FileSource\n * @throws Error if input type is not supported in the current environment\n */\nexport async function createFileSource(\n input: File | Blob | string\n): Promise<FileSource> {\n // Handle string paths (Node.js file path)\n if (typeof input === 'string') {\n if (!isNodeEnvironment()) {\n throw new Error(\n 'File path strings are only supported in Node.js. ' +\n 'In the browser, use a File or Blob object.'\n );\n }\n\n const source = new NodeFileSource(input);\n // Force initialization to populate size\n await source.ensureInitialized();\n return source;\n }\n\n // Handle File/Blob objects\n if (input instanceof Blob) {\n return new BrowserFileSource(input);\n }\n\n throw new Error(\n 'Unsupported input type. Expected File, Blob, or file path string.'\n );\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Get the content type for a file\n *\n * @param source - FileSource or filename\n * @returns MIME type or undefined\n */\nexport function getContentType(source: FileSource | string): string | undefined {\n if (typeof source === 'string') {\n return getMimeTypeFromExtension(source);\n }\n\n if (source.type) {\n return source.type;\n }\n\n return getMimeTypeFromExtension(source.name);\n}\n\n/**\n * Get MIME type from file extension\n */\nfunction getMimeTypeFromExtension(filename: string): string | undefined {\n const ext = filename.split('.').pop()?.toLowerCase();\n\n if (!ext) {\n return undefined;\n }\n\n const mimeTypes: Record<string, string> = {\n // Images\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n\n // Videos\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n wmv: 'video/x-ms-wmv',\n flv: 'video/x-flv',\n\n // Audio\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n m4a: 'audio/mp4',\n flac: 'audio/flac',\n aac: 'audio/aac',\n\n // Documents\n pdf: 'application/pdf',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n\n // Archives\n zip: 'application/zip',\n rar: 'application/vnd.rar',\n '7z': 'application/x-7z-compressed',\n tar: 'application/x-tar',\n gz: 'application/gzip',\n\n // Text\n txt: 'text/plain',\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n json: 'application/json',\n xml: 'application/xml',\n csv: 'text/csv',\n md: 'text/markdown',\n\n // Other\n wasm: 'application/wasm',\n woff: 'font/woff',\n woff2: 'font/woff2',\n ttf: 'font/ttf',\n otf: 'font/otf',\n eot: 'application/vnd.ms-fontobject',\n };\n\n return mimeTypes[ext];\n}\n\n/**\n * Calculate the number of chunks for a file\n *\n * @param fileSize - Total file size in bytes\n * @param chunkSize - Size of each chunk in bytes\n * @returns Number of chunks\n */\nexport function calculateChunkCount(fileSize: number, chunkSize: number): number {\n return Math.ceil(fileSize / chunkSize);\n}\n\n/**\n * Get the byte range for a specific chunk\n *\n * @param chunkIndex - Zero-based chunk index\n * @param chunkSize - Size of each chunk in bytes\n * @param fileSize - Total file size in bytes\n * @returns Object with start and end byte offsets\n */\nexport function getChunkRange(\n chunkIndex: number,\n chunkSize: number,\n fileSize: number\n): { start: number; end: number } {\n const start = chunkIndex * chunkSize;\n const end = Math.min(start + chunkSize, fileSize);\n return { start, end };\n}\n","/**\n * Workspace operations interface\n */\n\nimport { NodeOperations } from './nodes';\nimport { EventSubscriptions, EventHandler } from './events';\nimport { Transaction } from './transactions';\nimport {\n Workspace,\n WorkspaceCreatePayload,\n WorkspaceGetPayload,\n WorkspaceDeletePayload,\n WorkspaceUpdatePayload,\n RequestContext,\n} from './protocol';\nimport { logger } from './logger';\nimport type { Upload, UploadOptions, BatchUpload, BatchUploadOptions } from './upload/types';\nimport type { UploadManager } from './upload/uploader';\nimport { createFileSource } from './upload/file-source';\nimport type { SignAssetOptions, SignedAssetUrl } from './http-client';\n\n/**\n * Options for creating a workspace\n */\nexport interface WorkspaceCreateOptions {\n /** Workspace name */\n name: string;\n /** Workspace description */\n description?: string;\n}\n\n/**\n * Options for updating a workspace\n */\nexport interface WorkspaceUpdateOptions {\n /** Workspace description */\n description?: string;\n /** Allowed node types */\n allowed_node_types?: string[];\n /** Allowed root node types */\n allowed_root_node_types?: string[];\n}\n\n/**\n * Workspace interface for content operations\n */\nexport class WorkspaceClient {\n private name: string;\n private _context: RequestContext;\n private sendRequest: (payload: unknown, requestType?: string) => Promise<unknown>;\n private eventHandler: EventHandler;\n private nodeOps?: NodeOperations;\n private eventSubs?: EventSubscriptions;\n private branch?: string;\n private revision?: string;\n private getUploadManager?: () => UploadManager;\n private getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>;\n\n constructor(\n name: string,\n context: RequestContext,\n sendRequest: (payload: unknown, requestType?: string, contextOverride?: RequestContext) => Promise<unknown>,\n eventHandler: EventHandler,\n branch?: string,\n revision?: string,\n getUploadManager?: () => UploadManager,\n getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>\n ) {\n this.name = name;\n this.branch = branch;\n this.revision = revision;\n // Store context with workspace set\n this._context = {\n ...context,\n workspace: name,\n branch: branch || context.branch,\n revision: revision || context.revision\n };\n // Wrap sendRequest to always include our workspace context\n this.sendRequest = (payload: unknown, requestType?: string) => {\n logger.debug('WorkspaceClient sendRequest wrapper called');\n logger.debug('WorkspaceClient workspace context:', JSON.stringify(this._context, null, 2));\n return sendRequest(payload, requestType, this._context);\n };\n this.eventHandler = eventHandler;\n this.getUploadManager = getUploadManager;\n this.getSignAssetUrl = getSignAssetUrl;\n }\n\n /**\n * Get the workspace name\n */\n getName(): string {\n return this.name;\n }\n\n /**\n * Create a new WorkspaceClient instance scoped to a specific branch.\n *\n * @param branch - Branch name\n * @returns New WorkspaceClient instance with branch context\n */\n onBranch(branch: string): WorkspaceClient {\n return new WorkspaceClient(\n this.name,\n this._context,\n this.sendRequest,\n this.eventHandler,\n branch,\n this.revision,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n\n /**\n * Create a new WorkspaceClient instance scoped to a specific revision/commit.\n *\n * @param revision - Revision/commit ID\n * @returns New WorkspaceClient instance with revision context\n */\n atRevision(revision: string): WorkspaceClient {\n return new WorkspaceClient(\n this.name,\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.branch,\n revision,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n\n /**\n * Get node operations for this workspace\n */\n nodes(): NodeOperations {\n if (!this.nodeOps) {\n this.nodeOps = new NodeOperations(\n (payload, requestType?) =>\n this.sendRequest(payload, requestType || this.inferRequestType(payload)),\n this.name\n );\n }\n return this.nodeOps;\n }\n\n /**\n * Get event subscriptions for this workspace\n */\n events(): EventSubscriptions {\n if (!this.eventSubs) {\n this.eventSubs = new EventSubscriptions(this.eventHandler, {\n workspace: this.name,\n });\n }\n return this.eventSubs;\n }\n\n /**\n * Create a new transaction for this workspace\n *\n * @returns Transaction instance\n *\n * @example\n * ```typescript\n * const tx = ws.transaction();\n * await tx.begin({ message: 'Create initial content' });\n *\n * try {\n * await tx.nodes().create({ type: 'Page', path: '/home', properties: { title: 'Home' } });\n * await tx.nodes().create({ type: 'Page', path: '/about', properties: { title: 'About' } });\n * await tx.commit();\n * } catch (error) {\n * await tx.rollback();\n * throw error;\n * }\n * ```\n */\n transaction(): Transaction {\n // Need to pass the raw sendRequest that accepts contextOverride\n // We can't use this.sendRequest because it always injects workspace context\n // Transaction will handle context management\n\n // Extract the original sendRequest from the constructor parameter\n // by creating a new wrapper that bypasses our workspace context injection\n const rawSendRequest = (payload: unknown, requestType: string, _contextOverride?: RequestContext) => {\n // Use the sendRequest but respect the contextOverride from Transaction\n return this.sendRequest(payload, requestType);\n };\n\n return new Transaction(this._context, rawSendRequest);\n }\n\n // ============================================================================\n // Upload Methods (convenience methods that delegate to UploadManager)\n // ============================================================================\n\n /**\n * Create a resumable upload for this workspace (Browser)\n *\n * Convenience method that pre-fills repository and workspace context.\n *\n * @param file - File or Blob to upload\n * @param path - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const upload = await ws.upload(file, '/videos/my-video.mp4', {\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * await upload.start();\n * ```\n */\n async upload(\n file: File | Blob,\n path: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n if (!this.getUploadManager) {\n throw new Error('Upload not available: client does not support uploads');\n }\n\n const fileSource = await createFileSource(file);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n repository: this._context.repository!,\n workspace: this.name,\n path,\n branch: options?.branch ?? this._context.branch,\n });\n }\n\n /**\n * Create a resumable upload for this workspace (Node.js)\n *\n * Convenience method that pre-fills repository and workspace context.\n *\n * @param filePath - Path to the file to upload\n * @param nodePath - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('data').workspace('backups');\n * const upload = await ws.uploadFile('/path/to/backup.zip', '/backup.zip');\n * await upload.start();\n * ```\n */\n async uploadFile(\n filePath: string,\n nodePath: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n if (!this.getUploadManager) {\n throw new Error('Upload not available: client does not support uploads');\n }\n\n const fileSource = await createFileSource(filePath);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n repository: this._context.repository!,\n workspace: this.name,\n path: nodePath,\n branch: options?.branch ?? this._context.branch,\n });\n }\n\n /**\n * Upload multiple files to this workspace\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param basePath - Base path for all uploads (files go to basePath/filename)\n * @param options - Additional batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await ws.uploadFiles(files, '/uploads', {\n * concurrency: 3,\n * onProgress: (p) => console.log(`${p.filesCompleted}/${p.filesTotal}`),\n * });\n * const result = await batch.start();\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n basePath: string,\n options?: Partial<Omit<BatchUploadOptions, 'repository' | 'workspace' | 'basePath'>>\n ): Promise<BatchUpload> {\n if (!this.getUploadManager) {\n throw new Error('Upload not available: client does not support uploads');\n }\n\n const sources = await Promise.all(\n Array.from(files).map((f) => createFileSource(f))\n );\n const manager = this.getUploadManager();\n return manager.createBatchUpload(sources, {\n ...options,\n repository: this._context.repository!,\n workspace: this.name,\n basePath,\n branch: options?.branch ?? this._context.branch,\n });\n }\n\n // ============================================================================\n // Asset Signed URL Methods\n // ============================================================================\n\n /**\n * Get a signed URL for an asset in this workspace\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param path - Path to the asset node\n * @param command - 'download' (forces download) or 'display' (shows inline)\n * @param options - Optional settings: expiresIn (seconds), propertyPath (e.g., 'thumbnail')\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const { url } = await ws.signAssetUrl('/files/image.jpeg', 'display');\n * document.querySelector('img').src = url;\n *\n * // Get thumbnail instead of main file\n * const { url: thumbUrl } = await ws.signAssetUrl('/files/image.jpeg', 'display', { propertyPath: 'thumbnail' });\n * ```\n */\n async signAssetUrl(\n path: string,\n command: 'download' | 'display' = 'display',\n options?: { expiresIn?: number; propertyPath?: string }\n ): Promise<SignedAssetUrl> {\n if (!this.getSignAssetUrl) {\n throw new Error('SignAssetUrl not available: client does not support it');\n }\n return this.getSignAssetUrl({\n repository: this._context.repository!,\n workspace: this.name,\n path,\n command,\n branch: this._context.branch,\n expiresIn: options?.expiresIn,\n propertyPath: options?.propertyPath,\n });\n }\n\n /**\n * Infer request type from payload\n * This is a helper to determine the correct RequestType enum value\n */\n private inferRequestType(payload: unknown): string {\n if (typeof payload !== 'object' || payload === null) {\n throw new Error('Invalid payload');\n }\n\n const keys = Object.keys(payload);\n\n if ('node_type' in payload && 'path' in payload) {\n return 'node_create';\n }\n if ('node_id' in payload && 'properties' in payload) {\n return 'node_update';\n }\n if ('node_id' in payload && keys.length === 1) {\n if ((payload as any).node_id) {\n return 'node_get';\n }\n return 'node_delete';\n }\n if ('query' in payload) {\n return 'node_query';\n }\n\n throw new Error('Unable to infer request type from payload');\n }\n}\n\n/**\n * Workspace management operations\n */\nexport class WorkspaceManager {\n private _context: RequestContext;\n private sendRequest: (payload: unknown, requestType?: string, contextOverride?: RequestContext) => Promise<unknown>;\n private eventHandler: EventHandler;\n private getUploadManager?: () => UploadManager;\n private getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>;\n\n constructor(\n context: RequestContext,\n sendRequest: (payload: unknown, requestType?: string, contextOverride?: RequestContext) => Promise<unknown>,\n eventHandler: EventHandler,\n getUploadManager?: () => UploadManager,\n getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>\n ) {\n this._context = context;\n this.sendRequest = sendRequest;\n this.eventHandler = eventHandler;\n this.getUploadManager = getUploadManager;\n this.getSignAssetUrl = getSignAssetUrl;\n }\n\n /**\n * Get a workspace client for operations\n *\n * @param name - Workspace name\n * @returns Workspace client\n */\n workspace(name: string): WorkspaceClient {\n return new WorkspaceClient(\n name,\n this._context,\n this.sendRequest,\n this.eventHandler,\n undefined,\n undefined,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n\n /**\n * Create a new workspace\n *\n * @param options - Workspace creation options\n * @returns Created workspace\n */\n async create(options: WorkspaceCreateOptions): Promise<Workspace> {\n const payload: WorkspaceCreatePayload = {\n name: options.name,\n description: options.description,\n };\n\n const result = await this.sendRequest(payload, 'workspace_create');\n return result as Workspace;\n }\n\n /**\n * Get workspace metadata\n *\n * @param name - Workspace name\n * @returns Workspace metadata\n */\n async get(name: string): Promise<Workspace | null> {\n const payload: WorkspaceGetPayload = {\n name,\n };\n\n try {\n const result = await this.sendRequest(payload, 'workspace_get');\n return result as Workspace;\n } catch (error) {\n if (error instanceof Error && error.message.includes('not found')) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * List all workspaces\n *\n * @returns Array of workspaces\n */\n async list(): Promise<Workspace[]> {\n const result = await this.sendRequest({}, 'workspace_list');\n return result as Workspace[];\n }\n\n /**\n * Update workspace metadata\n *\n * @param name - Workspace name\n * @param options - Update options\n * @returns Updated workspace\n */\n async update(name: string, options: WorkspaceUpdateOptions): Promise<Workspace> {\n const payload: WorkspaceUpdatePayload = {\n name,\n description: options.description,\n allowed_node_types: options.allowed_node_types,\n allowed_root_node_types: options.allowed_root_node_types,\n };\n\n const result = await this.sendRequest(payload, 'workspace_update');\n return result as Workspace;\n }\n\n /**\n * Delete a workspace\n *\n * @param name - Workspace name\n * @returns true if deleted successfully\n */\n async delete(name: string): Promise<boolean> {\n const payload: WorkspaceDeletePayload = {\n name,\n };\n\n await this.sendRequest(payload, 'workspace_delete');\n return true;\n }\n}\n","/**\n * SQL query support with template literals\n */\n\nimport { SqlQueryPayload, SqlResult } from './protocol';\n\n/**\n * SQL query builder with template literal support\n */\nexport class SqlQuery {\n private sendRequest: (payload: SqlQueryPayload) => Promise<unknown>;\n\n constructor(sendRequest: (payload: SqlQueryPayload) => Promise<unknown>) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Execute a SQL query using template literals\n *\n * @param strings - Template literal strings\n * @param values - Template literal values (automatically parameterized)\n * @returns SQL query result\n *\n * @example\n * ```typescript\n * const results = await sql`SELECT * FROM nodes WHERE node_type = ${nodeType}`;\n * ```\n */\n async query(strings: TemplateStringsArray, ...values: unknown[]): Promise<SqlResult> {\n // Build parameterized query\n let query = strings[0];\n for (let i = 0; i < values.length; i++) {\n query += `$${i + 1}` + strings[i + 1];\n }\n\n const payload: SqlQueryPayload = {\n query,\n params: values,\n };\n\n const result = await this.sendRequest(payload);\n return result as SqlResult;\n }\n\n /**\n * Execute a raw SQL query with explicit parameters\n *\n * @param query - SQL query string with $1, $2, etc. placeholders\n * @param params - Query parameters\n * @returns SQL query result\n *\n * @example\n * ```typescript\n * const results = await sql.execute(\n * 'SELECT * FROM nodes WHERE node_type = $1 AND created_at > $2',\n * ['page', '2024-01-01']\n * );\n * ```\n */\n async execute(query: string, params?: unknown[]): Promise<SqlResult> {\n const payload: SqlQueryPayload = {\n query,\n params,\n };\n\n const result = await this.sendRequest(payload);\n return result as SqlResult;\n }\n\n /**\n * Execute a raw SQL query without parameters\n * Use with caution - prefer parameterized queries for safety\n *\n * @param query - SQL query string\n * @returns SQL query result\n */\n async raw(query: string): Promise<SqlResult> {\n return this.execute(query);\n }\n}\n\n/**\n * Helper function to create SQL template literal handler\n *\n * @param sendRequest - Function to send SQL query request\n * @returns Template literal function\n */\nexport function createSqlHandler(\n sendRequest: (payload: SqlQueryPayload) => Promise<unknown>\n): (strings: TemplateStringsArray, ...values: unknown[]) => Promise<SqlResult> {\n const sqlQuery = new SqlQuery(sendRequest);\n return (strings: TemplateStringsArray, ...values: unknown[]) =>\n sqlQuery.query(strings, ...values);\n}\n","/**\n * NodeType management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class NodeTypes {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new NodeType\n */\n async create(name: string, nodeType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n node_type: nodeType\n },\n RequestType.NodeTypeCreate\n );\n }\n\n /**\n * Get a NodeType by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeGet\n );\n }\n\n /**\n * List all NodeTypes\n */\n async list(publishedOnly = false): Promise<unknown[]> {\n const result = await this.sendRequest(\n {\n published_only: publishedOnly\n },\n RequestType.NodeTypeList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update a NodeType\n */\n async update(name: string, nodeType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n node_type: nodeType\n },\n RequestType.NodeTypeUpdate\n );\n }\n\n /**\n * Delete a NodeType\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeDelete\n );\n }\n\n /**\n * Publish a NodeType\n */\n async publish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypePublish\n );\n }\n\n /**\n * Unpublish a NodeType\n */\n async unpublish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeUnpublish\n );\n }\n\n /**\n * Validate a node against its NodeType\n */\n async validate(node: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n node\n },\n RequestType.NodeTypeValidate\n );\n }\n\n /**\n * Get resolved NodeType with full inheritance applied\n */\n async getResolved(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.NodeTypeGetResolved\n );\n }\n}\n","/**\n * Archetype management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class Archetypes {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new Archetype\n */\n async create(name: string, archetype: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n archetype\n },\n RequestType.ArchetypeCreate\n );\n }\n\n /**\n * Get an Archetype by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeGet\n );\n }\n\n /**\n * List all Archetypes\n */\n async list(publishedOnly = false): Promise<unknown[]> {\n const result = await this.sendRequest(\n {\n published_only: publishedOnly\n },\n RequestType.ArchetypeList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update an Archetype\n */\n async update(name: string, archetype: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n archetype\n },\n RequestType.ArchetypeUpdate\n );\n }\n\n /**\n * Delete an Archetype\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeDelete\n );\n }\n\n /**\n * Publish an Archetype\n */\n async publish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypePublish\n );\n }\n\n /**\n * Unpublish an Archetype\n */\n async unpublish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeUnpublish\n );\n }\n\n /**\n * Get resolved Archetype with full inheritance applied\n */\n async getResolved(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ArchetypeGetResolved\n );\n }\n}\n","/**\n * ElementType management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class ElementTypes {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new ElementType\n */\n async create(name: string, elementType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n element_type: elementType\n },\n RequestType.ElementTypeCreate\n );\n }\n\n /**\n * Get an ElementType by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeGet\n );\n }\n\n /**\n * List all ElementTypes\n */\n async list(publishedOnly = false): Promise<unknown[]> {\n const result = await this.sendRequest(\n {\n published_only: publishedOnly\n },\n RequestType.ElementTypeList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Update an ElementType\n */\n async update(name: string, elementType: Record<string, unknown>): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n element_type: elementType\n },\n RequestType.ElementTypeUpdate\n );\n }\n\n /**\n * Delete an ElementType\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeDelete\n );\n }\n\n /**\n * Publish an ElementType\n */\n async publish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypePublish\n );\n }\n\n /**\n * Unpublish an ElementType\n */\n async unpublish(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeUnpublish\n );\n }\n\n /**\n * Get resolved ElementType with full inheritance applied\n */\n async getResolved(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.ElementTypeGetResolved\n );\n }\n}\n","/**\n * Branch management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\n/**\n * Branch divergence information (similar to \"N commits ahead/behind\").\n */\nexport interface BranchDivergence {\n /** Number of commits on the compared branch not on the base branch */\n ahead: number;\n /** Number of commits on the base branch not on the compared branch */\n behind: number;\n /** Common ancestor revision (HLC string, e.g. \"1705584000000-5\") */\n common_ancestor: string;\n}\n\n/**\n * Per-node change in a branch diff (relative to the merge-base).\n */\nexport interface NodeDiffInfo {\n /** Node id that changed */\n node_id: string;\n /** Workspace the node belongs to */\n workspace: string;\n /** Path on the diffed branch (null when only a tombstone exists, e.g. some deletes) */\n path: string | null;\n /** Operation: \"added\" | \"modified\" | \"deleted\" | \"reordered\" */\n operation: string;\n /** Translation locale when the change is to a translation (absent = base node) */\n translation_locale?: string;\n}\n\n/**\n * Per-node diff of a branch relative to a base branch's merge-base.\n *\n * Unlike {@link BranchDivergence} (ahead/behind counts only), this\n * enumerates exactly which nodes changed since the two branches diverged.\n */\nexport interface BranchDiff {\n /** The common ancestor (merge-base) the diff is computed against (HLC string) */\n common_ancestor: string;\n /** Nodes present on the branch but not on the base */\n added: NodeDiffInfo[];\n /** Nodes changed on the branch (operation \"modified\" / \"reordered\") */\n modified: NodeDiffInfo[];\n /** Nodes removed on the branch */\n deleted: NodeDiffInfo[];\n}\n\n/**\n * Per-node change from a cross-branch node-set copy.\n */\nexport interface CrossBranchNodeChange {\n /** Node id (ids are preserved across branches) */\n node_id: string;\n /** Path of the node on the target branch */\n path: string;\n /** NodeType of the node */\n node_type: string;\n /** Operation on the target branch: \"added\" | \"modified\" | \"deleted\" */\n operation: string;\n}\n\n/**\n * Summary of a cross-branch node-set copy (see {@link Branches.copyNodes}).\n */\nexport interface CrossBranchCopySummary {\n /** Number of nodes written to the target branch (added + modified) */\n copied: number;\n /** Number of target-branch nodes pruned (deleteMissing only) */\n deleted: number;\n /** The single revision all changes were committed under (HLC string) */\n revision: string;\n /** Per-node change list */\n changes: CrossBranchNodeChange[];\n}\n\nexport class Branches {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new branch\n */\n async create(\n name: string,\n options?: {\n fromRevision?: string;\n fromBranch?: string;\n }\n ): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n from_revision: options?.fromRevision,\n from_branch: options?.fromBranch\n },\n RequestType.BranchCreate\n );\n }\n\n /**\n * Get a branch by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.BranchGet\n );\n }\n\n /**\n * List all branches\n */\n async list(): Promise<unknown[]> {\n const result = await this.sendRequest(\n {},\n RequestType.BranchList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Delete a branch\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.BranchDelete\n );\n }\n\n /**\n * Get the HEAD revision of a branch\n */\n async getHead(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.BranchGetHead\n );\n }\n\n /**\n * Update the HEAD revision of a branch\n */\n async updateHead(name: string, revision: string): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n revision\n },\n RequestType.BranchUpdateHead\n );\n }\n\n /**\n * Merge a source branch into a target branch\n */\n async merge(\n sourceBranch: string,\n targetBranch: string,\n options?: {\n strategy?: string;\n message?: string;\n }\n ): Promise<unknown> {\n return this.sendRequest(\n {\n source_branch: sourceBranch,\n target_branch: targetBranch,\n strategy: options?.strategy,\n message: options?.message\n },\n RequestType.BranchMerge\n );\n }\n\n /**\n * Compare two branches to calculate divergence\n */\n async compare(branch: string, baseBranch: string): Promise<BranchDivergence> {\n return this.sendRequest(\n {\n branch,\n base_branch: baseBranch\n },\n RequestType.BranchCompare\n ) as Promise<BranchDivergence>;\n }\n\n /**\n * Per-node diff of `branch` relative to `baseBranch` (added/modified/deleted).\n *\n * Cheaper than reading both branch listings: cost scales with the number of\n * changed nodes since the branches diverged, not the total content.\n */\n async diff(branch: string, baseBranch: string): Promise<BranchDiff> {\n return this.sendRequest(\n {\n branch,\n base_branch: baseBranch\n },\n RequestType.BranchDiff\n ) as Promise<BranchDiff>;\n }\n\n /**\n * Copy a node set from `sourceBranch` onto `targetBranch` (branch\n * promotion): node ids are preserved, so repeated copies update the same\n * target nodes; all changes land in ONE atomic commit on the target branch.\n *\n * Each root's parent path must already exist on the target branch. With\n * `deleteMissing`, target nodes under the roots that are absent from the\n * copied source set are pruned (one-way sync).\n *\n * `sourceRevision` pins the read to a point in time. A promotion of a large\n * set is not instantaneous, so without it the copy reads each node when its\n * turn comes and a writer working in parallel lands partly inside the result\n * — a torn snapshot. Pass the revision captured when the operation was\n * decided (see `getHead`) to copy exactly that state. The target branch is\n * always resolved at its head: the pin says WHAT to copy, never where.\n */\n async copyNodes(\n sourceBranch: string,\n targetBranch: string,\n opts: {\n workspace: string;\n roots: string[];\n recursive?: boolean;\n deleteMissing?: boolean;\n sourceRevision?: string;\n }\n ): Promise<CrossBranchCopySummary> {\n return this.sendRequest(\n {\n source_branch: sourceBranch,\n target_branch: targetBranch,\n workspace: opts.workspace,\n roots: opts.roots,\n recursive: opts.recursive ?? true,\n delete_missing: opts.deleteMissing ?? false,\n source_revision: opts.sourceRevision ?? null\n },\n RequestType.BranchCopyNodes\n ) as Promise<CrossBranchCopySummary>;\n }\n}\n","/**\n * One-shot scheduled invocation operations.\n *\n * Schedule a single future run of a server-side function or flow, cancel it\n * before it fires (by job id or a caller-supplied external key), and inspect\n * pending/completed invocations. Scheduling is restart-safe: the invocation\n * is persisted server-side and fires even if the server restarts before\n * `runAt`.\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\n/** What a scheduled invocation targets. */\nexport type ScheduledInvocationTargetKind = 'function' | 'flow';\n\n/** Options for {@link SchedulerApi.schedule}. */\nexport interface ScheduleInvocationOptions {\n /** \"function\" or \"flow\" */\n targetKind: ScheduledInvocationTargetKind;\n /** Path of the target function or flow node */\n targetPath: string;\n /** Input passed to the target when it fires */\n input?: unknown;\n /** When to fire — RFC3339 string or Date (a past time fires immediately) */\n runAt: string | Date;\n /** Caller-supplied idempotency/lookup key (find or cancel by this later) */\n externalKey?: string;\n /** Branch the invocation executes against (default \"main\") */\n branch?: string;\n /** Workspace the invocation executes against (default \"functions\") */\n workspace?: string;\n /** Retry attempts if the invocation fails (default 0 — one-shot) */\n maxRetries?: number;\n}\n\n/** Result of scheduling an invocation. */\nexport interface ScheduledInvocationRef {\n job_id: string;\n invocation_id: string;\n status: string;\n run_at: string;\n}\n\n/** A scheduled invocation as returned by get/list. */\nexport interface ScheduledInvocation {\n job_id: string;\n invocation_id: string;\n target_kind: string;\n target_path: string | null;\n input: unknown;\n actor: string | null;\n external_key: string | null;\n run_at: string | null;\n /** \"scheduled\" | \"running\" | \"completed\" | \"cancelled\" | \"failed\" */\n status: string;\n error: string | null;\n result: unknown;\n}\n\n/** Filters for {@link SchedulerApi.list}. */\nexport interface ListInvocationsFilter {\n externalKey?: string;\n status?: string;\n}\n\nexport class SchedulerApi {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Schedule a one-shot invocation of a function or flow at a fixed time.\n */\n async schedule(options: ScheduleInvocationOptions): Promise<ScheduledInvocationRef> {\n const runAt =\n options.runAt instanceof Date ? options.runAt.toISOString() : options.runAt;\n return this.sendRequest(\n {\n target_kind: options.targetKind,\n target_path: options.targetPath,\n input: options.input ?? {},\n run_at: runAt,\n external_key: options.externalKey,\n branch: options.branch,\n workspace: options.workspace,\n max_retries: options.maxRetries\n },\n RequestType.ScheduledInvocationCreate\n ) as Promise<ScheduledInvocationRef>;\n }\n\n /**\n * Cancel a pending invocation before it fires, by job id or external key.\n */\n async cancel(\n ref: string | { jobId?: string; externalKey?: string }\n ): Promise<{ job_id: string; status: string }> {\n const payload =\n typeof ref === 'string'\n ? { job_id: ref }\n : { job_id: ref.jobId, external_key: ref.externalKey };\n return this.sendRequest(\n payload,\n RequestType.ScheduledInvocationCancel\n ) as Promise<{ job_id: string; status: string }>;\n }\n\n /**\n * List this repository's scheduled invocations.\n */\n async list(filter?: ListInvocationsFilter): Promise<ScheduledInvocation[]> {\n const result = (await this.sendRequest(\n {\n external_key: filter?.externalKey,\n status: filter?.status\n },\n RequestType.ScheduledInvocationList\n )) as { invocations?: ScheduledInvocation[] };\n return result?.invocations ?? [];\n }\n\n /**\n * Fetch a single scheduled invocation, by job id or external key.\n */\n async get(\n ref: string | { jobId?: string; externalKey?: string }\n ): Promise<ScheduledInvocation> {\n const payload =\n typeof ref === 'string'\n ? { job_id: ref }\n : { job_id: ref.jobId, external_key: ref.externalKey };\n return this.sendRequest(\n payload,\n RequestType.ScheduledInvocationGet\n ) as Promise<ScheduledInvocation>;\n }\n}\n","/**\n * Tag management operations\n */\n\nimport { RequestContext, RequestType } from './protocol';\n\nexport class Tags {\n private sendRequest: (payload: unknown, requestType: string) => Promise<unknown>;\n\n constructor(\n _context: RequestContext,\n sendRequest: (payload: unknown, requestType: string) => Promise<unknown>\n ) {\n this.sendRequest = sendRequest;\n }\n\n /**\n * Create a new tag\n */\n async create(name: string, revision: string, message?: string): Promise<unknown> {\n return this.sendRequest(\n {\n name,\n revision,\n message\n },\n RequestType.TagCreate\n );\n }\n\n /**\n * Get a tag by name\n */\n async get(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.TagGet\n );\n }\n\n /**\n * List all tags\n */\n async list(): Promise<unknown[]> {\n const result = await this.sendRequest(\n {},\n RequestType.TagList\n );\n return Array.isArray(result) ? result : [];\n }\n\n /**\n * Delete a tag\n */\n async delete(name: string): Promise<unknown> {\n return this.sendRequest(\n {\n name\n },\n RequestType.TagDelete\n );\n }\n}\n","/**\n * FlowsApi - WebSocket-based flow operations.\n *\n * Routes all flow operations through the existing WebSocket connection\n * instead of separate HTTP/SSE requests.\n */\n\nimport type { RequestContext, EventMessage } from './protocol';\nimport { RequestType } from './protocol';\nimport type { EventHandler } from './events';\nimport type {\n FlowRunResponse,\n FlowExecutionEvent,\n FlowInstanceStatusResponse,\n} from './types/flow';\n\ntype SendRequestFn = (\n payload: unknown,\n requestType: string,\n contextOverride?: RequestContext,\n) => Promise<unknown>;\n\nexport class FlowsApi {\n private context: RequestContext;\n private sendRequest: SendRequestFn;\n private eventHandler: EventHandler;\n\n constructor(\n repository: string,\n context: RequestContext,\n sendRequest: SendRequestFn,\n eventHandler: EventHandler,\n ) {\n this.context = { ...context, repository };\n this.sendRequest = sendRequest;\n this.eventHandler = eventHandler;\n }\n\n /** Run a flow by path */\n async run(\n flowPath: string,\n input: Record<string, unknown> = {},\n ): Promise<FlowRunResponse> {\n return (await this.sendRequest(\n { flow_path: flowPath, input },\n RequestType.FlowRun,\n this.context,\n )) as FlowRunResponse;\n }\n\n /** Get instance status */\n async getInstanceStatus(instanceId: string): Promise<FlowInstanceStatusResponse> {\n return (await this.sendRequest(\n { instance_id: instanceId },\n RequestType.FlowGetInstanceStatus,\n this.context,\n )) as FlowInstanceStatusResponse;\n }\n\n /** Resume a waiting flow */\n async resume(instanceId: string, data: unknown): Promise<FlowRunResponse> {\n return (await this.sendRequest(\n { instance_id: instanceId, resume_data: data },\n RequestType.FlowResume,\n this.context,\n )) as FlowRunResponse;\n }\n\n /** Cancel a running flow */\n async cancel(instanceId: string): Promise<void> {\n await this.sendRequest(\n { instance_id: instanceId },\n RequestType.FlowCancel,\n this.context,\n );\n }\n\n /**\n * Subscribe to flow execution events.\n * Returns an async iterable of FlowExecutionEvent + unsubscribe function.\n * Uses WS EventMessage subscription pattern.\n */\n async subscribeEvents(instanceId: string): Promise<{\n events: AsyncIterable<FlowExecutionEvent>;\n unsubscribe: () => Promise<void>;\n }> {\n // 1. Subscribe on server - get subscription_id back\n const response = (await this.sendRequest(\n { instance_id: instanceId },\n RequestType.FlowSubscribeEvents,\n this.context,\n )) as { subscription_id: string };\n\n const subscriptionId = response.subscription_id;\n\n // 2. Create async queue for events\n const queue = createAsyncQueue<FlowExecutionEvent>();\n\n // 3. Register callback for EventMessages with this subscription_id\n const callback = (event: EventMessage) => {\n const payload = event.payload as unknown as FlowExecutionEvent;\n queue.push(payload);\n if (\n payload.type === 'flow_completed' ||\n payload.type === 'flow_failed'\n ) {\n queue.end();\n }\n };\n\n // Register the subscription_id -> callback in the event handler\n this.eventHandler.addFlowEventListener(subscriptionId, callback);\n\n return {\n events: queue,\n unsubscribe: async () => {\n this.eventHandler.removeFlowEventListener(subscriptionId);\n queue.end();\n try {\n await this.sendRequest(\n { subscription_id: subscriptionId },\n RequestType.FlowUnsubscribeEvents,\n this.context,\n );\n } catch {\n // Best effort - server may have already cleaned up\n }\n },\n };\n }\n}\n\n/**\n * Simple async queue that implements AsyncIterable.\n * Push events from callbacks, consume them with for-await-of.\n */\nfunction createAsyncQueue<T>(): AsyncIterableQueue<T> {\n const buffer: T[] = [];\n let resolve: ((value: IteratorResult<T>) => void) | null = null;\n let done = false;\n\n return {\n push(item: T) {\n if (done) return;\n if (resolve) {\n const r = resolve;\n resolve = null;\n r({ done: false, value: item });\n } else {\n buffer.push(item);\n }\n },\n end() {\n done = true;\n if (resolve) {\n const r = resolve;\n resolve = null;\n r({ done: true, value: undefined });\n }\n },\n [Symbol.asyncIterator]() {\n return {\n next(): Promise<IteratorResult<T>> {\n if (buffer.length > 0) {\n return Promise.resolve({ done: false, value: buffer.shift()! });\n }\n if (done) {\n return Promise.resolve({ done: true, value: undefined });\n }\n return new Promise<IteratorResult<T>>((r) => {\n resolve = r;\n });\n },\n return(): Promise<IteratorResult<T>> {\n done = true;\n resolve = null;\n buffer.length = 0;\n return Promise.resolve({ done: true, value: undefined });\n },\n };\n },\n };\n}\n\ninterface AsyncIterableQueue<T> extends AsyncIterable<T> {\n push(item: T): void;\n end(): void;\n}\n","/**\n * FunctionsApi - Transport-agnostic function invocation.\n *\n * Invoke server-side functions through WebSocket or HTTP.\n * Functions can be queued as background jobs (async) or executed inline (sync).\n */\n\nimport type { RequestContext } from './protocol';\nimport { RequestType } from './protocol';\n\ntype SendRequestFn = (\n payload: unknown,\n requestType: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number },\n) => Promise<unknown>;\n\nexport interface FunctionInvokeResponse {\n execution_id: string;\n job_id: string;\n status?: string;\n completed?: boolean;\n timed_out?: boolean;\n waited?: boolean;\n result?: unknown;\n error?: string;\n duration_ms?: number;\n logs?: string[];\n}\n\nexport interface FunctionInvokeSyncResponse {\n execution_id: string;\n result?: unknown;\n error?: string;\n duration_ms?: number;\n logs?: string[];\n}\n\nexport interface FunctionInvokeOptions {\n waitForResult?: boolean;\n waitTimeoutMs?: number;\n requestTimeoutMs?: number;\n}\n\n/**\n * FunctionsApi for WebSocket transport.\n *\n * Sends function invocation requests over the existing WS connection.\n */\nexport class FunctionsApi {\n private context: RequestContext;\n private sendRequest: SendRequestFn;\n\n constructor(\n repository: string,\n context: RequestContext,\n sendRequest: SendRequestFn,\n ) {\n this.context = { ...context, repository };\n this.sendRequest = sendRequest;\n }\n\n /**\n * Invoke a server-side function by name (async).\n *\n * Queues a `FunctionExecution` job and returns the execution and job IDs\n * immediately. The function runs asynchronously on the server.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution ID and job ID for tracking\n */\n async invoke(\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ): Promise<FunctionInvokeResponse> {\n const effectiveRequestTimeoutMs = options?.requestTimeoutMs;\n let effectiveWaitTimeoutMs = options?.waitTimeoutMs;\n if (options?.waitForResult) {\n const transportTimeoutBudget = effectiveRequestTimeoutMs ?? 30000;\n effectiveWaitTimeoutMs = Math.min(\n effectiveWaitTimeoutMs ?? transportTimeoutBudget,\n transportTimeoutBudget,\n );\n }\n\n return (await this.sendRequest(\n {\n function_name: functionName,\n input: input ?? {},\n wait_for_completion: options?.waitForResult ?? false,\n wait_timeout_ms: effectiveWaitTimeoutMs,\n },\n RequestType.FunctionInvoke,\n this.context,\n effectiveRequestTimeoutMs != null ? { timeoutMs: effectiveRequestTimeoutMs } : undefined,\n )) as FunctionInvokeResponse;\n }\n\n /**\n * Invoke a server-side function synchronously.\n *\n * Executes the function inline on the server and returns the result\n * directly. Bypasses the job queue for immediate execution.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution result including output, logs, and duration\n */\n async invokeSync(\n functionName: string,\n input?: Record<string, unknown>,\n ): Promise<FunctionInvokeSyncResponse> {\n return (await this.sendRequest(\n { function_name: functionName, input: input ?? {} },\n RequestType.FunctionInvokeSync,\n this.context,\n )) as FunctionInvokeSyncResponse;\n }\n}\n\n/**\n * HTTP-backed FunctionsApi for SSR / RaisinHttpClient.\n *\n * Calls `POST /api/functions/{repo}/{name}/invoke` via the HTTP client.\n */\nexport class HttpFunctionsApi {\n constructor(\n private repository: string,\n private invokeFn: (\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ) => Promise<FunctionInvokeResponse>,\n private invokeSyncFn: (\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n ) => Promise<FunctionInvokeSyncResponse>,\n ) {}\n\n /**\n * Invoke a server-side function by name (async).\n *\n * Calls the HTTP invoke endpoint and returns the execution and job IDs.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution ID and job ID for tracking\n */\n async invoke(\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ): Promise<FunctionInvokeResponse> {\n return this.invokeFn(this.repository, functionName, input, options);\n }\n\n /**\n * Invoke a server-side function synchronously.\n *\n * Calls the HTTP invoke endpoint with `sync: true` and returns the\n * result directly.\n *\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution result including output, logs, and duration\n */\n async invokeSync(\n functionName: string,\n input?: Record<string, unknown>,\n ): Promise<FunctionInvokeSyncResponse> {\n return this.invokeSyncFn(this.repository, functionName, input);\n }\n}\n","/**\n * Error types for the RaisinDB JS SDK.\n *\n * Provides a structured error hierarchy for programmatic error handling.\n * All errors extend RaisinError and include a string `code` field for\n * easy matching in switch statements or error handlers.\n *\n * @example\n * ```typescript\n * import { RaisinError, RaisinConnectionError } from '@raisindb/client';\n *\n * try {\n * await flows.run('/flows/my-flow', {});\n * } catch (err) {\n * if (err instanceof RaisinConnectionError) {\n * console.log('Network issue:', err.code);\n * }\n * }\n * ```\n */\n\n// ============================================================================\n// Error Codes\n// ============================================================================\n\n/** Error codes for connection errors */\nexport type ConnectionErrorCode =\n | 'CONNECTION_FAILED'\n | 'CONNECTION_LOST'\n | 'SSE_STREAM_ERROR';\n\n/**\n * Error codes for authentication errors.\n *\n * Includes the well-known codes plus any server-provided code string\n * (e.g. identity endpoints return codes like `LOGIN_FAILED`).\n */\nexport type AuthErrorCode =\n | 'AUTH_UNAUTHORIZED'\n | 'AUTH_FORBIDDEN'\n | 'AUTH_TOKEN_EXPIRED'\n | 'LOGIN_FAILED'\n | 'REGISTRATION_FAILED'\n // eslint-disable-next-line @typescript-eslint/ban-types\n | (string & {});\n\n/** Error codes for flow execution errors */\nexport type FlowErrorCode =\n | 'FLOW_NOT_FOUND'\n | 'FLOW_EXECUTION_FAILED'\n | 'FLOW_INSTANCE_NOT_FOUND'\n | 'FLOW_RESUME_FAILED';\n\n/** Error codes for timeout errors */\nexport type TimeoutErrorCode =\n | 'REQUEST_TIMEOUT'\n | 'CONNECTION_TIMEOUT'\n | 'POLL_TIMEOUT'\n | 'SSE_INACTIVITY_TIMEOUT';\n\n/** Error codes for abort/cancellation errors */\nexport type AbortErrorCode = 'ABORTED';\n\n/** All error codes */\nexport type RaisinErrorCode =\n | ConnectionErrorCode\n | AuthErrorCode\n | FlowErrorCode\n | TimeoutErrorCode\n | AbortErrorCode;\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\n/**\n * Base error class for all RaisinDB SDK errors.\n *\n * All SDK errors extend this class, making it easy to catch any\n * RaisinDB-specific error with a single `instanceof` check.\n */\nexport class RaisinError extends Error {\n /** String error code for programmatic handling */\n readonly code: RaisinErrorCode;\n /** Optional additional details */\n readonly details?: unknown;\n\n constructor(message: string, code: RaisinErrorCode, details?: unknown) {\n super(message);\n this.name = 'RaisinError';\n this.code = code;\n this.details = details;\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Thrown when a network or connection failure occurs.\n *\n * This includes SSE stream errors, fetch failures, and lost connections.\n */\nexport class RaisinConnectionError extends RaisinError {\n /** HTTP status code, if available */\n readonly status?: number;\n\n constructor(message: string, code: ConnectionErrorCode, options?: { status?: number; details?: unknown }) {\n super(message, code, options?.details);\n this.name = 'RaisinConnectionError';\n this.status = options?.status;\n }\n}\n\n/**\n * Thrown when an authentication or authorization failure occurs.\n *\n * This includes 401 Unauthorized, 403 Forbidden, and expired tokens.\n */\nexport class RaisinAuthError extends RaisinError {\n /** HTTP status code (401 or 403) */\n readonly status: number;\n\n constructor(message: string, code: AuthErrorCode, status: number, details?: unknown) {\n super(message, code, details);\n this.name = 'RaisinAuthError';\n this.status = status;\n }\n}\n\n/**\n * Thrown when a flow execution error occurs.\n *\n * This includes flow not found, execution failures, and resume errors.\n */\nexport class RaisinFlowError extends RaisinError {\n /** Flow instance ID, if available */\n readonly instanceId?: string;\n\n constructor(message: string, code: FlowErrorCode, instanceId?: string, details?: unknown) {\n super(message, code, details);\n this.name = 'RaisinFlowError';\n this.instanceId = instanceId;\n }\n}\n\n/**\n * Thrown when a request or operation times out.\n *\n * Includes the timeout duration for debugging.\n */\nexport class RaisinTimeoutError extends RaisinError {\n /** Timeout duration in milliseconds */\n readonly timeoutMs: number;\n\n constructor(message: string, code: TimeoutErrorCode, timeoutMs: number, details?: unknown) {\n super(message, code, details);\n this.name = 'RaisinTimeoutError';\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Thrown when an operation is aborted via AbortSignal.\n */\nexport class RaisinAbortError extends RaisinError {\n constructor(message = 'Operation was aborted') {\n super(message, 'ABORTED');\n this.name = 'RaisinAbortError';\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Classify an HTTP response error into the appropriate RaisinError subclass.\n *\n * @internal\n */\nexport function classifyHttpError(\n status: number,\n message: string,\n details?: unknown,\n): RaisinError {\n if (status === 401) {\n return new RaisinAuthError(message, 'AUTH_UNAUTHORIZED', status, details);\n }\n if (status === 403) {\n return new RaisinAuthError(message, 'AUTH_FORBIDDEN', status, details);\n }\n if (status === 404) {\n return new RaisinFlowError(message, 'FLOW_NOT_FOUND', undefined, details);\n }\n return new RaisinConnectionError(message, 'CONNECTION_FAILED', { status, details });\n}\n","/**\n * SSE (Server-Sent Events) client for streaming flow execution events.\n *\n * Uses fetch-based approach for better control over connection lifecycle,\n * headers, and reconnection compared to the native EventSource API.\n */\n\nimport { logger } from '../logger';\nimport { ReconnectManager, type ReconnectOptions } from '../utils/reconnect';\nimport { RaisinConnectionError, RaisinAuthError, RaisinAbortError, RaisinTimeoutError } from '../errors';\n\n/**\n * Parsed SSE event from the wire format\n */\nexport interface SSEEvent<T = unknown> {\n /** SSE event type (from \"event:\" field) */\n type: string;\n /** Parsed event data */\n data: T;\n /** SSE event ID (from \"id:\" field, if present) */\n id?: string;\n}\n\n/**\n * SSE connection state\n */\nexport type SSEConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';\n\n/**\n * Callback for SSE connection state changes\n */\nexport type SSEStateCallback = (state: SSEConnectionState) => void;\n\n/**\n * Options for creating an SSE client\n */\nexport interface SSEClientOptions {\n /** HTTP headers to include (e.g., Authorization) */\n headers?: Record<string, string>;\n /** Event types to filter for (if empty, all events are passed through) */\n eventTypes?: string[];\n /** Reconnection options (uses ReconnectManager) */\n reconnect?: ReconnectOptions & {\n /** Whether to automatically reconnect on disconnect (default: true) */\n enabled?: boolean;\n };\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n /** Connection state change callback */\n onStateChange?: SSEStateCallback;\n /** Last-Event-ID for resuming streams */\n lastEventId?: string;\n /** External AbortSignal for cancellation */\n signal?: AbortSignal;\n /** HTTP method (default: 'GET'). Use 'POST' to avoid path in URL params. */\n method?: 'GET' | 'POST';\n /** Request body for POST requests (JSON-serialized automatically) */\n body?: unknown;\n /**\n * Inactivity timeout in milliseconds (default: disabled).\n *\n * The timer is reset whenever any bytes arrive on the stream (events,\n * comments/keep-alives, partial frames). If the stream produces nothing\n * for this long — including a fetch that never responds — the connection\n * is torn down. With reconnection enabled the client reconnects; with\n * reconnection disabled the stream ends with a `RaisinTimeoutError`\n * (code `SSE_INACTIVITY_TIMEOUT`).\n */\n inactivityTimeoutMs?: number;\n}\n\n/**\n * Parse a single SSE message block into event type, data, and id.\n *\n * SSE wire format:\n * event: <type>\\n\n * data: <json>\\n\n * id: <id>\\n\n * \\n\n */\nfunction parseSSEBlock(block: string): { event: string; data: string; id?: string } | null {\n let event = 'message';\n let data = '';\n let id: string | undefined;\n\n const lines = block.split('\\n');\n for (const line of lines) {\n if (line.startsWith('event:')) {\n event = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n // Accumulate data lines (SSE spec allows multi-line data)\n if (data) data += '\\n';\n data += line.slice(5).trim();\n } else if (line.startsWith('id:')) {\n id = line.slice(3).trim();\n }\n // Lines starting with \":\" are comments (keep-alive), ignore them\n // Empty lines are block separators, handled by the caller\n }\n\n if (!data) return null;\n\n return { event, data, id };\n}\n\n/**\n * Fetch-based SSE client with reconnection, filtering, and AsyncIterable support.\n *\n * @example\n * ```typescript\n * const sse = new SSEClient('https://api.example.com/events/flow/123', {\n * headers: { Authorization: `Bearer ${token}` },\n * eventTypes: ['step_started', 'step_completed', 'flow_completed'],\n * });\n *\n * // AsyncIterable usage\n * for await (const event of sse) {\n * console.log(event.type, event.data);\n * }\n *\n * // Callback usage\n * sse.connect((event) => {\n * console.log(event.type, event.data);\n * });\n *\n * // Cleanup\n * sse.close();\n * ```\n */\nexport class SSEClient<T = unknown> implements AsyncIterable<SSEEvent<T>> {\n private url: string;\n private options: SSEClientOptions;\n private abortController: AbortController | null = null;\n private reconnectManager: ReconnectManager;\n private fetchImpl: typeof fetch;\n private _state: SSEConnectionState = 'disconnected';\n private _lastEventId?: string;\n private eventTypeSet: Set<string> | null;\n private autoReconnect: boolean;\n private externalSignal?: AbortSignal;\n private inactivityTimeoutMs?: number;\n\n constructor(url: string, options: SSEClientOptions = {}) {\n this.url = url;\n this.options = options;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this._lastEventId = options.lastEventId;\n this.autoReconnect = options.reconnect?.enabled ?? true;\n this.externalSignal = options.signal;\n this.inactivityTimeoutMs = options.inactivityTimeoutMs;\n this.eventTypeSet = options.eventTypes?.length\n ? new Set(options.eventTypes)\n : null;\n\n this.reconnectManager = new ReconnectManager({\n initialDelay: options.reconnect?.initialDelay ?? 1000,\n maxDelay: options.reconnect?.maxDelay ?? 30000,\n backoffMultiplier: options.reconnect?.backoffMultiplier ?? 2,\n maxAttempts: options.reconnect?.maxAttempts ?? Infinity,\n });\n }\n\n /** Current connection state */\n get state(): SSEConnectionState {\n return this._state;\n }\n\n /**\n * Returns a promise that resolves once the SSE connection is established.\n *\n * Useful for ensuring the connection is ready before triggering events\n * on the server side (e.g., calling resume before consuming the stream).\n * If the client is already connected, resolves immediately.\n */\n waitUntilConnected(): Promise<void> {\n if (this._state === 'connected') return Promise.resolve();\n return new Promise<void>((resolve, reject) => {\n const originalOnState = this.options.onStateChange;\n this.options.onStateChange = (state) => {\n originalOnState?.(state);\n if (state === 'connected') {\n // Restore original callback and resolve\n this.options.onStateChange = originalOnState;\n resolve();\n } else if (state === 'disconnected') {\n this.options.onStateChange = originalOnState;\n reject(new Error('SSE connection failed'));\n }\n };\n });\n }\n\n /** Last received event ID */\n get lastEventId(): string | undefined {\n return this._lastEventId;\n }\n\n private setState(state: SSEConnectionState): void {\n if (this._state !== state) {\n this._state = state;\n this.options.onStateChange?.(state);\n }\n }\n\n /**\n * Connect and consume events via callback.\n *\n * @param onEvent - Called for each matching SSE event\n * @param onError - Called when an error occurs (optional)\n */\n async connect(\n onEvent: (event: SSEEvent<T>) => void,\n onError?: (error: Error) => void,\n ): Promise<void> {\n this.close();\n await this.startStream(onEvent, onError);\n }\n\n /**\n * Close the SSE connection and stop reconnection attempts.\n */\n close(): void {\n this.reconnectManager.cancelReconnect();\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n this.setState('disconnected');\n }\n\n /**\n * AsyncIterable interface: allows `for await (const event of sseClient)`.\n *\n * The iterator ends when close() is called or the server closes the stream\n * (and auto-reconnect is disabled or max attempts are exhausted).\n */\n async *[Symbol.asyncIterator](): AsyncIterator<SSEEvent<T>> {\n // Use a queue and resolve-based approach for backpressure\n type QueueItem =\n | { done: false; value: SSEEvent<T> }\n | { done: true; error?: Error };\n\n const queue: QueueItem[] = [];\n let resolve: ((item: QueueItem) => void) | null = null;\n let finished = false;\n\n const push = (item: QueueItem) => {\n if (finished) return;\n if (resolve) {\n const r = resolve;\n resolve = null;\n r(item);\n } else {\n queue.push(item);\n }\n };\n\n const pull = (): Promise<QueueItem> => {\n const queued = queue.shift();\n if (queued) return Promise.resolve(queued);\n return new Promise<QueueItem>((r) => {\n resolve = r;\n });\n };\n\n // Start streaming in the background\n this.startStream(\n (event) => push({ done: false, value: event }),\n (error) => push({ done: true, error }),\n ).then(() => {\n push({ done: true });\n }).catch((error) => {\n push({ done: true, error });\n });\n\n try {\n while (!finished) {\n const item = await pull();\n if (item.done) {\n finished = true;\n if (item.error) {\n throw item.error;\n }\n return;\n }\n yield item.value;\n }\n } finally {\n finished = true;\n this.close();\n }\n }\n\n /**\n * Core streaming loop: connects, reads the SSE stream, and handles reconnection.\n */\n private async startStream(\n onEvent: (event: SSEEvent<T>) => void,\n onError?: (error: Error) => void,\n ): Promise<void> {\n while (true) {\n try {\n await this.readStream(onEvent);\n\n // Stream ended cleanly (server closed connection)\n if (!this.autoReconnect || this._state === 'disconnected') {\n return;\n }\n\n // Schedule reconnection\n this.setState('reconnecting');\n const scheduled = await this.waitForReconnect();\n if (!scheduled) {\n // Max attempts reached\n logger.warn('SSE max reconnection attempts reached');\n this.setState('disconnected');\n return;\n }\n } catch (error) {\n if (this._state === 'disconnected') {\n // close() was called, exit cleanly\n return;\n }\n\n const err = error instanceof Error ? error : new Error(String(error));\n\n // AbortError means close() was called or external AbortSignal fired\n if (err.name === 'AbortError' || err instanceof RaisinAbortError) {\n return;\n }\n\n // Inactivity timeout: reconnect silently if enabled, otherwise end\n // the stream with the typed timeout error.\n if (err instanceof RaisinTimeoutError && err.code === 'SSE_INACTIVITY_TIMEOUT') {\n logger.warn('SSE inactivity timeout:', err.message);\n if (!this.autoReconnect) {\n this.setState('disconnected');\n onError?.(err);\n throw err;\n }\n this.setState('reconnecting');\n const scheduled = await this.waitForReconnect();\n if (!scheduled) {\n logger.warn('SSE max reconnection attempts reached');\n this.setState('disconnected');\n onError?.(err);\n throw err;\n }\n continue;\n }\n\n logger.error('SSE connection error:', err.message);\n onError?.(err);\n\n if (!this.autoReconnect) {\n this.setState('disconnected');\n throw err;\n }\n\n // Schedule reconnection\n this.setState('reconnecting');\n const scheduled = await this.waitForReconnect();\n if (!scheduled) {\n logger.warn('SSE max reconnection attempts reached');\n this.setState('disconnected');\n throw err;\n }\n }\n }\n }\n\n /**\n * Perform a single fetch and read the response body as SSE stream.\n */\n private async readStream(onEvent: (event: SSEEvent<T>) => void): Promise<void> {\n this.abortController = new AbortController();\n this.setState('connecting');\n\n // If an external signal is provided, forward its abort to our internal controller\n if (this.externalSignal) {\n if (this.externalSignal.aborted) {\n this.abortController.abort();\n } else {\n const ctrl = this.abortController;\n this.externalSignal.addEventListener('abort', () => ctrl.abort(), { once: true });\n }\n }\n\n const headers: Record<string, string> = {\n Accept: 'text/event-stream',\n 'Cache-Control': 'no-cache',\n ...this.options.headers,\n };\n\n // Resume from last event ID if available\n if (this._lastEventId) {\n headers['Last-Event-ID'] = this._lastEventId;\n }\n\n const method = this.options.method ?? 'GET';\n const fetchOptions: RequestInit = {\n method,\n headers,\n signal: this.abortController.signal,\n };\n if (method === 'POST' && this.options.body !== undefined) {\n (fetchOptions.headers as Record<string, string>)['Content-Type'] = 'application/json';\n fetchOptions.body = JSON.stringify(this.options.body);\n }\n\n const response = await this.withInactivityTimeout(\n this.fetchImpl(this.url, fetchOptions),\n );\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n const msg = `SSE connection failed: ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`;\n if (response.status === 401 || response.status === 403) {\n throw new RaisinAuthError(\n msg,\n response.status === 401 ? 'AUTH_UNAUTHORIZED' : 'AUTH_FORBIDDEN',\n response.status,\n );\n }\n throw new RaisinConnectionError(msg, 'SSE_STREAM_ERROR', { status: response.status });\n }\n\n if (!response.body) {\n throw new RaisinConnectionError('SSE response has no body', 'SSE_STREAM_ERROR');\n }\n\n this.setState('connected');\n this.reconnectManager.reset();\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await this.withInactivityTimeout(reader.read());\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE events are separated by double newlines\n const blocks = buffer.split('\\n\\n');\n // Last element is incomplete, keep it in the buffer\n buffer = blocks.pop() ?? '';\n\n for (const block of blocks) {\n const trimmed = block.trim();\n if (!trimmed) continue;\n\n const parsed = parseSSEBlock(trimmed);\n if (!parsed) continue;\n\n // Track event ID for reconnection\n if (parsed.id) {\n this._lastEventId = parsed.id;\n }\n\n // Apply event type filter\n if (this.eventTypeSet && !this.eventTypeSet.has(parsed.event)) {\n continue;\n }\n\n // Parse JSON data\n let data: T;\n try {\n data = JSON.parse(parsed.data) as T;\n } catch {\n // If data isn't valid JSON, pass it as-is\n data = parsed.data as unknown as T;\n }\n\n const sseEvent = {\n type: parsed.event,\n data,\n id: parsed.id,\n };\n onEvent(sseEvent);\n }\n }\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // Releasing while a read is pending can throw in some implementations\n }\n }\n }\n\n /**\n * Race a stream operation against the inactivity timeout.\n *\n * If no bytes (or response) arrive within `inactivityTimeoutMs`, the\n * internal connection is aborted and the operation rejects with a\n * `RaisinTimeoutError` (code `SSE_INACTIVITY_TIMEOUT`). The timer is\n * effectively reset on every chunk because each `reader.read()` is\n * wrapped individually.\n */\n private withInactivityTimeout<T>(promise: Promise<T>): Promise<T> {\n const timeoutMs = this.inactivityTimeoutMs;\n if (!timeoutMs || timeoutMs <= 0) return promise;\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n // Swallow the eventual rejection of the underlying promise\n // (e.g. AbortError after we abort) to avoid unhandled rejections.\n promise.catch(() => undefined);\n this.abortController?.abort();\n reject(\n new RaisinTimeoutError(\n `SSE stream inactive for ${timeoutMs}ms`,\n 'SSE_INACTIVITY_TIMEOUT',\n timeoutMs,\n ),\n );\n }, timeoutMs);\n\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n }\n\n /**\n * Wait for the reconnect manager to schedule a reconnection attempt.\n * Returns true if reconnection was scheduled, false if max attempts reached.\n */\n private waitForReconnect(): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const scheduled = this.reconnectManager.scheduleReconnect(() => {\n resolve(true);\n });\n if (!scheduled) {\n resolve(false);\n }\n });\n }\n}\n","import type { ChatDoneEvent, ChatEvent } from '../types/chat';\n\n/**\n * Detect safety-net done events emitted by backend recovery paths.\n *\n * These events can appear while async tool calls are still running.\n * They carry `recovered: true` and an empty content payload.\n */\nexport function isRecoveredDoneEvent(event: ChatEvent): event is ChatDoneEvent & { recovered: true } {\n if (event.type !== 'done') return false;\n const done = event as ChatDoneEvent & { recovered?: unknown };\n if (done.recovered !== true) return false;\n return typeof done.content !== 'string' || done.content.trim().length === 0;\n}\n\n","/**\n * User home path normalization.\n *\n * Some server responses (JWT claims, RAISIN_CURRENT_USER(), identity\n * endpoints) return the user home as a workspace-prefixed path like\n * `/raisin:access_control/users/internal/alice`, while others return the\n * workspace-relative form `/users/internal/alice`. SDK code that builds\n * child paths (inbox, chats, outbox) expects the workspace-relative form.\n */\n\n/** Workspace prefix that may leak into user home paths */\nconst ACCESS_CONTROL_PREFIX = '/raisin:access_control';\n\n/**\n * Normalize a user home path to its workspace-relative form.\n *\n * Strips a leading `/raisin:access_control` workspace prefix and trailing\n * slashes, so `/raisin:access_control/users/internal/alice/` becomes\n * `/users/internal/alice`. Paths without the prefix are returned unchanged\n * (modulo trailing-slash trimming). Returns `null` for empty input.\n *\n * @example\n * ```typescript\n * normalizeHomePath('/raisin:access_control/users/internal/alice');\n * // => '/users/internal/alice'\n * normalizeHomePath('/users/internal/alice');\n * // => '/users/internal/alice'\n * ```\n */\nexport function normalizeHomePath(home: string | null | undefined): string | null {\n if (home === null || home === undefined) return null;\n\n let path = home.trim();\n if (path.length === 0) return null;\n\n if (path === ACCESS_CONTROL_PREFIX) return '/';\n if (path.startsWith(`${ACCESS_CONTROL_PREFIX}/`)) {\n path = path.slice(ACCESS_CONTROL_PREFIX.length);\n }\n\n // Trim trailing slashes (but keep root \"/\")\n while (path.length > 1 && path.endsWith('/')) {\n path = path.slice(0, -1);\n }\n\n return path;\n}\n","/**\n * Unified ConversationManager for RaisinDB.\n *\n * Merges all conversation operations (previously split across ChatClient,\n * ConversationClient, and FlowClient) into a single API accessed via\n * `db.conversations`.\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n *\n * // List conversations\n * const convos = await db.conversations.list({ type: 'ai_chat' });\n *\n * // Create a new conversation with an agent\n * const convo = await db.conversations.create({ participant: '/agents/support' });\n *\n * // Send a message and stream the response\n * for await (const event of db.conversations.sendMessage(convo.conversationPath, 'Hello!', { stream: true })) {\n * if (event.type === 'text_chunk') process.stdout.write(event.text);\n * }\n *\n * // Get full message history\n * const messages = await db.conversations.getMessages(convo.conversationPath);\n * ```\n */\n\nimport type { AuthManager } from './auth';\nimport type {\n ChatEvent,\n ChatMessage,\n Conversation,\n ConversationType,\n ConversationListItem,\n ToolCallRecord,\n MessageChild,\n PlanTask,\n} from './types/chat';\nimport { logger } from './logger';\nimport { SSEClient } from './streaming/sse-client';\nimport { RaisinAbortError, RaisinTimeoutError, classifyHttpError } from './errors';\nimport type { SqlResult } from './protocol';\nimport { isRecoveredDoneEvent } from './utils/chat-events';\nimport { normalizeHomePath } from './utils/home-path';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Options for listing conversations */\nexport interface ListConversationsOptions {\n /** Filter by conversation type */\n type?: ConversationType;\n /** Maximum number of conversations to return */\n limit?: number;\n /** Abort signal */\n signal?: AbortSignal;\n}\n\n/** Options for creating a conversation */\nexport interface CreateConversationOptions {\n /**\n * Participant identifier — auto-detects agents vs users.\n *\n * Agent paths (e.g. `/agents/support` or `agent:support`) create an\n * `ai_chat` conversation. Anything else creates a `direct_message`.\n */\n participant: string;\n /** Optional subject line */\n subject?: string;\n /** Additional input data passed to the conversation */\n input?: Record<string, unknown>;\n /** Abort signal */\n signal?: AbortSignal;\n}\n\n/** Default inactivity timeout for sendMessage SSE streams (2 minutes) */\nexport const DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS = 120_000;\n\n/** Options for sending a message */\nexport interface SendMessageOptions {\n /** Whether to stream events via SSE (default: true) */\n stream?: boolean;\n /** Abort signal */\n signal?: AbortSignal;\n /**\n * Inactivity timeout for the per-turn SSE stream in milliseconds\n * (default: 120000). If the stream produces no bytes for this long,\n * the turn ends with a synthetic `waiting` event instead of hanging\n * forever. Set to 0 to disable.\n */\n inactivityTimeoutMs?: number;\n}\n\n/** Handle for a persistent conversation SSE subscription */\nexport interface ConversationSubscription {\n /** Close the SSE connection */\n unsubscribe(): void;\n /** Wait until the SSE connection is established */\n waitUntilConnected(): Promise<void>;\n}\n\n/** Immediate receipt for queued plan actions (non-blocking). */\nexport interface PlanActionReceipt {\n accepted: boolean;\n action: 'approve' | 'reject';\n actionId: string;\n planPath: string;\n executionId: string;\n jobId: string;\n status?: string;\n}\n\n/** Options for plan actions */\nexport interface PlanActionOptions {\n actionId?: string;\n requestTimeoutMs?: number;\n}\n\n/** Options for constructing the ConversationManager */\nexport interface ConversationManagerOptions {\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n /** Request timeout in milliseconds (default: 60000) */\n requestTimeout?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Internal type for SQL query response */\ninterface SqlQueryResponse {\n columns?: string[];\n rows?: Record<string, unknown>[];\n}\n\ninterface SqlInvokeReceipt {\n execution_id?: string;\n job_id?: string;\n}\n\n// ---------------------------------------------------------------------------\n// ConversationManager\n// ---------------------------------------------------------------------------\n\n/**\n * Unified conversation manager for RaisinDB.\n *\n * Handles the full lifecycle: listing, creating, opening, deleting, messaging,\n * streaming, and plan approval/rejection for all conversation types.\n */\nexport class ConversationManager {\n private baseUrl: string;\n private repository: string;\n private authManager: AuthManager;\n private fetchImpl: typeof fetch;\n private requestTimeout: number;\n\n private executeSql?: (query: string, params?: unknown[]) => Promise<SqlResult>;\n private cachedUserId?: string;\n private cachedUserHome?: string;\n\n constructor(\n baseUrl: string,\n repository: string,\n authManager: AuthManager,\n options: ConversationManagerOptions = {},\n executeSql?: (query: string, params?: unknown[]) => Promise<SqlResult>,\n ) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.repository = repository;\n this.authManager = authManager;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.requestTimeout = options.requestTimeout ?? 60000;\n this.executeSql = executeSql;\n }\n\n // ==========================================================================\n // User context\n // ==========================================================================\n\n private async ensureCurrentUser(): Promise<{ userId: string; userHome: string }> {\n if (this.cachedUserId && this.cachedUserHome) {\n return { userId: this.cachedUserId, userHome: this.cachedUserHome };\n }\n const result = await this.sqlQuery(\n `SELECT RAISIN_CURRENT_USER()->>'path'::String as home, RAISIN_CURRENT_USER()->>'id'::String as user_id`,\n );\n if (!result?.rows?.[0]) throw new Error('User not authenticated');\n const row = result.rows[0] as Record<string, unknown>;\n const userHome = normalizeHomePath(row.home as string);\n if (!userHome) throw new Error('User home path not found');\n this.cachedUserHome = userHome;\n this.cachedUserId = (row.user_id as string) || userHome;\n return { userId: this.cachedUserId, userHome };\n }\n\n // ==========================================================================\n // Conversation listing\n // ==========================================================================\n\n /**\n * List conversations for the current user.\n */\n async list(options?: ListConversationsOptions): Promise<ConversationListItem[]> {\n const workspace = 'raisin:access_control';\n const { userHome } = await this.ensureCurrentUser();\n\n const sql = `\n SELECT id, path, properties, created_at, updated_at\n FROM '${workspace}'\n WHERE node_type = 'raisin:Conversation'\n AND DESCENDANT_OF($1)\n ${options?.type ? \"AND properties->>'conversation_type'::String = $2\" : ''}\n ORDER BY updated_at DESC\n ${options?.limit ? `LIMIT ${options.limit}` : ''}\n `;\n const params = options?.type\n ? [`${userHome}/inbox/chats`, options.type]\n : [`${userHome}/inbox/chats`];\n const response = await this.sqlQuery(sql, params);\n\n if (!response || !Array.isArray(response.rows)) return [];\n\n const rows = response.rows as unknown as Record<string, unknown>[];\n return rows.map((row: any) => {\n const props = row.properties ?? {};\n return {\n id: row.id,\n type: (props.conversation_type as ConversationType) ?? 'ai_chat',\n conversationPath: row.path,\n conversationWorkspace: workspace,\n agentRef: props.agent_ref,\n participants: props.participants,\n unreadCount: props.unread_count,\n lastMessage: props.last_message,\n updatedAt: row.updated_at ?? row.created_at,\n } satisfies ConversationListItem;\n });\n }\n\n // ==========================================================================\n // Conversation lifecycle\n // ==========================================================================\n\n /**\n * Create a new conversation.\n *\n * `participant` auto-detects whether the target is an agent or a user:\n * - Paths starting with `/agents/` or `agent:` create an `ai_chat`\n * - Everything else creates a `direct_message`\n */\n async create(options: CreateConversationOptions): Promise<Conversation> {\n logger.info('[ConversationManager] Creating conversation', { participant: options.participant });\n const conversationId = `chat-${crypto.randomUUID()}`;\n const workspace = 'raisin:access_control';\n\n const recipientId = this.normalizeRecipientId(options.participant);\n const isAgent = recipientId.startsWith('agent:');\n const conversationType: ConversationType = isAgent ? 'ai_chat' : 'direct_message';\n const agentPath = isAgent ? this.normalizeAgentPath(options.participant) : undefined;\n\n const { userId, userHome } = await this.ensureCurrentUser();\n const conversationPath = `${userHome}/inbox/chats/${conversationId}`;\n\n await this.ensureFolderNode(workspace, `${userHome}/inbox`, 'Inbox');\n await this.ensureFolderNode(workspace, `${userHome}/inbox/chats`, 'Chats');\n\n const participants = [userId, recipientId].filter(Boolean);\n\n const properties: Record<string, unknown> = {\n conversation_type: conversationType,\n conversation_id: conversationId,\n subject: options.subject || 'Chat',\n participants,\n stream_channel: `chat:${conversationId}`,\n unread_count: 0,\n ...(agentPath ? {\n agent_ref: { 'raisin:path': agentPath, 'raisin:workspace': 'functions' },\n } : {}),\n ...(options.input ?? {}),\n };\n\n const sql = `\n INSERT INTO '${workspace}' (path, node_type, properties)\n VALUES ($1, 'raisin:Conversation', $2::jsonb)\n RETURNING id, path\n `;\n const result = await this.sqlQuery(sql, [conversationPath, JSON.stringify(properties)]);\n\n if (!result?.rows?.[0]) throw new Error('Failed to create conversation');\n\n const resultRow = result.rows[0] as Record<string, unknown>;\n const now = new Date().toISOString();\n\n logger.info('[ConversationManager] Conversation created', { path: conversationPath });\n\n return {\n id: resultRow.id as string,\n type: conversationType,\n agentRef: agentPath,\n participants,\n conversationPath,\n conversationWorkspace: workspace,\n initialEvents: [\n { type: 'conversation_created', conversationPath, workspace, timestamp: now },\n { type: 'waiting', timestamp: now },\n ],\n };\n }\n\n /**\n * Open an existing conversation by path.\n * Returns null if not found.\n */\n async open(conversationPath: string): Promise<Conversation | null> {\n const workspace = 'raisin:access_control';\n try {\n const sql = `SELECT id, path, properties, created_at FROM '${workspace}' WHERE path = $1 AND node_type = 'raisin:Conversation' LIMIT 1`;\n const response = await this.sqlQuery(sql, [conversationPath]);\n\n if (!response || !Array.isArray(response.rows) || response.rows.length === 0) {\n return null;\n }\n\n const rows = response.rows as unknown as Record<string, unknown>[];\n const row = rows[0];\n const props = (row.properties ?? {}) as Record<string, unknown>;\n\n return {\n id: row.id as string,\n type: (props.conversation_type as ConversationType) ?? 'ai_chat',\n agentRef: props.agent_ref as string | undefined,\n participants: props.participants as string[] | undefined,\n participantDetails: props.participant_details as Record<string, { display_name: string }> | undefined,\n unreadCount: props.unread_count as number | undefined,\n lastMessage: props.last_message as { content: string; sender_id: string; created_at: string } | undefined,\n conversationPath,\n conversationWorkspace: workspace,\n initialEvents: [{ type: 'waiting', timestamp: new Date().toISOString() }],\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Delete a conversation and all its children.\n */\n async delete(conversationPath: string): Promise<void> {\n const workspace = 'raisin:access_control';\n await this.sqlQuery(\n `DELETE FROM '${workspace}' WHERE path = $1 OR path LIKE $2`,\n [conversationPath, `${conversationPath}/%`],\n );\n }\n\n /**\n * Mark a conversation as read by setting unread_count to 0.\n */\n async markAsRead(conversationPath: string): Promise<void> {\n const workspace = 'raisin:access_control';\n await this.sqlQuery(\n `UPDATE '${workspace}' SET properties = jsonb_set(properties, '{unread_count}', '0'::jsonb) WHERE path = $1 AND node_type = 'raisin:Conversation'`,\n [conversationPath],\n );\n }\n\n /**\n * Mark a single message as read by the current user.\n */\n async markMessageAsRead(messagePath: string): Promise<void> {\n const workspace = 'raisin:access_control';\n const now = new Date().toISOString();\n await this.sqlQuery(\n `UPDATE '${workspace}' SET properties = jsonb_set(properties, '{read_at}', $2::jsonb) WHERE path = $1 AND node_type = 'raisin:Message'`,\n [messagePath, JSON.stringify(now)],\n );\n }\n\n // ==========================================================================\n // Messaging\n // ==========================================================================\n\n /**\n * Get the full message history for a conversation.\n */\n async getMessages(conversationPath: string): Promise<ChatMessage[]> {\n return this.getMessagesFromNodeTree(conversationPath);\n }\n\n /**\n * Send a message to a conversation.\n *\n * Returns an `AsyncIterable<ChatEvent>` for streaming. By default streams\n * via SSE. Set `options.stream = false` to fire-and-forget.\n */\n async *sendMessage(\n conversationPath: string,\n content: string,\n options?: SendMessageOptions,\n ): AsyncIterable<ChatEvent> {\n const shouldStream = options?.stream !== false;\n\n logger.debug('[ConversationManager] Starting SSE stream for message send');\n\n if (!shouldStream) {\n await this.createUserMessage(conversationPath, content);\n yield { type: 'waiting', timestamp: new Date().toISOString() };\n return;\n }\n\n const workspace = 'raisin:access_control';\n const streamTarget = await this.resolveConversationStreamTarget(conversationPath, workspace);\n\n // Subscribe to SSE BEFORE creating the message so we don't miss events.\n const sseUrl = `${this.baseUrl}/api/conversations/${this.repository}/events`;\n const headers: Record<string, string> = {};\n const token = this.authManager.getAccessToken();\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n const sse = new SSEClient<ChatEvent>(sseUrl, {\n headers,\n eventTypes: ['conversation-event', 'message'],\n reconnect: { enabled: false },\n fetch: this.fetchImpl,\n signal: options?.signal,\n method: 'POST',\n body: { channel: streamTarget.channel, path: streamTarget.path },\n inactivityTimeoutMs:\n options?.inactivityTimeoutMs ?? DEFAULT_SEND_MESSAGE_INACTIVITY_TIMEOUT_MS,\n });\n\n const iterator = sse[Symbol.asyncIterator]();\n let pendingFirst: Promise<IteratorResult<{ type: string; data: ChatEvent }>> | null = iterator.next();\n\n try {\n await sse.waitUntilConnected();\n } catch {\n // Avoid an unhandled rejection if the iterator errors after we bail\n pendingFirst?.catch(() => undefined);\n pendingFirst = null;\n sse.close();\n logger.debug('SSE connection failed, falling back to create-only');\n }\n\n // Create the user message node\n try {\n await this.createUserMessage(conversationPath, content);\n } catch (error) {\n logger.error('[ConversationManager] Failed to create user message', error);\n sse.close();\n throw error;\n }\n\n // Stream events from SSE\n if (pendingFirst) {\n try {\n while (true) {\n let result;\n if (pendingFirst) {\n result = await pendingFirst;\n pendingFirst = null;\n } else {\n result = await iterator.next();\n }\n\n if (result.done) break;\n\n const event = result.value.data;\n if (isRecoveredDoneEvent(event)) {\n logger.debug('[ConversationManager] Ignoring recovered done event while turn may still be active');\n continue;\n }\n if (event.type === 'done' && event.dispatchPhase && event.dispatchPhase !== 'terminal') {\n logger.debug('[ConversationManager] Ignoring non-terminal done event');\n continue;\n }\n yield event;\n\n if (event.type === 'done' || event.type === 'completed' || event.type === 'failed' || event.type === 'waiting') {\n return;\n }\n }\n } catch (error) {\n if (error instanceof RaisinTimeoutError && error.code === 'SSE_INACTIVITY_TIMEOUT') {\n // The SSE stream went silent mid-turn. End the turn gracefully so\n // chat UIs don't hang; the persistent subscription / message reload\n // will pick up any late events.\n logger.warn(\n `[ConversationManager] SSE stream inactive for ${error.timeoutMs}ms, ending turn with synthetic waiting event`,\n );\n yield { type: 'waiting', timestamp: new Date().toISOString() };\n return;\n }\n throw error;\n } finally {\n sse.close();\n }\n }\n\n yield { type: 'waiting', timestamp: new Date().toISOString() };\n }\n\n /**\n * Create a user message in a conversation.\n *\n * The message node triggers server-side handlers (via triggers);\n * events arrive via the persistent subscription.\n */\n async createUserMessage(conversationPath: string, content: string): Promise<void> {\n logger.debug('[ConversationManager] Creating user message', { path: conversationPath });\n const workspace = 'raisin:access_control';\n const { userId, userHome } = await this.ensureCurrentUser();\n const messageId = crypto.randomUUID();\n\n const properties = await this.loadConversationProperties(conversationPath, workspace);\n const participants = Array.isArray(properties?.participants)\n ? (properties.participants as unknown[])\n : [];\n let recipientId = participants.find((p) =>\n typeof p === 'string' && p.length > 0 && p !== userId && p !== userHome\n ) as string | undefined;\n if (recipientId) recipientId = this.normalizeRecipientId(recipientId);\n\n const conversationId = (typeof properties?.conversation_id === 'string' && properties.conversation_id.length > 0)\n ? (properties.conversation_id as string)\n : conversationPath.split('/').pop() || '';\n\n if (!recipientId) {\n throw new Error(`Conversation recipient not found for ${conversationPath}`);\n }\n\n const messagePath = `${userHome}/outbox/msg-${messageId}`;\n const outboxProperties = {\n role: 'user',\n message_type: 'chat',\n status: 'pending',\n sender_id: userId,\n sender_path: userHome,\n recipient_id: recipientId,\n body: { content, message_text: content, thread_id: conversationId },\n conversation_id: conversationId,\n client_id: messageId,\n created_at: new Date().toISOString(),\n };\n\n await this.sqlQuery(\n `INSERT INTO '${workspace}' (path, node_type, properties) VALUES ($1, 'raisin:Message', $2::jsonb) RETURNING id`,\n [messagePath, JSON.stringify(outboxProperties)],\n );\n }\n\n // ==========================================================================\n // Persistent subscription\n // ==========================================================================\n\n /**\n * Subscribe to a conversation's events via a persistent SSE connection.\n *\n * Keeps a long-lived connection that survives across turns. Useful for\n * receiving async events between turns (background tool results, agent-\n * initiated messages, etc.). Auto-reconnects on disconnect.\n */\n subscribe(\n conversationPath: string,\n onEvent: (event: ChatEvent) => void,\n options?: { signal?: AbortSignal },\n ): ConversationSubscription {\n logger.info('[ConversationManager] Subscribing to SSE', { path: conversationPath });\n const sseUrl = `${this.baseUrl}/api/conversations/${this.repository}/events`;\n const headers: Record<string, string> = {};\n const token = this.authManager.getAccessToken();\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n let sse: SSEClient<ChatEvent> | null = null;\n let unsubscribed = false;\n\n const setupPromise = (async () => {\n const streamTarget = await this.resolveConversationStreamTarget(conversationPath);\n if (unsubscribed) return null;\n\n sse = new SSEClient<ChatEvent>(sseUrl, {\n headers,\n eventTypes: ['conversation-event', 'message'],\n reconnect: { enabled: true },\n fetch: this.fetchImpl,\n signal: options?.signal,\n method: 'POST',\n body: { channel: streamTarget.channel, path: streamTarget.path },\n });\n\n sse.connect(\n (sseEvent) => onEvent(sseEvent.data),\n (error) => logger.error('Conversation SSE error:', error.message),\n );\n return sse;\n })();\n\n return {\n unsubscribe: () => {\n unsubscribed = true;\n sse?.close();\n },\n waitUntilConnected: async () => {\n const activeSse = await setupPromise;\n if (!activeSse) return;\n await activeSse.waitUntilConnected();\n },\n };\n }\n\n // ==========================================================================\n // Plan actions\n // ==========================================================================\n\n /**\n * Approve a pending plan without waiting for completion.\n * Returns an enqueue receipt; final state is observed via conversation events.\n */\n async approvePlan(planPath: string, options?: PlanActionOptions): Promise<PlanActionReceipt> {\n logger.info('[ConversationManager] Plan action: approve', { path: planPath });\n return this.invokePlanAction('approve', planPath, undefined, options);\n }\n\n /**\n * Reject a pending plan without waiting for completion.\n */\n async rejectPlan(planPath: string, feedback?: string, options?: PlanActionOptions): Promise<PlanActionReceipt> {\n logger.info('[ConversationManager] Plan action: reject', { path: planPath });\n return this.invokePlanAction('reject', planPath, feedback, options);\n }\n\n // ==========================================================================\n // One-shot convenience\n // ==========================================================================\n\n /**\n * One-shot chat: create a conversation, send a message, return response.\n */\n async chat(\n participant: string,\n message: string,\n options?: { signal?: AbortSignal; input?: Record<string, unknown> },\n ): Promise<{ response: string; conversationPath: string }> {\n const convo = await this.create({\n participant,\n input: options?.input,\n signal: options?.signal,\n });\n\n let response = '';\n for await (const event of this.sendMessage(convo.conversationPath, message, {\n signal: options?.signal,\n stream: true,\n })) {\n if (event.type === 'text_chunk') response += event.text;\n }\n\n return { response, conversationPath: convo.conversationPath };\n }\n\n // ==========================================================================\n // Health checks (used by ConversationStore watchdog)\n // ==========================================================================\n\n /**\n * Query pending (in-flight) tool calls from the node tree.\n * Used by ConversationStore to rebuild `_activeToolCalls` on reload.\n */\n async getActiveToolCalls(\n conversationPath: string,\n ): Promise<{ id: string; name: string; status: string }[]> {\n const workspace = 'raisin:access_control';\n const sql = `\n SELECT id, properties->>'function_name'::String as name, properties->>'status'::String as status\n FROM '${workspace}'\n WHERE DESCENDANT_OF($1)\n AND node_type = 'raisin:AIToolCall'\n AND properties->>'status'::String IN ('pending', 'running')\n ORDER BY created_at ASC\n `;\n try {\n const response = await this.sqlQuery(sql, [conversationPath]);\n if (!response?.rows || !Array.isArray(response.rows)) return [];\n return (response.rows as any[]).map((row: any) => ({\n id: row.id ?? '',\n name: row.name ?? '',\n status: row.status ?? 'pending',\n }));\n } catch {\n return [];\n }\n }\n\n /**\n * Check the health of the latest assistant turn.\n * Returns 'streaming' if the turn appears active, 'done' if it's finished,\n * or 'unknown' if no assistant message is found.\n */\n async checkTurnHealth(\n conversationPath: string,\n ): Promise<'streaming' | 'done' | 'unknown'> {\n const workspace = 'raisin:access_control';\n const sql = `\n SELECT properties->>'status'::String as status,\n properties->>'finish_reason'::String as finish_reason,\n properties->>'dispatch_phase'::String as dispatch_phase\n FROM '${workspace}'\n WHERE CHILD_OF($1)\n AND node_type = 'raisin:Message'\n AND properties->>'role'::String = 'assistant'\n ORDER BY created_at DESC LIMIT 1\n `;\n try {\n const response = await this.sqlQuery(sql, [conversationPath]);\n if (!response?.rows || !Array.isArray(response.rows) || response.rows.length === 0) {\n return 'unknown';\n }\n const row = response.rows[0] as Record<string, unknown>;\n const finishReason = row.finish_reason as string | undefined;\n const dispatchPhase = row.dispatch_phase as string | undefined;\n if (dispatchPhase) {\n return dispatchPhase === 'terminal' ? 'done' : 'streaming';\n }\n // If the message has a terminal finish_reason, the turn is done\n if (finishReason && finishReason !== 'tool_calls') {\n return 'done';\n }\n return 'streaming';\n } catch {\n return 'unknown';\n }\n }\n\n // ==========================================================================\n // Internal: message loading from node tree\n // ==========================================================================\n\n private async getMessagesFromNodeTree(conversationPath: string, workspace?: string): Promise<ChatMessage[]> {\n const ws = workspace ?? 'raisin:access_control';\n\n const [msgResponse, childResponse] = await Promise.all([\n this.sqlQuery(\n `SELECT id, path, name, properties, created_at FROM '${ws}' WHERE CHILD_OF('${conversationPath}') AND node_type = 'raisin:Message' AND (properties->>'message_type'::String IS NULL OR properties->>'message_type'::String NOT IN ('ai_tool_call', 'ai_tool_result', 'ai_thought')) ORDER BY created_at ASC`,\n ),\n this.sqlQuery(\n `SELECT id, path, name, node_type, properties, created_at FROM '${ws}' WHERE DESCENDANT_OF('${conversationPath}') AND node_type IN ('raisin:AIPlan', 'raisin:AITask', 'raisin:AIThought', 'raisin:AICostRecord') ORDER BY created_at ASC`,\n ),\n ]);\n\n if (!msgResponse || !Array.isArray(msgResponse.rows)) return [];\n\n // Group child nodes by parent message path; collect tasks separately\n const childrenByMsg = new Map<string, MessageChild[]>();\n const tasksByPlan = new Map<string, PlanTask[]>();\n const planByPath = new Map<string, MessageChild>();\n\n for (const row of ((childResponse?.rows ?? []) as any[])) {\n const parts = (row.path as string).split('/');\n\n if (row.node_type === 'raisin:AITask') {\n const planPath = parts.slice(0, -1).join('/');\n const tasks = tasksByPlan.get(planPath) ?? [];\n tasks.push({\n id: row.id,\n title: row.properties?.title ?? row.name,\n status: row.properties?.status ?? 'pending',\n });\n tasksByPlan.set(planPath, tasks);\n continue;\n }\n\n const msgPath = parts.slice(0, -1).join('/');\n const children = childrenByMsg.get(msgPath) ?? [];\n const child: MessageChild = {\n id: row.id,\n path: row.path,\n type:\n row.node_type === 'raisin:AIPlan'\n ? 'plan'\n : row.node_type === 'raisin:AICostRecord'\n ? 'cost'\n : 'thought',\n content: row.properties?.content ?? '',\n status: row.properties?.status ?? 'completed',\n };\n if (child.type === 'plan') {\n child.planTitle = row.properties?.title;\n child.toolName = 'create_plan';\n planByPath.set(row.path, child);\n } else if (child.type === 'cost') {\n const inputTokens = Number(row.properties?.input_tokens ?? 0);\n const outputTokens = Number(row.properties?.output_tokens ?? 0);\n const totalTokens = Number(row.properties?.total_tokens ?? (inputTokens + outputTokens));\n const costUsdRaw = Number(row.properties?.cost_usd);\n const durationMsRaw = Number(row.properties?.duration_ms);\n child.model = row.properties?.model ?? undefined;\n child.provider = row.properties?.provider ?? undefined;\n child.inputTokens = Number.isFinite(inputTokens) ? inputTokens : 0;\n child.outputTokens = Number.isFinite(outputTokens) ? outputTokens : 0;\n child.totalTokens = Number.isFinite(totalTokens) ? totalTokens : 0;\n child.costUsd = Number.isFinite(costUsdRaw) ? costUsdRaw : undefined;\n child.durationMs = Number.isFinite(durationMsRaw) ? durationMsRaw : undefined;\n child.content = `tokens: ${child.totalTokens ?? 0}`;\n }\n children.push(child);\n childrenByMsg.set(msgPath, children);\n }\n\n for (const [planPath, tasks] of tasksByPlan) {\n const plan = planByPath.get(planPath);\n if (plan) plan.tasks = tasks;\n }\n\n // Filter out empty intermediate continuation messages and tool-echo messages\n const filteredRows = (msgResponse.rows as any[]).filter((row: any) => {\n const props = row.properties ?? {};\n const msgContent = props.content\n ?? (typeof props.body === 'string' ? props.body : props.body?.content)\n ?? '';\n const finishReason = props.finish_reason ?? '';\n const msgType = props.message_type ?? '';\n\n // Skip empty messages with finish_reason=tool_calls (intermediate continuations)\n if (!msgContent.trim() && finishReason === 'tool_calls') return false;\n\n // Skip tool-echo messages like \"Calling update-task\"\n if (msgType === 'chat' && /^Calling\\s+[\\w-]+\\s*$/.test(msgContent.trim())) return false;\n\n return true;\n });\n\n return filteredRows.map((row: any) => {\n const props = row.properties ?? {};\n const message: ChatMessage = {\n role: props.role ?? 'assistant',\n content: props.content\n ?? (typeof props.body === 'string' ? props.body : props.body?.content)\n ?? props.data?.content\n ?? '',\n timestamp: row.created_at ?? new Date().toISOString(),\n id: row.id,\n path: row.path,\n children: childrenByMsg.get(row.path),\n };\n\n if (props.agent) message.agent = props.agent;\n if (props.finish_reason) message.finishReason = props.finish_reason;\n if (typeof props.dispatch_phase === 'string') {\n message.dispatchPhase = props.dispatch_phase as ChatMessage['dispatchPhase'];\n }\n if (typeof props.orchestration_mode === 'string') {\n message.orchestrationMode = props.orchestration_mode as ChatMessage['orchestrationMode'];\n }\n if (typeof props.orchestration_round === 'number') {\n message.orchestrationRound = props.orchestration_round;\n }\n if (props.terminal_reason_internal !== undefined) {\n message.terminalReasonInternal = (props.terminal_reason_internal ?? null) as string | null;\n }\n if (props.sender_id) message.senderId = props.sender_id;\n if (props.sender_display_name) message.senderDisplayName = props.sender_display_name;\n if (props.status) message.status = props.status;\n if (props.message_type) message.messageType = props.message_type;\n if (props.data && typeof props.data === 'object' && !Array.isArray(props.data)) {\n message.data = props.data as Record<string, unknown>;\n }\n\n if (Array.isArray(props.tool_calls) && props.tool_calls.length > 0) {\n message.toolCalls = props.tool_calls.map((tc: any) => ({\n id: tc.id ?? '',\n name: tc.name ?? tc.function?.name ?? '',\n arguments: tc.arguments ?? tc.function?.arguments,\n } satisfies ToolCallRecord));\n }\n\n if (props.tool_call_id) message.toolCallId = props.tool_call_id;\n\n if (Array.isArray(props.children) && props.children.length > 0) {\n const inlineChildren: MessageChild[] = props.children.map((c: any) => ({\n id: c.id ?? '',\n path: c.path,\n type: c.type ?? 'thought',\n content: c.content ?? '',\n toolName: c.tool_name,\n toolInput: c.tool_input,\n status: c.status,\n model: c.model,\n provider: c.provider,\n inputTokens: c.input_tokens,\n outputTokens: c.output_tokens,\n totalTokens: c.total_tokens,\n costUsd: c.cost_usd,\n durationMs: c.duration_ms,\n } satisfies MessageChild));\n message.children = [...(message.children ?? []), ...inlineChildren];\n }\n\n return message;\n });\n }\n\n // ==========================================================================\n // Internal: plan action\n // ==========================================================================\n\n private async invokePlanAction(\n action: 'approve' | 'reject',\n planPath: string,\n feedback: string | undefined,\n options?: PlanActionOptions,\n ): Promise<PlanActionReceipt> {\n const actionId = options?.actionId?.trim() || crypto.randomUUID();\n const payload: Record<string, unknown> = {\n action,\n plan_path: planPath,\n plan_action_id: actionId,\n };\n if (action === 'reject' && feedback?.trim()) {\n payload.feedback = feedback.trim();\n }\n\n const query = await this.sqlQuery(\n `SELECT INVOKE($1, $2::jsonb, $3) AS invoke`,\n ['/lib/raisin/ai/plan-approval-handler', JSON.stringify(payload), 'functions'],\n );\n const row = query?.rows?.[0] as Record<string, unknown> | undefined;\n const invoke = (row?.invoke ?? row?.INVOKE ?? null) as SqlInvokeReceipt | string | null;\n\n let receipt: SqlInvokeReceipt | null = null;\n if (invoke && typeof invoke === 'object') {\n receipt = invoke;\n } else if (typeof invoke === 'string' && invoke.trim()) {\n try { receipt = JSON.parse(invoke) as SqlInvokeReceipt; }\n catch { throw new Error(`Invalid SQL INVOKE receipt payload: ${invoke}`); }\n }\n\n if (!receipt?.job_id || !receipt?.execution_id) {\n throw new Error('Plan action was not accepted by the backend queue');\n }\n\n return {\n accepted: true,\n action,\n actionId,\n planPath,\n executionId: receipt.execution_id,\n jobId: receipt.job_id,\n status: 'scheduled',\n };\n }\n\n // ==========================================================================\n // Internal: HTTP + SQL helpers\n // ==========================================================================\n\n private async httpRequest<T>(options: {\n method: string;\n path: string;\n body?: unknown;\n signal?: AbortSignal;\n timeoutMs?: number;\n }): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\n const token = this.authManager.getAccessToken();\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n const controller = new AbortController();\n const requestTimeout = options.timeoutMs ?? this.requestTimeout;\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n if (options.signal) {\n if (options.signal.aborted) {\n clearTimeout(timeoutId);\n throw new RaisinAbortError();\n }\n options.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n } catch { errorMessage = errorText || `HTTP ${response.status}: ${response.statusText}`; }\n throw classifyHttpError(response.status, errorMessage);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) return (await response.json()) as T;\n return undefined as unknown as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof RaisinAbortError || error instanceof RaisinTimeoutError) throw error;\n if (error instanceof Error && error.name === 'AbortError') {\n if (options.signal?.aborted) throw new RaisinAbortError();\n throw new RaisinTimeoutError(`Request timeout after ${requestTimeout}ms`, 'REQUEST_TIMEOUT', requestTimeout);\n }\n throw error;\n }\n }\n\n private async sqlQuery(sql: string, params?: unknown[]): Promise<SqlQueryResponse> {\n if (this.executeSql) {\n const result = await this.executeSql(sql, params);\n return { columns: result.columns, rows: result.rows as unknown as Record<string, unknown>[] };\n }\n return this.httpRequest<SqlQueryResponse>({\n method: 'POST',\n path: `/api/sql/${this.repository}/query`,\n body: { sql, params },\n });\n }\n\n private async resolveConversationStreamTarget(\n conversationPath: string,\n workspace = 'raisin:access_control',\n ): Promise<{ channel: string; path: string }> {\n try {\n const result = await this.sqlQuery(\n `SELECT properties FROM '${workspace}' WHERE path = $1 AND node_type = 'raisin:Conversation' LIMIT 1`,\n [conversationPath],\n );\n const row = result?.rows?.[0] as Record<string, unknown> | undefined;\n const properties = (row?.properties ?? {}) as Record<string, unknown>;\n const streamChannel = properties.stream_channel;\n if (typeof streamChannel === 'string' && streamChannel.length > 0) {\n return { channel: streamChannel, path: conversationPath };\n }\n const conversationId = typeof properties.conversation_id === 'string'\n ? properties.conversation_id\n : (conversationPath.split('/').pop() || '');\n if (conversationId) return { channel: `chat:${conversationId}`, path: conversationPath };\n } catch (error) {\n logger.debug('Failed to resolve conversation stream channel, deriving from path', error);\n }\n const conversationId = conversationPath.split('/').pop() || conversationPath;\n return { channel: `chat:${conversationId}`, path: conversationPath };\n }\n\n private async loadConversationProperties(\n conversationPath: string,\n workspace = 'raisin:access_control',\n ): Promise<Record<string, unknown> | null> {\n const result = await this.sqlQuery(\n `SELECT properties FROM '${workspace}' WHERE path = $1 AND node_type = 'raisin:Conversation' LIMIT 1`,\n [conversationPath],\n );\n const row = result?.rows?.[0] as Record<string, unknown> | undefined;\n if (!row) return null;\n return (row.properties ?? null) as Record<string, unknown> | null;\n }\n\n private normalizeRecipientId(participant: string): string {\n if (participant.startsWith('agent:')) return participant;\n if (participant.startsWith('/agents/')) {\n const parts = participant.split('/').filter(Boolean);\n if (parts.length >= 2) return `agent:${parts[1]}`;\n }\n return participant;\n }\n\n private normalizeAgentPath(participant: string): string {\n if (participant.startsWith('/agents/')) return participant;\n if (participant.startsWith('agent:')) return `/agents/${participant.slice('agent:'.length)}`;\n return participant;\n }\n\n private async ensureFolderNode(workspace: string, path: string, title: string): Promise<void> {\n await this.sqlQuery(\n `UPSERT INTO '${workspace}' (path, node_type, properties) VALUES ($1, 'raisin:Folder', $2::jsonb)`,\n [path, JSON.stringify({ title })],\n );\n }\n}\n","/**\n * FlowClient for executing and monitoring RaisinDB flows.\n *\n * Provides methods to:\n * - Run a flow by path and receive an instance ID\n * - Stream real-time execution events via SSE\n * - Resume a waiting flow with external data\n * - Respond to human tasks within a flow\n *\n * @example\n * ```typescript\n * import { RaisinHttpClient } from '@raisindb/client';\n * import { FlowClient } from '@raisindb/client/flow-client';\n *\n * const httpClient = new RaisinHttpClient('http://localhost:8081');\n * await httpClient.authenticate({ username: 'admin', password: 'admin' });\n *\n * const flows = new FlowClient(httpClient, 'my-repo');\n *\n * // Start a flow\n * const { instance_id } = await flows.run('/flows/my-flow', { key: 'value' });\n *\n * // Stream events\n * for await (const event of flows.streamEvents(instance_id)) {\n * console.log(event.type, event);\n * if (event.type === 'flow_completed') break;\n * }\n * ```\n */\n\nimport type { AuthManager } from './auth';\nimport type { FlowsApi } from './flows';\nimport type {\n FlowRunResponse,\n FlowExecutionEvent,\n FlowInstanceStatusResponse,\n FlowCompletedEvent,\n FlowFailedEvent,\n} from './types/flow';\nimport { SSEClient, type SSEEvent } from './streaming/sse-client';\nimport {\n classifyHttpError,\n RaisinAbortError,\n RaisinTimeoutError,\n} from './errors';\n\n/** Options for creating a FlowClient */\nexport interface FlowClientOptions {\n /** Request timeout in milliseconds (default: 60000 for long-running flows) */\n requestTimeout?: number;\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n}\n\n/** Result from `runAndWait()` */\nexport interface FlowRunResult {\n /** Flow instance ID */\n instanceId: string;\n /** Terminal status */\n status: 'completed' | 'failed';\n /** Flow output (when completed) */\n output?: unknown;\n /** Error message (when failed) */\n error?: string;\n}\n\n/** Result from `runAndCollect()` */\nexport interface FlowCollectResult {\n /** Flow instance ID */\n instanceId: string;\n /** All collected events */\n events: FlowExecutionEvent[];\n}\n\n/**\n * Minimal interface the FlowClient needs from the HTTP client.\n * This avoids a hard dependency on the full RaisinHttpClient class.\n */\ninterface HttpClientLike {\n /** Get the auth manager for token access */\n getAuthManager(): AuthManager;\n}\n\n/**\n * Client for executing and monitoring RaisinDB flows.\n *\n * Uses the HTTP REST API for flow operations and SSE for real-time event streaming.\n */\nexport class FlowClient {\n private baseUrl: string;\n private repository: string;\n private authManager: AuthManager;\n private fetchImpl: typeof fetch;\n private requestTimeout: number;\n private flowsApi?: FlowsApi;\n\n /**\n * Create a new FlowClient.\n *\n * @param baseUrl - Base HTTP URL of the RaisinDB server (e.g., \"http://localhost:8081\")\n * @param repository - Repository name\n * @param authManager - Auth manager for token access\n * @param options - Additional options\n * @param flowsApi - Optional FlowsApi for WebSocket-based flow operations\n */\n constructor(\n baseUrl: string,\n repository: string,\n authManager: AuthManager,\n options: FlowClientOptions = {},\n flowsApi?: FlowsApi,\n ) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.repository = repository;\n this.authManager = authManager;\n this.fetchImpl = options.fetch ?? fetch;\n this.requestTimeout = options.requestTimeout ?? 60000;\n this.flowsApi = flowsApi;\n }\n\n /**\n * Create a FlowClient from an existing RaisinHttpClient.\n *\n * @param httpClient - An authenticated RaisinHttpClient instance\n * @param baseUrl - Base HTTP URL (same as the one used for the HTTP client)\n * @param repository - Repository name\n * @param options - Additional options\n */\n static fromHttpClient(\n httpClient: HttpClientLike,\n baseUrl: string,\n repository: string,\n options: FlowClientOptions = {},\n flowsApi?: FlowsApi,\n ): FlowClient {\n return new FlowClient(\n baseUrl,\n repository,\n httpClient.getAuthManager(),\n options,\n flowsApi,\n );\n }\n\n // ==========================================================================\n // Flow Execution\n // ==========================================================================\n\n /**\n * Execute a flow by path.\n *\n * Creates a FlowInstance and queues it for execution. Returns immediately\n * with the instance ID - use `streamEvents()` to monitor progress.\n *\n * @param flowPath - Path to the raisin:Flow node (e.g., \"/flows/my-flow\")\n * @param input - Input data passed to the flow\n * @returns Flow run response with instance_id and job_id\n *\n * @example\n * ```typescript\n * const result = await flows.run('/flows/process-order', {\n * orderId: 'ord-123',\n * items: [{ sku: 'ABC', qty: 2 }],\n * });\n * console.log('Instance:', result.instance_id);\n * ```\n */\n async run(\n flowPath: string,\n input: Record<string, unknown> = {},\n options?: { signal?: AbortSignal },\n ): Promise<FlowRunResponse> {\n if (this.flowsApi) {\n return this.flowsApi.run(flowPath, input);\n }\n const response = await this.request<FlowRunResponse>({\n method: 'POST',\n path: `/api/flows/${this.repository}/run`,\n body: { flow_path: flowPath, input },\n signal: options?.signal,\n });\n return response;\n }\n\n // ==========================================================================\n // Instance Status\n // ==========================================================================\n\n /**\n * Get the current status of a flow instance.\n *\n * Returns the instance status, variables, and metadata. Useful for\n * polling-based approaches where SSE is not reliable (e.g., initial\n * flow execution where events may be missed).\n *\n * @param instanceId - Flow instance ID (from `run()`)\n * @returns Instance status including variables and flow path\n *\n * @example\n * ```typescript\n * const status = await flows.getInstanceStatus('instance-123');\n * console.log('Status:', status.status); // 'waiting', 'completed', etc.\n * ```\n */\n async getInstanceStatus(\n instanceId: string,\n options?: { signal?: AbortSignal },\n ): Promise<FlowInstanceStatusResponse> {\n if (this.flowsApi) {\n return this.flowsApi.getInstanceStatus(instanceId);\n }\n return this.request<FlowInstanceStatusResponse>({\n method: 'GET',\n path: `/api/flows/${this.repository}/instances/${instanceId}`,\n signal: options?.signal,\n });\n }\n\n // ==========================================================================\n // Event Streaming (SSE)\n // ==========================================================================\n\n /**\n * Stream real-time execution events for a flow instance via SSE.\n *\n * Returns an async iterable that yields FlowExecutionEvent objects.\n * The stream automatically closes when a terminal event is received\n * (flow_completed or flow_failed).\n *\n * @param instanceId - Flow instance ID (from `run()`)\n * @returns Async iterable of flow execution events\n *\n * @example\n * ```typescript\n * const { instance_id } = await flows.run('/flows/my-flow', { key: 'value' });\n *\n * for await (const event of flows.streamEvents(instance_id)) {\n * switch (event.type) {\n * case 'step_started':\n * console.log(`Step ${event.node_id} started`);\n * break;\n * case 'step_completed':\n * console.log(`Step ${event.node_id} completed in ${event.duration_ms}ms`);\n * break;\n * case 'text_chunk':\n * process.stdout.write(event.text);\n * break;\n * case 'flow_completed':\n * console.log('Flow done:', event.output);\n * break;\n * case 'flow_failed':\n * console.error('Flow failed:', event.error);\n * break;\n * }\n * }\n * ```\n */\n async *streamEvents(\n instanceId: string,\n options?: { signal?: AbortSignal },\n ): AsyncIterable<FlowExecutionEvent> {\n if (this.flowsApi) {\n const sub = await this.flowsApi.subscribeEvents(instanceId);\n try {\n for await (const event of sub.events) {\n if (options?.signal?.aborted) throw new RaisinAbortError();\n yield event;\n if (event.type === 'flow_completed' || event.type === 'flow_failed') {\n return;\n }\n }\n } finally {\n await sub.unsubscribe();\n }\n return;\n }\n const url = `${this.baseUrl}/api/flows/${this.repository}/instances/${instanceId}/events`;\n const headers: Record<string, string> = {};\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const sse = new SSEClient<FlowExecutionEvent>(url, {\n headers,\n eventTypes: ['flow-event', 'message'],\n reconnect: { enabled: false },\n fetch: this.fetchImpl,\n signal: options?.signal,\n });\n\n try {\n for await (const sseEvent of sse) {\n const event = sseEvent.data;\n yield event;\n\n // Stop on terminal events\n if (\n event.type === 'flow_completed' ||\n event.type === 'flow_failed'\n ) {\n return;\n }\n }\n } finally {\n sse.close();\n }\n }\n\n /**\n * Create an eagerly-connected event stream for a flow instance.\n *\n * Unlike `streamEvents()` (a lazy async generator), this method opens the\n * SSE connection immediately and waits until it is established before\n * returning. This is critical for resume flows: you must subscribe to\n * events BEFORE calling `resume()`, otherwise events emitted between\n * the resume and the SSE connection are lost.\n *\n * @param instanceId - Flow instance ID\n * @returns Object with an async iterable `events` and a `close()` method\n */\n async createEventStream(\n instanceId: string,\n options?: { signal?: AbortSignal },\n ): Promise<{\n events: AsyncIterable<FlowExecutionEvent>;\n close: () => void;\n }> {\n if (this.flowsApi) {\n const sub = await this.flowsApi.subscribeEvents(instanceId);\n return {\n events: sub.events,\n close: () => { sub.unsubscribe(); },\n };\n }\n const url = `${this.baseUrl}/api/flows/${this.repository}/instances/${instanceId}/events`;\n const headers: Record<string, string> = {};\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const sse = new SSEClient<FlowExecutionEvent>(url, {\n headers,\n eventTypes: ['flow-event', 'message'],\n reconnect: { enabled: false },\n fetch: this.fetchImpl,\n signal: options?.signal,\n });\n\n // Kick-start the async generator to initiate the SSE connection.\n // Async generators are lazy — the body (which calls startStream)\n // only executes when .next() is called.\n const iterator = sse[Symbol.asyncIterator]();\n let pendingFirst: Promise<IteratorResult<SSEEvent<FlowExecutionEvent>>> | null = iterator.next();\n\n // Now that startStream is running, wait for the HTTP response\n await sse.waitUntilConnected();\n\n // Wrap in a terminal-event-aware iterable\n const events: AsyncIterable<FlowExecutionEvent> = {\n [Symbol.asyncIterator]() {\n return {\n async next() {\n let result;\n if (pendingFirst) {\n result = await pendingFirst;\n pendingFirst = null;\n } else {\n result = await iterator.next();\n }\n if (result.done) return { done: true as const, value: undefined };\n const event = result.value.data;\n return { done: false, value: event };\n },\n async return() {\n await iterator.return?.();\n sse.close();\n return { done: true as const, value: undefined };\n },\n };\n },\n };\n\n return { events, close: () => sse.close() };\n }\n\n // ==========================================================================\n // Flow Resume & Human Task\n // ==========================================================================\n\n /**\n * Resume a flow instance that is in a waiting state.\n *\n * Use this when a flow is waiting for external input (tool results,\n * external events, etc.). The resume data is passed to the waiting step.\n *\n * @param instanceId - Flow instance ID\n * @param data - Resume data to pass to the waiting step\n *\n * @example\n * ```typescript\n * await flows.resume('instance-123', {\n * tool_name: 'get_weather',\n * result: { temperature: 72, conditions: 'sunny' },\n * });\n * ```\n */\n async resume(\n instanceId: string,\n data: unknown,\n options?: { signal?: AbortSignal },\n ): Promise<void> {\n if (this.flowsApi) {\n await this.flowsApi.resume(instanceId, data);\n return;\n }\n await this.request<void>({\n method: 'POST',\n path: `/api/flows/${this.repository}/instances/${instanceId}/resume`,\n body: { resume_data: data },\n signal: options?.signal,\n });\n }\n\n /**\n * Respond to a human task within a flow.\n *\n * When a flow is waiting on a human_task step (approval, input, review),\n * use this method to submit the response. Completion is validated\n * (caller must be the task's assignee or an admin) and resumes the flow.\n *\n * Note: prefer `InboxApi` for full inbox functionality (listing tasks,\n * task details); this is a convenience passthrough to the same endpoint.\n *\n * @param instanceId - Flow instance ID (unused; kept for API stability)\n * @param taskId - The inbox task node ID (or path)\n * @param response - The response data\n *\n * @example\n * ```typescript\n * // Approve a task\n * await flows.respondToHumanTask('instance-123', 'task-abc', {\n * action: 'approve',\n * comment: 'Looks good!',\n * });\n * ```\n */\n async respondToHumanTask(\n _instanceId: string,\n taskId: string,\n response: unknown,\n options?: { signal?: AbortSignal },\n ): Promise<void> {\n await this.request<void>({\n method: 'POST',\n path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}/complete`,\n body: { response },\n signal: options?.signal,\n });\n }\n\n // ==========================================================================\n // Convenience Methods\n // ==========================================================================\n\n /**\n * Run a flow and wait for the final result.\n *\n * Starts the flow, streams all events, and returns the terminal outcome.\n * This is a one-shot helper for fire-and-forget flows where you only\n * care about the final output.\n *\n * @param flowPath - Path to the raisin:Flow node\n * @param input - Input data passed to the flow\n * @param options - Optional abort signal\n * @returns The flow outcome including output or error\n *\n * @example\n * ```typescript\n * const result = await flows.runAndWait('/flows/process-order', { orderId: '123' });\n * if (result.status === 'completed') {\n * console.log('Output:', result.output);\n * }\n * ```\n */\n async runAndWait(\n flowPath: string,\n input: Record<string, unknown> = {},\n options?: { signal?: AbortSignal },\n ): Promise<FlowRunResult> {\n const { instance_id } = await this.run(flowPath, input, options);\n\n for await (const event of this.streamEvents(instance_id, options)) {\n if (event.type === 'flow_completed') {\n return {\n instanceId: instance_id,\n status: 'completed',\n output: (event as FlowCompletedEvent).output,\n };\n }\n if (event.type === 'flow_failed') {\n return {\n instanceId: instance_id,\n status: 'failed',\n error: (event as FlowFailedEvent).error,\n };\n }\n }\n\n return { instanceId: instance_id, status: 'failed', error: 'Stream ended without terminal event' };\n }\n\n /**\n * Run a flow and collect all events into an array.\n *\n * Starts the flow, streams all events, and returns them as a collected array.\n * Useful for testing, logging, or post-processing all flow events.\n *\n * @param flowPath - Path to the raisin:Flow node\n * @param input - Input data passed to the flow\n * @param options - Optional abort signal\n * @returns The instance ID and all collected events\n *\n * @example\n * ```typescript\n * const { events } = await flows.runAndCollect('/flows/etl-pipeline', { source: 'db' });\n * const steps = events.filter(e => e.type === 'step_completed');\n * console.log(`Completed ${steps.length} steps`);\n * ```\n */\n async runAndCollect(\n flowPath: string,\n input: Record<string, unknown> = {},\n options?: { signal?: AbortSignal },\n ): Promise<FlowCollectResult> {\n const { instance_id } = await this.run(flowPath, input, options);\n const events: FlowExecutionEvent[] = [];\n\n for await (const event of this.streamEvents(instance_id, options)) {\n events.push(event);\n }\n\n return { instanceId: instance_id, events };\n }\n\n // ==========================================================================\n // Internal HTTP request helper\n // ==========================================================================\n\n private async request<T>(options: {\n method: string;\n path: string;\n body?: unknown;\n signal?: AbortSignal;\n }): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);\n\n // Forward external signal to our internal controller\n if (options.signal) {\n if (options.signal.aborted) {\n clearTimeout(timeoutId);\n throw new RaisinAbortError();\n }\n options.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n } catch {\n errorMessage =\n errorText || `HTTP ${response.status}: ${response.statusText}`;\n }\n\n throw classifyHttpError(response.status, errorMessage);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return (await response.json()) as T;\n }\n\n return undefined as unknown as T;\n } catch (error) {\n clearTimeout(timeoutId);\n // Re-throw our own errors as-is\n if (error instanceof RaisinAbortError || error instanceof RaisinTimeoutError) {\n throw error;\n }\n if (error instanceof Error && error.name === 'AbortError') {\n // Distinguish external abort from internal timeout\n if (options.signal?.aborted) {\n throw new RaisinAbortError();\n }\n throw new RaisinTimeoutError(\n `Request timeout after ${this.requestTimeout}ms`,\n 'REQUEST_TIMEOUT',\n this.requestTimeout,\n );\n }\n throw error;\n }\n }\n}\n","/**\n * InboxApi for human-in-the-loop tasks.\n *\n * Inbox tasks are the primitive workflows use for approvals, input\n * requests, reviews, and generic actions. A `human_task` step creates a\n * task in the assignee's inbox and pauses the flow; completing the task\n * resumes it. Assignees can be users OR AI agents - agents decide tasks\n * automatically (with escalation back to humans), and both complete tasks\n * through the same API.\n *\n * @example\n * ```typescript\n * const inbox = new InboxApi('http://localhost:8081', 'my-repo', authManager);\n *\n * // List my pending tasks\n * const { tasks } = await inbox.listTasks({ status: 'pending' });\n *\n * // Approve the first one\n * await inbox.completeTask(tasks[0].id, {\n * action: 'approve',\n * comment: 'Looks good!',\n * });\n * ```\n */\n\nimport type { AuthManager } from './auth';\nimport type { InboxTask, TaskCompletionResult } from './types/flow-definition';\nimport {\n classifyHttpError,\n RaisinAbortError,\n RaisinTimeoutError,\n} from './errors';\n\n/** Options for creating an InboxApi */\nexport interface InboxApiOptions {\n /** Request timeout in milliseconds (default: 30000) */\n requestTimeout?: number;\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n}\n\n/** Filters for listing inbox tasks */\nexport interface ListTasksOptions {\n /** Filter by status */\n status?: 'pending' | 'completed' | 'expired' | 'cancelled';\n /** List another principal's inbox (admins only) */\n assignee?: string;\n /** Abort signal */\n signal?: AbortSignal;\n}\n\n/** Response from listing inbox tasks */\nexport interface ListTasksResponse {\n /** The inbox owner the tasks belong to */\n assignee: string;\n /** Number of tasks returned */\n count: number;\n /** The tasks, pending first, then by priority and due time */\n tasks: InboxTask[];\n}\n\n/**\n * Client for the inbox task endpoints.\n */\nexport class InboxApi {\n private baseUrl: string;\n private repository: string;\n private authManager: AuthManager;\n private fetchImpl: typeof fetch;\n private requestTimeout: number;\n\n constructor(\n baseUrl: string,\n repository: string,\n authManager: AuthManager,\n options: InboxApiOptions = {},\n ) {\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.repository = repository;\n this.authManager = authManager;\n this.fetchImpl = options.fetch ?? fetch;\n this.requestTimeout = options.requestTimeout ?? 30000;\n }\n\n /**\n * List the caller's inbox tasks.\n *\n * Tasks are sorted pending-first, then by priority (highest first) and\n * due time (earliest first).\n */\n async listTasks(options: ListTasksOptions = {}): Promise<ListTasksResponse> {\n const params = new URLSearchParams();\n if (options.status) params.set('status', options.status);\n if (options.assignee) params.set('assignee', options.assignee);\n const query = params.size > 0 ? `?${params.toString()}` : '';\n\n return this.request<ListTasksResponse>({\n method: 'GET',\n path: `/api/inbox/${this.repository}${query}`,\n signal: options.signal,\n });\n }\n\n /**\n * Get a single inbox task by ID (or path).\n */\n async getTask(\n taskId: string,\n options?: { signal?: AbortSignal },\n ): Promise<InboxTask> {\n return this.request<InboxTask>({\n method: 'GET',\n path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}`,\n signal: options?.signal,\n });\n }\n\n /**\n * Complete an inbox task.\n *\n * The caller must be the task's assignee (or an admin). Completion marks\n * the task done, records who decided, and resumes the owning flow.\n *\n * @param taskId - Task node ID (or path)\n * @param response - The response payload:\n * - approval tasks: `{ action: '<option value>', comment?: string }`\n * - input tasks: the input value(s) matching the task's input_schema\n * - review/action tasks: any acknowledgement payload\n *\n * @example\n * ```typescript\n * await inbox.completeTask('task-123', { action: 'approve' });\n * ```\n */\n async completeTask(\n taskId: string,\n response: unknown,\n options?: { signal?: AbortSignal },\n ): Promise<TaskCompletionResult> {\n return this.request<TaskCompletionResult>({\n method: 'POST',\n path: `/api/inbox/${this.repository}/tasks/${encodeURIComponent(taskId)}/complete`,\n body: { response },\n signal: options?.signal,\n });\n }\n\n // ==========================================================================\n // Internal HTTP request helper\n // ==========================================================================\n\n private async request<T>(options: {\n method: string;\n path: string;\n body?: unknown;\n signal?: AbortSignal;\n }): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);\n\n if (options.signal) {\n if (options.signal.aborted) {\n clearTimeout(timeoutId);\n throw new RaisinAbortError();\n }\n options.signal.addEventListener('abort', () => controller.abort(), {\n once: true,\n });\n }\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n } catch {\n errorMessage =\n errorText || `HTTP ${response.status}: ${response.statusText}`;\n }\n throw classifyHttpError(response.status, errorMessage);\n }\n\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n return (await response.json()) as T;\n }\n return undefined as unknown as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (\n error instanceof RaisinAbortError ||\n error instanceof RaisinTimeoutError\n ) {\n throw error;\n }\n if (error instanceof Error && error.name === 'AbortError') {\n if (options.signal?.aborted) {\n throw new RaisinAbortError();\n }\n throw new RaisinTimeoutError(\n `Request timeout after ${this.requestTimeout}ms`,\n 'REQUEST_TIMEOUT',\n this.requestTimeout,\n );\n }\n throw error;\n }\n }\n}\n","/**\n * Database/repository interface\n */\n\nimport { WorkspaceClient, WorkspaceManager } from './workspace';\nimport { SqlQuery, createSqlHandler } from './sql';\nimport { EventHandler } from './events';\nimport { RequestContext, SqlQueryPayload, SqlResult } from './protocol';\nimport { NodeTypes } from './node-types';\nimport { Archetypes } from './archetypes';\nimport { ElementTypes } from './element-types';\nimport { Branches } from './branches';\nimport { SchedulerApi } from './scheduler';\nimport { Tags } from './tags';\nimport { FlowsApi } from './flows';\nimport { FunctionsApi } from './functions-api';\nimport { ConversationManager } from './conversations';\nimport { FlowClient } from './flow-client';\nimport { InboxApi } from './inbox';\nimport type { AuthManager } from './auth';\nimport type { UploadManager } from './upload/uploader';\nimport type { SignAssetOptions, SignedAssetUrl } from './http-client';\n\n/**\n * Options for HTTP-based features (chat, flow) on a Database instance.\n * Provided automatically when the Database is created via `RaisinClient.database()`.\n */\nexport interface DatabaseHttpOptions {\n /** HTTP base URL of the RaisinDB server */\n httpBaseUrl?: string;\n /** Auth manager for token access */\n authManager?: AuthManager;\n}\n\n/**\n * Database interface for repository operations\n */\nexport class Database {\n private repository: string;\n private _context: RequestContext;\n private sendRequest: (\n payload: unknown,\n requestType?: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ) => Promise<unknown>;\n private eventHandler: EventHandler;\n private workspaceManager?: WorkspaceManager;\n private sqlQuery?: SqlQuery;\n private sqlHandler?: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<SqlResult>;\n private branch?: string;\n private revision?: string;\n private getUploadManager?: () => UploadManager;\n private getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>;\n private httpOptions?: DatabaseHttpOptions;\n private _flowsApi?: FlowsApi;\n private _functionsApi?: FunctionsApi;\n private _conversationManager?: ConversationManager;\n private _flowClient?: FlowClient;\n private _inboxApi?: InboxApi;\n\n constructor(\n repository: string,\n context: RequestContext,\n sendRequest: (\n payload: unknown,\n requestType: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ) => Promise<unknown>,\n eventHandler: EventHandler,\n branch?: string,\n revision?: string,\n getUploadManager?: () => UploadManager,\n getSignAssetUrl?: (options: SignAssetOptions) => Promise<SignedAssetUrl>,\n httpOptions?: DatabaseHttpOptions,\n ) {\n this.repository = repository;\n this.branch = branch;\n this.revision = revision;\n this._context = {\n ...context,\n repository,\n branch: branch || context.branch,\n revision: revision || context.revision\n };\n // Wrap sendRequest to use our context by default, but allow override\n this.sendRequest = (\n payload: unknown,\n requestType?: string,\n contextOverride?: RequestContext,\n requestOptions?: { timeoutMs?: number }\n ) => sendRequest(\n payload,\n requestType || 'node_create',\n contextOverride || this._context,\n requestOptions\n );\n this.eventHandler = eventHandler;\n this.getUploadManager = getUploadManager;\n this.getSignAssetUrl = getSignAssetUrl;\n this.httpOptions = httpOptions;\n }\n\n /**\n * Get the repository name\n */\n getRepository(): string {\n return this.repository;\n }\n\n /**\n * Create a new Database instance scoped to a specific branch.\n *\n * @param branch - Branch name\n * @returns New Database instance with branch context\n */\n onBranch(branch: string): Database {\n return new Database(\n this.repository,\n this._context,\n this.sendRequest,\n this.eventHandler,\n branch,\n this.revision,\n this.getUploadManager,\n this.getSignAssetUrl,\n this.httpOptions,\n );\n }\n\n /**\n * Create a new Database instance scoped to a specific revision/commit.\n *\n * @param revision - Revision/commit ID\n * @returns New Database instance with revision context\n */\n atRevision(revision: string): Database {\n return new Database(\n this.repository,\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.branch,\n revision,\n this.getUploadManager,\n this.getSignAssetUrl,\n this.httpOptions,\n );\n }\n\n /**\n * Get a workspace client\n *\n * @param name - Workspace name\n * @returns Workspace client for operations\n */\n workspace(name: string): WorkspaceClient {\n if (!this.workspaceManager) {\n this.workspaceManager = new WorkspaceManager(\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n return this.workspaceManager.workspace(name);\n }\n\n /**\n * Get workspace management operations\n */\n workspaces(): WorkspaceManager {\n if (!this.workspaceManager) {\n this.workspaceManager = new WorkspaceManager(\n this._context,\n this.sendRequest,\n this.eventHandler,\n this.getUploadManager,\n this.getSignAssetUrl\n );\n }\n return this.workspaceManager;\n }\n\n /**\n * Create a new workspace (convenience method)\n *\n * @param name - Workspace name\n * @param description - Workspace description\n * @returns Created workspace\n */\n async createWorkspace(name: string, description?: string): Promise<unknown> {\n return this.workspaces().create({ name, description });\n }\n\n /**\n * List all workspaces (convenience method)\n *\n * @returns Array of workspaces\n */\n async listWorkspaces(): Promise<unknown[]> {\n return this.workspaces().list();\n }\n\n /**\n * Execute SQL query using template literals\n *\n * @param strings - Template literal strings\n * @param values - Template literal values\n * @returns SQL query result\n *\n * @example\n * ```typescript\n * const results = await db.sql`SELECT * FROM nodes WHERE node_type = ${'Page'}`;\n * ```\n */\n async sql(strings: TemplateStringsArray, ...values: unknown[]): Promise<SqlResult> {\n if (!this.sqlHandler) {\n this.sqlHandler = createSqlHandler((payload: SqlQueryPayload) =>\n this.sendRequest(payload, 'sql_query')\n );\n }\n return this.sqlHandler(strings, ...values);\n }\n\n /**\n * Get SQL query builder for more advanced queries\n */\n getSqlQuery(): SqlQuery {\n if (!this.sqlQuery) {\n this.sqlQuery = new SqlQuery((payload: SqlQueryPayload) =>\n this.sendRequest(payload, 'sql_query')\n );\n }\n return this.sqlQuery;\n }\n\n /**\n * Execute a raw SQL query\n *\n * @param query - SQL query string\n * @param params - Query parameters\n * @returns SQL query result\n */\n async executeSql(query: string, params?: unknown[]): Promise<SqlResult> {\n return this.getSqlQuery().execute(query, params);\n }\n\n /**\n * Get NodeTypes management operations\n */\n nodeTypes(): NodeTypes {\n return new NodeTypes(this._context, this.sendRequest);\n }\n\n /**\n * Get Archetypes management operations\n */\n archetypes(): Archetypes {\n return new Archetypes(this._context, this.sendRequest);\n }\n\n /**\n * Get ElementTypes management operations\n */\n elementTypes(): ElementTypes {\n return new ElementTypes(this._context, this.sendRequest);\n }\n\n /**\n * Get Branches management operations\n */\n branches(): Branches {\n return new Branches(this._context, this.sendRequest);\n }\n\n /**\n * Get Tags management operations\n */\n tags(): Tags {\n return new Tags(this._context, this.sendRequest);\n }\n\n /**\n * Get SchedulerApi for one-shot scheduled invocations (time-based\n * function/flow runs).\n */\n scheduler(): SchedulerApi {\n return new SchedulerApi(this._context, this.sendRequest);\n }\n\n /**\n * Get FlowsApi for running flows via WebSocket\n */\n flows(): FlowsApi {\n if (!this._flowsApi) {\n this._flowsApi = new FlowsApi(\n this.repository,\n this._context,\n this.sendRequest,\n this.eventHandler,\n );\n }\n return this._flowsApi;\n }\n\n /**\n * Get FunctionsApi for invoking server-side functions via WebSocket\n */\n functions(): FunctionsApi {\n if (!this._functionsApi) {\n this._functionsApi = new FunctionsApi(\n this.repository,\n this._context,\n this.sendRequest,\n );\n }\n return this._functionsApi;\n }\n\n /**\n * Get a pre-configured ConversationManager for managing conversations.\n *\n * Unified API for conversation lifecycle, messaging, streaming, and\n * plan approval/rejection. Replaces the previous ChatClient and\n * ConversationClient split.\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const convos = await db.conversations.list({ type: 'ai_chat' });\n * const convo = await db.conversations.create({ participant: '/agents/support' });\n * ```\n */\n get conversations(): ConversationManager {\n if (!this._conversationManager) {\n if (!this.httpOptions?.httpBaseUrl || !this.httpOptions?.authManager) {\n throw new Error(\n 'db.conversations requires HTTP context. Use client.database() to get a Database with conversation support.',\n );\n }\n this._conversationManager = new ConversationManager(\n this.httpOptions.httpBaseUrl,\n this.repository,\n this.httpOptions.authManager,\n {},\n (query: string, params?: unknown[]) => this.executeSql(query, params),\n );\n }\n return this._conversationManager;\n }\n\n /**\n * Get a pre-configured FlowClient for executing flows via HTTP/SSE.\n *\n * Requires the Database to have been created via `RaisinClient.database()`\n * (which automatically provides HTTP context). Throws if HTTP context is unavailable.\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const result = await db.flow.runAndWait('/flows/my-flow', { key: 'value' });\n * ```\n */\n get flow(): FlowClient {\n if (!this._flowClient) {\n if (!this.httpOptions?.httpBaseUrl || !this.httpOptions?.authManager) {\n throw new Error(\n 'db.flow requires HTTP context. Use client.database() to get a Database with flow support.',\n );\n }\n this._flowClient = new FlowClient(\n this.httpOptions.httpBaseUrl,\n this.repository,\n this.httpOptions.authManager,\n {},\n this.flows(),\n );\n }\n return this._flowClient;\n }\n\n /**\n * Get a pre-configured InboxApi for human-in-the-loop tasks.\n *\n * Requires the Database to have been created via `RaisinClient.database()`\n * (which automatically provides HTTP context).\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const { tasks } = await db.inbox.listTasks({ status: 'pending' });\n * await db.inbox.completeTask(tasks[0].id, { action: 'approve' });\n * ```\n */\n get inbox(): InboxApi {\n if (!this._inboxApi) {\n if (!this.httpOptions?.httpBaseUrl || !this.httpOptions?.authManager) {\n throw new Error(\n 'db.inbox requires HTTP context. Use client.database() to get a Database with inbox support.',\n );\n }\n this._inboxApi = new InboxApi(\n this.httpOptions.httpBaseUrl,\n this.repository,\n this.httpOptions.authManager,\n );\n }\n return this._inboxApi;\n }\n\n /**\n * Get EventHandler for subscribing to real-time events\n *\n * Path filter semantics for subscriptions (matched server-side):\n * - A plain path matches **only that exact node** — there is no implicit\n * prefix matching.\n * - `*` matches exactly one path segment (`/inbox/*` matches `/inbox/a`,\n * not `/inbox/a/b`).\n * - `**` matches recursively (`/inbox/**` matches all descendants of\n * `/inbox`, but not `/inbox` itself).\n */\n events(): EventHandler {\n return this.eventHandler;\n }\n}\n","/**\n * RaisinDB HTTP client for server-side rendering (SSR)\n *\n * This client uses HTTP REST API instead of WebSocket for initial data fetching\n * during server-side rendering. After client hydration, applications can upgrade\n * to WebSocket mode for real-time updates.\n */\n\nimport { EventEmitter } from 'events';\nimport { AuthManager, Credentials, AdminCredentials, isJwtCredentials, TokenStorage } from './auth';\nimport {\n RequestContext,\n SqlResult,\n Node,\n Workspace,\n NodeCreatePayload,\n WorkspaceCreatePayload,\n WorkspaceUpdatePayload,\n AuthenticatePayload,\n AuthenticateResponse,\n} from './protocol';\nimport {\n HttpFunctionsApi,\n type FunctionInvokeOptions,\n type FunctionInvokeResponse,\n type FunctionInvokeSyncResponse\n} from './functions-api';\nimport type { Upload, UploadOptions, BatchUpload, BatchUploadOptions } from './upload/types';\nimport { createFileSource } from './upload/file-source';\nimport { UploadManager } from './upload/uploader';\nimport { HttpNodeTypes, HttpArchetypes, HttpElementTypes } from './http-schema';\nimport { McpClient, type McpTransport, type McpFrameStream, type McpJsonRpcFrame } from './mcp';\nimport { SSEClient } from './streaming/sse-client';\nimport { IdentityAuthApi, type IdentityAuthResult } from './identity-auth';\n\n/**\n * Current user info\n */\nexport interface CurrentUser {\n /** User ID (identity UUID) */\n userId: string;\n /** Roles assigned to the user */\n roles?: string[];\n /** Whether this is an anonymous user */\n anonymous: boolean;\n /** The full user node from the repository */\n node?: UserNode;\n}\n\n/**\n * User node from the repository\n */\nexport interface UserNode {\n /** Node ID */\n id: string;\n /** Node path (e.g., '/users/internal/john-at-example-com') */\n path: string;\n /** Node name */\n name: string;\n /** Node type (e.g., 'raisin:User') */\n node_type: string;\n /** Node properties */\n properties: Record<string, unknown>;\n}\n\n/**\n * Response from /auth/{repo}/me endpoint\n */\ninterface AuthMeResponse {\n user_id: string;\n user_path: string;\n user_node?: UserNode;\n roles: string[];\n anonymous: boolean;\n}\n\n/**\n * HTTP client options\n */\nexport interface HttpClientOptions {\n /** Token storage (default: in-memory) */\n tokenStorage?: TokenStorage;\n /** Request timeout in milliseconds (default: 30000) */\n requestTimeout?: number;\n /** Tenant ID */\n tenantId?: string;\n /** Default branch (default: \"main\") */\n defaultBranch?: string;\n /** Custom fetch implementation (for testing or custom behavior) */\n fetch?: typeof fetch;\n}\n\n/**\n * HTTP response wrapper\n */\ninterface HttpResponse<T = unknown> {\n data: T;\n status: number;\n headers: Headers;\n}\n\n/**\n * Options for signing an asset URL\n */\nexport interface SignAssetOptions {\n /** Repository name */\n repository: string;\n /** Workspace name */\n workspace: string;\n /** Path to the asset node */\n path: string;\n /** Command type: 'download' forces download, 'display' shows inline */\n command: 'download' | 'display';\n /** Branch (default: context branch or \"main\") */\n branch?: string;\n /** Expiry time in seconds (default: 300) */\n expiresIn?: number;\n /** Property path to access (default: 'file'). Use 'thumbnail' for thumbnail images. */\n propertyPath?: string;\n}\n\n/**\n * Signed URL response\n */\nexport interface SignedAssetUrl {\n /** The signed URL for accessing the asset */\n url: string;\n /** When the URL expires (ISO 8601) */\n expiresAt: string;\n /** @deprecated Use expiresAt instead */\n expires_at?: string;\n}\n\n/**\n * RaisinDB HTTP client for SSR\n */\nexport class RaisinHttpClient extends EventEmitter {\n private baseUrl: string;\n private authManager: AuthManager;\n private _context: RequestContext;\n private options: Required<Omit<HttpClientOptions, 'tokenStorage' | 'fetch'>>;\n private fetchImpl: typeof fetch;\n /** Monotonic JSON-RPC id counter for MCP requests. */\n private _mcpRequestId = 0;\n private _currentUser: CurrentUser | null = null;\n private _uploadManager: UploadManager | null = null;\n\n constructor(baseUrl: string, options: HttpClientOptions = {}) {\n super();\n\n // Remove trailing slash from baseUrl\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n\n this.options = {\n requestTimeout: options.requestTimeout ?? 30000,\n tenantId: options.tenantId ?? 'default',\n defaultBranch: options.defaultBranch ?? 'main',\n };\n\n // Initialize context\n this._context = {\n tenant_id: this.options.tenantId,\n branch: this.options.defaultBranch,\n };\n\n // Initialize auth manager\n this.authManager = new AuthManager(options.tokenStorage);\n\n // Use custom fetch or global fetch\n this.fetchImpl = options.fetch ?? fetch;\n }\n\n /**\n * Authenticate with credentials\n *\n * Supports two authentication modes:\n * - Admin auth: { username: string, password: string }\n * - JWT auth: { type: 'jwt', token: string }\n *\n * @param credentials - User credentials\n */\n async authenticate(credentials: Credentials, repository?: string): Promise<void> {\n if (isJwtCredentials(credentials)) {\n // For HTTP client, JWT auth is typically done via Authorization header\n // Just store the token for future requests\n this.authManager.storage.setAccessToken(credentials.token);\n\n // Fetch user info from /auth/{repo}/me endpoint if repository is provided\n if (repository) {\n try {\n const userInfo = await this.fetchCurrentUser(repository);\n if (userInfo) {\n this._currentUser = userInfo;\n }\n } catch {\n // User info fetch failed, continue without it\n }\n }\n\n // Emit authenticated event\n this.emit('authenticated', { type: 'jwt', token: credentials.token });\n } else {\n // Admin authentication with username/password\n const payload: AuthenticatePayload = AuthManager.createAuthPayload(credentials as AdminCredentials);\n\n // The admin auth endpoint returns { token, user_id, username, ... }\n // (NOT the WebSocket protocol's { access_token, refresh_token }).\n const response = await this.request<\n AuthenticateResponse & { token?: string; user_id?: string; username?: string }\n >({\n method: 'POST',\n path: `/api/raisindb/sys/${this._context.tenant_id}/auth`,\n body: payload,\n skipAuth: true,\n });\n\n if (response.data.token) {\n this.authManager.storage.setAccessToken(response.data.token);\n } else {\n this.authManager.setTokens(response.data);\n }\n\n // Set admin user info\n this._currentUser = {\n userId: response.data.user_id ?? 'admin',\n anonymous: false,\n };\n\n // Emit authenticated event\n this.emit('authenticated', response.data);\n }\n }\n\n /**\n * Execute SQL query\n *\n * @param repository - Repository name\n * @param query - SQL query string\n * @param params - Query parameters\n * @param branch - Optional branch (uses new /api/sql/{repo}/{branch} endpoint)\n * @returns SQL query result\n */\n async executeSql(\n repository: string,\n query: string,\n params?: unknown[],\n branch?: string\n ): Promise<SqlResult> {\n // Note: The HTTP API expects 'sql' field, not 'query'\n const payload = {\n sql: query,\n params: params || [],\n };\n\n // Use branch-specific endpoint if branch is provided\n const path = branch\n ? `/api/sql/${repository}/${branch}`\n : `/api/sql/${repository}`;\n\n const response = await this.request<SqlResult>({\n method: 'POST',\n path,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Get a node by ID\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodeId - Node ID\n * @returns Node data\n */\n async getNode(\n repository: string,\n workspace: string,\n nodeId: string\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n const response = await this.request<Node>({\n method: 'GET',\n path: `/api/repository/${repository}/${branch}/head/${workspace}/$ref/${nodeId}`,\n });\n\n return response.data;\n }\n\n /**\n * Get a node by path\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodePath - Node path (e.g., \"/content/my-page\")\n * @returns Node data\n */\n async getNodeByPath(\n repository: string,\n workspace: string,\n nodePath: string\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n // Ensure path starts with /\n const path = nodePath.startsWith('/') ? nodePath : `/${nodePath}`;\n\n const response = await this.request<Node>({\n method: 'GET',\n path: `/api/repository/${repository}/${branch}/head/${workspace}${path}`,\n });\n\n return response.data;\n }\n\n /**\n * Create a new node\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param payload - Node creation payload\n * @returns Created node\n */\n async createNode(\n repository: string,\n workspace: string,\n payload: NodeCreatePayload\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n const response = await this.request<Node>({\n method: 'POST',\n path: `/api/repository/${repository}/${branch}/head/${workspace}/`,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Update a node\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodeId - Node ID\n * @param properties - Properties to update\n * @returns Updated node\n */\n async updateNode(\n repository: string,\n workspace: string,\n nodeId: string,\n properties: Record<string, unknown>\n ): Promise<Node> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n // First get the node to get its path\n const node = await this.getNode(repository, workspace, nodeId);\n\n const response = await this.request<Node>({\n method: 'PUT',\n path: `/api/repository/${repository}/${branch}/head/${workspace}${node.path}`,\n body: { properties },\n });\n\n return response.data;\n }\n\n /**\n * Delete a node\n *\n * @param repository - Repository name\n * @param workspace - Workspace name\n * @param nodeId - Node ID\n */\n async deleteNode(\n repository: string,\n workspace: string,\n nodeId: string\n ): Promise<void> {\n const branch = this._context.branch ?? this.options.defaultBranch;\n\n // First get the node to get its path\n const node = await this.getNode(repository, workspace, nodeId);\n\n await this.request<void>({\n method: 'DELETE',\n path: `/api/repository/${repository}/${branch}/head/${workspace}${node.path}`,\n });\n }\n\n /**\n * List workspaces\n *\n * @param repository - Repository name\n * @returns Array of workspaces\n */\n async listWorkspaces(repository: string): Promise<Workspace[]> {\n const response = await this.request<Workspace[]>({\n method: 'GET',\n path: `/api/workspaces/${repository}`,\n });\n\n return response.data;\n }\n\n /**\n * Get a workspace\n *\n * @param repository - Repository name\n * @param name - Workspace name\n * @returns Workspace data\n */\n async getWorkspace(repository: string, name: string): Promise<Workspace> {\n const response = await this.request<Workspace>({\n method: 'GET',\n path: `/api/workspaces/${repository}/${name}`,\n });\n\n return response.data;\n }\n\n /**\n * Create a workspace\n *\n * @param repository - Repository name\n * @param payload - Workspace creation payload\n * @returns Created workspace\n */\n async createWorkspace(\n repository: string,\n payload: WorkspaceCreatePayload\n ): Promise<Workspace> {\n const response = await this.request<Workspace>({\n method: 'POST',\n path: `/api/workspaces/${repository}`,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Update a workspace\n *\n * @param repository - Repository name\n * @param name - Workspace name\n * @param payload - Workspace update payload\n * @returns Updated workspace\n */\n async updateWorkspace(\n repository: string,\n name: string,\n payload: WorkspaceUpdatePayload\n ): Promise<Workspace> {\n const response = await this.request<Workspace>({\n method: 'PUT',\n path: `/api/workspaces/${repository}/${name}`,\n body: payload,\n });\n\n return response.data;\n }\n\n /**\n * Delete a workspace\n *\n * @param repository - Repository name\n * @param name - Workspace name\n */\n async deleteWorkspace(repository: string, name: string): Promise<void> {\n await this.request<void>({\n method: 'DELETE',\n path: `/api/workspaces/${repository}/${name}`,\n });\n }\n\n /**\n * Create a new repository\n *\n * @param repositoryId - Repository identifier\n * @param description - Repository description\n * @param config - Repository configuration\n * @returns Repository creation result\n */\n async createRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'POST',\n path: '/api/repositories',\n body: {\n repository_id: repositoryId,\n description,\n config,\n },\n });\n\n return response.data;\n }\n\n /**\n * Get a repository by ID\n *\n * @param repositoryId - Repository identifier\n * @returns Repository information\n */\n async getRepository(repositoryId: string): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'GET',\n path: `/api/repositories/${repositoryId}`,\n });\n\n return response.data;\n }\n\n /**\n * List all repositories\n *\n * @returns Array of repository information\n */\n async listRepositories(): Promise<unknown[]> {\n const response = await this.request<unknown[]>({\n method: 'GET',\n path: '/api/repositories',\n });\n\n return response.data;\n }\n\n /**\n * Update a repository\n *\n * @param repositoryId - Repository identifier\n * @param description - New repository description\n * @param config - New repository configuration\n * @returns Repository update result\n */\n async updateRepository(\n repositoryId: string,\n description?: string,\n config?: Record<string, unknown>\n ): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'PUT',\n path: `/api/repositories/${repositoryId}`,\n body: {\n description,\n config,\n },\n });\n\n return response.data;\n }\n\n /**\n * Delete a repository\n *\n * @param repositoryId - Repository identifier\n * @returns Repository deletion result\n */\n async deleteRepository(repositoryId: string): Promise<unknown> {\n const response = await this.request<unknown>({\n method: 'DELETE',\n path: `/api/repositories/${repositoryId}`,\n });\n\n return response.data;\n }\n\n /**\n * Set branch for subsequent requests\n *\n * @param branch - Branch name\n */\n setBranch(branch: string): void {\n this._context.branch = branch;\n }\n\n /**\n * Get current branch\n */\n getBranch(): string {\n return this._context.branch ?? this.options.defaultBranch;\n }\n\n /**\n * Get current tenant ID\n */\n getTenantId(): string {\n return this._context.tenant_id;\n }\n\n /**\n * Check if authenticated\n */\n isAuthenticated(): boolean {\n return this.authManager.isAuthenticated();\n }\n\n /**\n * Get current user info\n *\n * Returns the current authenticated user's information including\n * their ID, node in the repository, and roles.\n *\n * @returns Current user info or null if not authenticated\n */\n getCurrentUser(): CurrentUser | null {\n return this._currentUser;\n }\n\n /**\n * Get current user ID\n *\n * @returns User ID or null if not authenticated\n */\n getCurrentUserId(): string | null {\n return this._currentUser?.userId ?? null;\n }\n\n /**\n * Get current user's node path in the repository\n *\n * @returns User's node path (e.g., '/users/internal/john-at-example-com') or null\n */\n getCurrentUserPath(): string | null {\n return this._currentUser?.node?.path ?? null;\n }\n\n /**\n * Fetch current user info from /auth/{repo}/me endpoint\n *\n * @param repository - Repository name\n * @returns Current user info or null if fetch fails\n */\n async fetchCurrentUser(repository: string): Promise<CurrentUser | null> {\n try {\n const response = await this.request<AuthMeResponse>({\n method: 'GET',\n path: `/auth/${repository}/me`,\n });\n\n return {\n userId: response.data.user_id,\n roles: response.data.roles,\n anonymous: response.data.anonymous,\n node: response.data.user_node,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Get auth manager (for token access)\n */\n getAuthManager(): AuthManager {\n return this.authManager;\n }\n\n // ============================================================================\n // Identity Authentication\n // ============================================================================\n\n /**\n * Identity authentication (magic link, password, providers) for one\n * repository.\n *\n * Identities are per repository — their home nodes and roles live there — so\n * the repository is required rather than inferred from client state, which\n * would silently sign somebody into whichever one happened to be current.\n *\n * ```ts\n * const auth = client.auth('studio');\n * await auth.sendMagicLink('a@example.com', {\n * redirectUrl: 'https://app.example.com/account/callback',\n * });\n * // …on the callback route:\n * const tokens = readTokensFromFragment(window.location.hash);\n * if (tokens) client.setIdentityTokens(tokens.accessToken, tokens.refreshToken);\n * ```\n */\n auth(repository: string): IdentityAuthApi {\n return new IdentityAuthApi(repository, async (options) => {\n const response = await this.request({\n method: options.method,\n path: options.path,\n body: options.body,\n skipAuth: options.skipAuth,\n });\n return response.data as never;\n });\n }\n\n /**\n * Adopt an identity's tokens for every subsequent call on this client.\n *\n * Takes the loose form so it serves both callers: the whole result of a\n * sign-in, and the pair recovered from a redirect fragment (which carries no\n * identity object and may carry no refresh token).\n */\n setIdentityTokens(\n accessTokenOrResult: string | IdentityAuthResult,\n refreshToken?: string | null,\n ): void {\n if (typeof accessTokenOrResult === 'string') {\n this.authManager.storage.setAccessToken(accessTokenOrResult);\n if (refreshToken) this.authManager.storage.setRefreshToken(refreshToken);\n return;\n }\n const result = accessTokenOrResult;\n this.authManager.setTokens({\n access_token: result.access_token,\n refresh_token: result.refresh_token,\n // The server reports an absolute expiry; AuthManager schedules from a\n // duration. Deriving it here keeps the refresh timer honest instead of\n // leaving it unset, which reads as \"never expires\".\n expires_in: Math.max(0, result.expires_at - Math.floor(Date.now() / 1000)),\n } as AuthenticateResponse);\n }\n\n /** Forget the current identity's tokens. */\n clearIdentityTokens(): void {\n this.authManager.clear();\n }\n\n // ============================================================================\n // Upload Methods\n // ============================================================================\n\n /**\n * Get or create the upload manager\n */\n private getUploadManager(): UploadManager {\n if (!this._uploadManager) {\n this._uploadManager = new UploadManager({\n baseUrl: this.baseUrl,\n authManager: this.authManager,\n fetchImpl: this.fetchImpl,\n requestTimeout: this.options.requestTimeout,\n });\n }\n return this._uploadManager;\n }\n\n /**\n * Create a resumable upload from a File or Blob (Browser)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support.\n *\n * @param file - File or Blob to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const file = document.querySelector('input').files[0];\n * const upload = await client.upload(file, {\n * repository: 'media',\n * workspace: 'assets',\n * path: '/videos/my-video.mp4',\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * const result = await upload.start();\n * ```\n */\n async upload(file: File | Blob, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(file);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Create a resumable upload from a file path (Node.js)\n *\n * Creates an upload session for large files with progress tracking,\n * pause/resume, and automatic retry support.\n *\n * @param filePath - Path to the file to upload\n * @param options - Upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const upload = await client.uploadFile('/path/to/file.zip', {\n * repository: 'data',\n * workspace: 'backups',\n * path: '/backup.zip'\n * });\n * await upload.start();\n * ```\n */\n async uploadFile(filePath: string, options: UploadOptions): Promise<Upload> {\n const fileSource = await createFileSource(filePath);\n const manager = this.getUploadManager();\n return manager.createUpload(fileSource, {\n ...options,\n branch: options.branch ?? this._context.branch ?? this.options.defaultBranch,\n });\n }\n\n /**\n * Resume an existing upload by ID\n *\n * Note: This requires the upload session to still be valid on the server.\n * Sessions typically expire after 24 hours.\n *\n * @param uploadId - ID of the upload to resume\n * @returns Upload controller\n */\n getUpload(uploadId: string): Upload | undefined {\n const manager = this.getUploadManager();\n return manager.getUpload(uploadId);\n }\n\n /**\n * Get all active uploads\n *\n * @returns Array of active upload controllers\n */\n getActiveUploads(): Upload[] {\n const manager = this.getUploadManager();\n return manager.getActiveUploads();\n }\n\n /**\n * Cancel all active uploads\n */\n async cancelAllUploads(): Promise<void> {\n const manager = this.getUploadManager();\n await manager.cancelAll();\n }\n\n // ============================================================================\n // Asset Signed URL Methods\n // ============================================================================\n\n /**\n * Get a signed URL for accessing an asset's binary content.\n *\n * Server validates user access before generating URL. The returned URL\n * can be used without authentication (signature provides access).\n *\n * @param options - Sign URL options\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const { url, expiresAt } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/image.jpeg',\n * command: 'display',\n * });\n *\n * // Use in <img> tag\n * document.querySelector('img').src = url;\n *\n * // Or force download\n * const { url: downloadUrl } = await client.signAssetUrl({\n * repository: 'media',\n * workspace: 'assets',\n * path: '/files/document.pdf',\n * command: 'download',\n * });\n * ```\n */\n async signAssetUrl(options: SignAssetOptions): Promise<SignedAssetUrl> {\n const branch = options.branch ?? this._context.branch ?? 'main';\n // Add @propertyPath suffix if specified (for thumbnails, etc.)\n // Only add suffix when propertyPath is provided - maintains backward compatibility\n const pathWithProperty = options.propertyPath\n ? `${options.path}@${options.propertyPath}`\n : options.path;\n const endpoint = `/api/repository/${options.repository}/${branch}/head/${options.workspace}${pathWithProperty}/raisin:sign`;\n\n const response = await this.request<SignedAssetUrl>({\n method: 'POST',\n path: endpoint,\n body: {\n command: options.command,\n expires_in: options.expiresIn ?? 300,\n },\n });\n\n return {\n url: `${this.baseUrl}${response.data.url}`,\n expiresAt: response.data.expiresAt ?? response.data.expires_at,\n };\n }\n\n /**\n * Upload multiple files as a batch\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param options - Batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await client.uploadFiles(files, {\n * repository: 'media',\n * workspace: 'assets',\n * basePath: '/uploads',\n * concurrency: 3,\n * onProgress: (p) => {\n * console.log(`${p.filesCompleted}/${p.filesTotal} files`);\n * console.log(`${Math.round(p.progress * 100)}% complete`);\n * },\n * onFileComplete: (file, result) => console.log(`Uploaded: ${file}`),\n * onFileError: (file, err) => console.error(`Failed: ${file}`, err),\n * });\n *\n * const result = await batch.start();\n * console.log(`Success: ${result.successful.length}, Failed: ${result.failed.length}`);\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n options: BatchUploadOptions\n ): Promise<BatchUpload> {\n const sources = await Promise.all(\n Array.from(files).map((f) => createFileSource(f))\n );\n const manager = this.getUploadManager();\n return manager.createBatchUpload(sources, options);\n }\n\n /**\n * Make an HTTP request\n *\n * @param options - Request options\n * @returns HTTP response\n */\n private async request<T = unknown>(options: {\n method: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n skipAuth?: boolean;\n timeoutMs?: number;\n }): Promise<HttpResponse<T>> {\n const url = `${this.baseUrl}${options.path}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n\n // Send the token whenever we hold one.\n //\n // Deliberately NOT gated on `isAuthenticated()`. That asks whether the\n // token is known to be unexpired, and an expiry we never learned reads as\n // expired — so a client given a bare token (`authenticate({type:'jwt'})`,\n // `setIdentityTokens(token)`) sent no Authorization header at all and every\n // call ran anonymously. It failed silently, because an anonymous read\n // returns an empty result rather than a 401.\n //\n // The server is the authority on whether a token is still good. Withholding\n // it locally turns a 401 the caller could act on into a wrong answer.\n if (!options.skipAuth) {\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n }\n\n // Create AbortController for timeout\n const controller = new AbortController();\n const requestTimeout = options.timeoutMs ?? this.options.requestTimeout;\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Handle error responses\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n let errorCode: string = response.statusText;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.message || errorJson.error || errorText;\n errorCode = errorJson.code || errorCode;\n } catch {\n errorMessage = errorText || `HTTP ${response.status}: ${response.statusText}`;\n }\n\n const error = new Error(errorMessage);\n (error as any).code = errorCode;\n (error as any).status = response.status;\n throw error;\n }\n\n // Parse response\n const contentType = response.headers.get('content-type');\n let data: T;\n\n if (contentType?.includes('application/json')) {\n data = await response.json();\n } else {\n data = (await response.text()) as unknown as T;\n }\n\n return {\n data,\n status: response.status,\n headers: response.headers,\n };\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new Error(`Request timeout after ${requestTimeout}ms`);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Invoke a server-side function by name.\n *\n * Calls `POST /api/functions/{repo}/{name}/invoke`.\n *\n * @param repository - Repository name\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution ID and job ID for tracking\n */\n async invokeFunction(\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n options?: FunctionInvokeOptions,\n ): Promise<FunctionInvokeResponse> {\n const requestTimeoutMs = options?.requestTimeoutMs ?? this.options.requestTimeout;\n let waitTimeoutMs = options?.waitTimeoutMs;\n if (options?.waitForResult) {\n waitTimeoutMs = Math.min(waitTimeoutMs ?? requestTimeoutMs, requestTimeoutMs);\n }\n\n const response = await this.request<FunctionInvokeResponse>({\n method: 'POST',\n path: `/api/functions/${repository}/${functionName}/invoke`,\n body: {\n input: input ?? {},\n wait_for_completion: options?.waitForResult ?? false,\n wait_timeout_ms: waitTimeoutMs\n },\n timeoutMs: requestTimeoutMs,\n });\n return response.data;\n }\n\n /**\n * Invoke a server-side function synchronously.\n *\n * Calls `POST /api/functions/{repo}/{name}/invoke` with `sync: true`.\n * The function executes inline and the result is returned directly.\n *\n * @param repository - Repository name\n * @param functionName - Name of the function to invoke\n * @param input - Input data passed to the function\n * @returns Execution result including output, logs, and duration\n */\n async invokeFunctionSync(\n repository: string,\n functionName: string,\n input?: Record<string, unknown>,\n ): Promise<FunctionInvokeSyncResponse> {\n const response = await this.request<FunctionInvokeSyncResponse>({\n method: 'POST',\n path: `/api/functions/${repository}/${functionName}/invoke`,\n body: { input: input ?? {}, sync: true },\n });\n return response.data;\n }\n\n /**\n * Send one JSON-RPC request to an MCP server endpoint and return its\n * unwrapped `result`.\n *\n * Calls `POST /mcp/{repo}/{branch}/{slug}` carrying a single JSON-RPC 2.0\n * message. MCP errors are returned in the JSON-RPC envelope (HTTP `200`), so\n * this method inspects the body's `error` member and throws on failure.\n *\n * @internal Used by {@link McpClient} via the transport built in `mcp()`.\n */\n async mcpRpc(\n repository: string,\n branch: string,\n slug: string,\n method: string,\n params?: unknown,\n ): Promise<unknown> {\n const id = ++this._mcpRequestId;\n const response = await this.request<McpJsonRpcFrame>({\n method: 'POST',\n path: `/mcp/${repository}/${branch}/${slug}`,\n body: {\n jsonrpc: '2.0',\n id,\n method,\n ...(params !== undefined ? { params } : {}),\n },\n });\n const frame = response.data;\n if (frame?.error) {\n const err = new Error(frame.error.message || `MCP error ${frame.error.code}`);\n (err as any).code = frame.error.code;\n (err as any).data = frame.error.data;\n throw err;\n }\n return frame?.result;\n }\n\n /**\n * Open the `resources/subscribe` SSE stream for an MCP server endpoint.\n *\n * Streams JSON-RPC frames (the subscription ack followed by\n * `notifications/resources/updated` frames) from\n * `POST /mcp/{repo}/{branch}/{slug}`.\n *\n * @internal Used by {@link McpClient} via the transport built in `mcp()`.\n */\n mcpSubscribe(\n repository: string,\n branch: string,\n slug: string,\n method: string,\n params: unknown,\n ): McpFrameStream {\n const headers: Record<string, string> = {};\n // Same rule as `request()`: hold a token, send it. Gating on\n // `isAuthenticated()` dropped it whenever the expiry was unknown, which\n // opened the stream anonymously.\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n const sse = new SSEClient<McpJsonRpcFrame>(\n `${this.baseUrl}/mcp/${repository}/${branch}/${slug}`,\n {\n method: 'POST',\n body: {\n jsonrpc: '2.0',\n id: ++this._mcpRequestId,\n method,\n params,\n },\n headers,\n fetch: this.fetchImpl,\n reconnect: { enabled: false },\n },\n );\n return {\n close: () => sse.close(),\n async *[Symbol.asyncIterator](): AsyncIterator<McpJsonRpcFrame> {\n for await (const event of sse) {\n yield event.data;\n }\n },\n };\n }\n\n /**\n * Get an {@link McpClient} for a content-declared MCP server.\n *\n * @param slug - The `raisin:McpServer` slug (resolved in the `mcp` workspace).\n * @param branch - Branch to address; defaults to the client's current branch.\n */\n mcp(slug: string, branch?: string): McpClient {\n const repository = this._context.repository;\n if (!repository) {\n throw new Error('mcp() requires a repository; call database(name) first');\n }\n const effectiveBranch = branch ?? this.getBranch();\n const transport: McpTransport = {\n rpc: (m, p) => this.mcpRpc(repository, effectiveBranch, slug, m, p),\n subscribe: (m, p) => this.mcpSubscribe(repository, effectiveBranch, slug, m, p),\n };\n return new McpClient(transport);\n }\n\n /**\n * Make a management REST request and return the parsed body.\n *\n * @internal Used by the HTTP schema-management helpers\n * ({@link HttpNodeTypes}/{@link HttpArchetypes}/{@link HttpElementTypes}) to\n * reuse the client's centralized auth, timeout, and base-URL handling.\n */\n async managementRequest<T = unknown>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const response = await this.request<T>({ method, path, body });\n return response.data;\n }\n\n /**\n * Get a simplified database interface for SSR\n * This returns an HTTP-based database client\n */\n database(name: string): HttpDatabase {\n this._context.repository = name;\n return new HttpDatabase(name, this);\n }\n}\n\n/**\n * HTTP-based database interface for SSR\n */\nexport class HttpDatabase {\n private branch?: string;\n\n constructor(\n private repository: string,\n private client: RaisinHttpClient,\n branch?: string\n ) {\n this.branch = branch;\n }\n\n /**\n * Get the repository name\n */\n getRepository(): string {\n return this.repository;\n }\n\n /**\n * Get the current branch (if set)\n */\n getBranch(): string | undefined {\n return this.branch;\n }\n\n /**\n * Create a new HttpDatabase instance scoped to a specific branch.\n *\n * @param branch - Branch name\n * @returns New HttpDatabase instance with branch context\n *\n * @example\n * ```typescript\n * const db = client.database('my-repo');\n * const staging = db.onBranch('staging');\n * const result = await staging.executeSql('SELECT * FROM content');\n * ```\n */\n onBranch(branch: string): HttpDatabase {\n return new HttpDatabase(this.repository, this.client, branch);\n }\n\n /**\n * Execute SQL query\n *\n * @param query - SQL query string\n * @param params - Query parameters\n * @returns SQL query result\n */\n async executeSql(query: string, params?: unknown[]): Promise<SqlResult> {\n return this.client.executeSql(this.repository, query, params, this.branch);\n }\n\n /**\n * Get workspace client\n */\n workspace(name: string): HttpWorkspaceClient {\n return new HttpWorkspaceClient(this.repository, name, this.client);\n }\n\n /**\n * List workspaces\n */\n async listWorkspaces(): Promise<Workspace[]> {\n return this.client.listWorkspaces(this.repository);\n }\n\n /**\n * Get a workspace\n */\n async getWorkspace(name: string): Promise<Workspace> {\n return this.client.getWorkspace(this.repository, name);\n }\n\n /**\n * Create a workspace\n */\n async createWorkspace(name: string, description?: string): Promise<Workspace> {\n return this.client.createWorkspace(this.repository, { name, description });\n }\n\n /**\n * Get FunctionsApi for invoking server-side functions via HTTP\n */\n functions(): HttpFunctionsApi {\n return new HttpFunctionsApi(\n this.repository,\n (repo, name, input, options) => this.client.invokeFunction(repo, name, input, options),\n (repo, name, input) => this.client.invokeFunctionSync(repo, name, input),\n );\n }\n\n /**\n * Get an {@link McpClient} for a content-declared MCP server on this database.\n *\n * @param slug - The `raisin:McpServer` slug (resolved in the `mcp` workspace).\n * @returns A client scoped to `{repo}/{branch}/{slug}`, using this database's\n * branch (falling back to the HTTP client's current branch).\n */\n mcp(slug: string): McpClient {\n const transport: McpTransport = {\n rpc: (m, p) =>\n this.client.mcpRpc(this.repository, this.schemaBranch(), slug, m, p),\n subscribe: (m, p) =>\n this.client.mcpSubscribe(this.repository, this.schemaBranch(), slug, m, p),\n };\n return new McpClient(transport);\n }\n\n /** Effective branch for management calls. */\n private schemaBranch(): string {\n return this.branch ?? this.client.getBranch();\n }\n\n /** NodeType management (get/list/getResolved/create/update/delete/publish/unpublish). */\n nodeTypes(): HttpNodeTypes {\n return new HttpNodeTypes(this.repository, this.schemaBranch(), this.client);\n }\n\n /** Archetype management (get/list/getResolved/create/update/delete/publish/unpublish). */\n archetypes(): HttpArchetypes {\n return new HttpArchetypes(this.repository, this.schemaBranch(), this.client);\n }\n\n /** ElementType management (get/list/getResolved/create/update/delete/publish/unpublish). */\n elementTypes(): HttpElementTypes {\n return new HttpElementTypes(this.repository, this.schemaBranch(), this.client);\n }\n}\n\n/**\n * HTTP-based workspace client for SSR\n */\nexport class HttpWorkspaceClient {\n constructor(\n private repository: string,\n private workspace: string,\n private client: RaisinHttpClient\n ) {}\n\n /**\n * Get workspace name\n */\n getWorkspace(): string {\n return this.workspace;\n }\n\n /**\n * Get a node by ID\n */\n async getNode(nodeId: string): Promise<Node> {\n return this.client.getNode(this.repository, this.workspace, nodeId);\n }\n\n /**\n * Get a node by path\n */\n async getNodeByPath(nodePath: string): Promise<Node> {\n return this.client.getNodeByPath(this.repository, this.workspace, nodePath);\n }\n\n /**\n * Create a node\n */\n async createNode(payload: NodeCreatePayload): Promise<Node> {\n return this.client.createNode(this.repository, this.workspace, payload);\n }\n\n /**\n * Update a node\n */\n async updateNode(nodeId: string, properties: Record<string, unknown>): Promise<Node> {\n return this.client.updateNode(this.repository, this.workspace, nodeId, properties);\n }\n\n /**\n * Delete a node\n */\n async deleteNode(nodeId: string): Promise<void> {\n return this.client.deleteNode(this.repository, this.workspace, nodeId);\n }\n\n /**\n * Create a resumable upload for this workspace (Browser)\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param file - File or Blob to upload\n * @param path - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const upload = await ws.upload(file, '/videos/my-video.mp4', {\n * onProgress: (p) => console.log(`${Math.round(p.progress * 100)}%`)\n * });\n * await upload.start();\n * ```\n */\n async upload(\n file: File | Blob,\n path: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n return this.client.upload(file, {\n ...options,\n repository: this.repository,\n workspace: this.workspace,\n path,\n });\n }\n\n /**\n * Create a resumable upload for this workspace (Node.js)\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param filePath - Path to the file to upload\n * @param nodePath - Path for the new node\n * @param options - Additional upload options\n * @returns Upload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('data').workspace('backups');\n * const upload = await ws.uploadFile('/path/to/backup.zip', '/backup.zip');\n * await upload.start();\n * ```\n */\n async uploadFile(\n filePath: string,\n nodePath: string,\n options?: Partial<Omit<UploadOptions, 'repository' | 'workspace' | 'path'>>\n ): Promise<Upload> {\n return this.client.uploadFile(filePath, {\n ...options,\n repository: this.repository,\n workspace: this.workspace,\n path: nodePath,\n });\n }\n\n /**\n * Upload multiple files to this workspace\n *\n * Creates a batch upload with concurrency control and aggregate progress tracking.\n *\n * @param files - FileList, File[], or Blob[] to upload\n * @param basePath - Base path for all uploads (files go to basePath/filename)\n * @param options - Additional batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const files = document.querySelector('input[type=\"file\"]').files;\n * const batch = await ws.uploadFiles(files, '/uploads', {\n * concurrency: 3,\n * onProgress: (p) => console.log(`${p.filesCompleted}/${p.filesTotal}`),\n * });\n * const result = await batch.start();\n * ```\n */\n async uploadFiles(\n files: FileList | File[] | Blob[],\n basePath: string,\n options?: Partial<Omit<BatchUploadOptions, 'repository' | 'workspace' | 'basePath'>>\n ): Promise<BatchUpload> {\n return this.client.uploadFiles(files, {\n ...options,\n repository: this.repository,\n workspace: this.workspace,\n basePath,\n });\n }\n\n /**\n * Get a signed URL for an asset in this workspace\n *\n * Convenience method that pre-fills repository and workspace.\n *\n * @param path - Path to the asset node\n * @param command - 'download' (forces download) or 'display' (shows inline)\n * @param options - Optional settings: expiresIn (seconds), propertyPath (e.g., 'thumbnail')\n * @returns Signed URL and expiry time\n *\n * @example\n * ```typescript\n * const ws = client.database('media').workspace('assets');\n * const { url } = await ws.signAssetUrl('/files/image.jpeg', 'display');\n * document.querySelector('img').src = url;\n *\n * // Get thumbnail instead of main file\n * const { url: thumbUrl } = await ws.signAssetUrl('/files/image.jpeg', 'display', { propertyPath: 'thumbnail' });\n * ```\n */\n async signAssetUrl(\n path: string,\n command: 'download' | 'display' = 'display',\n options?: { expiresIn?: number; propertyPath?: string }\n ): Promise<SignedAssetUrl> {\n return this.client.signAssetUrl({\n repository: this.repository,\n workspace: this.workspace,\n path,\n command,\n expiresIn: options?.expiresIn,\n propertyPath: options?.propertyPath,\n });\n }\n}\n","/**\n * Upload type definitions for resumable chunked uploads\n *\n * This module defines types for the resumable upload system supporting\n * files up to 10GB+ with progress tracking, pause/resume, and auto-retry.\n */\n\nimport type { Node } from '../protocol';\n\n// ============================================================================\n// Upload Status\n// ============================================================================\n\n/**\n * Possible states of an upload\n */\nexport type UploadStatus =\n | 'pending'\n | 'uploading'\n | 'paused'\n | 'completing'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\n// ============================================================================\n// Upload Options\n// ============================================================================\n\n/**\n * Options for creating a resumable upload\n */\nexport interface UploadOptions {\n /** Repository to upload to */\n repository: string;\n /** Branch name (default: \"main\") */\n branch?: string;\n /** Workspace to store the node */\n workspace: string;\n /** Path for the new node */\n path: string;\n /** Node type (default: \"raisin:Asset\") */\n nodeType?: string;\n /** Additional metadata for the node */\n metadata?: Record<string, unknown>;\n /** Chunk size in bytes (default: 10MB) */\n chunkSize?: number;\n /** Progress callback */\n onProgress?: (progress: UploadProgress) => void;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n /** Commit message for the upload */\n commitMessage?: string;\n /** Actor/user identifier for the commit */\n commitActor?: string;\n /** Enable automatic retry on retryable errors (default: true) */\n autoRetry?: boolean;\n /** Maximum number of retry attempts (default: 3) */\n maxRetries?: number;\n}\n\n// ============================================================================\n// Upload Progress\n// ============================================================================\n\n/**\n * Progress information for an upload\n */\nexport interface UploadProgress {\n /** Bytes uploaded so far */\n bytesUploaded: number;\n /** Total bytes to upload */\n bytesTotal: number;\n /** Progress as a fraction (0-1) */\n progress: number;\n /** Current upload speed in bytes/second */\n speed: number;\n /** Estimated time remaining in seconds */\n eta: number;\n /** Current chunk being uploaded (1-indexed) */\n currentChunk: number;\n /** Total number of chunks */\n totalChunks: number;\n /** Current upload status */\n status: UploadStatus;\n}\n\n// ============================================================================\n// Upload Result\n// ============================================================================\n\n/**\n * Result of a completed upload\n */\nexport interface UploadResult {\n /** The created node */\n node: Node;\n /** Revision/commit ID */\n revision?: string;\n /** Storage key for the binary content */\n storageKey: string;\n}\n\n// ============================================================================\n// Upload Interface\n// ============================================================================\n\n/**\n * Interface for controlling an upload\n */\nexport interface Upload {\n /** Unique upload ID */\n id: string;\n /** Start or resume the upload */\n start(): Promise<UploadResult>;\n /** Pause the upload */\n pause(): void;\n /** Resume a paused upload */\n resume(): Promise<UploadResult>;\n /** Cancel the upload */\n cancel(): Promise<void>;\n /** Get current progress */\n getProgress(): UploadProgress;\n /** Check if the upload is currently active */\n isActive(): boolean;\n}\n\n// ============================================================================\n// API Request/Response Types\n// ============================================================================\n\n/**\n * Request payload for creating an upload session\n */\nexport interface CreateUploadRequest {\n /** Repository name */\n repository: string;\n /** Branch name */\n branch: string;\n /** Workspace name */\n workspace: string;\n /** Node path */\n path: string;\n /** Original filename */\n filename: string;\n /** Total file size in bytes */\n file_size: number;\n /** Content MIME type */\n content_type?: string;\n /** Node type for the created node */\n node_type?: string;\n /** Chunk size in bytes */\n chunk_size?: number;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Response from creating an upload session\n */\nexport interface CreateUploadResponse {\n /** Unique upload session ID */\n upload_id: string;\n /** URL for uploading chunks */\n upload_url: string;\n /** Chunk size determined by server */\n chunk_size: number;\n /** Total number of chunks expected */\n total_chunks: number;\n /** Session expiration time */\n expires_at: string;\n}\n\n/**\n * Response from uploading a chunk\n */\nexport interface ChunkUploadResponse {\n /** Upload session ID */\n upload_id: string;\n /** Total bytes received so far */\n bytes_received: number;\n /** Total bytes expected */\n bytes_total: number;\n /** Number of chunks completed */\n chunks_completed: number;\n /** Total number of chunks */\n chunks_total: number;\n /** Progress as a fraction (0-1) */\n progress: number;\n}\n\n/**\n * Response from getting upload status\n */\nexport interface UploadStatusResponse {\n /** Upload session ID */\n upload_id: string;\n /** Session status */\n status: string;\n /** Bytes received so far */\n bytes_received: number;\n /** Total bytes expected */\n bytes_total: number;\n /** Chunks completed */\n chunks_completed: number;\n /** Total chunks */\n chunks_total: number;\n /** Session expiration time */\n expires_at: string;\n}\n\n/**\n * Request payload for completing an upload\n */\nexport interface CompleteUploadRequest {\n /** Optional commit message */\n commit_message?: string;\n /** Optional commit actor */\n commit_actor?: string;\n}\n\n/**\n * Response from completing an upload\n */\nexport interface CompleteUploadResponse {\n /** The created node */\n node: Node;\n /** Revision/commit ID */\n revision?: string;\n /** Storage key for the binary */\n storage_key: string;\n}\n\n// ============================================================================\n// Retry Options\n// ============================================================================\n\n/**\n * Options for retry behavior\n */\nexport interface RetryOptions {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds */\n baseDelay: number;\n /** Maximum delay in milliseconds */\n maxDelay: number;\n /** Use exponential backoff */\n exponentialBackoff: boolean;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Error codes for upload operations\n */\nexport enum UploadErrorCode {\n /** Invalid file (empty, too large, etc.) */\n INVALID_FILE = 'INVALID_FILE',\n /** File exceeds maximum size limit */\n FILE_TOO_LARGE = 'FILE_TOO_LARGE',\n /** Upload session has expired */\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n /** Upload session not found */\n SESSION_NOT_FOUND = 'SESSION_NOT_FOUND',\n /** Chunk offset doesn't match expected position */\n CHUNK_OFFSET_MISMATCH = 'CHUNK_OFFSET_MISMATCH',\n /** Chunk checksum verification failed */\n CHECKSUM_MISMATCH = 'CHECKSUM_MISMATCH',\n /** Backend storage error */\n STORAGE_ERROR = 'STORAGE_ERROR',\n /** Server-side error */\n SERVER_ERROR = 'SERVER_ERROR',\n /** Network connectivity error */\n NETWORK_ERROR = 'NETWORK_ERROR',\n /** Request timeout */\n TIMEOUT = 'TIMEOUT',\n /** Upload was cancelled */\n CANCELLED = 'CANCELLED',\n}\n\n/**\n * Custom error class for upload operations\n */\nexport class UploadError extends Error {\n /**\n * Create an upload error\n *\n * @param message - Human-readable error message\n * @param code - Error code\n * @param retryable - Whether this error can be retried\n * @param details - Additional error details\n */\n constructor(\n message: string,\n public readonly code: UploadErrorCode,\n public readonly retryable: boolean,\n public readonly details?: unknown\n ) {\n super(message);\n this.name = 'UploadError';\n // Maintain proper stack trace in V8\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, UploadError);\n }\n }\n\n /**\n * Create a network error\n */\n static networkError(message: string, details?: unknown): UploadError {\n return new UploadError(message, UploadErrorCode.NETWORK_ERROR, true, details);\n }\n\n /**\n * Create a timeout error\n */\n static timeoutError(message: string, details?: unknown): UploadError {\n return new UploadError(message, UploadErrorCode.TIMEOUT, true, details);\n }\n\n /**\n * Create a cancelled error\n */\n static cancelledError(message = 'Upload was cancelled'): UploadError {\n return new UploadError(message, UploadErrorCode.CANCELLED, false);\n }\n\n /**\n * Create a session expired error\n */\n static sessionExpiredError(uploadId: string): UploadError {\n return new UploadError(\n `Upload session ${uploadId} has expired`,\n UploadErrorCode.SESSION_EXPIRED,\n false,\n { uploadId }\n );\n }\n\n /**\n * Create a session not found error\n */\n static sessionNotFoundError(uploadId: string): UploadError {\n return new UploadError(\n `Upload session ${uploadId} not found`,\n UploadErrorCode.SESSION_NOT_FOUND,\n false,\n { uploadId }\n );\n }\n\n /**\n * Create an error from an HTTP response\n */\n static fromResponse(status: number, body: unknown): UploadError {\n const message = typeof body === 'object' && body !== null && 'message' in body\n ? String((body as { message: unknown }).message)\n : `HTTP error ${status}`;\n\n // Map HTTP status to error code\n let code: UploadErrorCode;\n let retryable: boolean;\n\n switch (status) {\n case 400:\n code = UploadErrorCode.INVALID_FILE;\n retryable = false;\n break;\n case 404:\n code = UploadErrorCode.SESSION_NOT_FOUND;\n retryable = false;\n break;\n case 409:\n code = UploadErrorCode.CHUNK_OFFSET_MISMATCH;\n retryable = false;\n break;\n case 410:\n code = UploadErrorCode.SESSION_EXPIRED;\n retryable = false;\n break;\n case 413:\n code = UploadErrorCode.FILE_TOO_LARGE;\n retryable = false;\n break;\n case 500:\n case 502:\n case 503:\n case 504:\n code = UploadErrorCode.SERVER_ERROR;\n retryable = true;\n break;\n default:\n code = UploadErrorCode.SERVER_ERROR;\n retryable = status >= 500;\n }\n\n return new UploadError(message, code, retryable, body);\n }\n}\n\n// ============================================================================\n// Default Values\n// ============================================================================\n\n/** Default chunk size: 10 MB */\nexport const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024;\n\n/** Default maximum retries */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** Default base delay for retries: 1 second */\nexport const DEFAULT_RETRY_BASE_DELAY = 1000;\n\n/** Default maximum delay for retries: 30 seconds */\nexport const DEFAULT_RETRY_MAX_DELAY = 30000;\n\n/** Default node type for uploads */\nexport const DEFAULT_NODE_TYPE = 'raisin:Asset';\n\n/** Default branch */\nexport const DEFAULT_BRANCH = 'main';\n\n/** Default concurrency for batch uploads */\nexport const DEFAULT_BATCH_CONCURRENCY = 3;\n\n// ============================================================================\n// Batch Upload Types\n// ============================================================================\n\n/**\n * Progress for a single file in a batch upload\n */\nexport interface BatchFileProgress {\n /** Filename */\n file: string;\n /** Current upload status */\n status: UploadStatus;\n /** Bytes uploaded so far */\n bytesUploaded: number;\n /** Total bytes to upload */\n bytesTotal: number;\n /** Progress as a fraction (0-1) */\n progress: number;\n /** Error if upload failed */\n error?: Error;\n}\n\n/**\n * Aggregate progress across all files in a batch upload\n */\nexport interface BatchProgress {\n /** Total number of files in the batch */\n filesTotal: number;\n /** Number of files completed successfully */\n filesCompleted: number;\n /** Number of files that failed */\n filesFailed: number;\n /** Number of files currently uploading */\n filesInProgress: number;\n /** Number of files waiting in queue */\n filesPending: number;\n /** Total bytes uploaded across all files */\n bytesUploaded: number;\n /** Total bytes across all files */\n bytesTotal: number;\n /** Overall progress as a fraction (0-1) */\n progress: number;\n /** Aggregate upload speed in bytes/second */\n speed: number;\n /** Estimated time remaining in seconds */\n eta: number;\n /** Per-file progress details */\n files: BatchFileProgress[];\n}\n\n/**\n * Result of a completed batch upload\n */\nexport interface BatchUploadResult {\n /** Successfully uploaded files */\n successful: Array<{ file: string; result: UploadResult }>;\n /** Files that failed to upload */\n failed: Array<{ file: string; error: Error }>;\n}\n\n/**\n * Options for batch upload operations\n */\nexport interface BatchUploadOptions {\n /** Repository to upload to */\n repository: string;\n /** Branch name (default: \"main\") */\n branch?: string;\n /** Workspace to store the nodes */\n workspace: string;\n /** Base path - files will be uploaded to basePath/filename */\n basePath?: string;\n /** Custom function to determine path for each file */\n pathResolver?: (file: { name: string; size: number }) => string;\n /** Node type (default: \"raisin:Asset\") */\n nodeType?: string;\n /** Additional metadata for all nodes */\n metadata?: Record<string, unknown>;\n /** Chunk size in bytes (default: 10MB) */\n chunkSize?: number;\n /** Max concurrent uploads (default: 3) */\n concurrency?: number;\n /** Progress callback for aggregate progress */\n onProgress?: (progress: BatchProgress) => void;\n /** Called when individual file completes */\n onFileComplete?: (file: string, result: UploadResult) => void;\n /** Called when individual file fails */\n onFileError?: (file: string, error: Error) => void;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n /** Commit message for all uploads */\n commitMessage?: string;\n /** Actor/user identifier for all commits */\n commitActor?: string;\n /** Enable automatic retry on retryable errors (default: true) */\n autoRetry?: boolean;\n /** Maximum number of retry attempts per file (default: 3) */\n maxRetries?: number;\n /** Continue uploading remaining files if one fails (default: true) */\n continueOnError?: boolean;\n}\n\n/**\n * Interface for controlling a batch upload\n */\nexport interface BatchUpload {\n /** Start all uploads */\n start(): Promise<BatchUploadResult>;\n /** Pause all active uploads */\n pause(): void;\n /** Resume paused uploads */\n resume(): Promise<BatchUploadResult>;\n /** Cancel all uploads */\n cancel(): Promise<void>;\n /** Get current aggregate progress */\n getProgress(): BatchProgress;\n /** Check if any uploads are active */\n isActive(): boolean;\n}\n","/**\n * Retry utility with exponential backoff and jitter\n *\n * Implements a robust retry strategy for handling transient failures\n * in upload operations.\n */\n\nimport {\n RetryOptions,\n UploadError,\n UploadErrorCode,\n DEFAULT_MAX_RETRIES,\n DEFAULT_RETRY_BASE_DELAY,\n DEFAULT_RETRY_MAX_DELAY,\n} from './types';\n\n// ============================================================================\n// Default Options\n// ============================================================================\n\n/**\n * Default retry options\n */\nexport const DEFAULT_RETRY_OPTIONS: RetryOptions = {\n maxRetries: DEFAULT_MAX_RETRIES,\n baseDelay: DEFAULT_RETRY_BASE_DELAY,\n maxDelay: DEFAULT_RETRY_MAX_DELAY,\n exponentialBackoff: true,\n};\n\n// ============================================================================\n// Retry Context\n// ============================================================================\n\n/**\n * Context passed to retry callbacks\n */\nexport interface RetryContext {\n /** Current attempt number (1-indexed) */\n attempt: number;\n /** Total attempts allowed */\n maxAttempts: number;\n /** Last error that occurred */\n lastError: Error | null;\n /** Whether this is a retry (not the first attempt) */\n isRetry: boolean;\n}\n\n/**\n * Callback for retry events\n */\nexport type RetryCallback = (context: RetryContext) => void;\n\n// ============================================================================\n// Delay Calculation\n// ============================================================================\n\n/**\n * Calculate delay with exponential backoff and jitter\n *\n * Uses the formula: delay = min(maxDelay, baseDelay * 2^attempt + jitter)\n * Jitter is a random value between 0 and 30% of the base delay.\n *\n * @param attempt - Current attempt number (0-indexed)\n * @param options - Retry options\n * @returns Delay in milliseconds\n */\nexport function calculateDelay(attempt: number, options: RetryOptions): number {\n const { baseDelay, maxDelay, exponentialBackoff } = options;\n\n let delay: number;\n\n if (exponentialBackoff) {\n // Exponential: baseDelay * 2^attempt\n delay = baseDelay * Math.pow(2, attempt);\n } else {\n // Linear: just use base delay\n delay = baseDelay;\n }\n\n // Add jitter (0-30% of base delay)\n const jitter = Math.random() * 0.3 * baseDelay;\n delay += jitter;\n\n // Cap at max delay\n return Math.min(delay, maxDelay);\n}\n\n/**\n * Sleep for a given number of milliseconds\n *\n * @param ms - Milliseconds to sleep\n * @param signal - Optional abort signal\n * @returns Promise that resolves after the delay\n * @throws UploadError if aborted\n */\nexport async function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n // Check if already aborted\n if (signal?.aborted) {\n reject(UploadError.cancelledError());\n return;\n }\n\n const timeoutId = setTimeout(resolve, ms);\n\n // Listen for abort\n if (signal) {\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(UploadError.cancelledError());\n };\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n // Clean up listener after timeout\n setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n }, ms);\n }\n });\n}\n\n// ============================================================================\n// Retry Functions\n// ============================================================================\n\n/**\n * Determine if an error is retryable\n *\n * @param error - Error to check\n * @returns True if the error can be retried\n */\nexport function isRetryableError(error: unknown): boolean {\n // UploadError has explicit retryable flag\n if (error instanceof UploadError) {\n return error.retryable;\n }\n\n // Check for common retryable error patterns\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Network errors\n if (\n message.includes('network') ||\n message.includes('fetch') ||\n message.includes('connection') ||\n message.includes('econnreset') ||\n message.includes('econnrefused') ||\n message.includes('etimedout') ||\n message.includes('timeout')\n ) {\n return true;\n }\n\n // Check error name/type\n const name = error.name.toLowerCase();\n if (name === 'networkerror' || name === 'typeerror') {\n // TypeError can occur with fetch on network failures\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Execute a function with retry logic\n *\n * @param fn - Async function to execute\n * @param options - Retry options\n * @param signal - Optional abort signal\n * @param onRetry - Optional callback for retry events\n * @returns Result of the function\n * @throws Last error if all retries are exhausted\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> = {},\n signal?: AbortSignal,\n onRetry?: RetryCallback\n): Promise<T> {\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\n const maxAttempts = opts.maxRetries + 1; // Total attempts = retries + 1\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n // Check for abort\n if (signal?.aborted) {\n throw UploadError.cancelledError();\n }\n\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry if not retryable\n if (!isRetryableError(error)) {\n throw error;\n }\n\n // Don't retry if this was the last attempt\n if (attempt >= maxAttempts - 1) {\n throw error;\n }\n\n // Calculate delay\n const delay = calculateDelay(attempt, opts);\n\n // Notify retry callback\n if (onRetry) {\n onRetry({\n attempt: attempt + 1,\n maxAttempts,\n lastError,\n isRetry: true,\n });\n }\n\n // Wait before next attempt\n await sleep(delay, signal);\n }\n }\n\n // Should not reach here, but TypeScript needs a return\n throw lastError ?? new Error('Retry failed');\n}\n\n// ============================================================================\n// Retry Builder (Fluent API)\n// ============================================================================\n\n/**\n * Builder for creating retry configurations\n *\n * @example\n * ```typescript\n * const result = await new RetryBuilder()\n * .maxRetries(5)\n * .baseDelay(2000)\n * .onRetry((ctx) => console.log(`Retry ${ctx.attempt}/${ctx.maxAttempts}`))\n * .execute(() => uploadChunk(data));\n * ```\n */\nexport class RetryBuilder {\n private options: RetryOptions = { ...DEFAULT_RETRY_OPTIONS };\n private signal?: AbortSignal;\n private retryCallback?: RetryCallback;\n\n /**\n * Set maximum number of retries\n */\n maxRetries(count: number): this {\n this.options.maxRetries = count;\n return this;\n }\n\n /**\n * Set base delay in milliseconds\n */\n baseDelay(ms: number): this {\n this.options.baseDelay = ms;\n return this;\n }\n\n /**\n * Set maximum delay in milliseconds\n */\n maxDelay(ms: number): this {\n this.options.maxDelay = ms;\n return this;\n }\n\n /**\n * Enable or disable exponential backoff\n */\n exponentialBackoff(enabled: boolean): this {\n this.options.exponentialBackoff = enabled;\n return this;\n }\n\n /**\n * Set abort signal\n */\n withSignal(signal: AbortSignal): this {\n this.signal = signal;\n return this;\n }\n\n /**\n * Set retry callback\n */\n onRetry(callback: RetryCallback): this {\n this.retryCallback = callback;\n return this;\n }\n\n /**\n * Execute a function with retry\n */\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n return withRetry(fn, this.options, this.signal, this.retryCallback);\n }\n}\n\n// ============================================================================\n// Error Classification\n// ============================================================================\n\n/**\n * Classify an error for retry decisions\n */\nexport interface ErrorClassification {\n /** Error code */\n code: UploadErrorCode;\n /** Whether the error is retryable */\n retryable: boolean;\n /** Suggested delay multiplier for this error type */\n delayMultiplier: number;\n /** Human-readable description */\n description: string;\n}\n\n/**\n * Classify an error for retry decisions\n *\n * @param error - Error to classify\n * @returns Error classification\n */\nexport function classifyError(error: unknown): ErrorClassification {\n if (error instanceof UploadError) {\n return {\n code: error.code,\n retryable: error.retryable,\n delayMultiplier: getDelayMultiplier(error.code),\n description: error.message,\n };\n }\n\n // Handle generic errors\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Timeout errors - moderate backoff\n if (message.includes('timeout')) {\n return {\n code: UploadErrorCode.TIMEOUT,\n retryable: true,\n delayMultiplier: 1.5,\n description: 'Request timed out',\n };\n }\n\n // Network errors - aggressive backoff\n if (\n message.includes('network') ||\n message.includes('connection') ||\n message.includes('econnreset')\n ) {\n return {\n code: UploadErrorCode.NETWORK_ERROR,\n retryable: true,\n delayMultiplier: 2.0,\n description: 'Network connection error',\n };\n }\n }\n\n // Unknown error - conservative approach\n return {\n code: UploadErrorCode.SERVER_ERROR,\n retryable: false,\n delayMultiplier: 1.0,\n description: 'Unknown error',\n };\n}\n\n/**\n * Get delay multiplier for an error code\n */\nfunction getDelayMultiplier(code: UploadErrorCode): number {\n switch (code) {\n case UploadErrorCode.NETWORK_ERROR:\n return 2.0; // Network issues - wait longer\n case UploadErrorCode.TIMEOUT:\n return 1.5; // Timeouts - moderate wait\n case UploadErrorCode.SERVER_ERROR:\n return 1.5; // Server overload - moderate wait\n case UploadErrorCode.STORAGE_ERROR:\n return 1.0; // Storage issues - normal wait\n default:\n return 1.0;\n }\n}\n","/**\n * Batch upload implementation for multiple files\n *\n * Provides concurrent upload of multiple files with:\n * - Configurable concurrency limit\n * - Aggregate and per-file progress tracking\n * - Pause/resume/cancel support\n * - Error handling with continue-on-error option\n */\n\nimport type {\n BatchUpload,\n BatchUploadOptions,\n BatchUploadResult,\n BatchProgress,\n BatchFileProgress,\n UploadResult,\n UploadStatus,\n} from './types';\nimport {\n DEFAULT_BATCH_CONCURRENCY,\n DEFAULT_BRANCH,\n DEFAULT_NODE_TYPE,\n DEFAULT_CHUNK_SIZE,\n DEFAULT_MAX_RETRIES,\n} from './types';\nimport type { FileSource } from './file-source';\nimport type { UploaderConfig } from './uploader';\nimport { Uploader } from './uploader';\n\n// ============================================================================\n// Speed Tracker for Batch\n// ============================================================================\n\n/**\n * Track aggregate upload speed using a sliding window\n */\nclass BatchSpeedTracker {\n private samples: Array<{ bytes: number; timestamp: number }> = [];\n private readonly windowSize: number;\n private readonly maxSamples: number;\n\n constructor(windowSizeMs = 5000, maxSamples = 50) {\n this.windowSize = windowSizeMs;\n this.maxSamples = maxSamples;\n }\n\n addSample(bytes: number): void {\n const now = Date.now();\n this.samples.push({ bytes, timestamp: now });\n\n // Remove old samples\n const cutoff = now - this.windowSize;\n this.samples = this.samples.filter((s) => s.timestamp > cutoff);\n\n // Limit max samples\n if (this.samples.length > this.maxSamples) {\n this.samples = this.samples.slice(-this.maxSamples);\n }\n }\n\n getSpeed(): number {\n if (this.samples.length < 2) {\n return 0;\n }\n\n const first = this.samples[0];\n const last = this.samples[this.samples.length - 1];\n const timeDelta = (last.timestamp - first.timestamp) / 1000;\n\n if (timeDelta === 0) {\n return 0;\n }\n\n const totalBytes = this.samples.reduce((sum, s) => sum + s.bytes, 0);\n return totalBytes / timeDelta;\n }\n\n getEta(remainingBytes: number): number {\n const speed = this.getSpeed();\n if (speed === 0) {\n return 0;\n }\n return remainingBytes / speed;\n }\n\n reset(): void {\n this.samples = [];\n }\n}\n\n// ============================================================================\n// File State\n// ============================================================================\n\ninterface FileState {\n file: FileSource;\n status: UploadStatus;\n bytesUploaded: number;\n uploader: Uploader | null;\n result: UploadResult | null;\n error: Error | null;\n}\n\n// ============================================================================\n// Batch Uploader\n// ============================================================================\n\n/**\n * Manages concurrent upload of multiple files\n */\nexport class BatchUploader implements BatchUpload {\n private readonly config: UploaderConfig;\n private readonly files: FileSource[];\n private readonly options: Required<\n Omit<\n BatchUploadOptions,\n 'onProgress' | 'onFileComplete' | 'onFileError' | 'signal' | 'pathResolver' | 'metadata' | 'commitMessage' | 'commitActor'\n >\n > &\n Pick<BatchUploadOptions, 'onProgress' | 'onFileComplete' | 'onFileError' | 'signal' | 'pathResolver' | 'metadata' | 'commitMessage' | 'commitActor'>;\n\n private readonly fileStates: Map<string, FileState> = new Map();\n private readonly queue: string[] = [];\n private readonly speedTracker = new BatchSpeedTracker();\n\n private activeWorkers = 0;\n private paused = false;\n private cancelled = false;\n private started = false;\n private resolveWhenResumed: (() => void) | null = null;\n private lastBytesUploaded = 0;\n\n /**\n * Create a batch uploader\n */\n constructor(\n config: UploaderConfig,\n files: FileSource[],\n options: BatchUploadOptions\n ) {\n this.config = config;\n this.files = files;\n\n // Merge with defaults\n this.options = {\n repository: options.repository,\n branch: options.branch ?? DEFAULT_BRANCH,\n workspace: options.workspace,\n basePath: options.basePath ?? '',\n pathResolver: options.pathResolver,\n nodeType: options.nodeType ?? DEFAULT_NODE_TYPE,\n metadata: options.metadata,\n chunkSize: options.chunkSize ?? DEFAULT_CHUNK_SIZE,\n concurrency: options.concurrency ?? DEFAULT_BATCH_CONCURRENCY,\n onProgress: options.onProgress,\n onFileComplete: options.onFileComplete,\n onFileError: options.onFileError,\n signal: options.signal,\n commitMessage: options.commitMessage,\n commitActor: options.commitActor,\n autoRetry: options.autoRetry ?? true,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n continueOnError: options.continueOnError ?? true,\n };\n\n // Initialize file states\n for (const file of files) {\n this.fileStates.set(file.name, {\n file,\n status: 'pending',\n bytesUploaded: 0,\n uploader: null,\n result: null,\n error: null,\n });\n this.queue.push(file.name);\n }\n }\n\n /**\n * Start all uploads\n */\n async start(): Promise<BatchUploadResult> {\n if (this.started && !this.paused) {\n throw new Error('Batch upload already started');\n }\n\n this.started = true;\n this.paused = false;\n this.cancelled = false;\n\n // Link external abort signal\n if (this.options.signal) {\n this.options.signal.addEventListener('abort', () => {\n this.cancel();\n });\n }\n\n // Start workers\n const concurrency = Math.min(this.options.concurrency, this.queue.length);\n const workers = Array(concurrency)\n .fill(null)\n .map(() => this.worker());\n\n await Promise.all(workers);\n\n return this.getResult();\n }\n\n /**\n * Pause all active uploads\n */\n pause(): void {\n if (!this.started || this.paused || this.cancelled) {\n return;\n }\n\n this.paused = true;\n\n // Pause all active uploaders\n for (const state of this.fileStates.values()) {\n if (state.uploader && state.status === 'uploading') {\n state.uploader.pause();\n state.status = 'paused';\n }\n }\n\n this.emitProgress();\n }\n\n /**\n * Resume paused uploads\n */\n async resume(): Promise<BatchUploadResult> {\n if (!this.paused) {\n throw new Error('Batch upload is not paused');\n }\n\n this.paused = false;\n\n // Resume all paused uploaders\n for (const state of this.fileStates.values()) {\n if (state.status === 'paused') {\n state.status = 'uploading';\n }\n }\n\n // Wake up waiting workers\n if (this.resolveWhenResumed) {\n this.resolveWhenResumed();\n this.resolveWhenResumed = null;\n }\n\n this.emitProgress();\n\n // Continue with remaining uploads\n return this.start();\n }\n\n /**\n * Cancel all uploads\n */\n async cancel(): Promise<void> {\n this.cancelled = true;\n this.paused = false;\n\n // Cancel all active uploaders\n const cancelPromises: Promise<void>[] = [];\n for (const state of this.fileStates.values()) {\n if (state.uploader && (state.status === 'uploading' || state.status === 'paused')) {\n cancelPromises.push(state.uploader.cancel());\n state.status = 'cancelled';\n }\n }\n\n // Mark pending files as cancelled\n for (const state of this.fileStates.values()) {\n if (state.status === 'pending') {\n state.status = 'cancelled';\n }\n }\n\n // Wake up waiting workers\n if (this.resolveWhenResumed) {\n this.resolveWhenResumed();\n this.resolveWhenResumed = null;\n }\n\n await Promise.all(cancelPromises);\n\n this.emitProgress();\n }\n\n /**\n * Get current aggregate progress\n */\n getProgress(): BatchProgress {\n const fileProgresses: BatchFileProgress[] = [];\n\n let bytesUploaded = 0;\n let bytesTotal = 0;\n let filesCompleted = 0;\n let filesFailed = 0;\n let filesInProgress = 0;\n let filesPending = 0;\n\n for (const state of this.fileStates.values()) {\n const fileProgress: BatchFileProgress = {\n file: state.file.name,\n status: state.status,\n bytesUploaded: state.bytesUploaded,\n bytesTotal: state.file.size,\n progress: state.file.size > 0 ? state.bytesUploaded / state.file.size : 0,\n error: state.error ?? undefined,\n };\n fileProgresses.push(fileProgress);\n\n bytesUploaded += state.bytesUploaded;\n bytesTotal += state.file.size;\n\n switch (state.status) {\n case 'completed':\n filesCompleted++;\n break;\n case 'failed':\n filesFailed++;\n break;\n case 'uploading':\n case 'completing':\n filesInProgress++;\n break;\n case 'pending':\n case 'paused':\n filesPending++;\n break;\n }\n }\n\n const progress = bytesTotal > 0 ? bytesUploaded / bytesTotal : 0;\n const speed = this.speedTracker.getSpeed();\n const remainingBytes = bytesTotal - bytesUploaded;\n const eta = this.speedTracker.getEta(remainingBytes);\n\n return {\n filesTotal: this.files.length,\n filesCompleted,\n filesFailed,\n filesInProgress,\n filesPending,\n bytesUploaded,\n bytesTotal,\n progress,\n speed,\n eta,\n files: fileProgresses,\n };\n }\n\n /**\n * Check if any uploads are active\n */\n isActive(): boolean {\n return this.started && !this.paused && !this.cancelled && this.activeWorkers > 0;\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n /**\n * Worker that processes files from the queue\n */\n private async worker(): Promise<void> {\n this.activeWorkers++;\n\n try {\n while (this.queue.length > 0 && !this.cancelled) {\n // Wait if paused\n if (this.paused) {\n await this.waitForResume();\n if (this.cancelled) break;\n }\n\n // Get next file from queue\n const fileName = this.queue.shift();\n if (!fileName) break;\n\n const state = this.fileStates.get(fileName);\n if (!state) continue;\n\n // Upload the file\n await this.uploadFile(state);\n }\n } finally {\n this.activeWorkers--;\n }\n }\n\n /**\n * Wait until resume() is called\n */\n private async waitForResume(): Promise<void> {\n return new Promise((resolve) => {\n this.resolveWhenResumed = resolve;\n });\n }\n\n /**\n * Upload a single file\n */\n private async uploadFile(state: FileState): Promise<void> {\n const path = this.resolvePath(state.file);\n\n // Create uploader\n const uploader = new Uploader(\n this.config,\n state.file,\n {\n repository: this.options.repository,\n branch: this.options.branch,\n workspace: this.options.workspace,\n path,\n nodeType: this.options.nodeType,\n metadata: this.options.metadata,\n chunkSize: this.options.chunkSize,\n commitMessage: this.options.commitMessage,\n commitActor: this.options.commitActor,\n autoRetry: this.options.autoRetry,\n maxRetries: this.options.maxRetries,\n onProgress: (progress) => {\n state.bytesUploaded = progress.bytesUploaded;\n state.status = progress.status;\n this.updateSpeedTracker();\n this.emitProgress();\n },\n }\n );\n\n state.uploader = uploader;\n state.status = 'uploading';\n\n try {\n const result = await uploader.start();\n state.status = 'completed';\n state.result = result;\n state.bytesUploaded = state.file.size;\n\n // Notify file complete\n this.options.onFileComplete?.(state.file.name, result);\n } catch (error) {\n state.status = 'failed';\n state.error = error instanceof Error ? error : new Error(String(error));\n\n // Notify file error\n this.options.onFileError?.(state.file.name, state.error);\n\n // Stop if not continuing on error\n if (!this.options.continueOnError) {\n this.cancelled = true;\n }\n } finally {\n this.emitProgress();\n }\n }\n\n /**\n * Resolve the path for a file\n */\n private resolvePath(file: FileSource): string {\n if (this.options.pathResolver) {\n return this.options.pathResolver({ name: file.name, size: file.size });\n }\n\n // Default: basePath/filename\n const basePath = this.options.basePath.replace(/\\/$/, '');\n return basePath ? `${basePath}/${file.name}` : `/${file.name}`;\n }\n\n /**\n * Update speed tracker with delta bytes\n */\n private updateSpeedTracker(): void {\n const progress = this.getProgress();\n const delta = progress.bytesUploaded - this.lastBytesUploaded;\n if (delta > 0) {\n this.speedTracker.addSample(delta);\n this.lastBytesUploaded = progress.bytesUploaded;\n }\n }\n\n /**\n * Emit progress update\n */\n private emitProgress(): void {\n if (this.options.onProgress) {\n this.options.onProgress(this.getProgress());\n }\n }\n\n /**\n * Get final result\n */\n private getResult(): BatchUploadResult {\n const successful: Array<{ file: string; result: UploadResult }> = [];\n const failed: Array<{ file: string; error: Error }> = [];\n\n for (const state of this.fileStates.values()) {\n if (state.status === 'completed' && state.result) {\n successful.push({ file: state.file.name, result: state.result });\n } else if (state.status === 'failed' && state.error) {\n failed.push({ file: state.file.name, error: state.error });\n } else if (state.status === 'cancelled') {\n failed.push({\n file: state.file.name,\n error: new Error('Upload cancelled'),\n });\n }\n }\n\n return { successful, failed };\n }\n}\n","/**\n * Main Upload implementation\n *\n * Provides resumable chunked uploads with progress tracking,\n * pause/resume, and automatic retry support.\n */\n\nimport type { AuthManager } from '../auth';\nimport type {\n Upload,\n UploadOptions,\n UploadProgress,\n UploadResult,\n UploadStatus,\n CreateUploadRequest,\n CreateUploadResponse,\n ChunkUploadResponse,\n CompleteUploadRequest,\n CompleteUploadResponse,\n UploadStatusResponse,\n RetryOptions,\n BatchUpload,\n BatchUploadOptions,\n} from './types';\nimport {\n UploadError,\n UploadErrorCode,\n DEFAULT_CHUNK_SIZE,\n DEFAULT_MAX_RETRIES,\n DEFAULT_NODE_TYPE,\n DEFAULT_BRANCH,\n} from './types';\nimport type { FileSource } from './file-source';\nimport { getContentType, getChunkRange, calculateChunkCount } from './file-source';\nimport { withRetry } from './retry';\nimport { BatchUploader } from './batch';\n\n// ============================================================================\n// Speed Tracker\n// ============================================================================\n\n/**\n * Track upload speed using a sliding window\n */\nclass SpeedTracker {\n private samples: Array<{ bytes: number; timestamp: number }> = [];\n private readonly windowSize: number;\n private readonly maxSamples: number;\n\n constructor(windowSizeMs = 5000, maxSamples = 20) {\n this.windowSize = windowSizeMs;\n this.maxSamples = maxSamples;\n }\n\n /**\n * Add a sample\n */\n addSample(bytes: number): void {\n const now = Date.now();\n this.samples.push({ bytes, timestamp: now });\n\n // Remove old samples\n const cutoff = now - this.windowSize;\n this.samples = this.samples.filter((s) => s.timestamp > cutoff);\n\n // Limit max samples\n if (this.samples.length > this.maxSamples) {\n this.samples = this.samples.slice(-this.maxSamples);\n }\n }\n\n /**\n * Get current speed in bytes/second\n */\n getSpeed(): number {\n if (this.samples.length < 2) {\n return 0;\n }\n\n const first = this.samples[0];\n const last = this.samples[this.samples.length - 1];\n const timeDelta = (last.timestamp - first.timestamp) / 1000; // seconds\n\n if (timeDelta === 0) {\n return 0;\n }\n\n const totalBytes = this.samples.reduce((sum, s) => sum + s.bytes, 0);\n return totalBytes / timeDelta;\n }\n\n /**\n * Calculate ETA in seconds\n */\n getEta(remainingBytes: number): number {\n const speed = this.getSpeed();\n if (speed === 0) {\n return 0;\n }\n return remainingBytes / speed;\n }\n\n /**\n * Reset tracker\n */\n reset(): void {\n this.samples = [];\n }\n}\n\n// ============================================================================\n// Chunk Uploader (Browser vs Node.js)\n// ============================================================================\n\n/**\n * Upload a chunk using XHR (browser) for progress tracking\n */\nasync function uploadChunkXhr(\n url: string,\n chunk: ArrayBuffer,\n headers: Record<string, string>,\n onProgress?: (loaded: number) => void,\n signal?: AbortSignal\n): Promise<Response> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n // Handle abort\n const onAbort = () => {\n xhr.abort();\n reject(UploadError.cancelledError());\n };\n\n if (signal) {\n if (signal.aborted) {\n reject(UploadError.cancelledError());\n return;\n }\n signal.addEventListener('abort', onAbort, { once: true });\n }\n\n // Track upload progress\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable && onProgress) {\n onProgress(event.loaded);\n }\n };\n\n // Handle completion\n xhr.onload = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n\n // Create a Response-like object\n const response = new Response(xhr.responseText, {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: parseXhrHeaders(xhr.getAllResponseHeaders()),\n });\n\n resolve(response);\n };\n\n // Handle errors\n xhr.onerror = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n reject(UploadError.networkError('XHR network error'));\n };\n\n xhr.ontimeout = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n reject(UploadError.timeoutError('XHR timeout'));\n };\n\n xhr.onabort = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n reject(UploadError.cancelledError());\n };\n\n // Open and send\n xhr.open('PATCH', url);\n\n // Set headers\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value);\n }\n\n xhr.send(chunk);\n });\n}\n\n/**\n * Parse XHR response headers into Headers object\n */\nfunction parseXhrHeaders(headerString: string): Headers {\n const headers = new Headers();\n const lines = headerString.trim().split(/[\\r\\n]+/);\n\n for (const line of lines) {\n const parts = line.split(': ');\n const key = parts.shift();\n const value = parts.join(': ');\n if (key) {\n headers.append(key, value);\n }\n }\n\n return headers;\n}\n\n/**\n * Upload a chunk using fetch (Node.js or fallback)\n */\nasync function uploadChunkFetch(\n url: string,\n chunk: ArrayBuffer,\n headers: Record<string, string>,\n signal?: AbortSignal,\n fetchFn: typeof fetch = fetch\n): Promise<Response> {\n try {\n return await fetchFn(url, {\n method: 'PATCH',\n headers,\n body: chunk,\n signal,\n });\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw UploadError.cancelledError();\n }\n throw UploadError.networkError(error.message, error);\n }\n throw error;\n }\n}\n\n/**\n * Detect if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof XMLHttpRequest !== 'undefined';\n}\n\n// ============================================================================\n// Uploader Implementation\n// ============================================================================\n\n/**\n * Configuration for creating an Uploader\n */\nexport interface UploaderConfig {\n /** Base URL for the API */\n baseUrl: string;\n /** Auth manager for authentication */\n authManager: AuthManager;\n /** Custom fetch implementation */\n fetchImpl?: typeof fetch;\n /** Request timeout in milliseconds */\n requestTimeout?: number;\n}\n\n/**\n * Main upload implementation\n */\nexport class Uploader implements Upload {\n readonly id: string;\n\n private readonly baseUrl: string;\n private readonly authManager: AuthManager;\n private readonly fetchImpl: typeof fetch;\n private readonly requestTimeout: number;\n\n private readonly fileSource: FileSource;\n private readonly options: Required<\n Omit<UploadOptions, 'onProgress' | 'signal' | 'metadata' | 'commitMessage' | 'commitActor'>\n > & Pick<UploadOptions, 'onProgress' | 'signal' | 'metadata' | 'commitMessage' | 'commitActor'>;\n\n private session: CreateUploadResponse | null = null;\n private status: UploadStatus = 'pending';\n private bytesUploaded = 0;\n private currentChunk = 0;\n private totalChunks = 0;\n private readonly speedTracker = new SpeedTracker();\n\n private pauseRequested = false;\n private abortController: AbortController | null = null;\n\n /**\n * Create a new Uploader\n */\n constructor(\n config: UploaderConfig,\n fileSource: FileSource,\n options: UploadOptions,\n uploadId?: string\n ) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.authManager = config.authManager;\n this.fetchImpl = config.fetchImpl ?? fetch;\n this.requestTimeout = config.requestTimeout ?? 30000;\n\n this.fileSource = fileSource;\n this.id = uploadId ?? generateUploadId();\n\n // Merge with defaults\n this.options = {\n repository: options.repository,\n branch: options.branch ?? DEFAULT_BRANCH,\n workspace: options.workspace,\n path: options.path,\n nodeType: options.nodeType ?? DEFAULT_NODE_TYPE,\n chunkSize: options.chunkSize ?? DEFAULT_CHUNK_SIZE,\n commitMessage: options.commitMessage,\n commitActor: options.commitActor,\n autoRetry: options.autoRetry ?? true,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n onProgress: options.onProgress,\n signal: options.signal,\n metadata: options.metadata,\n };\n\n // Calculate total chunks\n this.totalChunks = calculateChunkCount(\n this.fileSource.size,\n this.options.chunkSize\n );\n }\n\n /**\n * Start the upload\n */\n async start(): Promise<UploadResult> {\n if (this.status === 'completed') {\n throw new UploadError(\n 'Upload already completed',\n UploadErrorCode.INVALID_FILE,\n false\n );\n }\n\n if (this.status === 'uploading') {\n throw new UploadError(\n 'Upload already in progress',\n UploadErrorCode.INVALID_FILE,\n false\n );\n }\n\n this.pauseRequested = false;\n this.abortController = new AbortController();\n\n // Link external abort signal\n if (this.options.signal) {\n this.options.signal.addEventListener('abort', () => {\n this.abortController?.abort();\n });\n }\n\n try {\n // Create session if not already created\n if (!this.session) {\n await this.createSession();\n }\n\n // Upload chunks\n this.status = 'uploading';\n this.emitProgress();\n\n await this.uploadChunks();\n\n // Complete the upload\n this.status = 'completing';\n this.emitProgress();\n\n const result = await this.completeUpload();\n\n this.status = 'completed';\n this.emitProgress();\n\n return result;\n } catch (error) {\n if (this.status !== 'paused' && this.status !== 'cancelled') {\n this.status = 'failed';\n this.emitProgress();\n }\n throw error;\n }\n }\n\n /**\n * Pause the upload\n */\n pause(): void {\n if (this.status !== 'uploading') {\n return;\n }\n\n this.pauseRequested = true;\n this.status = 'paused';\n this.emitProgress();\n }\n\n /**\n * Resume a paused upload\n */\n async resume(): Promise<UploadResult> {\n if (this.status !== 'paused') {\n throw new UploadError(\n 'Upload is not paused',\n UploadErrorCode.INVALID_FILE,\n false\n );\n }\n\n // Refresh session status\n await this.refreshSessionStatus();\n\n // Continue uploading\n return this.start();\n }\n\n /**\n * Cancel the upload\n */\n async cancel(): Promise<void> {\n this.pauseRequested = true;\n this.abortController?.abort();\n this.status = 'cancelled';\n this.emitProgress();\n\n // Try to cancel server-side\n if (this.session) {\n try {\n await this.deleteSession();\n } catch {\n // Ignore errors during cancel\n }\n }\n }\n\n /**\n * Get current progress\n */\n getProgress(): UploadProgress {\n const bytesTotal = this.fileSource.size;\n const progress = bytesTotal > 0 ? this.bytesUploaded / bytesTotal : 0;\n const speed = this.speedTracker.getSpeed();\n const remainingBytes = bytesTotal - this.bytesUploaded;\n const eta = this.speedTracker.getEta(remainingBytes);\n\n return {\n bytesUploaded: this.bytesUploaded,\n bytesTotal,\n progress,\n speed,\n eta,\n currentChunk: this.currentChunk + 1, // 1-indexed for display\n totalChunks: this.totalChunks,\n status: this.status,\n };\n }\n\n /**\n * Check if upload is active\n */\n isActive(): boolean {\n return this.status === 'uploading' || this.status === 'completing';\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n /**\n * Create upload session\n */\n private async createSession(): Promise<void> {\n const contentType = getContentType(this.fileSource);\n\n const request: CreateUploadRequest = {\n repository: this.options.repository,\n branch: this.options.branch,\n workspace: this.options.workspace,\n path: this.options.path,\n filename: this.fileSource.name,\n file_size: this.fileSource.size,\n content_type: contentType,\n node_type: this.options.nodeType,\n chunk_size: this.options.chunkSize,\n metadata: this.options.metadata,\n };\n\n const response = await this.apiRequest<CreateUploadResponse>(\n '/api/uploads',\n {\n method: 'POST',\n body: request,\n }\n );\n\n this.session = response;\n this.totalChunks = response.total_chunks;\n }\n\n /**\n * Refresh session status from server\n */\n private async refreshSessionStatus(): Promise<void> {\n if (!this.session) {\n return;\n }\n\n const response = await this.apiRequest<UploadStatusResponse>(\n `/api/uploads/${this.session.upload_id}`,\n { method: 'GET' }\n );\n\n // Update local state based on server state\n this.bytesUploaded = response.bytes_received;\n this.currentChunk = response.chunks_completed;\n\n // Check for expiration\n const expiresAt = new Date(response.expires_at);\n if (expiresAt < new Date()) {\n throw UploadError.sessionExpiredError(this.session.upload_id);\n }\n }\n\n /**\n * Upload all remaining chunks\n */\n private async uploadChunks(): Promise<void> {\n const signal = this.abortController?.signal;\n\n while (this.currentChunk < this.totalChunks) {\n // Check for pause/cancel\n if (this.pauseRequested || signal?.aborted) {\n if (signal?.aborted) {\n throw UploadError.cancelledError();\n }\n return; // Paused\n }\n\n // Upload chunk with retry\n if (this.options.autoRetry) {\n const retryOptions: Partial<RetryOptions> = {\n maxRetries: this.options.maxRetries,\n };\n\n await withRetry(\n () => this.uploadChunk(this.currentChunk),\n retryOptions,\n signal\n );\n } else {\n await this.uploadChunk(this.currentChunk);\n }\n\n this.currentChunk++;\n }\n }\n\n /**\n * Upload a single chunk\n */\n private async uploadChunk(chunkIndex: number): Promise<void> {\n if (!this.session) {\n throw new UploadError(\n 'No active session',\n UploadErrorCode.SESSION_NOT_FOUND,\n false\n );\n }\n\n const signal = this.abortController?.signal;\n const { start, end } = getChunkRange(\n chunkIndex,\n this.options.chunkSize,\n this.fileSource.size\n );\n\n // Read chunk data\n const chunk = await this.fileSource.slice(start, end);\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/octet-stream',\n 'Content-Range': `bytes ${start}-${end - 1}/${this.fileSource.size}`,\n };\n\n // Add auth header\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const url = `${this.baseUrl}/api/uploads/${this.session.upload_id}`;\n\n // Upload using XHR (browser) or fetch (Node.js)\n let response: Response;\n\n const chunkStartBytes = this.bytesUploaded;\n\n if (isBrowser()) {\n response = await uploadChunkXhr(\n url,\n chunk,\n headers,\n (loaded) => {\n // Update bytes uploaded with partial progress\n this.bytesUploaded = chunkStartBytes + loaded;\n this.speedTracker.addSample(loaded);\n this.emitProgress();\n },\n signal\n );\n } else {\n response = await uploadChunkFetch(url, chunk, headers, signal, this.fetchImpl);\n }\n\n // Handle response\n if (!response.ok) {\n const body = await response.json().catch(() => ({}));\n throw UploadError.fromResponse(response.status, body);\n }\n\n const result: ChunkUploadResponse = await response.json();\n\n // Update state\n this.bytesUploaded = result.bytes_received;\n this.speedTracker.addSample(end - start);\n this.emitProgress();\n }\n\n /**\n * Complete the upload\n */\n private async completeUpload(): Promise<UploadResult> {\n if (!this.session) {\n throw new UploadError(\n 'No active session',\n UploadErrorCode.SESSION_NOT_FOUND,\n false\n );\n }\n\n const request: CompleteUploadRequest = {\n commit_message: this.options.commitMessage,\n commit_actor: this.options.commitActor,\n };\n\n const response = await this.apiRequest<CompleteUploadResponse>(\n `/api/uploads/${this.session.upload_id}/complete`,\n {\n method: 'POST',\n body: request,\n }\n );\n\n return {\n node: response.node,\n revision: response.revision,\n storageKey: response.storage_key,\n };\n }\n\n /**\n * Delete upload session\n */\n private async deleteSession(): Promise<void> {\n if (!this.session) {\n return;\n }\n\n await this.apiRequest<void>(\n `/api/uploads/${this.session.upload_id}`,\n { method: 'DELETE' }\n );\n }\n\n /**\n * Make an API request\n */\n private async apiRequest<T>(\n path: string,\n options: {\n method: string;\n body?: unknown;\n }\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Add auth header\n const token = this.authManager.getAccessToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);\n\n try {\n const response = await this.fetchImpl(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.json().catch(() => ({}));\n throw UploadError.fromResponse(response.status, body);\n }\n\n // Handle empty responses\n const text = await response.text();\n if (!text) {\n return undefined as T;\n }\n\n return JSON.parse(text) as T;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw UploadError.timeoutError(`Request timeout after ${this.requestTimeout}ms`);\n }\n\n throw error;\n }\n }\n\n /**\n * Emit progress update\n */\n private emitProgress(): void {\n if (this.options.onProgress) {\n this.options.onProgress(this.getProgress());\n }\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Generate a unique upload ID\n */\nfunction generateUploadId(): string {\n // Use crypto.randomUUID if available\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback to manual UUID generation\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n// ============================================================================\n// Upload Manager\n// ============================================================================\n\n/**\n * Manager for creating and tracking uploads\n */\nexport class UploadManager {\n private readonly config: UploaderConfig;\n private readonly uploads = new Map<string, Uploader>();\n\n /**\n * Create an upload manager\n */\n constructor(config: UploaderConfig) {\n this.config = config;\n }\n\n /**\n * Create a new upload\n */\n createUpload(fileSource: FileSource, options: UploadOptions): Upload {\n const uploader = new Uploader(this.config, fileSource, options);\n this.uploads.set(uploader.id, uploader);\n return uploader;\n }\n\n /**\n * Get an existing upload by ID\n */\n getUpload(id: string): Upload | undefined {\n return this.uploads.get(id);\n }\n\n /**\n * Get all active uploads\n */\n getActiveUploads(): Upload[] {\n return Array.from(this.uploads.values()).filter((u) => u.isActive());\n }\n\n /**\n * Cancel all active uploads\n */\n async cancelAll(): Promise<void> {\n const active = this.getActiveUploads();\n await Promise.all(active.map((u) => u.cancel()));\n }\n\n /**\n * Remove completed/cancelled uploads from tracking\n */\n cleanup(): void {\n for (const [id, upload] of this.uploads) {\n const progress = upload.getProgress();\n if (\n progress.status === 'completed' ||\n progress.status === 'cancelled' ||\n progress.status === 'failed'\n ) {\n this.uploads.delete(id);\n }\n }\n }\n\n /**\n * Create a batch upload for multiple files\n *\n * @param files - Array of FileSource objects to upload\n * @param options - Batch upload options\n * @returns BatchUpload controller\n *\n * @example\n * ```typescript\n * const batch = manager.createBatchUpload(fileSources, {\n * repository: 'media',\n * workspace: 'assets',\n * basePath: '/uploads',\n * concurrency: 3,\n * onProgress: (p) => console.log(`${p.filesCompleted}/${p.filesTotal}`)\n * });\n * const result = await batch.start();\n * ```\n */\n createBatchUpload(files: FileSource[], options: BatchUploadOptions): BatchUpload {\n return new BatchUploader(this.config, files, options);\n }\n}\n","/**\n * HTTP schema-management operations (NodeTypes / Archetypes / ElementTypes)\n *\n * These classes give the HTTP (SSR) client the same schema surface as the\n * WebSocket `Database`, backed by the management REST API\n * (`/api/management/{repo}/{branch}/...`). They mirror the WebSocket SDK\n * method names so call sites can swap clients with minimal changes.\n */\n\nimport type { RaisinHttpClient } from './http-client';\n\n/** Optional commit metadata for write operations. Server-side it is optional\n * (falls back to a default message + the `\"system\"` actor). */\nexport interface SchemaCommit {\n message: string;\n actor?: string;\n}\n\ntype SchemaKind = 'nodetypes' | 'archetypes' | 'elementtypes';\ntype SchemaDefField = 'node_type' | 'archetype' | 'element_type';\n\n/**\n * Shared CRUD/publish/resolve implementation for the three schema kinds.\n */\nabstract class HttpSchemaBase {\n protected abstract readonly kind: SchemaKind;\n protected abstract readonly defField: SchemaDefField;\n\n constructor(\n protected readonly repository: string,\n protected readonly branch: string,\n protected readonly client: RaisinHttpClient\n ) {}\n\n /** Base management URL for this schema kind. */\n protected base(): string {\n return `/api/management/${this.repository}/${this.branch}/${this.kind}`;\n }\n\n /** List all schemas (or only published ones). */\n async list(publishedOnly = false): Promise<unknown[]> {\n const path = publishedOnly ? `${this.base()}/published` : this.base();\n const result = await this.client.managementRequest<unknown>('GET', path);\n return Array.isArray(result) ? result : [];\n }\n\n /** Get a single schema by name. */\n async get(name: string): Promise<unknown> {\n return this.client.managementRequest('GET', `${this.base()}/${encodeURIComponent(name)}`);\n }\n\n /** Get the schema with full inheritance (`extends`) applied. */\n async getResolved(name: string): Promise<unknown> {\n return this.client.managementRequest(\n 'GET',\n `${this.base()}/${encodeURIComponent(name)}/resolved`\n );\n }\n\n /** Create a schema. `name` is folded into the definition body if absent. */\n async create(\n name: string,\n definition: Record<string, unknown>,\n commit?: SchemaCommit\n ): Promise<unknown> {\n return this.client.managementRequest('POST', this.base(), {\n [this.defField]: { name, ...definition },\n commit,\n });\n }\n\n /** Update an existing schema. */\n async update(\n name: string,\n definition: Record<string, unknown>,\n commit?: SchemaCommit\n ): Promise<unknown> {\n return this.client.managementRequest(\n 'PUT',\n `${this.base()}/${encodeURIComponent(name)}`,\n { [this.defField]: { name, ...definition }, commit }\n );\n }\n\n /** Delete a schema. */\n async delete(name: string, commit?: SchemaCommit): Promise<unknown> {\n return this.client.managementRequest(\n 'DELETE',\n `${this.base()}/${encodeURIComponent(name)}`,\n commit\n );\n }\n\n /** Publish a schema. */\n async publish(name: string, commit?: SchemaCommit): Promise<unknown> {\n return this.client.managementRequest(\n 'POST',\n `${this.base()}/${encodeURIComponent(name)}/publish`,\n commit\n );\n }\n\n /** Unpublish a schema. */\n async unpublish(name: string, commit?: SchemaCommit): Promise<unknown> {\n return this.client.managementRequest(\n 'POST',\n `${this.base()}/${encodeURIComponent(name)}/unpublish`,\n commit\n );\n }\n}\n\n/** NodeType management over HTTP REST. */\nexport class HttpNodeTypes extends HttpSchemaBase {\n protected readonly kind: SchemaKind = 'nodetypes';\n protected readonly defField: SchemaDefField = 'node_type';\n\n /**\n * Get the resolved NodeType. Unlike archetypes/element types, NodeType\n * resolution can be workspace-aware (honors workspace NodeType pins).\n */\n async getResolved(name: string, opts?: { workspace?: string }): Promise<unknown> {\n const query = opts?.workspace ? `?workspace=${encodeURIComponent(opts.workspace)}` : '';\n return this.client.managementRequest(\n 'GET',\n `${this.base()}/${encodeURIComponent(name)}/resolved${query}`\n );\n }\n}\n\n/** Archetype management over HTTP REST. */\nexport class HttpArchetypes extends HttpSchemaBase {\n protected readonly kind: SchemaKind = 'archetypes';\n protected readonly defField: SchemaDefField = 'archetype';\n}\n\n/** ElementType management over HTTP REST. */\nexport class HttpElementTypes extends HttpSchemaBase {\n protected readonly kind: SchemaKind = 'elementtypes';\n protected readonly defField: SchemaDefField = 'element_type';\n}\n","/**\n * McpClient — typed wrappers over a RaisinDB MCP server's JSON-RPC endpoint.\n *\n * A `raisin:McpServer` node is exposed over the MCP Streamable HTTP binding at\n * `POST /mcp/{repo}/{branch}/{slug}`, carrying one JSON-RPC 2.0 message per\n * request. This client mirrors the {@link FunctionsApi} shape: it is a thin,\n * transport-injected wrapper so any JS/TS backend (not just AI agents) can talk\n * to a RaisinDB MCP server programmatically, using the exact JSON-RPC method\n * names the engine implements (`tools/list`, `tools/call`, `resources/read`,\n * `resources/subscribe`).\n *\n * The transport is injected (see {@link McpTransport}) so the client stays\n * unit-testable and independent of the concrete HTTP layer — the HTTP client\n * supplies a real transport via its `.mcp(slug)` accessor.\n */\n\n/**\n * A single content block returned by a tool call or resource read.\n *\n * The engine serializes structured results into `text` blocks for spec\n * compliance; machine-readable output is carried separately in\n * {@link McpCallToolResult.structuredContent}.\n */\nexport interface McpContentBlock {\n /** Block discriminator, e.g. `\"text\"`. */\n type: string;\n /** Present on `text` blocks. */\n text?: string;\n /** Allow forward-compatible block variants (`image`, `resource`, …). */\n [key: string]: unknown;\n}\n\n/** A tool descriptor as advertised by `tools/list`. */\nexport interface McpToolDescriptor {\n /** Unique tool name used as the `name` argument to {@link McpClient.callTool}. */\n name: string;\n /** Human-readable description. */\n description?: string;\n /** JSON Schema describing the tool's accepted arguments. */\n inputSchema?: unknown;\n /** JSON Schema describing the tool's structured output, when declared. */\n outputSchema?: unknown;\n /** Forward-compatible extra fields (e.g. `ui`, annotations). */\n [key: string]: unknown;\n}\n\n/** Result of a `tools/call` invocation. */\nexport interface McpCallToolResult {\n /** Result content blocks (typically a single `text` block). */\n content: McpContentBlock[];\n /** `true` when the tool reported a domain-level failure. */\n isError?: boolean;\n /**\n * Machine-readable result conforming to the tool's `outputSchema`, present\n * only for tools that declare one.\n */\n structuredContent?: unknown;\n /** Forward-compatible extra fields. */\n [key: string]: unknown;\n}\n\n/** One entry returned by `resources/read`. */\nexport interface McpResourceContents {\n /** `raisin://` URI of the resource that was read. */\n uri: string;\n /** MIME type of the content, when known. */\n mimeType?: string;\n /** Text payload (JSON-only resources return their properties here). */\n text?: string;\n /** Base64-encoded binary payload, for byte-serving resources. */\n blob?: string;\n /** Forward-compatible extra fields. */\n [key: string]: unknown;\n}\n\n/** Result of `resources/read`. */\nexport interface McpReadResourceResult {\n /** One content entry per URI read. */\n contents: McpResourceContents[];\n}\n\n/**\n * A `notifications/resources/updated` payload pushed over the subscription\n * stream when a watched resource changes.\n */\nexport interface McpResourceUpdate {\n /** URI of the resource that changed. */\n uri: string;\n}\n\n/**\n * A live subscription to resource-change notifications.\n *\n * Iterate it with `for await (const update of subscription) { … }`; call\n * {@link McpResourceSubscription.close} to tear the stream down.\n */\nexport interface McpResourceSubscription extends AsyncIterable<McpResourceUpdate> {\n /** Close the underlying stream and stop receiving updates. */\n close(): void;\n}\n\n/**\n * Transport abstraction the {@link McpClient} is built on.\n *\n * `rpc` performs one request/response JSON-RPC round trip and returns the\n * already-unwrapped `result` (throwing on a JSON-RPC `error`). `subscribe`\n * opens the `resources/subscribe` SSE stream and yields each raw JSON-RPC frame\n * forwarded by the server.\n */\nexport interface McpTransport {\n /**\n * Send one JSON-RPC request and resolve with its `result` payload.\n *\n * @param method - JSON-RPC method name (e.g. `\"tools/list\"`).\n * @param params - Method parameters, shape depends on `method`.\n */\n rpc(method: string, params?: unknown): Promise<unknown>;\n\n /**\n * Open an SSE stream for a subscribing method and yield each JSON-RPC frame\n * the server pushes (the initial ack plus subsequent notifications).\n *\n * @param method - Subscribing JSON-RPC method (`\"resources/subscribe\"`).\n * @param params - Method parameters (`{ uri }`).\n */\n subscribe(method: string, params: unknown): McpFrameStream;\n}\n\n/** A raw JSON-RPC frame as delivered over the subscription SSE stream. */\nexport interface McpJsonRpcFrame {\n jsonrpc?: string;\n id?: unknown;\n method?: string;\n params?: unknown;\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n}\n\n/** A closeable async stream of raw JSON-RPC frames. */\nexport interface McpFrameStream extends AsyncIterable<McpJsonRpcFrame> {\n /** Close the underlying stream. */\n close(): void;\n}\n\n/**\n * Typed client for a single RaisinDB MCP server, addressed by\n * `{repo}/{branch}/{slug}`.\n *\n * @example\n * ```typescript\n * const mcp = client.database('my-repo').mcp('assistant');\n * const { tools } = await mcp.listTools();\n * const result = await mcp.callTool('order_card', { orderId: '42' });\n * const doc = await mcp.readResource('raisin://content/site/home');\n *\n * const sub = mcp.subscribeResource('raisin://content/site/home');\n * for await (const update of sub) {\n * console.log('changed:', update.uri);\n * }\n * ```\n */\nexport class McpClient {\n constructor(private readonly transport: McpTransport) {}\n\n /**\n * List the tools this MCP server advertises to the calling identity.\n *\n * Wraps the `tools/list` JSON-RPC method. The visible set is RLS-scoped to\n * the authenticated caller (or the anonymous role).\n *\n * @returns The advertised tool descriptors.\n */\n async listTools(): Promise<{ tools: McpToolDescriptor[] }> {\n const result = (await this.transport.rpc('tools/list')) as {\n tools?: McpToolDescriptor[];\n };\n return { tools: result?.tools ?? [] };\n }\n\n /**\n * Invoke a tool by name.\n *\n * Wraps the `tools/call` JSON-RPC method. The underlying `raisin:Function`\n * runs RLS-scoped to the calling identity. A domain-level tool failure is\n * reported via {@link McpCallToolResult.isError} (not thrown); transport and\n * protocol errors are thrown.\n *\n * @param name - Tool name from {@link listTools}.\n * @param args - Arguments object matching the tool's `inputSchema`.\n * @returns The tool's content blocks and optional structured content.\n */\n async callTool(\n name: string,\n args?: Record<string, unknown>,\n ): Promise<McpCallToolResult> {\n const result = (await this.transport.rpc('tools/call', {\n name,\n arguments: args ?? {},\n })) as McpCallToolResult;\n return result;\n }\n\n /**\n * Read a resource by its `raisin://` URI.\n *\n * Wraps the `resources/read` JSON-RPC method. JSON-only resources return\n * their properties as a `text` entry; byte-serving resources return base64\n * in `blob`.\n *\n * @param uri - `raisin://{workspace}/{path}` URI to read.\n * @returns One content entry per URI read.\n */\n async readResource(uri: string): Promise<McpReadResourceResult> {\n const result = (await this.transport.rpc('resources/read', {\n uri,\n })) as McpReadResourceResult;\n return { contents: result?.contents ?? [] };\n }\n\n /**\n * Subscribe to change notifications for a resource URI (or URI prefix).\n *\n * Wraps the `resources/subscribe` JSON-RPC method, which upgrades to an SSE\n * stream. The returned {@link McpResourceSubscription} is an async iterable of\n * {@link McpResourceUpdate}; the server's initial subscription ack is consumed\n * internally and not yielded. Call `close()` to end the stream.\n *\n * @param uri - `raisin://` URI (or prefix) to watch.\n * @returns A live, closeable subscription.\n */\n subscribeResource(uri: string): McpResourceSubscription {\n const stream = this.transport.subscribe('resources/subscribe', { uri });\n return {\n close: () => stream.close(),\n async *[Symbol.asyncIterator](): AsyncIterator<McpResourceUpdate> {\n for await (const frame of stream) {\n if (frame.method === 'notifications/resources/updated') {\n const params = (frame.params ?? {}) as Partial<McpResourceUpdate>;\n if (typeof params.uri === 'string') {\n yield { uri: params.uri };\n }\n }\n }\n },\n };\n }\n}\n","/**\n * IdentityAuthApi — passwordless and password sign-in for end users.\n *\n * This is the *identity* half of authentication (the people using an\n * application), distinct from {@link AuthManager}, which is the admin/JWT\n * credential holder the transports authenticate with. The two meet at the\n * token: everything here returns an {@link IdentityAuthResponse}, and\n * `client.setIdentityTokens(...)` hands it to the AuthManager so subsequent\n * SQL, node and function calls run as that person.\n *\n * Every endpoint is repository-scoped (`/auth/{repo}/…`). A repository is not\n * optional: identities, their home nodes and their roles are per repository,\n * so a call that omitted it would have to guess which one, and guessing wrong\n * signs somebody into the wrong data.\n */\n\n/** Transport hook: performs one JSON HTTP call and returns the parsed body. */\nexport type IdentityAuthTransport = <T>(options: {\n method: string;\n path: string;\n body?: unknown;\n /** Send no Authorization header — the point of a sign-in call. */\n skipAuth?: boolean;\n}) => Promise<T>;\n\n/** Identity returned alongside a token pair. */\nexport interface IdentityInfo {\n id: string;\n email: string;\n display_name: string | null;\n avatar_url: string | null;\n email_verified: boolean;\n linked_providers: string[];\n /** The person's home node path in this repository. */\n home: string | null;\n}\n\n/** A successful sign-in: tokens plus who they belong to. */\nexport interface IdentityAuthResult {\n access_token: string;\n refresh_token: string;\n token_type: string;\n /** Unix seconds. */\n expires_at: number;\n identity: IdentityInfo;\n}\n\n/**\n * Acknowledgement that a magic link was *sent*.\n *\n * Deliberately carries no token and no unmasked address: this response is\n * shown to whoever typed the email, who is not yet proven to own it.\n */\nexport interface MagicLinkSent {\n message: string;\n /** e.g. `u***@example.com` — enough to spot a typo, not to harvest. */\n masked_email: string;\n expires_in_minutes: number;\n}\n\nexport interface MagicLinkOptions {\n /**\n * Where RaisinDB sends the browser after it verifies the token.\n *\n * The server checks this against the tenant's redirect allowlist and\n * refuses anything outside it, so an attacker cannot aim a victim's\n * one-time token at their own host. Omit it to use the configured default.\n */\n redirectUrl?: string;\n}\n\n/** Which sign-in methods this repository actually offers. */\nexport interface AuthProviders {\n providers: Array<{\n id: string;\n display_name: string;\n icon: string;\n auth_url: string;\n }>;\n local_enabled: boolean;\n magic_link_enabled: boolean;\n}\n\n/** Who the caller currently is, as this repository sees them. */\nexport interface IdentityMe {\n id: string;\n email: string | null;\n roles: string[];\n anonymous: boolean;\n home: string | null;\n}\n\n/**\n * Identity authentication scoped to one repository.\n *\n * Obtain it from `client.auth(repository)` rather than constructing it.\n */\nexport class IdentityAuthApi {\n constructor(\n private readonly repository: string,\n private readonly transport: IdentityAuthTransport,\n ) {}\n\n private get base(): string {\n return `/auth/${encodeURIComponent(this.repository)}`;\n }\n\n /**\n * Ask RaisinDB to email a sign-in link.\n *\n * The reply is an acknowledgement, never a token — the token only exists in\n * the email. It also resolves for an address that has no account, because a\n * response that differed would turn this endpoint into an account-existence\n * oracle.\n */\n async sendMagicLink(email: string, options?: MagicLinkOptions): Promise<MagicLinkSent> {\n return this.transport<MagicLinkSent>({\n method: 'POST',\n path: `${this.base}/magic-link`,\n body: { email, redirect_url: options?.redirectUrl },\n skipAuth: true,\n });\n }\n\n /**\n * Exchange a magic-link token for a session.\n *\n * Most applications never call this: following the emailed link hits\n * RaisinDB directly, which verifies and 302s to the redirect URL with the\n * tokens in the URL **fragment** (so they stay out of server logs and out\n * of the Referer header) — see {@link readTokensFromFragment}. Call this\n * only when handling the token yourself, and note it is single-use.\n */\n async verifyMagicLink(token: string): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'GET',\n path: `${this.base}/magic-link/verify?token=${encodeURIComponent(token)}`,\n skipAuth: true,\n });\n }\n\n /** Sign in with email and password, where the repository enables it. */\n async login(\n email: string,\n password: string,\n options?: { rememberMe?: boolean },\n ): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'POST',\n path: `${this.base}/login`,\n body: { email, password, remember_me: options?.rememberMe ?? false },\n skipAuth: true,\n });\n }\n\n /** Create an account with email and password. */\n async register(\n email: string,\n password: string,\n options?: { displayName?: string },\n ): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'POST',\n path: `${this.base}/register`,\n body: { email, password, display_name: options?.displayName },\n skipAuth: true,\n });\n }\n\n /** Trade a refresh token for a fresh pair. */\n async refresh(refreshToken: string): Promise<IdentityAuthResult> {\n return this.transport<IdentityAuthResult>({\n method: 'POST',\n path: `${this.base}/refresh`,\n body: { refresh_token: refreshToken },\n skipAuth: true,\n });\n }\n\n /**\n * Which sign-in methods to render.\n *\n * Ask rather than hard-code: magic link and password are per-repository\n * configuration, and a button for a disabled method is a dead end.\n */\n async providers(): Promise<AuthProviders> {\n return this.transport<AuthProviders>({\n method: 'GET',\n path: `${this.base}/providers`,\n skipAuth: true,\n });\n }\n\n /** Who the current token belongs to in this repository. */\n async me(): Promise<IdentityMe> {\n return this.transport<IdentityMe>({ method: 'GET', path: `${this.base}/me` });\n }\n}\n\n/**\n * Read the tokens a magic-link verify redirect left in the URL fragment.\n *\n * Pass `window.location.hash` (or the whole URL) on the callback route. The\n * fragment never reaches a server, which is why the tokens travel there.\n *\n * Returns `null` when the fragment carries no tokens, so a plain visit to the\n * callback route is distinguishable from an arrival from a link.\n */\nexport function readTokensFromFragment(\n hashOrUrl: string,\n): { accessToken: string; refreshToken: string | null } | null {\n const hash = hashOrUrl.includes('#') ? hashOrUrl.slice(hashOrUrl.indexOf('#') + 1) : hashOrUrl;\n if (!hash) return null;\n const params = new URLSearchParams(hash);\n const accessToken = params.get('access_token');\n if (!accessToken) return null;\n return { accessToken, refreshToken: params.get('refresh_token') };\n}\n","/**\n * NodeBuilder - Ergonomic builder pattern for creating RaisinDB nodes\n *\n * @example\n * ```typescript\n * const node = NodeBuilder.create()\n * .nodeType(\"Page\")\n * .name(\"My Page\")\n * .path(\"/content/my-page\")\n * .property(\"title\", \"Welcome\")\n * .property(\"published\", true)\n * .build();\n * ```\n */\n\nimport { Node, PropertyValue, RelationRef } from './protocol';\n\nexport class NodeBuilder {\n private node: Partial<Node> = {\n properties: {},\n children: [],\n relations: [],\n version: 1,\n };\n\n /**\n * Create a new NodeBuilder instance\n */\n static create(): NodeBuilder {\n return new NodeBuilder();\n }\n\n /**\n * Set the node ID\n */\n id(id: string): this {\n this.node.id = id;\n return this;\n }\n\n /**\n * Set the node name\n */\n name(name: string): this {\n this.node.name = name;\n return this;\n }\n\n /**\n * Set the node path\n */\n path(path: string): this {\n this.node.path = path;\n return this;\n }\n\n /**\n * Set the node type\n */\n nodeType(nodeType: string): this {\n this.node.node_type = nodeType;\n return this;\n }\n\n /**\n * Set the archetype\n */\n archetype(archetype: string): this {\n this.node.archetype = archetype;\n return this;\n }\n\n /**\n * Set a property value\n */\n property(key: string, value: PropertyValue): this {\n if (!this.node.properties) {\n this.node.properties = {};\n }\n this.node.properties[key] = value;\n return this;\n }\n\n /**\n * Set multiple properties at once\n */\n properties(properties: Record<string, PropertyValue>): this {\n this.node.properties = properties;\n return this;\n }\n\n /**\n * Add a child node ID\n */\n child(childId: string): this {\n if (!this.node.children) {\n this.node.children = [];\n }\n this.node.children.push(childId);\n return this;\n }\n\n /**\n * Set the children array\n */\n children(children: string[]): this {\n this.node.children = children;\n return this;\n }\n\n /**\n * Set the order key.\n *\n * @deprecated The server owns editorial ordering: the order key is assigned by\n * the ordering index on write, so any value set here is overwritten. To place a\n * node, create it (it appends to the end of its parent) then call\n * `nodes.reorder()`, `nodes.moveChildBefore()` or `nodes.moveChildAfter()`.\n */\n orderKey(orderKey: string): this {\n this.node.order_key = orderKey;\n return this;\n }\n\n /**\n * Set the parent name\n */\n parent(parent: string): this {\n this.node.parent = parent;\n return this;\n }\n\n /**\n * Set the version\n */\n version(version: number): this {\n this.node.version = version;\n return this;\n }\n\n /**\n * Set the workspace\n */\n workspace(workspace: string): this {\n this.node.workspace = workspace;\n return this;\n }\n\n /**\n * Set the tenant ID\n */\n tenantId(tenantId: string): this {\n this.node.tenant_id = tenantId;\n return this;\n }\n\n /**\n * Add a relation to another node\n */\n relation(relation: RelationRef): this {\n if (!this.node.relations) {\n this.node.relations = [];\n }\n this.node.relations.push(relation);\n return this;\n }\n\n /**\n * Add a relation using individual parameters\n */\n addRelation(\n target: string,\n workspace: string,\n relationType: string,\n targetNodeType?: string,\n weight?: number\n ): this {\n return this.relation({\n target,\n workspace,\n relation_type: relationType,\n target_node_type: targetNodeType || '',\n weight,\n });\n }\n\n /**\n * Set the relations array\n */\n relations(relations: RelationRef[]): this {\n this.node.relations = relations;\n return this;\n }\n\n /**\n * Build and return the Node object\n * @throws {Error} if required fields are missing\n */\n build(): Node {\n // Validate required fields\n if (!this.node.id) {\n throw new Error('Node ID is required');\n }\n if (!this.node.name) {\n throw new Error('Node name is required');\n }\n if (!this.node.path) {\n throw new Error('Node path is required');\n }\n if (!this.node.node_type) {\n throw new Error('Node type is required');\n }\n\n // Ensure required array fields are initialized\n //\n // `order_key` is deliberately left empty: the ordering index assigns it at\n // write time and overwrites whatever arrives, so seeding a value here would\n // only mislead. New children are appended to the end of their parent.\n if (this.node.order_key === undefined) this.node.order_key = '';\n if (!this.node.children) this.node.children = [];\n if (!this.node.relations) this.node.relations = [];\n if (!this.node.properties) this.node.properties = {};\n if (typeof this.node.version !== 'number') this.node.version = 1;\n\n return this.node as Node;\n }\n}\n\n/**\n * Helper functions for working with Node objects\n */\nexport class NodeHelpers {\n /**\n * Get a property value from a node\n */\n static getProperty<T = PropertyValue>(node: Node, key: string): T | undefined {\n return node.properties[key] as T | undefined;\n }\n\n /**\n * Set a property value on a node (mutating)\n */\n static setProperty(node: Node, key: string, value: PropertyValue): void {\n node.properties[key] = value;\n }\n\n /**\n * Get the parent path derived from the node's path\n */\n static getParentPath(node: Node): string | null {\n if (!node.path || node.path === '/') {\n return null;\n }\n const lastSlash = node.path.lastIndexOf('/');\n if (lastSlash <= 0) {\n return '/';\n }\n return node.path.substring(0, lastSlash);\n }\n\n /**\n * Check if the node is published\n */\n static isPublished(node: Node): boolean {\n return node.published_at != null && node.published_at.length > 0;\n }\n\n /**\n * Check if the node has children\n */\n static hasChildren(node: Node): boolean {\n return node.has_children ?? (node.children?.length ?? 0) > 0;\n }\n\n /**\n * Add a relation to a node (mutating)\n */\n static addRelation(\n node: Node,\n target: string,\n workspace: string,\n relationType: string,\n targetNodeType?: string,\n weight?: number\n ): void {\n if (!node.relations) {\n node.relations = [];\n }\n node.relations.push({\n target,\n workspace,\n relation_type: relationType,\n target_node_type: targetNodeType || '',\n weight,\n });\n }\n\n /**\n * Get relations of a specific type\n */\n static getRelationsByType(node: Node, relationType: string): RelationRef[] {\n return (node.relations || []).filter(r => r.relation_type === relationType);\n }\n\n /**\n * Get the name from a path (last segment)\n */\n static getNameFromPath(path: string): string {\n const parts = path.split('/').filter(p => p.length > 0);\n return parts[parts.length - 1] || '';\n }\n\n /**\n * Create a minimal node for testing/mocking\n */\n static createMock(overrides?: Partial<Node>): Node {\n return {\n id: 'mock-id',\n name: 'Mock Node',\n path: '/mock',\n node_type: 'MockType',\n properties: {},\n children: [],\n order_key: '',\n relations: [],\n version: 1,\n ...overrides,\n };\n }\n}\n","/**\n * Event type constants for subscribing to node events\n *\n * @example\n * ```typescript\n * import { RaisinClient, NodeEventType } from '@raisindb/client';\n *\n * client.events.subscribeToTypes([NodeEventType.Created, NodeEventType.Updated], (event) => {\n * console.log('Node changed:', event);\n * });\n * ```\n */\nexport const NodeEventType = {\n /** Node was created */\n Created: 'node:created',\n /** Node was updated */\n Updated: 'node:updated',\n /** Node was deleted */\n Deleted: 'node:deleted',\n /** Node was reordered among siblings */\n Reordered: 'node:reordered',\n /** Node was published */\n Published: 'node:published',\n /** Node was unpublished */\n Unpublished: 'node:unpublished',\n /** A single property was changed */\n PropertyChanged: 'node:property_changed',\n /** A relation was added to the node */\n RelationAdded: 'node:relation_added',\n /** A relation was removed from the node */\n RelationRemoved: 'node:relation_removed',\n} as const;\n\n/** Type for node event type values */\nexport type NodeEventTypeValue = (typeof NodeEventType)[keyof typeof NodeEventType];\n\n/**\n * All node event types as an array (useful for subscribing to all events)\n *\n * @example\n * ```typescript\n * client.events.subscribeToTypes(AllNodeEventTypes, (event) => {\n * console.log('Any node event:', event);\n * });\n * ```\n */\nexport const AllNodeEventTypes: NodeEventTypeValue[] = Object.values(NodeEventType);\n","/**\n * React Router 7 integration for RaisinDB\n *\n * Provides helpers for server-side rendering with React Router 7, including:\n * - Loader utilities for data fetching\n * - Client context management\n * - Hybrid mode support (HTTP on server, WebSocket on client)\n */\n\nimport { RaisinHttpClient, HttpClientOptions } from '../http-client';\nimport { RaisinClient, ClientOptions } from '../client';\nimport { Credentials } from '../auth';\nimport { logger } from '../logger';\n\n/**\n * Configuration for SSR client factory\n */\nexport interface SSRClientConfig {\n /** Base URL for HTTP API (e.g., \"http://localhost:8080\") */\n httpBaseUrl: string;\n /** Base URL for WebSocket (e.g., \"ws://localhost:8080/sys/default\") */\n wsUrl: string;\n /** HTTP client options */\n httpOptions?: HttpClientOptions;\n /** WebSocket client options */\n wsOptions?: ClientOptions;\n /** Default credentials for authentication (optional) */\n credentials?: Credentials;\n}\n\n/**\n * Create an SSR-compatible client for React Router loaders\n *\n * This creates an HTTP client for server-side data fetching.\n * Use in loader functions to fetch data during SSR.\n *\n * @param config - SSR client configuration\n * @returns HTTP client instance\n *\n * @example\n * ```typescript\n * // In a React Router loader\n * export async function loader() {\n * const client = createSSRClient({\n * httpBaseUrl: 'http://localhost:8080',\n * wsUrl: 'ws://localhost:8080/sys/default',\n * credentials: { username: 'admin', password: 'admin' }\n * });\n *\n * await client.authenticate(config.credentials);\n *\n * const posts = await client.database('social')\n * .executeSql('SELECT * FROM social WHERE node_type = \"Post\"');\n *\n * return { posts };\n * }\n * ```\n */\nexport function createSSRClient(config: SSRClientConfig): RaisinHttpClient {\n const client = RaisinClient.forSSR(config.httpBaseUrl, config.httpOptions);\n\n // Auto-authenticate if credentials provided\n if (config.credentials) {\n // Note: This is async, but we return the client immediately\n // Callers should await client.authenticate() if needed\n // Or use the credentials in their loader\n }\n\n return client;\n}\n\n/**\n * Create a loader helper that provides an authenticated client\n *\n * This wraps your loader function and provides an authenticated HTTP client.\n *\n * @param config - SSR client configuration\n * @param loaderFn - Your loader function that receives the authenticated client\n * @returns React Router loader function\n *\n * @example\n * ```typescript\n * export const loader = createLoader(\n * {\n * httpBaseUrl: process.env.RAISIN_HTTP_URL || 'http://localhost:8080',\n * wsUrl: process.env.RAISIN_WS_URL || 'ws://localhost:8080/sys/default',\n * credentials: { username: 'admin', password: 'admin' }\n * },\n * async (client, { request, params }) => {\n * const db = client.database('social');\n * const posts = await db.executeSql('SELECT * FROM social WHERE node_type = \"Post\"');\n * return { posts: posts.rows };\n * }\n * );\n * ```\n */\nexport function createLoader<TData = unknown>(\n config: SSRClientConfig,\n loaderFn: (\n client: RaisinHttpClient,\n args: { request: Request; params: Record<string, string | undefined> }\n ) => Promise<TData>\n): (args: { request: Request; params: Record<string, string | undefined> }) => Promise<TData> {\n return async (args) => {\n const client = createSSRClient(config);\n\n // Authenticate if credentials provided\n if (config.credentials) {\n await client.authenticate(config.credentials);\n }\n\n try {\n return await loaderFn(client, args);\n } catch (error) {\n logger.error('SSR Loader error:', error);\n throw error;\n }\n };\n}\n\n/**\n * Create a request-scoped client for SSR\n *\n * This ensures each SSR request gets its own client instance,\n * preventing state leakage between requests.\n *\n * @param httpBaseUrl - Base HTTP URL\n * @param options - HTTP client options\n * @returns New HTTP client instance\n */\nexport function createRequestScopedClient(\n httpBaseUrl: string,\n options?: HttpClientOptions\n): RaisinHttpClient {\n return new RaisinHttpClient(httpBaseUrl, options);\n}\n\n/**\n * Helper to convert SQL result rows to objects\n *\n * @param columns - Column names from SQL result\n * @param rows - Row data from SQL result\n * @returns Array of objects with column names as keys\n *\n * @example\n * ```typescript\n * const result = await client.database('social')\n * .executeSql('SELECT id, title FROM posts');\n * const posts = rowsToObjects(result.columns, result.rows);\n * // [{ id: '1', title: 'First Post' }, ...]\n * ```\n */\nexport function rowsToObjects<T = Record<string, unknown>>(\n _columns: string[],\n rows: Record<string, unknown>[]\n): T[] {\n return rows as T[];\n}\n\n/**\n * Extract error message from various error types\n *\n * @param error - Error object\n * @returns Error message string\n */\nexport function getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === 'string') {\n return error;\n }\n if (error && typeof error === 'object' && 'message' in error) {\n return String((error as any).message);\n }\n return 'An unknown error occurred';\n}\n\n/**\n * Type for hybrid client that can be either HTTP or WebSocket\n */\nexport type HybridClient = RaisinHttpClient | RaisinClient;\n\n/**\n * Check if client is HTTP-based\n */\nexport function isHttpClient(client: HybridClient): client is RaisinHttpClient {\n return client instanceof RaisinHttpClient;\n}\n\n/**\n * Check if client is WebSocket-based\n */\nexport function isWebSocketClient(client: HybridClient): client is RaisinClient {\n return client instanceof RaisinClient;\n}\n","/**\n * Flow execution types for the RaisinDB JS SDK.\n *\n * These types mirror the backend FlowEvent / FlowExecutionEvent enums\n * used for real-time SSE streaming of flow step-level events.\n */\n\n// ============================================================================\n// Flow Instance\n// ============================================================================\n\n/** Response returned when a flow is started via the run endpoint. */\nexport interface FlowRunResponse {\n /** The created flow instance ID */\n instance_id: string;\n /** Job ID for tracking execution */\n job_id: string;\n /** Status (always \"queued\" for async execution) */\n status: string;\n}\n\n/** Flow instance status values */\nexport type FlowInstanceStatus =\n | 'queued'\n | 'pending'\n | 'running'\n | 'completed'\n | 'failed'\n | 'waiting'\n | 'cancelled';\n\n/** Response from GET flow instance status endpoint. */\nexport interface FlowInstanceStatusResponse {\n /** Flow instance ID */\n id: string;\n /** Current status */\n status: FlowInstanceStatus;\n /** Flow-scoped variables */\n variables: Record<string, unknown>;\n /** Path to the flow definition */\n flow_path: string;\n /** ISO 8601 timestamp of when the flow started */\n started_at: string;\n /** Error message (if status is failed) */\n error?: string;\n /** Execution metrics, when the server includes them. */\n metrics?: FlowMetrics;\n}\n\n/** Execution metrics for a flow run. */\nexport interface FlowMetrics {\n total_duration_ms: number;\n step_count: number;\n retry_count: number;\n compensation_count: number;\n ai_iteration_count: number;\n /**\n * Model calls whose usage was reported.\n *\n * Counted separately from the token totals: a call that reported no usage is\n * a different fact from no call at all.\n */\n ai_call_count: number;\n total_input_tokens: number;\n total_output_tokens: number;\n}\n\n// ============================================================================\n// Flow Execution Events (matching backend FlowEvent enum)\n// ============================================================================\n\n/** Base properties shared by all events */\ninterface BaseFlowEvent {\n timestamp: string;\n}\n\n/** A step has started execution */\nexport interface StepStartedEvent extends BaseFlowEvent {\n type: 'step_started';\n node_id: string;\n step_name?: string;\n step_type: string;\n}\n\n/**\n * Model usage attributable to ONE step.\n *\n * Mirrors the engine's `StepUsage`. Providers disagree on the wire spelling\n * (`input_tokens`/`output_tokens` vs OpenAI's `prompt_tokens`/\n * `completion_tokens`); the server normalises them, so these two names are what\n * ever reaches a client.\n */\nexport interface StepUsage {\n input_tokens: number;\n output_tokens: number;\n}\n\n/** A step has completed successfully */\nexport interface StepCompletedEvent extends BaseFlowEvent {\n type: 'step_completed';\n node_id: string;\n output: unknown;\n duration_ms: number;\n /**\n * Model usage for THIS step, when it made a model call.\n *\n * Absent means no call was made (a function step, a decision) — as distinct\n * from a call that reported nothing, which arrives as zeros. Flow-level totals\n * live on the instance's metrics; this is what attributes cost to a node,\n * which is the question anyone tuning an agent graph has.\n */\n usage?: StepUsage;\n}\n\n/** A step has failed */\nexport interface StepFailedEvent extends BaseFlowEvent {\n type: 'step_failed';\n node_id: string;\n error: string;\n duration_ms: number;\n}\n\n/** Flow is waiting for external input (human task, approval, etc.) */\nexport interface FlowWaitingEvent extends BaseFlowEvent {\n type: 'flow_waiting';\n node_id: string;\n wait_type: string;\n reason: string;\n}\n\n/** Flow has resumed after waiting */\nexport interface FlowResumedEvent extends BaseFlowEvent {\n type: 'flow_resumed';\n node_id: string;\n wait_duration_ms: number;\n}\n\n/** Flow has completed successfully */\nexport interface FlowCompletedEvent extends BaseFlowEvent {\n type: 'flow_completed';\n output: unknown;\n total_duration_ms: number;\n}\n\n/** Flow has failed */\nexport interface FlowFailedEvent extends BaseFlowEvent {\n type: 'flow_failed';\n error: string;\n failed_at_node?: string;\n total_duration_ms: number;\n}\n\n/** Partial text content from AI streaming */\nexport interface TextChunkEvent extends BaseFlowEvent {\n type: 'text_chunk';\n text: string;\n}\n\n/** AI tool call started */\nexport interface ToolCallStartedEvent extends BaseFlowEvent {\n type: 'tool_call_started';\n tool_call_id: string;\n function_name: string;\n arguments: unknown;\n}\n\n/** AI tool call completed */\nexport interface ToolCallCompletedEvent extends BaseFlowEvent {\n type: 'tool_call_completed';\n tool_call_id: string;\n result: unknown;\n /** Error message if the tool call failed */\n error?: string;\n /** Execution duration in milliseconds */\n duration_ms?: number;\n}\n\n/** Partial thinking/reasoning content from AI streaming */\nexport interface ThoughtChunkEvent extends BaseFlowEvent {\n type: 'thought_chunk';\n text: string;\n}\n\n/** AI conversation node was created or resolved */\nexport interface ConversationCreatedEvent extends BaseFlowEvent {\n type: 'conversation_created';\n conversation_path: string;\n workspace: string;\n}\n\n/** An AI message was persisted to the node tree */\nexport interface MessageSavedEvent extends BaseFlowEvent {\n type: 'message_saved';\n message_path: string;\n role: string;\n conversation_path: string;\n}\n\n/** Log message from flow execution */\nexport interface LogEvent extends BaseFlowEvent {\n type: 'log';\n level: string;\n message: string;\n node_id?: string;\n}\n\n/** Union of all flow execution events streamed via SSE */\nexport type FlowExecutionEvent =\n | StepStartedEvent\n | StepCompletedEvent\n | StepFailedEvent\n | FlowWaitingEvent\n | FlowResumedEvent\n | FlowCompletedEvent\n | FlowFailedEvent\n | TextChunkEvent\n | ToolCallStartedEvent\n | ToolCallCompletedEvent\n | ThoughtChunkEvent\n | ConversationCreatedEvent\n | MessageSavedEvent\n | LogEvent;\n\n/** Type guard: is this a terminal event (flow_completed or flow_failed)? */\nexport function isTerminalEvent(\n event: FlowExecutionEvent,\n): event is FlowCompletedEvent | FlowFailedEvent {\n return event.type === 'flow_completed' || event.type === 'flow_failed';\n}\n","/**\n * Workflow definition types for RaisinDB flows.\n *\n * This is the canonical, shared data model for `raisin:Flow` definitions\n * (the `workflow_data` property of a flow node). The visual designer\n * (@raisindb/flow-designer), the admin console, and SDK consumers all\n * describe flows with these shapes.\n *\n * A flow definition is a tree of steps and containers:\n * - `FlowStep` - a single unit of work: function call, AI agent call,\n * human task (approval/input/review/action), or chat session\n * - `FlowContainer` - groups children: and / or / parallel / ai_sequence\n *\n * Functions, AI agents, and humans are uniform step concepts: a human task\n * whose `assignee` resolves to an AI agent is decided by the agent (with\n * confidence-threshold escalation back to a human).\n */\n\n// ============================================================================\n// References\n// ============================================================================\n\n/**\n * RaisinDB reference (PropertyValue::Reference) - cross-node reference\n * with workspace context.\n */\nexport interface RaisinReference {\n /** Node ID or path (raisin:ref) */\n 'raisin:ref': string;\n /** Workspace context */\n 'raisin:workspace': string;\n /** Optional resolved path */\n 'raisin:path'?: string;\n}\n\n/** Extract a display name from a reference path. */\nexport function getRefDisplayName(ref: RaisinReference): string {\n const path = ref['raisin:path'] || ref['raisin:ref'];\n const segments = path.split('/').filter(Boolean);\n return segments[segments.length - 1] || path;\n}\n\n/** Get the full path from a reference. */\nexport function getRefPath(ref: RaisinReference): string {\n return ref['raisin:path'] || ref['raisin:ref'];\n}\n\n// ============================================================================\n// Core enums\n// ============================================================================\n\n/** Container types */\nexport type ContainerType = 'and' | 'or' | 'parallel' | 'loop' | 'ai_sequence' | 'competition';\n\n/** Step error behavior */\nexport type StepErrorBehavior = 'stop' | 'skip' | 'continue';\n\n/** Flow-level error strategy */\nexport type FlowErrorStrategy = 'fail_fast' | 'continue';\n\n// ============================================================================\n// Retry\n// ============================================================================\n\n/** Retry configuration for a step */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (0 = no retries) */\n max_retries: number;\n /** Base delay in milliseconds for exponential backoff */\n base_delay_ms: number;\n /** Maximum delay cap in milliseconds */\n max_delay_ms: number;\n}\n\n/** Predefined retry strategies */\nexport const RETRY_STRATEGIES = {\n none: { max_retries: 0, base_delay_ms: 0, max_delay_ms: 0 },\n quick: { max_retries: 3, base_delay_ms: 1000, max_delay_ms: 10000 },\n standard: { max_retries: 5, base_delay_ms: 2000, max_delay_ms: 60000 },\n aggressive: { max_retries: 10, base_delay_ms: 5000, max_delay_ms: 120000 },\n llm: { max_retries: 5, base_delay_ms: 10000, max_delay_ms: 120000 },\n} as const;\n\nexport type RetryStrategy = keyof typeof RETRY_STRATEGIES;\n\n// ============================================================================\n// Human tasks\n// ============================================================================\n\n/** The human task types the flow runtime understands semantically */\nexport const CANONICAL_TASK_TYPES = ['approval', 'input', 'review', 'action'] as const;\n\n/** A canonical human task type */\nexport type CanonicalTaskType = (typeof CANONICAL_TASK_TYPES)[number];\n\n/**\n * Human task type.\n *\n * The canonical types are suggestions, not a closed set: an application may\n * define its own task vocabulary, and any slug matching\n * `[a-z][a-z0-9_-]{0,63}` is carried through to the task node verbatim for\n * a task UI to dispatch on. Spelled this way so the canonical values still\n * autocomplete.\n */\nexport type HumanTaskType = CanonicalTaskType | (string & {});\n\n/** Human task option for approval tasks */\nexport interface TaskOption {\n /** Option value returned when selected */\n value: string;\n /** Display label */\n label: string;\n /** Visual style */\n style?: 'default' | 'success' | 'danger' | 'warning';\n}\n\n// ============================================================================\n// Chat steps\n// ============================================================================\n\n/** Handoff target for chat steps */\nexport interface HandoffTarget {\n /** Target agent reference */\n agent_ref: RaisinReference;\n /** Trigger phrase patterns */\n trigger_phrases?: string[];\n /** When to trigger handoff */\n trigger_condition?: string;\n}\n\n/** Chat termination mode */\nexport type ChatTerminationMode =\n | 'user_request'\n | 'max_turns'\n | 'inactivity'\n | 'ai_decision';\n\n/** Chat termination configuration */\nexport interface ChatTerminationConfig {\n /** Termination modes that end the chat */\n modes: ChatTerminationMode[];\n /** Inactivity timeout in milliseconds */\n inactivity_timeout_ms?: number;\n /** Termination phrases to detect */\n termination_phrases?: string[];\n}\n\n/** Chat step configuration */\nexport interface ChatStepConfig {\n /** Reference to the agent node */\n agent_ref?: RaisinReference;\n /** System prompt override */\n system_prompt?: string;\n /** Agents to hand off to */\n handoff_targets: HandoffTarget[];\n /** Session timeout in milliseconds */\n session_timeout_ms?: number;\n /** Maximum number of conversation turns */\n max_turns: number;\n /** Termination configuration */\n termination: ChatTerminationConfig;\n}\n\n// ============================================================================\n// AI containers\n// ============================================================================\n\n/** Tool execution mode for AI container */\nexport type AiToolMode = 'auto' | 'explicit' | 'hybrid';\n\n/** AI error handling behavior */\nexport type AiErrorBehavior = 'stop' | 'continue' | 'retry';\n\n/** AI Container configuration (for ai_sequence containers) */\nexport interface AiContainerConfig {\n /** Reference to the agent node */\n agent_ref?: RaisinReference;\n /** Tool execution mode */\n tool_mode: AiToolMode;\n /** Tools to expose as explicit steps (for hybrid mode) */\n explicit_tools: string[];\n /** Maximum iterations for tool call loops */\n max_iterations: number;\n /** Enable AI thinking/reasoning display */\n thinking_enabled: boolean;\n /** Reference to existing conversation to continue */\n conversation_ref?: RaisinReference;\n /** Error handling behavior */\n on_error: AiErrorBehavior;\n /** Maximum retries on transient AI failures (default: 2) */\n max_retries?: number;\n /** Base delay between retries in milliseconds (default: 1000) */\n retry_delay_ms?: number;\n /** Timeout for entire container execution in milliseconds */\n timeout_ms?: number;\n /** Response format: \"text\", \"json_object\", or \"json_schema\" */\n response_format?: string;\n /** JSON schema for structured output (when response_format = \"json_schema\") */\n output_schema?: unknown;\n}\n\n// ============================================================================\n// Steps and containers\n// ============================================================================\n\n/** Base flow node interface */\nexport interface FlowDefinitionNodeBase {\n id: string;\n node_type: 'raisin:FlowStep' | 'raisin:FlowContainer';\n}\n\n/** Step properties */\nexport interface FlowStepProperties {\n /** Action name/label */\n action?: string;\n /** Function reference */\n function_ref?: RaisinReference;\n /** Agent reference */\n agent_ref?: RaisinReference;\n /** Function arguments - values support template expressions like\n * `{{ input.value }}` or `${steps.prev.id}` */\n arguments?: Record<string, unknown>;\n /** Lua script for evaluation */\n lua_script?: string;\n /** Condition expression (REL) - same namespaces as templates:\n * `input.*`, `steps.<id>.*`, `trigger.*`, `visits.<step_id>` (how many times a\n * node has been entered — what bounds a cyclic graph), `history.<step_id>`\n * (that node's output per visit, oldest first), flow variables */\n condition?: string;\n /** Key for payload data */\n payload_key?: string;\n /** Whether step is disabled */\n disabled?: boolean;\n /** Step type - distinguishes AI agent, chat, and human task steps */\n step_type?: 'default' | 'ai_agent' | 'human_task' | 'chat' | 'wait' | 'sub_flow' | 'decision';\n /** Prompt for ai_agent steps (template expressions supported) */\n prompt?: string;\n /** Retry configuration for this step */\n retry?: RetryConfig;\n /** Retry strategy preset (alternative to custom retry config) */\n retry_strategy?: RetryStrategy;\n /** Step timeout in milliseconds */\n timeout_ms?: number;\n\n // Error handling\n\n /** Target node ID for error flow (error edge) */\n error_edge?: string;\n /** Target node ID when a wait deadline expires */\n timeout_edge?: string;\n /** Reference to compensation function for saga rollback */\n compensation_ref?: RaisinReference;\n /** Mapping for the compensation input - values support template\n * expressions; the forward step's output is available as `output.*` */\n compensation_input_mapping?: Record<string, unknown>;\n /** Continue workflow on step failure */\n continue_on_fail?: boolean;\n /** Execute step in isolated branch for safety */\n isolated_branch?: boolean;\n /** Execution identity mode for permission handling */\n execution_identity?: 'agent' | 'caller' | 'function';\n\n // Human task (step_type = 'human_task')\n\n /** Type of human task */\n task_type?: HumanTaskType;\n /** Assignee path - a user (\"/users/alice\") or an AI agent\n * (\"/agents/support\"); agents decide tasks automatically */\n assignee?: string;\n /** Task description */\n task_description?: string;\n /** Options for approval tasks */\n options?: TaskOption[];\n /** JSON schema for input tasks */\n input_schema?: object;\n /**\n * Task due time in seconds from creation (doubles as the wait deadline).\n * A template expression (e.g. \"${input.due_seconds}\") is allowed, so a\n * deadline can come from data instead of being authored into the flow.\n */\n due_in_seconds?: number | string;\n /** Task priority (1-5, where 5 is highest); a template expression is allowed */\n priority?: number | string;\n /** Minimum confidence (0-1) for an agent assignee's decision to be\n * accepted; below it the task escalates (default 0.7) */\n min_confidence?: number;\n /** Human assignee to escalate to when an agent assignee fails or is\n * not confident enough */\n escalation_assignee?: string;\n\n // Wait step (step_type = 'wait')\n\n /** What to wait for (defaults to 'delay') */\n wait_type?: 'delay' | 'until' | 'event' | 'cron';\n /** Duration for a 'delay' wait, e.g. \"30m\" (templates allowed) */\n duration?: string;\n /** Absolute timestamp for an 'until' wait (templates allowed) */\n until?: string;\n /** Event type for an 'event' wait */\n event_type?: string;\n /** Optional deadline for an 'event' wait */\n timeout?: string;\n /** Cron expression for a 'cron' wait */\n cron?: string;\n\n // Sub-flow step (step_type = 'sub_flow')\n\n /** The flow to invoke */\n flow_ref?: RaisinReference;\n /** Input mapping for the child flow (template expressions) */\n input_mapping?: object;\n /** Run the child flow asynchronously */\n async?: boolean;\n\n // Decision step (step_type = 'decision', or any step with a condition)\n\n /** Node id to run when the condition is true (defaults to the next sibling) */\n yes_branch?: string;\n /** Node id to run when the condition is false (defaults to the next sibling) */\n no_branch?: string;\n\n // Chat step (step_type = 'chat')\n\n /** Chat step configuration */\n chat_config?: ChatStepConfig;\n}\n\n/** Basic workflow step */\nexport interface FlowDefinitionStep extends FlowDefinitionNodeBase {\n node_type: 'raisin:FlowStep';\n properties: FlowStepProperties;\n on_error?: StepErrorBehavior;\n /** Target node ID for error flow (error edge at node level) */\n error_edge?: string;\n}\n\n/** Container rule for conditional execution */\nexport interface ContainerRule {\n /** Condition expression */\n condition: string;\n /** ID of next step if condition matches */\n next_step: string;\n}\n\n/**\n * Fan-out configuration for parallel containers.\n *\n * Without it, a parallel container's children ARE its branches - a fixed\n * set, all running at once. With it, the children form ONE branch subgraph\n * that runs once per item of a runtime collection, and the container joins\n * every one of those runs. That is what a per-item human task needs: one\n * task per row, then a real join.\n */\nexport interface FanOutConfig {\n /** Collection expression to fan out over, e.g. \"${steps.plan.items}\" */\n over: string;\n /** Safety cap on branches created (fan-out width comes from runtime data) */\n max_branches?: number;\n}\n\n/** How a parallel container joins its branches */\nexport type MergeStrategy = 'merge_all' | 'first_success' | 'all_success';\n\n/**\n * How a loop container iterates.\n *\n * EXACTLY ONE of `over`, `while` or `times` decides the shape. `over` was once\n * required — correct while the engine hardcoded `for_each` and its while/times\n * arms were unreachable from the designer format — so it is optional here, and\n * naming none or several is refused by the engine rather than resolved by\n * precedence.\n */\nexport interface LoopConfig {\n /** for_each: expression resolving to the collection to iterate. */\n over?: string;\n /** while: a REL condition re-tested BEFORE each iteration. */\n while?: string;\n /** times: a fixed repeat count. */\n times?: number;\n /** Variable name for the current item (default `item`). */\n item?: string;\n /** Variable name for the current 0-based index. */\n index?: string;\n /** Safety cap on iterations. */\n max_iterations?: number;\n /**\n * `while` only: drop the iteration ceiling and run purely on the condition.\n *\n * Opt-in rather than the meaning of an absent `max_iterations`. Safe because\n * the executor bounds a runaway itself, so a condition that never goes false\n * costs a failed flow rather than a wedged worker.\n */\n unbounded?: boolean;\n /** Early-exit REL condition, evaluated after each completed iteration. */\n until?: string;\n}\n\n/** Container node with children (AND/OR/Parallel/Loop/AI/Competition) */\nexport interface FlowDefinitionContainer extends FlowDefinitionNodeBase {\n node_type: 'raisin:FlowContainer';\n container_type: ContainerType;\n rules?: ContainerRule[];\n children: FlowDefinitionNode[];\n /** Iteration configuration (only for loop type) */\n loop?: LoopConfig;\n /** AI container configuration (only for ai_sequence type) */\n ai_config?: AiContainerConfig;\n /** Fan-out configuration (only for parallel type): one branch per collection item */\n fan_out?: FanOutConfig;\n /** How branches are joined (only for parallel type; default \"merge_all\") */\n merge_strategy?: MergeStrategy;\n /** Container timeout in milliseconds */\n timeout_ms?: number;\n}\n\n/** Union type for all flow definition nodes */\nexport type FlowDefinitionNode = FlowDefinitionStep | FlowDefinitionContainer;\n\n/** Complete flow definition (the `workflow_data` of a raisin:Flow node) */\nexport interface FlowDefinition {\n /** Schema version */\n version: number;\n /** Error handling strategy */\n error_strategy: FlowErrorStrategy;\n /** Global timeout in milliseconds */\n timeout_ms?: number;\n /** Root workflow nodes */\n nodes: FlowDefinitionNode[];\n}\n\n/** Type guard for FlowDefinitionStep */\nexport function isFlowDefinitionStep(\n node: FlowDefinitionNode,\n): node is FlowDefinitionStep {\n return node.node_type === 'raisin:FlowStep';\n}\n\n/** Type guard for FlowDefinitionContainer */\nexport function isFlowDefinitionContainer(\n node: FlowDefinitionNode,\n): node is FlowDefinitionContainer {\n return node.node_type === 'raisin:FlowContainer';\n}\n\n// ============================================================================\n// Inbox tasks (human-in-the-loop primitive)\n// ============================================================================\n\n/** Status of an inbox task */\nexport type InboxTaskStatus = 'pending' | 'completed' | 'expired' | 'cancelled';\n\n/**\n * An inbox task (`raisin:InboxTask` node) - created by human_task steps\n * (or `raisin.tasks.create` in functions) and completed by users or agents.\n */\nexport interface InboxTask {\n /** Node ID */\n id: string;\n /** Node path (under the assignee's inbox) */\n path: string;\n /** Task type */\n task_type: HumanTaskType;\n /** Task title */\n title: string;\n /** Task description */\n description?: string;\n /** Assignee path (user or agent) */\n assignee: string;\n /** Current status */\n status: InboxTaskStatus;\n /** Priority (1-5, where 5 is highest) */\n priority?: number;\n /** Options for approval tasks */\n options?: TaskOption[];\n /** JSON schema for input tasks */\n input_schema?: object;\n /** Owning flow instance (absent for standalone tasks) */\n flow_instance_id?: string;\n /** Step that created the task */\n step_id?: string;\n /** Creation timestamp (ISO 8601) */\n created_at?: string;\n /** Due timestamp (ISO 8601) */\n due_at?: string;\n /** The submitted response (when completed) */\n response?: Record<string, unknown>;\n /** Who completed the task (user id or agent path) */\n completed_by?: string;\n /** Completion timestamp (ISO 8601) */\n responded_at?: string;\n /** Set when an agent assignee escalated the task */\n escalated_from?: string;\n /** Why the task was escalated */\n escalation_reason?: string;\n}\n\n/** Result of completing an inbox task */\nexport interface TaskCompletionResult {\n task_id: string;\n task_path: string;\n status: string;\n /** Present when the completion resumed a waiting flow */\n flow?: {\n instance_id: string;\n job_id: string;\n };\n}\n","/**\n * Plan projection utility.\n *\n * Builds deterministic plan/task state from persisted chat messages.\n */\n\nimport type { ChatMessage } from '../types/chat';\n\nexport interface PlanProjectionTask {\n taskId?: string;\n title: string;\n status: string;\n description?: string;\n priority?: string;\n}\n\nexport interface PlanProjection {\n key: string;\n planPath?: string;\n planId?: string;\n title: string;\n status: string;\n requiresApproval: boolean;\n tasks: PlanProjectionTask[];\n sourceMessagePath?: string;\n updatedAt?: string;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nexport function parsePlanTasks(rawTasks: unknown): PlanProjectionTask[] {\n if (!Array.isArray(rawTasks)) return [];\n return rawTasks\n .map((rawTask, index) => {\n if (typeof rawTask === 'string') {\n return {\n title: rawTask,\n status: 'pending',\n } satisfies PlanProjectionTask;\n }\n const task = asRecord(rawTask);\n if (!task) return null;\n return {\n taskId: asString(task.task_id) ?? asString(task.id),\n title: asString(task.title) ?? `Task ${index + 1}`,\n status: asString(task.status) ?? 'pending',\n description: asString(task.description),\n priority: asString(task.priority),\n } satisfies PlanProjectionTask;\n })\n .filter((task): task is PlanProjectionTask => task !== null);\n}\n\nconst TERMINAL_TASK_STATUSES = new Set(['completed', 'cancelled']);\nconst TERMINAL_PLAN_STATUSES = new Set(['completed', 'failed', 'cancelled']);\n\n/**\n * Same race as upsertTask: an ai_task_update message carrying a stale\n * plan_status (e.g. \"in_progress\", computed before the final task's\n * completion count caught up) can be persisted and thus replayed here after\n * the message that actually reflects the terminal plan status. Guard it the\n * same way - never regress out of a terminal plan status.\n */\nfunction setPlanStatus(plan: PlanProjection, nextStatus: string | undefined): void {\n if (!nextStatus) return;\n if (TERMINAL_PLAN_STATUSES.has(plan.status) && !TERMINAL_PLAN_STATUSES.has(nextStatus)) {\n return;\n }\n plan.status = nextStatus;\n}\n\nexport function upsertTask(plan: PlanProjection, nextTask: PlanProjectionTask): void {\n const existingIndex = plan.tasks.findIndex((task) =>\n (nextTask.taskId && task.taskId === nextTask.taskId) ||\n (!nextTask.taskId && task.title === nextTask.title)\n );\n if (existingIndex === -1) {\n plan.tasks.push(nextTask);\n return;\n }\n const existing = plan.tasks[existingIndex];\n // Mirrors the server-side monotonic guard in update-task/index.js: tool\n // calls from one model turn can execute in parallel, so an ai_task_update\n // message for an earlier \"in_progress\" transition can be persisted (and\n // thus replayed here) after the \"completed\" message for the same task.\n // Never let that regress an already-terminal status.\n if (TERMINAL_TASK_STATUSES.has(existing.status) && !TERMINAL_TASK_STATUSES.has(nextTask.status)) {\n return;\n }\n plan.tasks[existingIndex] = {\n ...existing,\n ...nextTask,\n };\n}\n\nexport function ensurePlan(\n plans: Map<string, PlanProjection>,\n key: string,\n fallbackTitle: string,\n timestamp: string | undefined,\n): PlanProjection {\n const existing = plans.get(key);\n if (existing) {\n if (timestamp) existing.updatedAt = timestamp;\n return existing;\n }\n const created: PlanProjection = {\n key,\n title: fallbackTitle,\n status: 'pending_approval',\n requiresApproval: true,\n tasks: [],\n updatedAt: timestamp,\n };\n plans.set(key, created);\n return created;\n}\n\n/**\n * Build deterministic plan/task state from persisted chat messages.\n * Uses ai_plan as canonical plan source and ai_task_update for incremental task status changes.\n */\nexport function projectPlansFromMessages(messages: ChatMessage[]): PlanProjection[] {\n const ordered = [...messages].sort((a, b) => {\n const aTime = Date.parse(a.timestamp || '');\n const bTime = Date.parse(b.timestamp || '');\n return (Number.isNaN(aTime) ? 0 : aTime) - (Number.isNaN(bTime) ? 0 : bTime);\n });\n\n const plans = new Map<string, PlanProjection>();\n\n for (const message of ordered) {\n const timestamp = message.timestamp;\n const data = asRecord(message.data);\n\n if (message.messageType === 'ai_plan' && data) {\n const planPath = asString(data.plan_path);\n const planId = asString(data.plan_id);\n const key = planPath || planId || message.path || message.id || `plan:${timestamp}`;\n const plan = ensurePlan(\n plans,\n key,\n asString(data.title) || message.content || 'Plan',\n timestamp\n );\n\n plan.planPath = planPath ?? plan.planPath;\n plan.planId = planId ?? plan.planId;\n plan.title = asString(data.title) || plan.title;\n setPlanStatus(plan, asString(data.status));\n plan.requiresApproval = Boolean(data.requires_approval) || plan.status === 'pending_approval';\n plan.sourceMessagePath = message.path ?? plan.sourceMessagePath;\n\n const parsedTasks = parsePlanTasks(data.tasks);\n if (parsedTasks.length > 0) {\n plan.tasks = parsedTasks;\n }\n }\n\n if (message.messageType === 'ai_task_update' && data) {\n const planPath = asString(data.plan_path);\n const planId = asString(data.plan_id);\n const key = planPath || planId;\n if (!key) continue;\n\n const plan = ensurePlan(plans, key, 'Plan', timestamp);\n plan.planPath = planPath ?? plan.planPath;\n plan.planId = planId ?? plan.planId;\n setPlanStatus(plan, asString(data.plan_status));\n plan.requiresApproval = plan.status === 'pending_approval';\n\n const taskUpdate: PlanProjectionTask = {\n taskId: asString(data.task_id),\n title: asString(data.task_title) || asString(data.title) || 'Task',\n status: asString(data.status) || 'pending',\n };\n upsertTask(plan, taskUpdate);\n }\n\n if (Array.isArray(message.children)) {\n for (const child of message.children) {\n if (child.type !== 'plan') continue;\n const key = child.path || message.path || message.id || `plan-child:${child.id}:${timestamp}`;\n const plan = ensurePlan(plans, key, child.planTitle || message.content || 'Plan', timestamp);\n plan.title = child.planTitle || plan.title;\n plan.status = child.status || plan.status;\n plan.requiresApproval = plan.status === 'pending_approval';\n if (Array.isArray(child.tasks) && child.tasks.length > 0) {\n plan.tasks = child.tasks.map((task) => ({\n taskId: task.id,\n title: task.title,\n status: task.status,\n }));\n }\n }\n }\n }\n\n // Belt-and-suspenders: if every task landed in a terminal state but the\n // plan's own status field is stuck non-terminal (the same message-race\n // that setPlanStatus guards against can also leave it simply never\n // updated), derive completion from the tasks - mirrors the server's\n // auto-complete check in update-task/index.js's updatePlanProgress.\n for (const plan of plans.values()) {\n if (\n !TERMINAL_PLAN_STATUSES.has(plan.status) &&\n plan.tasks.length > 0 &&\n plan.tasks.every((task) => TERMINAL_TASK_STATUSES.has(task.status))\n ) {\n plan.status = 'completed';\n plan.requiresApproval = false;\n }\n }\n\n return [...plans.values()].sort((a, b) => {\n const aTime = Date.parse(a.updatedAt || '');\n const bTime = Date.parse(b.updatedAt || '');\n return (Number.isNaN(bTime) ? 0 : bTime) - (Number.isNaN(aTime) ? 0 : aTime);\n });\n}\n","/**\n * Framework-agnostic conversation store for RaisinDB.\n *\n * Manages the full conversation lifecycle: creating conversations, sending\n * messages, streaming responses, persistent SSE subscriptions, message\n * history, tool call tracking, and plan projection. Notifies subscribers\n * on every state change so UI frameworks (React, Svelte, Vue) can bind.\n *\n * @example Svelte 5:\n * ```typescript\n * const store = new ConversationStore({ database: db, conversationPath: '/...' });\n * let snapshot = $state(store.getSnapshot());\n * store.subscribe(s => { snapshot = s; });\n * ```\n *\n * @example React (via useConversation hook):\n * ```tsx\n * const chat = useConversation(React, { database: db, conversationPath: '/...' });\n * ```\n */\n\nimport type { ConversationManager, ConversationSubscription } from '../conversations';\nimport type { Database } from '../database';\nimport type { ChatMessage, ChatEvent, ChatLogEvent } from '../types/chat';\nimport { logger, getLogLevel, LogLevel } from '../logger';\nimport { projectPlansFromMessages, type PlanProjection } from '../utils/plan-projection';\nimport { isRecoveredDoneEvent } from '../utils/chat-events';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Info about an in-flight tool call */\nexport interface ToolCallInfo {\n id: string;\n functionName: string;\n arguments: unknown;\n status: 'running' | 'completed' | 'failed';\n result?: unknown;\n durationMs?: number;\n}\n\n/** Snapshot of the conversation store state */\nexport interface ConversationStoreSnapshot {\n /** The conversation object, if loaded */\n conversation: { conversationPath: string; type: string } | null;\n /** All messages in the conversation */\n messages: ChatMessage[];\n /** Whether the AI is currently generating a response */\n isStreaming: boolean;\n /** Whether the chat is waiting for user input */\n isWaiting: boolean;\n /** Accumulated text from the current streaming response */\n streamingText: string;\n /** Current error, if any */\n error: string | null;\n /** Tracks in-flight tool executions */\n activeToolCalls: ToolCallInfo[];\n /** Deterministic plan/task projection from persisted messages */\n plans: PlanProjection[];\n /** Whether messages are being loaded */\n isLoading: boolean;\n /** Path to the conversation node */\n conversationPath: string | null;\n}\n\n/** Options for creating a ConversationStore */\nexport interface ConversationStoreOptions {\n /** Pre-configured Database instance */\n database: Database;\n /** Resume an existing conversation */\n conversationPath?: string;\n /** Create a new conversation on first message */\n createOptions?: {\n participant: string;\n input?: Record<string, unknown>;\n };\n /** Callback for individual chat events */\n onEvent?: (event: ChatEvent) => void;\n /** Streaming inactivity timeout in ms (default: 120000). Auto-recovers when no SSE event arrives within this window. */\n streamingTimeoutMs?: number;\n /** Activity watchdog polling interval in ms (default: 30000). Periodically checks backend turn health while streaming. */\n watchdogIntervalMs?: number;\n}\n\ntype Subscriber = (snapshot: ConversationStoreSnapshot) => void;\n\n// ---------------------------------------------------------------------------\n// ConversationStore\n// ---------------------------------------------------------------------------\n\n/**\n * Framework-agnostic store managing a single conversation's state.\n *\n * Handles the full lifecycle: creating conversations, sending messages,\n * streaming responses, tool call tracking, plan projection, and deferred\n * message reload on turn completion.\n */\nexport class ConversationStore {\n private manager: ConversationManager;\n private subscribers = new Set<Subscriber>();\n private onEvent?: (event: ChatEvent) => void;\n private createOptions?: { participant: string; input?: Record<string, unknown> };\n\n // Persistent SSE subscription\n private subscription: ConversationSubscription | null = null;\n\n // Internal mutable state\n private _conversationPath: string | null;\n private _messages: ChatMessage[] = [];\n private _isStreaming = false;\n private _isWaiting = false;\n private _streamingText = '';\n private _error: string | null = null;\n private _activeToolCalls: ToolCallInfo[] = [];\n private _isLoading = false;\n private _conversationType: string | null = null;\n\n // Streaming timeout (Fix A)\n private _streamingTimeoutMs: number;\n private _streamingTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Activity watchdog (Fix B)\n private _watchdogIntervalMs: number;\n private _watchdogTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(options: ConversationStoreOptions) {\n this.manager = options.database.conversations;\n this._conversationPath = options.conversationPath ?? null;\n this.createOptions = options.createOptions;\n this.onEvent = options.onEvent;\n this._streamingTimeoutMs = options.streamingTimeoutMs ?? 120_000;\n this._watchdogIntervalMs = options.watchdogIntervalMs ?? 30_000;\n\n // Auto-subscribe to existing conversation\n if (this._conversationPath) {\n this.ensureSubscription();\n }\n }\n\n // ==========================================================================\n // Subscription\n // ==========================================================================\n\n /**\n * Subscribe to state changes.\n * Returns an unsubscribe function.\n */\n subscribe(callback: Subscriber): () => void {\n this.subscribers.add(callback);\n callback(this.getSnapshot());\n return () => { this.subscribers.delete(callback); };\n }\n\n /**\n * Get the current state snapshot.\n */\n getSnapshot(): ConversationStoreSnapshot {\n return {\n conversation: this._conversationPath\n ? { conversationPath: this._conversationPath, type: this._conversationType || 'ai_chat' }\n : null,\n messages: [...this._messages],\n isStreaming: this._isStreaming,\n isWaiting: this._isWaiting,\n streamingText: this._streamingText,\n error: this._error,\n activeToolCalls: [...this._activeToolCalls],\n plans: projectPlansFromMessages(this._messages),\n isLoading: this._isLoading,\n conversationPath: this._conversationPath,\n };\n }\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Send a user message and stream the AI response.\n *\n * If no conversation exists yet and `createOptions` was provided,\n * the conversation is created automatically on the first call.\n */\n async sendMessage(content: string): Promise<void> {\n if (this._isStreaming) {\n logger.warn('[ConversationStore] Cannot send message while streaming');\n return;\n }\n\n logger.info('[ConversationStore] Sending message', { path: this._conversationPath });\n this._error = null;\n\n // Create conversation if needed\n if (!this._conversationPath) {\n if (!this.createOptions) {\n throw new Error('No conversationPath and no createOptions provided');\n }\n try {\n const convo = await this.manager.create({\n participant: this.createOptions.participant,\n input: this.createOptions.input,\n });\n this._conversationPath = convo.conversationPath;\n this._conversationType = convo.type;\n\n for (const event of convo.initialEvents ?? []) {\n this.onEvent?.(event);\n this.handleEvent(event);\n }\n\n this.notify();\n } catch (err) {\n this._error = err instanceof Error ? err.message : String(err);\n this.notify();\n return;\n }\n }\n\n // Add user message optimistically\n const userMessage: ChatMessage = {\n role: 'user',\n content,\n timestamp: new Date().toISOString(),\n };\n this._messages.push(userMessage);\n\n // Start streaming\n this._isStreaming = true;\n this._isWaiting = false;\n this._streamingText = '';\n this._activeToolCalls = [];\n this.resetStreamingTimer();\n this.startWatchdog();\n this.notify();\n\n // Use persistent SSE subscription + create message node\n try {\n this.ensureSubscription();\n await this.subscription!.waitUntilConnected();\n await this.manager.createUserMessage(this._conversationPath!, content);\n // Events arrive via the persistent subscription → handleEvent\n } catch (err) {\n logger.error('[ConversationStore] Send failed', err);\n this._error = err instanceof Error ? err.message : String(err);\n this._isStreaming = false;\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n }\n }\n\n /**\n * Load messages from the persisted node tree.\n * Useful for loading history on page reload.\n */\n async loadMessages(): Promise<ChatMessage[]> {\n if (!this._conversationPath) return [];\n this._isLoading = true;\n this.notify();\n try {\n const messages = await this.manager.getMessages(this._conversationPath);\n logger.debug(`[ConversationStore] Loaded ${messages.length} messages`);\n if (messages.length > 0) {\n this._messages = messages;\n // Rebuild tool call state from messages\n this._activeToolCalls = [];\n }\n return messages;\n } finally {\n this._isLoading = false;\n this.notify();\n }\n }\n\n /**\n * Approve a pending plan.\n */\n async approvePlan(planPath: string): Promise<void> {\n await this.manager.approvePlan(planPath);\n }\n\n /**\n * Reject a pending plan.\n */\n async rejectPlan(planPath: string, feedback?: string): Promise<void> {\n await this.manager.rejectPlan(planPath, feedback);\n }\n\n /**\n * Mark a single message as read.\n */\n async markMessageAsRead(messagePath: string): Promise<void> {\n await this.manager.markMessageAsRead(messagePath);\n }\n\n /**\n * Stop the current streaming response.\n */\n stop(): void {\n this._isStreaming = false;\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n }\n\n /**\n * Clean up the store and release resources.\n */\n destroy(): void {\n this.stop();\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.subscription?.unsubscribe();\n this.subscription = null;\n this.subscribers.clear();\n }\n\n /**\n * Get the conversation path.\n */\n getConversationPath(): string | null {\n return this._conversationPath;\n }\n\n // ==========================================================================\n // Internal\n // ==========================================================================\n\n private ensureSubscription(): void {\n if (this.subscription) return;\n if (!this._conversationPath) return;\n\n this.subscription = this.manager.subscribe(\n this._conversationPath,\n (event) => {\n this.onEvent?.(event);\n this.handleEvent(event);\n },\n );\n }\n\n private handleEvent(event: ChatEvent): void {\n logger.debug('[ConversationStore] SSE:', event.type);\n // Every SSE event resets the streaming inactivity timer\n if (this._isStreaming) {\n this.resetStreamingTimer();\n }\n switch (event.type) {\n case 'text_chunk':\n this.markStreamingActivity();\n this._streamingText += event.text;\n this.notify();\n break;\n\n case 'thought_chunk':\n this.markStreamingActivity();\n this.notify();\n break;\n\n case 'assistant_message':\n this._messages.push(event.message);\n this._streamingText = '';\n this.notify();\n break;\n\n case 'tool_call_started': {\n this.markStreamingActivity();\n logger.debug('[ConversationStore] Tool started:', event.functionName);\n const info: ToolCallInfo = {\n id: event.toolCallId,\n functionName: event.functionName,\n arguments: event.arguments,\n status: 'running',\n };\n this._activeToolCalls.push(info);\n this.notify();\n break;\n }\n\n case 'tool_call_completed': {\n this.markStreamingActivity();\n logger.debug('[ConversationStore] Tool completed:', event.toolCallId);\n const idx = this._activeToolCalls.findIndex(tc => tc.id === event.toolCallId);\n if (idx >= 0) {\n this._activeToolCalls[idx] = {\n ...this._activeToolCalls[idx],\n status: event.error ? 'failed' : 'completed',\n result: event.result,\n durationMs: event.durationMs,\n };\n }\n this.notify();\n break;\n }\n\n case 'waiting': {\n logger.info('[ConversationStore] Waiting for input');\n this.flushStreamingText(event.timestamp);\n this._isStreaming = false;\n this._isWaiting = true;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n // Deferred reload: pick up canonical messages from node tree\n this.deferredReload();\n break;\n }\n\n case 'done': {\n if (isRecoveredDoneEvent(event)) {\n logger.debug('[ConversationStore] Ignoring recovered done event');\n this.reconcileRecoveredDone();\n break;\n }\n const doneEvent = event as import('../types/chat').ChatDoneEvent;\n if (doneEvent.dispatchPhase && doneEvent.dispatchPhase !== 'terminal') {\n logger.debug('[ConversationStore] Ignoring non-terminal done event');\n break;\n }\n logger.info('[ConversationStore] Turn done');\n this.flushStreamingText(event.timestamp);\n // Safety net: if streaming missed chunks, use the complete response from the event\n if (doneEvent.content && !this.lastMessageIsAssistant()) {\n this._messages.push({\n role: (doneEvent.role as ChatMessage['role']) || 'assistant',\n content: doneEvent.content,\n timestamp: event.timestamp,\n senderDisplayName: doneEvent.senderDisplayName,\n finishReason: doneEvent.finishReason,\n });\n }\n this._isStreaming = false;\n this._isWaiting = true;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n this.deferredReload();\n break;\n }\n\n case 'completed': {\n this.flushStreamingText(event.timestamp);\n if (event.messages && event.messages.length > 0) {\n this._messages = event.messages;\n }\n this._isStreaming = false;\n this._isWaiting = false;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n this.deferredReload();\n break;\n }\n\n case 'failed':\n logger.error('[ConversationStore] Turn failed', event.error);\n this._error = event.error;\n this._isStreaming = false;\n // A failed turn ends any waiting state too - otherwise UIs keyed on\n // isWaiting show a thinking indicator forever after a failure.\n this._isWaiting = false;\n this._streamingText = '';\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n break;\n\n case 'conversation_created':\n this._conversationPath = event.conversationPath;\n this.notify();\n break;\n\n case 'message_saved':\n // A message was persisted — reload to pick it up, then notify\n this.silentReload().catch(() => {});\n this.notify();\n break;\n\n case 'message_delivered':\n this._messages.push(event.message);\n this.notify();\n break;\n\n case 'log': {\n const logEvent = event as ChatLogEvent;\n const currentLevel = getLogLevel();\n const levelMap: Record<string, LogLevel> = {\n debug: LogLevel.Debug,\n info: LogLevel.Info,\n warn: LogLevel.Warn,\n error: LogLevel.Error,\n };\n const eventLevel = levelMap[logEvent.level] ?? LogLevel.Debug;\n if (currentLevel >= eventLevel) {\n const fn = logEvent.level === 'error' ? console.error\n : logEvent.level === 'warn' ? console.warn\n : logEvent.level === 'debug' ? console.debug\n : console.info;\n fn('[server]', logEvent.message);\n }\n break;\n }\n }\n }\n\n /**\n * Agent activity observed while the store thought the turn was over.\n *\n * This happens when execution continues WITHOUT a user message — plan\n * approval in approve_then_auto / step_by_step (approvePlan() returns an\n * enqueue receipt and the agent starts executing), or agent-initiated\n * follow-ups. The events arrive over the persistent live subscription\n * (no history replay), so activity is always \"now\": re-enter streaming\n * state so UIs show progress and the end-of-turn handling (done/waiting\n * → deferred reload) runs again for this continuation.\n */\n private markStreamingActivity(): void {\n if (this._isStreaming) return;\n logger.debug('[ConversationStore] Agent activity while idle — re-entering streaming state');\n this._isStreaming = true;\n this._isWaiting = false;\n this._streamingText = '';\n this.resetStreamingTimer();\n this.startWatchdog();\n }\n\n /**\n * If accumulated streaming text hasn't been captured in an assistant_message,\n * synthesize one.\n */\n private flushStreamingText(timestamp: string): void {\n if (this._streamingText && !this.lastMessageIsAssistant()) {\n this._messages.push({\n role: 'assistant',\n content: this._streamingText,\n timestamp,\n });\n }\n this._streamingText = '';\n }\n\n private lastMessageIsAssistant(): boolean {\n const last = this._messages[this._messages.length - 1];\n return last?.role === 'assistant';\n }\n\n /**\n * After a turn completes, reload canonical messages from the node tree\n * to catch any events missed during SSE gaps.\n */\n private deferredReload(): void {\n if (!this._conversationPath) return;\n logger.debug('[ConversationStore] Scheduling deferred reload');\n const attemptReload = (delay: number, retriesLeft: number) => {\n setTimeout(async () => {\n try {\n const prevCount = this._messages.length;\n await this.silentReload();\n // If no new messages appeared and retries remain, try again with exponential backoff\n if (this._messages.length === prevCount && retriesLeft > 0) {\n attemptReload(delay * 2, retriesLeft - 1);\n }\n } catch {}\n }, delay);\n };\n attemptReload(500, 2); // 500ms, 1000ms, 2000ms\n }\n\n private async silentReload(): Promise<void> {\n if (!this._conversationPath) return;\n try {\n const fresh = await this.manager.getMessages(this._conversationPath);\n if (fresh.length === 0) return;\n\n // Try incremental merge: match existing messages by role+content\n // to preserve object references (prevents Svelte DOM recreation)\n let matchCount = 0;\n const limit = Math.min(this._messages.length, fresh.length);\n for (let i = 0; i < limit; i++) {\n if (this._messages[i].role !== fresh[i].role ||\n this._messages[i].content !== fresh[i].content) break;\n matchCount++;\n }\n\n if (matchCount === this._messages.length && fresh.length === matchCount) {\n // Same content, possibly different metadata — update silently\n for (let i = 0; i < matchCount; i++) {\n const f = fresh[i];\n const e = this._messages[i];\n if (f.id) e.id = f.id;\n if (f.path) e.path = f.path;\n if (f.messageType) e.messageType = f.messageType;\n if (f.data) e.data = f.data;\n if (f.children) e.children = f.children;\n if (f.finishReason) e.finishReason = f.finishReason;\n }\n await this.rebuildToolCallState();\n return; // No visible change — don't notify\n }\n\n if (matchCount === this._messages.length && fresh.length > matchCount) {\n // Existing messages match prefix — append new ones\n for (let i = matchCount; i < fresh.length; i++) {\n this._messages.push(fresh[i]);\n }\n // Also update metadata on matched messages\n for (let i = 0; i < matchCount; i++) {\n const f = fresh[i];\n const e = this._messages[i];\n if (f.id) e.id = f.id;\n if (f.path) e.path = f.path;\n if (f.messageType) e.messageType = f.messageType;\n if (f.data) e.data = f.data;\n if (f.children) e.children = f.children;\n }\n await this.rebuildToolCallState();\n this.notify(); // New messages to show\n return;\n }\n\n // Fresh is a prefix subset — outbox delivery pending, keep extras\n if (matchCount === fresh.length && fresh.length < this._messages.length) {\n for (let i = 0; i < matchCount; i++) {\n const f = fresh[i];\n const e = this._messages[i];\n if (f.id) e.id = f.id;\n if (f.path) e.path = f.path;\n if (f.messageType) e.messageType = f.messageType;\n if (f.data) e.data = f.data;\n if (f.children) e.children = f.children;\n }\n await this.rebuildToolCallState();\n return; // Keep streaming-flushed extras — message_saved will trigger next reload\n }\n\n // Content mismatch — full replace\n this._messages = fresh;\n await this.rebuildToolCallState();\n this.notify();\n } catch (err) {\n logger.debug('[ConversationStore] Silent reload failed:', err);\n }\n }\n\n // ==========================================================================\n // Streaming timeout (Fix A) — auto-recover on SSE inactivity\n // ==========================================================================\n\n private resetStreamingTimer(): void {\n this.clearStreamingTimer();\n if (!this._isStreaming) return;\n this._streamingTimer = setTimeout(() => {\n if (this._isStreaming) {\n logger.warn('[ConversationStore] Streaming timeout — no SSE activity for', this._streamingTimeoutMs, 'ms');\n this.recoverFromHang();\n }\n }, this._streamingTimeoutMs);\n }\n\n private clearStreamingTimer(): void {\n if (this._streamingTimer) {\n clearTimeout(this._streamingTimer);\n this._streamingTimer = null;\n }\n }\n\n // ==========================================================================\n // Activity watchdog (Fix B) — periodic backend health check\n // ==========================================================================\n\n private startWatchdog(): void {\n this.stopWatchdog();\n if (!this._conversationPath) return;\n this._watchdogTimer = setInterval(async () => {\n if (!this._isStreaming || !this._conversationPath) {\n this.stopWatchdog();\n return;\n }\n try {\n const health = await this.manager.checkTurnHealth(this._conversationPath);\n if (health === 'done' && this._isStreaming) {\n logger.warn('[ConversationStore] Watchdog detected completed turn while still streaming — recovering');\n this.recoverFromHang();\n }\n } catch {\n // Ignore watchdog errors — it's a best-effort check\n }\n }, this._watchdogIntervalMs);\n }\n\n private stopWatchdog(): void {\n if (this._watchdogTimer) {\n clearInterval(this._watchdogTimer);\n this._watchdogTimer = null;\n }\n }\n\n // ==========================================================================\n // Hang recovery (shared by timeout + watchdog)\n // ==========================================================================\n\n private recoverFromHang(): void {\n logger.info('[ConversationStore] Recovering from hang');\n this.clearStreamingTimer();\n this.stopWatchdog();\n this._isStreaming = false;\n this._isWaiting = true;\n this._streamingText = '';\n this.notify();\n // Reload to pick up any persisted state we missed\n this.silentReload().catch(() => {});\n }\n\n /**\n * Reconcile a recovered done event against persisted state.\n * If the backend turn is actually complete, finalize the local state.\n * Otherwise keep streaming active and let normal events continue.\n */\n private reconcileRecoveredDone(): void {\n if (!this._conversationPath) return;\n void this.manager.checkTurnHealth(this._conversationPath).then((health) => {\n if (health !== 'done') return;\n if (!this._isStreaming) return;\n this._isStreaming = false;\n this._isWaiting = true;\n this._activeToolCalls = [];\n this.clearStreamingTimer();\n this.stopWatchdog();\n this.notify();\n this.deferredReload();\n }).catch(() => {\n // Best effort only; streaming watchdog still protects against hangs.\n });\n }\n\n // ==========================================================================\n // Tool call state rebuild (Fix C) — reconstruct from node tree on reload\n // ==========================================================================\n\n private async rebuildToolCallState(): Promise<void> {\n if (!this._conversationPath) {\n this._activeToolCalls = [];\n return;\n }\n try {\n const pendingCalls = await this.manager.getActiveToolCalls(this._conversationPath);\n if (pendingCalls.length > 0) {\n this._activeToolCalls = pendingCalls.map(tc => ({\n id: tc.id,\n functionName: tc.name,\n arguments: undefined,\n status: 'running' as const,\n }));\n // Keep streaming active if there are pending tool calls\n if (!this._isStreaming) {\n this._isStreaming = true;\n this.resetStreamingTimer();\n this.startWatchdog();\n }\n } else {\n this._activeToolCalls = [];\n // No pending tools — check if we should clear streaming\n if (this._isStreaming) {\n const lastMsg = this._messages[this._messages.length - 1];\n const isLastAssistantDone = lastMsg?.role === 'assistant' &&\n (lastMsg.dispatchPhase\n ? lastMsg.dispatchPhase === 'terminal'\n : (!!lastMsg.finishReason && lastMsg.finishReason !== 'tool_calls'));\n if (isLastAssistantDone) {\n this._isStreaming = false;\n this._isWaiting = true;\n this.clearStreamingTimer();\n this.stopWatchdog();\n }\n }\n }\n } catch {\n this._activeToolCalls = [];\n }\n }\n\n private notify(): void {\n const snapshot = this.getSnapshot();\n for (const sub of this.subscribers) {\n try { sub(snapshot); }\n catch (err) { logger.error('Error in conversation store subscriber:', err); }\n }\n }\n}\n","/**\n * Multi-conversation list store for RaisinDB.\n *\n * Manages the list of conversations: loading, creating, deleting, marking\n * as read, and optional real-time updates via WebSocket events.\n *\n * Provides a factory (`getConversationStore`) that returns cached\n * per-conversation `ConversationStore` instances.\n *\n * @example Svelte 5:\n * ```typescript\n * const listStore = new ConversationListStore({ database: db, realtime: true });\n * let snapshot = $state(listStore.getSnapshot());\n * listStore.subscribe(s => { snapshot = s; });\n * await listStore.load();\n * ```\n */\n\nimport type { Database } from '../database';\nimport type { ConversationType, ConversationListItem } from '../types/chat';\nimport { ConversationStore, type ConversationStoreOptions } from './conversation-store';\nimport { logger } from '../logger';\nimport { normalizeHomePath } from '../utils/home-path';\n\n/**\n * Build the realtime subscription filters for a user's chats folder.\n *\n * The server matches subscription paths literally with glob semantics:\n * `*` matches exactly one path segment, `**` matches recursively, and there\n * is NO implicit prefix matching — a plain path only matches that exact\n * node. To observe conversations created/updated under the chats folder we\n * therefore need the recursive `/**` suffix.\n *\n * Exported for testing.\n * @internal\n */\nexport function buildChatsSubscriptionFilters(userHome: string): {\n workspace: string;\n path: string;\n event_types: string[];\n} {\n const home = normalizeHomePath(userHome) ?? userHome;\n return {\n workspace: 'raisin:access_control',\n path: `${home}/inbox/chats/**`,\n event_types: ['node:created', 'node:updated'],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Snapshot of the conversation list state */\nexport interface ConversationListSnapshot {\n conversations: ConversationListItem[];\n totalUnreadCount: number;\n isLoading: boolean;\n error: string | null;\n}\n\n/** Options for creating a ConversationListStore */\nexport interface ConversationListStoreOptions {\n database: Database;\n /** Filter by conversation type */\n type?: ConversationType;\n /** Subscribe to WebSocket events for new conversations */\n realtime?: boolean;\n}\n\ntype Subscriber = (snapshot: ConversationListSnapshot) => void;\n\n// ---------------------------------------------------------------------------\n// ConversationListStore\n// ---------------------------------------------------------------------------\n\nexport class ConversationListStore {\n private database: Database;\n private type?: ConversationType;\n private realtime: boolean;\n private subscribers = new Set<Subscriber>();\n\n // Internal state\n private _conversations: ConversationListItem[] = [];\n private _isLoading = false;\n private _error: string | null = null;\n\n // Cached ConversationStore instances\n private _stores = new Map<string, ConversationStore>();\n\n // Real-time subscription\n private _realtimeSubscription: { unsubscribe: () => void } | null = null;\n\n constructor(options: ConversationListStoreOptions) {\n this.database = options.database;\n this.type = options.type;\n this.realtime = options.realtime ?? false;\n }\n\n // ==========================================================================\n // Subscription\n // ==========================================================================\n\n subscribe(callback: Subscriber): () => void {\n this.subscribers.add(callback);\n callback(this.getSnapshot());\n return () => { this.subscribers.delete(callback); };\n }\n\n getSnapshot(): ConversationListSnapshot {\n return {\n conversations: [...this._conversations],\n totalUnreadCount: this._conversations.reduce((sum, c) => sum + (c.unreadCount ?? 0), 0),\n isLoading: this._isLoading,\n error: this._error,\n };\n }\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Load conversations from the server.\n */\n async load(): Promise<void> {\n this._isLoading = true;\n this._error = null;\n this.notify();\n\n try {\n const conversations = await this.database.conversations.list({\n type: this.type,\n });\n logger.debug(`[ConversationListStore] Loaded ${conversations.length} conversations`);\n this._conversations = conversations;\n\n if (this.realtime) {\n this.startRealtimeSubscription();\n }\n } catch (err) {\n logger.error('[ConversationListStore] Failed to load conversations', err);\n this._error = err instanceof Error ? err.message : String(err);\n } finally {\n this._isLoading = false;\n this.notify();\n }\n }\n\n /**\n * Create a new conversation.\n */\n async createConversation(options: {\n participant: string;\n subject?: string;\n input?: Record<string, unknown>;\n }): Promise<ConversationListItem> {\n const convo = await this.database.conversations.create(options);\n\n const listItem: ConversationListItem = {\n id: convo.id,\n type: convo.type,\n conversationPath: convo.conversationPath,\n conversationWorkspace: convo.conversationWorkspace,\n agentRef: convo.agentRef,\n participants: convo.participants,\n unreadCount: 0,\n updatedAt: new Date().toISOString(),\n };\n\n this._conversations = [listItem, ...this._conversations];\n this.notify();\n return listItem;\n }\n\n /**\n * Delete a conversation.\n */\n async deleteConversation(conversationPath: string): Promise<void> {\n // Destroy cached store\n const store = this._stores.get(conversationPath);\n if (store) {\n store.destroy();\n this._stores.delete(conversationPath);\n }\n\n await this.database.conversations.delete(conversationPath);\n this._conversations = this._conversations.filter(c => c.conversationPath !== conversationPath);\n this.notify();\n }\n\n /**\n * Mark a conversation as read.\n */\n async markAsRead(conversationPath: string): Promise<void> {\n await this.database.conversations.markAsRead(conversationPath);\n this._conversations = this._conversations.map(c =>\n c.conversationPath === conversationPath ? { ...c, unreadCount: 0 } : c\n );\n this.notify();\n }\n\n /**\n * Get or create a ConversationStore for a specific conversation.\n * Caches instances so repeated calls return the same store.\n */\n getConversationStore(\n conversationPath: string,\n overrides?: Partial<ConversationStoreOptions>,\n ): ConversationStore {\n let store = this._stores.get(conversationPath);\n if (!store) {\n store = new ConversationStore({\n database: this.database,\n conversationPath,\n ...overrides,\n });\n this._stores.set(conversationPath, store);\n }\n return store;\n }\n\n /**\n * Clean up all resources.\n */\n destroy(): void {\n this._realtimeSubscription?.unsubscribe();\n this._realtimeSubscription = null;\n\n for (const store of this._stores.values()) {\n store.destroy();\n }\n this._stores.clear();\n this.subscribers.clear();\n }\n\n // ==========================================================================\n // Internal\n // ==========================================================================\n\n private async startRealtimeSubscription(): Promise<void> {\n if (this._realtimeSubscription) return;\n logger.debug('[ConversationListStore] Starting realtime subscription');\n\n try {\n const workspace = this.database.workspace('raisin:access_control');\n const events = workspace.events();\n\n // We need the user home path to subscribe to the right folder\n const result = await this.database.executeSql(\n `SELECT RAISIN_CURRENT_USER()->>'path'::String as home`,\n );\n const rows = result.rows as unknown as Record<string, unknown>[];\n const userHome = rows?.[0]?.home as string;\n if (!userHome) return;\n\n this._realtimeSubscription = await events.subscribe(\n buildChatsSubscriptionFilters(userHome),\n async (event) => {\n const eventData = event as any;\n const nodeId = eventData.payload?.node_id;\n if (!nodeId) return;\n\n try {\n const nodeResult = await this.database.executeSql(\n `SELECT id, path, node_type, properties, created_at, updated_at FROM 'raisin:access_control' WHERE id = $1 LIMIT 1`,\n [nodeId],\n );\n const row = (nodeResult.rows as unknown as Record<string, unknown>[])?.[0];\n if (!row || row.node_type !== 'raisin:Conversation') return;\n\n const convPath = row.path as string;\n const props = (row.properties ?? {}) as Record<string, unknown>;\n const item: ConversationListItem = {\n id: row.id as string,\n type: (props.conversation_type as ConversationType) ?? 'ai_chat',\n conversationPath: convPath,\n conversationWorkspace: 'raisin:access_control',\n agentRef: props.agent_ref as string | undefined,\n participants: props.participants as string[] | undefined,\n unreadCount: (props.unread_count as number) ?? 0,\n lastMessage: props.last_message as { content: string; sender_id: string; created_at: string } | undefined,\n updatedAt: (row.updated_at ?? row.created_at) as string,\n };\n\n const existingIdx = this._conversations.findIndex(c => c.conversationPath === convPath);\n if (existingIdx >= 0) {\n // Update existing conversation and move to top\n this._conversations.splice(existingIdx, 1);\n }\n this._conversations = [item, ...this._conversations];\n this.notify();\n } catch (err) {\n logger.debug('Failed to process conversation event:', err);\n }\n },\n );\n } catch (err) {\n logger.debug('Failed to start realtime subscription:', err);\n }\n }\n\n private notify(): void {\n const snapshot = this.getSnapshot();\n for (const sub of this.subscribers) {\n try { sub(snapshot); }\n catch (err) { logger.error('Error in conversation list store subscriber:', err); }\n }\n }\n}\n","/**\n * React adapters for the RaisinDB conversation stores.\n *\n * Since the SDK does not depend on React, the hooks accept React as a\n * parameter to avoid a hard dependency while providing full type safety.\n *\n * @example\n * ```tsx\n * import React from 'react';\n * import { useConversation, useConversationList } from '@raisindb/client';\n *\n * function Chat() {\n * const chat = useConversation(React, {\n * database: db,\n * conversationPath: '/...',\n * });\n * return (\n * <div>\n * {chat.messages.map((m, i) => <div key={i}>{m.content}</div>)}\n * {chat.isStreaming && <p>{chat.streamingText}</p>}\n * </div>\n * );\n * }\n * ```\n */\n\nimport {\n ConversationStore,\n type ConversationStoreOptions,\n type ConversationStoreSnapshot,\n} from '../stores/conversation-store';\nimport {\n ConversationListStore,\n type ConversationListStoreOptions,\n type ConversationListSnapshot,\n} from '../stores/conversation-list-store';\nimport type { ChatMessage, ConversationListItem } from '../types/chat';\n\n/** Minimal subset of the React API needed by the hooks */\nexport interface ReactLike {\n useState<T>(initial: T | (() => T)): [T, (value: T | ((prev: T) => T)) => void];\n useEffect(effect: () => void | (() => void), deps?: unknown[]): void;\n useRef<T>(initial: T): { current: T };\n useCallback<T extends (...args: never[]) => unknown>(fn: T, deps: unknown[]): T;\n}\n\n// ---------------------------------------------------------------------------\n// useConversation\n// ---------------------------------------------------------------------------\n\nconst INITIAL_SNAPSHOT: ConversationStoreSnapshot = {\n conversation: null,\n messages: [],\n isStreaming: false,\n isWaiting: false,\n streamingText: '',\n error: null,\n activeToolCalls: [],\n plans: [],\n isLoading: false,\n conversationPath: null,\n};\n\nexport interface UseConversationReturn extends ConversationStoreSnapshot {\n sendMessage: (content: string) => Promise<void>;\n approvePlan: (planPath: string) => Promise<void>;\n rejectPlan: (planPath: string, feedback?: string) => Promise<void>;\n stop: () => void;\n loadMessages: () => Promise<ChatMessage[]>;\n}\n\nexport function useConversation(\n react: ReactLike,\n options: ConversationStoreOptions,\n): UseConversationReturn {\n const { useState, useEffect, useRef, useCallback } = react;\n\n const [snapshot, setSnapshot] = useState<ConversationStoreSnapshot>(INITIAL_SNAPSHOT);\n const storeRef = useRef<ConversationStore | null>(null);\n\n useEffect(() => {\n const store = new ConversationStore(options);\n storeRef.current = store;\n\n const unsubscribe = store.subscribe((next) => setSnapshot(next));\n\n return () => {\n unsubscribe();\n store.destroy();\n storeRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.conversationPath]);\n\n const sendMessage = useCallback(async (content: string) => {\n await storeRef.current?.sendMessage(content);\n }, []);\n\n const approvePlan = useCallback(async (planPath: string) => {\n await storeRef.current?.approvePlan(planPath);\n }, []);\n\n const rejectPlan = useCallback(async (planPath: string, feedback?: string) => {\n await storeRef.current?.rejectPlan(planPath, feedback);\n }, []);\n\n const stop = useCallback(() => { storeRef.current?.stop(); }, []);\n\n const loadMessages = useCallback(async () => {\n return (await storeRef.current?.loadMessages()) ?? [];\n }, []);\n\n return {\n ...snapshot,\n sendMessage,\n approvePlan,\n rejectPlan,\n stop,\n loadMessages,\n };\n}\n\n// ---------------------------------------------------------------------------\n// useConversationList\n// ---------------------------------------------------------------------------\n\n// isLoading starts TRUE: the hook always calls store.load() in its mount\n// effect, but the first render happens before that effect runs — reporting\n// \"not loading\" there makes consumers mis-resolve an empty list as \"loaded,\n// no conversations\" (e.g. failing to resume the latest conversation).\nconst INITIAL_LIST_SNAPSHOT: ConversationListSnapshot = {\n conversations: [],\n totalUnreadCount: 0,\n isLoading: true,\n error: null,\n};\n\nexport interface UseConversationListReturn extends ConversationListSnapshot {\n createConversation: (options: { participant: string; subject?: string }) => Promise<ConversationListItem>;\n deleteConversation: (conversationPath: string) => Promise<void>;\n markAsRead: (conversationPath: string) => Promise<void>;\n}\n\nexport function useConversationList(\n react: ReactLike,\n options: ConversationListStoreOptions,\n): UseConversationListReturn {\n const { useState, useEffect, useRef, useCallback } = react;\n\n const [snapshot, setSnapshot] = useState<ConversationListSnapshot>(INITIAL_LIST_SNAPSHOT);\n const storeRef = useRef<ConversationListStore | null>(null);\n\n useEffect(() => {\n const store = new ConversationListStore(options);\n storeRef.current = store;\n\n const unsubscribe = store.subscribe((next) => setSnapshot(next));\n store.load();\n\n return () => {\n unsubscribe();\n store.destroy();\n storeRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.type, options.realtime]);\n\n const createConversation = useCallback(async (opts: { participant: string; subject?: string }) => {\n return storeRef.current!.createConversation(opts);\n }, []);\n\n const deleteConversation = useCallback(async (conversationPath: string) => {\n await storeRef.current?.deleteConversation(conversationPath);\n }, []);\n\n const markAsRead = useCallback(async (conversationPath: string) => {\n await storeRef.current?.markAsRead(conversationPath);\n }, []);\n\n return {\n ...snapshot,\n createConversation,\n deleteConversation,\n markAsRead,\n };\n}\n","/**\n * Svelte 5 helpers for RaisinDB conversation stores.\n *\n * Unlike the React integration which provides hooks, the Svelte 5 integration\n * provides factory functions that return objects designed to work seamlessly\n * with Svelte 5 runes. Use these in `.svelte.ts` files with `$state`.\n *\n * The SDK stores (ConversationStore, ConversationListStore) already have a\n * `.subscribe(callback)` API compatible with Svelte's reactivity. These\n * helpers simplify the most common patterns.\n *\n * @example Svelte 5 runes (in .svelte.ts file):\n * ```typescript\n * // stores/chat.svelte.ts\n * import { ConversationStore, type ConversationStoreSnapshot, type Database } from '@raisindb/client';\n *\n * class ChatState {\n * snapshot = $state<ConversationStoreSnapshot | null>(null);\n * #store: ConversationStore | null = null;\n * #unsub: (() => void) | null = null;\n *\n * get messages() { return this.snapshot?.messages ?? []; }\n * get isStreaming() { return this.snapshot?.isStreaming ?? false; }\n * get streamingText() { return this.snapshot?.streamingText ?? ''; }\n * get plans() { return this.snapshot?.plans ?? []; }\n * get error() { return this.snapshot?.error ?? null; }\n *\n * async open(db: Database, path: string) {\n * this.close();\n * this.#store = new ConversationStore({ database: db, conversationPath: path });\n * this.#unsub = this.#store.subscribe(s => { this.snapshot = s; });\n * await this.#store.loadMessages();\n * }\n *\n * sendMessage = async (content: string) => {\n * await this.#store?.sendMessage(content);\n * };\n *\n * close() {\n * this.#unsub?.();\n * this.#store?.destroy();\n * this.#store = null;\n * this.snapshot = null;\n * }\n * }\n *\n * export const chat = new ChatState();\n * ```\n *\n * @example In a .svelte component:\n * ```svelte\n * <script>\n * import { chat } from '$lib/stores/chat.svelte';\n *\n * // Properties are reactive — no $ prefix needed\n * const messages = $derived(chat.messages);\n * </script>\n *\n * {#each messages as msg}\n * <div>{msg.content}</div>\n * {/each}\n * {#if chat.isStreaming}\n * <p class=\"streaming\">{chat.streamingText}</p>\n * {/if}\n * ```\n *\n * @module\n */\n\nimport {\n ConversationStore,\n type ConversationStoreOptions,\n type ConversationStoreSnapshot,\n} from '../stores/conversation-store';\nimport {\n ConversationListStore,\n type ConversationListStoreOptions,\n type ConversationListSnapshot,\n} from '../stores/conversation-list-store';\n\n/**\n * Create a conversation store adapter for Svelte 5.\n *\n * Returns an object with the store, a snapshot getter, actions, and a\n * destroy function. In a `.svelte.ts` file, bind `snapshot` to `$state`\n * to get fine-grained reactivity.\n *\n * @example\n * ```typescript\n * const adapter = createConversationAdapter({ database: db, conversationPath: path });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n * // ...later\n * adapter.destroy();\n * ```\n */\nexport function createConversationAdapter(options: ConversationStoreOptions) {\n const store = new ConversationStore(options);\n\n return {\n /** The underlying ConversationStore instance */\n store,\n\n /** Get the current snapshot */\n getSnapshot: (): ConversationStoreSnapshot => store.getSnapshot(),\n\n /** Subscribe to snapshot changes. Returns unsubscribe function. */\n subscribe: (cb: (s: ConversationStoreSnapshot) => void) => store.subscribe(cb),\n\n /** Send a user message */\n sendMessage: (content: string) => store.sendMessage(content),\n\n /** Load persisted messages */\n loadMessages: () => store.loadMessages(),\n\n /** Approve a pending plan */\n approvePlan: (planPath: string) => store.approvePlan(planPath),\n\n /** Reject a pending plan */\n rejectPlan: (planPath: string, feedback?: string) => store.rejectPlan(planPath, feedback),\n\n /** Mark a message as read */\n markMessageAsRead: (messagePath: string) => store.markMessageAsRead(messagePath),\n\n /** Stop streaming */\n stop: () => store.stop(),\n\n /** Get the conversation path */\n getConversationPath: () => store.getConversationPath(),\n\n /** Destroy the store and release resources */\n destroy: () => store.destroy(),\n };\n}\n\n/**\n * Create a conversation list store adapter for Svelte 5.\n *\n * @example\n * ```typescript\n * const adapter = createConversationListAdapter({ database: db, realtime: true });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n * await adapter.load();\n * ```\n */\nexport function createConversationListAdapter(options: ConversationListStoreOptions) {\n const store = new ConversationListStore(options);\n\n return {\n /** The underlying ConversationListStore instance */\n store,\n\n /** Get the current snapshot */\n getSnapshot: (): ConversationListSnapshot => store.getSnapshot(),\n\n /** Subscribe to snapshot changes. Returns unsubscribe function. */\n subscribe: (cb: (s: ConversationListSnapshot) => void) => store.subscribe(cb),\n\n /** Load conversations from the server */\n load: () => store.load(),\n\n /** Create a new conversation */\n createConversation: (opts: { participant: string; subject?: string; input?: Record<string, unknown> }) =>\n store.createConversation(opts),\n\n /** Delete a conversation */\n deleteConversation: (path: string) => store.deleteConversation(path),\n\n /** Mark a conversation as read */\n markAsRead: (path: string) => store.markAsRead(path),\n\n /** Get or create a ConversationStore for a specific path */\n getConversationStore: (path: string) => store.getConversationStore(path),\n\n /** Destroy the store and release resources */\n destroy: () => store.destroy(),\n };\n}\n","import type { RaisinClient } from '../../client';\nimport type { IdentityUser } from '../../auth';\n\nexport interface AuthSnapshot {\n user: IdentityUser | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n}\n\nexport interface AuthAdapter {\n subscribe: (cb: (snapshot: AuthSnapshot) => void) => () => void;\n getSnapshot: () => AuthSnapshot;\n login: (email: string, password: string, repository: string) => Promise<IdentityUser>;\n register: (email: string, password: string, repository: string, displayName?: string) => Promise<IdentityUser>;\n logout: (options?: { disconnect?: boolean; reconnect?: boolean }) => Promise<void>;\n initSession: (repository: string) => Promise<IdentityUser | null>;\n destroy: () => void;\n}\n\n/**\n * Create an auth adapter for Svelte 5.\n *\n * Returns a plain object with `subscribe`, `getSnapshot`, auth actions, and `destroy`.\n * Bind `getSnapshot()` to `$state` in a `.svelte.ts` file for reactivity.\n *\n * @example\n * ```typescript\n * // lib/auth.svelte.ts\n * import { createAuthAdapter } from '@raisindb/client/svelte';\n * import { client } from '$lib/raisin';\n *\n * const adapter = createAuthAdapter(client);\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const auth = {\n * get user() { return snapshot.user; },\n * get isAuthenticated() { return snapshot.isAuthenticated; },\n * get isLoading() { return snapshot.isLoading; },\n * login: adapter.login,\n * register: adapter.register,\n * logout: adapter.logout,\n * initSession: adapter.initSession,\n * };\n * ```\n */\nexport function createAuthAdapter(client: RaisinClient): AuthAdapter {\n let snapshot: AuthSnapshot = {\n user: client.getStoredUser(),\n isAuthenticated: client.getStoredUser() !== null,\n isLoading: false,\n };\n\n const listeners = new Set<(s: AuthSnapshot) => void>();\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n function update(partial: Partial<AuthSnapshot>) {\n snapshot = { ...snapshot, ...partial };\n emit();\n }\n\n const unsubAuth = client.onAuthStateChange(({ event, session }) => {\n if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED' || event === 'USER_UPDATED') {\n update({ user: session.user, isAuthenticated: true });\n } else if (event === 'SIGNED_OUT' || event === 'SESSION_EXPIRED') {\n update({ user: null, isAuthenticated: false });\n }\n });\n\n const unsubUser = client.onUserChange(({ node }) => {\n if (!snapshot.user) return;\n update({\n user: {\n ...snapshot.user,\n home: node.path,\n displayName: (node.properties.display_name as string) ?? snapshot.user.displayName,\n avatarUrl: (node.properties.avatar_url as string) ?? snapshot.user.avatarUrl,\n },\n });\n });\n\n return {\n subscribe(cb: (s: AuthSnapshot) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n\n async login(email: string, password: string, repository: string) {\n update({ isLoading: true });\n try {\n return await client.loginWithEmail(email, password, repository);\n } finally {\n update({ isLoading: false });\n }\n },\n\n async register(email: string, password: string, repository: string, displayName?: string) {\n update({ isLoading: true });\n try {\n return await client.registerWithEmail(email, password, repository, displayName);\n } finally {\n update({ isLoading: false });\n }\n },\n\n async logout(options?: { disconnect?: boolean; reconnect?: boolean }) {\n update({ isLoading: true });\n try {\n await client.logout(options);\n } finally {\n update({ isLoading: false });\n }\n },\n\n async initSession(repository: string) {\n update({ isLoading: true });\n try {\n return await client.initSession(repository);\n } finally {\n update({ isLoading: false });\n }\n },\n\n destroy() {\n unsubAuth();\n unsubUser();\n listeners.clear();\n },\n };\n}\n","import type { RaisinClient } from '../../client';\nimport { ConnectionState } from '../../connection';\n\nexport interface ConnectionSnapshot {\n state: ConnectionState;\n isConnected: boolean;\n isReady: boolean;\n}\n\nexport interface ConnectionAdapter {\n subscribe: (cb: (snapshot: ConnectionSnapshot) => void) => () => void;\n getSnapshot: () => ConnectionSnapshot;\n connect: () => Promise<void>;\n disconnect: () => void;\n destroy: () => void;\n}\n\n/**\n * Create a connection adapter for Svelte 5.\n *\n * Tracks WebSocket connection state and ready state. Bind to `$state` in\n * a `.svelte.ts` file for reactivity.\n *\n * @example\n * ```typescript\n * // lib/connection.svelte.ts\n * import { createConnectionAdapter } from '@raisindb/client/svelte';\n * import { client } from '$lib/raisin';\n *\n * const adapter = createConnectionAdapter(client);\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const connection = {\n * get state() { return snapshot.state; },\n * get isConnected() { return snapshot.isConnected; },\n * get isReady() { return snapshot.isReady; },\n * connect: adapter.connect,\n * disconnect: adapter.disconnect,\n * };\n * ```\n */\nexport function createConnectionAdapter(client: RaisinClient): ConnectionAdapter {\n let snapshot: ConnectionSnapshot = {\n state: client.getConnectionState(),\n isConnected: client.getConnectionState() === ConnectionState.Connected,\n isReady: client.isReady(),\n };\n\n const listeners = new Set<(s: ConnectionSnapshot) => void>();\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n const unsubConn = client.onConnectionStateChange((newState) => {\n snapshot = {\n state: newState,\n isConnected: newState === ConnectionState.Connected,\n isReady: snapshot.isReady,\n };\n emit();\n });\n\n const unsubReady = client.onReadyStateChange((ready) => {\n snapshot = { ...snapshot, isReady: ready };\n emit();\n });\n\n return {\n subscribe(cb: (s: ConnectionSnapshot) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n\n async connect() {\n await client.connect();\n },\n\n disconnect() {\n client.disconnect();\n },\n\n destroy() {\n unsubConn();\n unsubReady();\n listeners.clear();\n },\n };\n}\n","import type { Database } from '../../database';\nimport type { SqlResult } from '../../protocol';\n\nexport interface SqlAdapterOptions {\n enabled?: boolean;\n refetchOnReconnect?: boolean;\n realtime?: {\n workspace: string;\n eventTypes?: string[];\n path?: string;\n nodeType?: string;\n };\n}\n\nexport interface SqlSnapshot<T> {\n data: T[] | null;\n isLoading: boolean;\n error: Error | null;\n}\n\nexport interface SqlAdapter<T> {\n subscribe: (cb: (snapshot: SqlSnapshot<T>) => void) => () => void;\n getSnapshot: () => SqlSnapshot<T>;\n refetch: () => Promise<void>;\n destroy: () => void;\n}\n\nfunction rowsToObjects<T>(result: SqlResult): T[] {\n return result.rows as T[];\n}\n\n/**\n * Create a SQL query adapter for Svelte 5.\n *\n * Executes a SQL query and maintains reactive snapshot state. Supports\n * realtime subscriptions and automatic refetch on reconnect.\n *\n * @example\n * ```typescript\n * // lib/posts.svelte.ts\n * import { createSqlAdapter } from '@raisindb/client/svelte';\n * import { db } from '$lib/raisin';\n *\n * const adapter = createSqlAdapter<{ title: string }>(db, \"SELECT * FROM 'content'\", [], {\n * realtime: { workspace: 'content' },\n * });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const posts = {\n * get data() { return snapshot.data; },\n * get isLoading() { return snapshot.isLoading; },\n * get error() { return snapshot.error; },\n * refetch: adapter.refetch,\n * };\n * ```\n */\nexport function createSqlAdapter<T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n): SqlAdapter<T> {\n let snapshot: SqlSnapshot<T> = {\n data: null,\n isLoading: false,\n error: null,\n };\n\n const listeners = new Set<(s: SqlSnapshot<T>) => void>();\n let destroyed = false;\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n function update(partial: Partial<SqlSnapshot<T>>) {\n snapshot = { ...snapshot, ...partial };\n emit();\n }\n\n async function fetchData() {\n if (destroyed) return;\n update({ isLoading: true, error: null });\n try {\n const result = await database.executeSql(sql, params);\n if (!destroyed) {\n update({ data: rowsToObjects<T>(result), isLoading: false });\n }\n } catch (err) {\n if (!destroyed) {\n update({\n error: err instanceof Error ? err : new Error(String(err)),\n isLoading: false,\n });\n }\n }\n }\n\n // Cleanup handles\n const cleanups: (() => void)[] = [];\n\n // Initial fetch\n const enabled = options?.enabled !== false;\n if (enabled) {\n fetchData();\n }\n\n // Refetch on reconnect\n const refetchOnReconnect = options?.refetchOnReconnect !== false;\n if (enabled && refetchOnReconnect) {\n const client = (database as any)._client;\n if (client?.onReconnected) {\n const unsub = client.onReconnected(() => { fetchData(); });\n cleanups.push(unsub);\n }\n }\n\n // Realtime subscription\n const realtime = options?.realtime;\n if (enabled && realtime) {\n let unsubscribe: (() => Promise<void>) | undefined;\n let cancelled = false;\n\n database.events().subscribe(\n {\n workspace: realtime.workspace,\n event_types: realtime.eventTypes,\n path: realtime.path,\n node_type: realtime.nodeType,\n },\n () => { fetchData(); },\n ).then((sub) => {\n if (cancelled) {\n sub.unsubscribe();\n } else {\n unsubscribe = () => sub.unsubscribe();\n }\n });\n\n cleanups.push(() => {\n cancelled = true;\n unsubscribe?.();\n });\n }\n\n return {\n subscribe(cb: (s: SqlSnapshot<T>) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n refetch: fetchData,\n\n destroy() {\n destroyed = true;\n for (const cleanup of cleanups) cleanup();\n listeners.clear();\n },\n };\n}\n","import type { Database } from '../../database';\nimport type { EventMessage, SubscriptionFilters } from '../../protocol';\n\nexport interface SubscriptionAdapter {\n destroy: () => void;\n}\n\n/**\n * Create an event subscription adapter for Svelte 5.\n *\n * Pure side-effect adapter — subscribes to database events and invokes the\n * callback on each matching event. Call `destroy()` to unsubscribe.\n *\n * @example\n * ```typescript\n * // In a .svelte component's script block or .svelte.ts file\n * import { createSubscriptionAdapter } from '@raisindb/client/svelte';\n * import { db } from '$lib/raisin';\n *\n * const sub = createSubscriptionAdapter(\n * db,\n * { workspace: 'content', node_type: 'Post' },\n * (event) => { console.log('Post changed:', event); },\n * );\n *\n * // In onDestroy or $effect cleanup:\n * sub.destroy();\n * ```\n */\nexport function createSubscriptionAdapter(\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n): SubscriptionAdapter {\n let unsubscribe: (() => Promise<void>) | undefined;\n let cancelled = false;\n\n database.events().subscribe(filters, (event) => {\n if (!cancelled) callback(event);\n }).then((sub) => {\n if (cancelled) {\n sub.unsubscribe();\n } else {\n unsubscribe = () => sub.unsubscribe();\n }\n });\n\n return {\n destroy() {\n cancelled = true;\n unsubscribe?.();\n },\n };\n}\n","import { FlowClient } from '../../flow-client';\nimport type { FlowClientOptions } from '../../flow-client';\nimport type { AuthManager } from '../../auth';\nimport type { FlowsApi } from '../../flows';\nimport type { Database } from '../../database';\nimport type { FlowExecutionEvent } from '../../types/flow';\n\nexport type FlowStatus = 'idle' | 'running' | 'waiting' | 'completed' | 'failed';\n\nexport interface FlowSnapshot {\n events: FlowExecutionEvent[];\n status: FlowStatus;\n isRunning: boolean;\n error: string | null;\n output: unknown | null;\n instanceId: string | null;\n}\n\nexport interface FlowAdapterOptions {\n database?: Database;\n baseUrl?: string;\n repository?: string;\n authManager?: AuthManager;\n clientOptions?: FlowClientOptions;\n flowsApi?: FlowsApi;\n}\n\nexport interface FlowAdapter {\n subscribe: (cb: (snapshot: FlowSnapshot) => void) => () => void;\n getSnapshot: () => FlowSnapshot;\n run: (flowPath: string, input?: Record<string, unknown>) => Promise<void>;\n resume: (data: unknown) => Promise<void>;\n reset: () => void;\n destroy: () => void;\n}\n\n/**\n * Create a flow execution adapter for Svelte 5.\n *\n * Manages the full flow lifecycle: starting, streaming events, resuming\n * waiting flows, and tracking completion. Bind snapshot to `$state` for reactivity.\n *\n * @example\n * ```typescript\n * // lib/flow.svelte.ts\n * import { createFlowAdapter } from '@raisindb/client/svelte';\n * import { db } from '$lib/raisin';\n *\n * const adapter = createFlowAdapter({ database: db });\n * let snapshot = $state(adapter.getSnapshot());\n * adapter.subscribe(s => { snapshot = s; });\n *\n * export const flow = {\n * get events() { return snapshot.events; },\n * get status() { return snapshot.status; },\n * get isRunning() { return snapshot.isRunning; },\n * get error() { return snapshot.error; },\n * get output() { return snapshot.output; },\n * run: adapter.run,\n * resume: adapter.resume,\n * reset: adapter.reset,\n * };\n * ```\n */\nexport function createFlowAdapter(options: FlowAdapterOptions): FlowAdapter {\n let snapshot: FlowSnapshot = {\n events: [],\n status: 'idle',\n isRunning: false,\n error: null,\n output: null,\n instanceId: null,\n };\n\n const listeners = new Set<(s: FlowSnapshot) => void>();\n let aborted = false;\n\n function emit() {\n for (const cb of listeners) cb(snapshot);\n }\n\n function update(partial: Partial<FlowSnapshot>) {\n snapshot = { ...snapshot, ...partial };\n if ('status' in partial) {\n snapshot.isRunning = snapshot.status === 'running';\n }\n emit();\n }\n\n // Resolve FlowClient\n let flowClient: FlowClient | null = null;\n if (options.database) {\n flowClient = options.database.flow;\n } else if (options.baseUrl && options.repository && options.authManager) {\n flowClient = new FlowClient(\n options.baseUrl,\n options.repository,\n options.authManager,\n options.clientOptions,\n options.flowsApi,\n );\n }\n\n return {\n subscribe(cb: (s: FlowSnapshot) => void) {\n listeners.add(cb);\n return () => { listeners.delete(cb); };\n },\n\n getSnapshot: () => snapshot,\n\n async run(flowPath: string, input: Record<string, unknown> = {}) {\n if (!flowClient) return;\n\n aborted = false;\n update({\n events: [],\n error: null,\n output: null,\n status: 'running',\n });\n\n try {\n const result = await flowClient.run(flowPath, input);\n update({ instanceId: result.instance_id });\n\n for await (const event of flowClient.streamEvents(result.instance_id)) {\n if (aborted) break;\n\n update({ events: [...snapshot.events, event] });\n\n if (event.type === 'flow_waiting') {\n update({ status: 'waiting' });\n } else if (event.type === 'flow_completed') {\n update({ output: event.output, status: 'completed' });\n } else if (event.type === 'flow_failed') {\n update({ error: event.error, status: 'failed' });\n }\n }\n } catch (err) {\n update({\n error: err instanceof Error ? err.message : String(err),\n status: 'failed',\n });\n }\n },\n\n async resume(data: unknown) {\n if (!flowClient || !snapshot.instanceId) return;\n\n update({ status: 'running', error: null });\n\n try {\n const stream = await flowClient.createEventStream(snapshot.instanceId);\n await flowClient.resume(snapshot.instanceId, data);\n\n for await (const event of stream.events) {\n if (aborted) break;\n\n update({ events: [...snapshot.events, event] });\n\n if (event.type === 'flow_waiting') {\n update({ status: 'waiting' });\n stream.close();\n return;\n } else if (event.type === 'flow_completed') {\n update({ output: event.output, status: 'completed' });\n stream.close();\n return;\n } else if (event.type === 'flow_failed') {\n update({ error: event.error, status: 'failed' });\n stream.close();\n return;\n }\n }\n\n stream.close();\n } catch (err) {\n update({\n error: err instanceof Error ? err.message : String(err),\n status: 'failed',\n });\n }\n },\n\n reset() {\n aborted = true;\n update({\n events: [],\n status: 'idle',\n error: null,\n output: null,\n instanceId: null,\n });\n },\n\n destroy() {\n aborted = true;\n listeners.clear();\n },\n };\n}\n","import type { RaisinClient } from '../../client';\n\n/**\n * Context value for the RaisinDB Svelte integration.\n *\n * Use with Svelte's `setContext`/`getContext` in `.svelte` files.\n *\n * @example Setup in `+layout.svelte`:\n * ```svelte\n * <script>\n * import { setContext } from 'svelte';\n * import { RAISIN_CONTEXT_KEY, type RaisinContext } from '@raisindb/client/svelte';\n * import { client } from '$lib/raisin';\n *\n * setContext<RaisinContext>(RAISIN_CONTEXT_KEY, { client, repository: 'myrepo' });\n * </script>\n *\n * {@render children()}\n * ```\n *\n * @example Usage in a child component:\n * ```svelte\n * <script>\n * import { getContext } from 'svelte';\n * import { RAISIN_CONTEXT_KEY, type RaisinContext } from '@raisindb/client/svelte';\n *\n * const { client, repository } = getContext<RaisinContext>(RAISIN_CONTEXT_KEY);\n * const db = client.database(repository!);\n * </script>\n * ```\n */\nexport interface RaisinContext {\n client: RaisinClient;\n repository?: string;\n}\n\n/**\n * Shared context key for RaisinDB. Use this with `setContext` and `getContext`\n * to ensure consistent key usage across your application.\n */\nexport const RAISIN_CONTEXT_KEY: unique symbol = Symbol('raisin');\n","/**\n * React flow adapter for RaisinDB.\n *\n * Provides a `useFlow` hook that wraps the FlowClient for executing\n * and monitoring RaisinDB flows in React applications. Returns reactive\n * state tracking flow events, status, and providing control actions.\n *\n * Since this SDK package does not depend on React, the hook accepts\n * React as a parameter via the `ReactLike` interface.\n *\n * @example\n * ```tsx\n * import React from 'react';\n * import { useFlow } from '@raisindb/client';\n *\n * function OrderProcessor() {\n * const flow = useFlow(React, {\n * baseUrl: 'http://localhost:8081',\n * repository: 'my-repo',\n * authManager,\n * });\n *\n * const handleRun = async () => {\n * await flow.run('/flows/process-order', { orderId: 'ord-123' });\n * };\n *\n * return (\n * <div>\n * <button onClick={handleRun} disabled={flow.isRunning}>Run</button>\n * <p>Status: {flow.status}</p>\n * {flow.events.map((e, i) => <div key={i}>{e.type}</div>)}\n * {flow.error && <p className=\"error\">{flow.error}</p>}\n * </div>\n * );\n * }\n * ```\n */\n\nimport { FlowClient } from '../flow-client';\nimport type { FlowClientOptions } from '../flow-client';\nimport type { AuthManager } from '../auth';\nimport type { FlowsApi } from '../flows';\nimport type { Database } from '../database';\nimport type { FlowExecutionEvent } from '../types/flow';\nimport type { ReactLike } from './react-conversation';\n\n/** Options for creating the FlowClient within useFlow */\nexport interface UseFlowOptions {\n /**\n * Pre-configured Database instance (from `client.database()`).\n * When provided, `baseUrl`, `repository`, `authManager`, and `flowsApi` are derived\n * automatically — no manual wiring needed.\n */\n database?: Database;\n /** Base HTTP URL of the RaisinDB server */\n baseUrl?: string;\n /** Repository name */\n repository?: string;\n /** Auth manager for token access */\n authManager?: AuthManager;\n /** Additional FlowClient options */\n clientOptions?: FlowClientOptions;\n /** Optional FlowsApi for WebSocket-based flow operations */\n flowsApi?: FlowsApi;\n}\n\n/** Flow execution status */\nexport type FlowStatus = 'idle' | 'running' | 'waiting' | 'completed' | 'failed';\n\n/** Return value from the useFlow hook */\nexport interface UseFlowReturn {\n /** Collected flow execution events */\n events: FlowExecutionEvent[];\n /** Current flow status */\n status: FlowStatus;\n /** Whether a flow is currently running */\n isRunning: boolean;\n /** Current error, if any */\n error: string | null;\n /** Output from the completed flow */\n output: unknown | null;\n /** Current flow instance ID, if running */\n instanceId: string | null;\n /** Run a flow by path with optional input data */\n run: (flowPath: string, input?: Record<string, unknown>) => Promise<void>;\n /** Resume a waiting flow with data */\n resume: (data: unknown) => Promise<void>;\n /** Reset the hook state (clear events, status, error) */\n reset: () => void;\n}\n\n/**\n * React hook for executing and monitoring RaisinDB flows.\n *\n * Manages the full lifecycle: starting a flow, streaming events,\n * resuming waiting flows, and tracking completion status.\n * Auto-cleans up on component unmount.\n *\n * @param react - The React instance (pass `React` or `{ useState, useEffect, useRef, useCallback }`)\n * @param options - Flow client options (baseUrl, repository, authManager, etc.)\n * @returns Reactive flow state and action functions\n *\n * @example\n * ```tsx\n * import React from 'react';\n * import { useFlow } from '@raisindb/client';\n *\n * function DataPipeline() {\n * const flow = useFlow(React, {\n * baseUrl: 'http://localhost:8081',\n * repository: 'my-repo',\n * authManager,\n * });\n *\n * return (\n * <div>\n * <button onClick={() => flow.run('/flows/etl', { source: 'api' })}>\n * Start Pipeline\n * </button>\n * <p>Status: {flow.status}</p>\n * <p>Events: {flow.events.length}</p>\n * {flow.status === 'waiting' && (\n * <button onClick={() => flow.resume({ approved: true })}>\n * Approve\n * </button>\n * )}\n * {flow.output && <pre>{JSON.stringify(flow.output, null, 2)}</pre>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useFlow(react: ReactLike, options: UseFlowOptions): UseFlowReturn {\n const { useState, useEffect, useRef, useCallback } = react;\n\n const [events, setEvents] = useState<FlowExecutionEvent[]>([]);\n const [status, setStatus] = useState<FlowStatus>('idle');\n const [error, setError] = useState<string | null>(null);\n const [output, setOutput] = useState<unknown | null>(null);\n const [instanceId, setInstanceId] = useState<string | null>(null);\n\n const clientRef = useRef<FlowClient | null>(null);\n const abortRef = useRef(false);\n\n // Create the FlowClient once\n useEffect(() => {\n if (options.database) {\n clientRef.current = options.database.flow;\n } else if (options.baseUrl && options.repository && options.authManager) {\n clientRef.current = new FlowClient(\n options.baseUrl,\n options.repository,\n options.authManager,\n options.clientOptions,\n options.flowsApi,\n );\n }\n\n return () => {\n abortRef.current = true;\n clientRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options.database, options.baseUrl, options.repository]);\n\n const run = useCallback(async (flowPath: string, input: Record<string, unknown> = {}) => {\n const client = clientRef.current;\n if (!client) return;\n\n // Reset state\n abortRef.current = false;\n setEvents([]);\n setError(null);\n setOutput(null);\n setStatus('running');\n\n try {\n const result = await client.run(flowPath, input);\n setInstanceId(result.instance_id);\n\n for await (const event of client.streamEvents(result.instance_id)) {\n if (abortRef.current) break;\n\n setEvents((prev) => [...prev, event]);\n\n if (event.type === 'flow_waiting') {\n setStatus('waiting');\n } else if (event.type === 'flow_completed') {\n setOutput(event.output);\n setStatus('completed');\n } else if (event.type === 'flow_failed') {\n setError(event.error);\n setStatus('failed');\n }\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setStatus('failed');\n }\n }, []);\n\n const resume = useCallback(async (data: unknown) => {\n const client = clientRef.current;\n if (!client || !instanceId) return;\n\n setStatus('running');\n setError(null);\n\n try {\n // Open event stream before resuming to avoid missing events\n const stream = await client.createEventStream(instanceId);\n await client.resume(instanceId, data);\n\n for await (const event of stream.events) {\n if (abortRef.current) break;\n\n setEvents((prev) => [...prev, event]);\n\n if (event.type === 'flow_waiting') {\n setStatus('waiting');\n stream.close();\n return;\n } else if (event.type === 'flow_completed') {\n setOutput(event.output);\n setStatus('completed');\n stream.close();\n return;\n } else if (event.type === 'flow_failed') {\n setError(event.error);\n setStatus('failed');\n stream.close();\n return;\n }\n }\n\n stream.close();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setStatus('failed');\n }\n }, [instanceId]);\n\n const reset = useCallback(() => {\n abortRef.current = true;\n setEvents([]);\n setStatus('idle');\n setError(null);\n setOutput(null);\n setInstanceId(null);\n }, []);\n\n return {\n events,\n status,\n isRunning: status === 'running',\n error,\n output,\n instanceId,\n run,\n resume,\n reset,\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseAuthReturn } from './types';\nimport type { IdentityUser } from '../../auth';\n\nexport function createUseAuth(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): () => UseAuthReturn {\n return function useAuth(): UseAuthReturn {\n const { useState, useEffect, useRef, useCallback, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useAuth must be used within a <RaisinProvider>');\n }\n const { client } = ctx;\n\n const [user, setUser] = useState<IdentityUser | null>(client.getStoredUser());\n const [isLoading, setIsLoading] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n\n const unsubAuth = client.onAuthStateChange(({ event, session }) => {\n if (!mountedRef.current) return;\n if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED' || event === 'USER_UPDATED') {\n setUser(session.user);\n } else if (event === 'SIGNED_OUT' || event === 'SESSION_EXPIRED') {\n setUser(null);\n }\n });\n\n const unsubUser = client.onUserChange(({ node }) => {\n if (!mountedRef.current) return;\n // Update user with the latest node properties\n setUser((prev) => {\n if (!prev) return prev;\n return {\n ...prev,\n home: node.path,\n displayName: (node.properties.display_name as string) ?? prev.displayName,\n avatarUrl: (node.properties.avatar_url as string) ?? prev.avatarUrl,\n };\n });\n });\n\n return () => {\n mountedRef.current = false;\n unsubAuth();\n unsubUser();\n };\n }, [client]);\n\n const login = useCallback(async (email: string, password: string, repository: string) => {\n setIsLoading(true);\n try {\n const result = await client.loginWithEmail(email, password, repository);\n return result;\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n const register = useCallback(async (email: string, password: string, repository: string, displayName?: string) => {\n setIsLoading(true);\n try {\n const result = await client.registerWithEmail(email, password, repository, displayName);\n return result;\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n const logout = useCallback(async (options?: { disconnect?: boolean; reconnect?: boolean }) => {\n setIsLoading(true);\n try {\n await client.logout(options);\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n const initSession = useCallback(async (repository: string) => {\n setIsLoading(true);\n try {\n const result = await client.initSession(repository);\n return result;\n } finally {\n if (mountedRef.current) setIsLoading(false);\n }\n }, [client]);\n\n return {\n user,\n isAuthenticated: user !== null,\n isLoading,\n login,\n register,\n logout,\n initSession,\n };\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseConnectionReturn } from './types';\nimport { ConnectionState } from '../../connection';\n\nexport function createUseConnection(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): () => UseConnectionReturn {\n return function useConnection(): UseConnectionReturn {\n const { useState, useEffect, useCallback, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useConnection must be used within a <RaisinProvider>');\n }\n const { client } = ctx;\n\n const [state, setState] = useState<ConnectionState>(client.getConnectionState());\n const [isReady, setIsReady] = useState(client.isReady());\n\n useEffect(() => {\n const unsubConn = client.onConnectionStateChange((newState) => {\n setState(newState);\n });\n\n const unsubReady = client.onReadyStateChange((ready) => {\n setIsReady(ready);\n });\n\n return () => {\n unsubConn();\n unsubReady();\n };\n }, [client]);\n\n const connect = useCallback(async () => {\n await client.connect();\n }, [client]);\n\n const disconnect = useCallback(() => {\n client.disconnect();\n }, [client]);\n\n return {\n state,\n isConnected: state === ConnectionState.Connected,\n isReady,\n connect,\n disconnect,\n };\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseSqlOptions, UseSqlReturn } from './types';\nimport type { SqlResult } from '../../protocol';\n\nfunction rowsToObjects<T>(result: SqlResult): T[] {\n return result.rows as T[];\n}\n\nexport function createUseSql(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): <T = Record<string, unknown>>(sql: string, params?: unknown[], options?: UseSqlOptions) => UseSqlReturn<T> {\n return function useSql<T = Record<string, unknown>>(\n sql: string,\n params?: unknown[],\n options?: UseSqlOptions,\n ): UseSqlReturn<T> {\n const { useState, useEffect, useRef, useCallback, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useSql must be used within a <RaisinProvider>');\n }\n const { client, repository: defaultRepo } = ctx;\n\n const [data, setData] = useState<T[] | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const mountedRef = useRef(true);\n\n const enabled = options?.enabled !== false;\n const repo = options?.repository ?? defaultRepo;\n const refetchOnReconnect = options?.refetchOnReconnect !== false;\n const realtime = options?.realtime;\n\n // Serialize params for dependency comparison\n const paramsKey = params ? JSON.stringify(params) : '';\n\n const fetchData = useCallback(async () => {\n if (!repo) return;\n setIsLoading(true);\n setError(null);\n try {\n const db = client.database(repo);\n const result = await db.executeSql(sql, params);\n if (mountedRef.current) {\n setData(rowsToObjects<T>(result));\n }\n } catch (err) {\n if (mountedRef.current) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n if (mountedRef.current) {\n setIsLoading(false);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, repo, sql, paramsKey]);\n\n // Initial fetch and re-fetch on query/params change\n useEffect(() => {\n mountedRef.current = true;\n if (enabled) {\n fetchData();\n }\n return () => {\n mountedRef.current = false;\n };\n }, [enabled, fetchData]);\n\n // Refetch on reconnect\n useEffect(() => {\n if (!enabled || !refetchOnReconnect) return;\n\n const unsub = client.onReconnected(() => {\n fetchData();\n });\n return unsub;\n }, [client, enabled, refetchOnReconnect, fetchData]);\n\n // Realtime subscription: refetch on matching events\n useEffect(() => {\n if (!enabled || !realtime || !repo) return;\n\n const db = client.database(repo);\n let unsubscribe: (() => Promise<void>) | undefined;\n\n db.events().subscribe(\n {\n workspace: realtime.workspace,\n event_types: realtime.eventTypes,\n path: realtime.path,\n node_type: realtime.nodeType,\n },\n () => {\n fetchData();\n },\n ).then((sub) => {\n unsubscribe = () => sub.unsubscribe();\n });\n\n return () => {\n unsubscribe?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, enabled, repo, realtime?.workspace, realtime?.path, realtime?.nodeType, fetchData]);\n\n return {\n data,\n isLoading,\n error,\n refetch: fetchData,\n };\n };\n}\n","import type { ReactLikeWithContext, ReactContext, RaisinContextValue, UseSubscriptionOptions } from './types';\nimport type { EventMessage } from '../../protocol';\n\nexport function createUseSubscription(\n react: ReactLikeWithContext,\n context: ReactContext<RaisinContextValue | null>,\n): (options: UseSubscriptionOptions, callback: (event: EventMessage) => void) => void {\n return function useSubscription(\n options: UseSubscriptionOptions,\n callback: (event: EventMessage) => void,\n ): void {\n const { useEffect, useRef, useContext } = react;\n\n const ctx = useContext(context);\n if (!ctx) {\n throw new Error('useSubscription must be used within a <RaisinProvider>');\n }\n const { client, repository } = ctx;\n\n // callbackRef pattern: avoid re-subscribing when callback identity changes\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n const enabled = options.enabled !== false;\n\n useEffect(() => {\n if (!enabled || !repository || !options.workspace) return;\n\n const db = client.database(repository);\n let unsubscribe: (() => Promise<void>) | undefined;\n let cancelled = false;\n\n db.events().subscribe(\n {\n workspace: options.workspace,\n event_types: options.event_types,\n path: options.path,\n node_type: options.node_type,\n include_node: options.include_node,\n },\n (event) => {\n if (!cancelled) {\n callbackRef.current(event);\n }\n },\n ).then((sub) => {\n if (cancelled) {\n sub.unsubscribe();\n } else {\n unsubscribe = () => sub.unsubscribe();\n }\n });\n\n return () => {\n cancelled = true;\n unsubscribe?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, repository, enabled, options.workspace, options.path, options.node_type, options.include_node]);\n };\n}\n","/**\n * React integration layer for RaisinDB.\n *\n * Provides a `createRaisinReact(React)` factory that returns a Provider\n * component and hooks for auth, connection, queries, and subscriptions.\n *\n * Uses the \"bring your own React\" pattern to avoid a peer dependency.\n *\n * @example\n * ```ts\n * import React from 'react';\n * import { RaisinClient, LocalStorageTokenStorage, createRaisinReact } from '@raisindb/client';\n *\n * const client = new RaisinClient('wss://localhost:8443/sys/default/myrepo', {\n * tokenStorage: new LocalStorageTokenStorage('myrepo'),\n * });\n *\n * export const {\n * RaisinProvider, useAuth, useConnection, useDatabase,\n * useSql, useSubscription, useConversation, useFlow,\n * } = createRaisinReact(React);\n * ```\n */\n\nimport type {\n ReactLikeWithContext,\n RaisinProviderProps,\n RaisinContextValue,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlOptions,\n UseSqlReturn,\n UseSubscriptionOptions,\n} from './types';\n\nimport type { RaisinClient } from '../../client';\nimport type { Database } from '../../database';\nimport type { EventMessage } from '../../protocol';\nimport type {\n ConversationStoreOptions,\n} from '../../stores/conversation-store';\nimport type { ConversationListStoreOptions } from '../../stores/conversation-list-store';\n\nimport { createUseAuth } from './use-auth';\nimport { createUseConnection } from './use-connection';\nimport { createUseSql } from './use-sql';\nimport { createUseSubscription } from './use-subscription';\n\nimport {\n useConversation as rawUseConversation,\n useConversationList as rawUseConversationList,\n type UseConversationReturn,\n type UseConversationListReturn,\n} from '../react-conversation';\nimport {\n useFlow as rawUseFlow,\n type UseFlowOptions,\n type UseFlowReturn,\n} from '../react-flow';\n\nexport interface RaisinReact {\n RaisinProvider: (props: RaisinProviderProps) => any;\n useRaisinClient: () => RaisinClient;\n useDatabase: (repository?: string) => Database;\n useAuth: () => UseAuthReturn;\n useConnection: () => UseConnectionReturn;\n useSql: <T = Record<string, unknown>>(sql: string, params?: unknown[], options?: UseSqlOptions) => UseSqlReturn<T>;\n useSubscription: (options: UseSubscriptionOptions, callback: (event: EventMessage) => void) => void;\n useConversation: (options: ConversationStoreOptions) => UseConversationReturn;\n useConversationList: (options: ConversationListStoreOptions) => UseConversationListReturn;\n useFlow: (options: UseFlowOptions) => UseFlowReturn;\n}\n\n/**\n * Create the full React integration for RaisinDB.\n *\n * Accepts a React instance and returns a Provider component plus hooks.\n * The React instance must include `createContext`, `useContext`, `useMemo`,\n * and `createElement` in addition to the base `ReactLike` interface.\n *\n * @param react - The React instance\n * @returns Provider component and hooks\n */\nexport function createRaisinReact(react: ReactLikeWithContext): RaisinReact {\n const RaisinContext = react.createContext<RaisinContextValue | null>(null);\n\n // --- Provider ---\n function RaisinProvider(props: RaisinProviderProps): any {\n const { client, repository, children } = props;\n\n const value = react.useMemo(\n () => ({ client, repository }),\n [client, repository],\n );\n\n return react.createElement(\n RaisinContext.Provider as unknown,\n { value },\n children,\n );\n }\n\n // --- Context accessors ---\n function useRaisinClient(): RaisinClient {\n const ctx = react.useContext(RaisinContext);\n if (!ctx) {\n throw new Error('useRaisinClient must be used within a <RaisinProvider>');\n }\n return ctx.client;\n }\n\n function useDatabase(repository?: string): Database {\n const ctx = react.useContext(RaisinContext);\n if (!ctx) {\n throw new Error('useDatabase must be used within a <RaisinProvider>');\n }\n const repo = repository ?? ctx.repository;\n if (!repo) {\n throw new Error('useDatabase requires a repository — pass it as an argument or set it on <RaisinProvider>');\n }\n return react.useMemo(() => ctx.client.database(repo), [ctx.client, repo]);\n }\n\n // --- Core hooks ---\n const useAuth = createUseAuth(react, RaisinContext);\n const useConnection = createUseConnection(react, RaisinContext);\n const useSql = createUseSql(react, RaisinContext);\n const useSubscription = createUseSubscription(react, RaisinContext);\n\n // --- Pre-bound existing hooks ---\n function useConversation(options: ConversationStoreOptions): UseConversationReturn {\n return rawUseConversation(react, options);\n }\n\n function useConversationList(options: ConversationListStoreOptions): UseConversationListReturn {\n return rawUseConversationList(react, options);\n }\n\n function useFlow(options: UseFlowOptions): UseFlowReturn {\n return rawUseFlow(react, options);\n }\n\n return {\n RaisinProvider,\n useRaisinClient,\n useDatabase,\n useAuth,\n useConnection,\n useSql,\n useSubscription,\n useConversation,\n useConversationList,\n useFlow,\n };\n}\n\n// Re-export types\nexport type {\n ReactLikeWithContext,\n RaisinProviderProps,\n RaisinContextValue,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlOptions,\n UseSqlReturn,\n UseSubscriptionOptions,\n} from './types';\n\n// Hook return/option types (parity with the @raisindb/client/vue subpath):\n// apps need these to type props that carry a hook's return value around.\nexport type {\n ReactLike,\n UseConversationReturn,\n UseConversationListReturn,\n} from '../react-conversation';\nexport type { UseFlowOptions, UseFlowReturn, FlowStatus } from '../react-flow';\nexport type {\n ConversationStoreOptions,\n ConversationStoreSnapshot,\n ToolCallInfo,\n} from '../../stores/conversation-store';\nexport type {\n ConversationListStoreOptions,\n ConversationListSnapshot,\n} from '../../stores/conversation-list-store';\nexport type { PlanProjection, PlanProjectionTask } from '../../utils/plan-projection';\nexport type { ChatMessage, ConversationListItem } from '../../types/chat';\n","import type { VueLike, VueRef, UseAuthReturn } from './types';\nimport type { RaisinClient } from '../../client';\n// Framework-free snapshot adapter shared with the Svelte integration.\nimport { createAuthAdapter, type AuthSnapshot } from '../svelte/svelte-auth';\n\nexport function createUseAuth(vue: VueLike): (client: RaisinClient) => UseAuthReturn {\n return function useAuth(client: RaisinClient): UseAuthReturn {\n const adapter = createAuthAdapter(client);\n const snapshot = vue.ref(adapter.getSnapshot()) as VueRef<AuthSnapshot>;\n const unsubscribe = adapter.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n adapter.destroy();\n });\n\n return {\n user: vue.computed(() => snapshot.value.user),\n isAuthenticated: vue.computed(() => snapshot.value.isAuthenticated),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n login: adapter.login,\n register: adapter.register,\n logout: adapter.logout,\n initSession: adapter.initSession,\n };\n };\n}\n","import type { VueLike, VueRef, UseConnectionReturn } from './types';\nimport type { RaisinClient } from '../../client';\n// Framework-free snapshot adapter shared with the Svelte integration.\nimport { createConnectionAdapter, type ConnectionSnapshot } from '../svelte/svelte-connection';\n\nexport function createUseConnection(vue: VueLike): (client: RaisinClient) => UseConnectionReturn {\n return function useConnection(client: RaisinClient): UseConnectionReturn {\n const adapter = createConnectionAdapter(client);\n const snapshot = vue.ref(adapter.getSnapshot()) as VueRef<ConnectionSnapshot>;\n const unsubscribe = adapter.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n adapter.destroy();\n });\n\n return {\n state: vue.computed(() => snapshot.value.state),\n isConnected: vue.computed(() => snapshot.value.isConnected),\n isReady: vue.computed(() => snapshot.value.isReady),\n connect: adapter.connect,\n disconnect: adapter.disconnect,\n };\n };\n}\n","import type { VueLike, VueRef, UseSqlReturn } from './types';\nimport type { Database } from '../../database';\n// Framework-free snapshot adapter shared with the Svelte integration.\nimport {\n createSqlAdapter,\n type SqlAdapterOptions,\n type SqlSnapshot,\n} from '../svelte/svelte-sql';\n\nexport function createUseSql(\n vue: VueLike,\n): <T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n) => UseSqlReturn<T> {\n return function useSql<T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n ): UseSqlReturn<T> {\n const adapter = createSqlAdapter<T>(database, sql, params, options);\n const snapshot = vue.ref(adapter.getSnapshot()) as VueRef<SqlSnapshot<T>>;\n const unsubscribe = adapter.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n adapter.destroy();\n });\n\n return {\n data: vue.computed(() => snapshot.value.data),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n error: vue.computed(() => snapshot.value.error),\n refetch: adapter.refetch,\n };\n };\n}\n","import type { VueLike, UseSubscriptionReturn } from './types';\nimport type { Database } from '../../database';\nimport type { EventMessage, SubscriptionFilters } from '../../protocol';\n// Framework-free side-effect adapter shared with the Svelte integration.\nimport { createSubscriptionAdapter } from '../svelte/svelte-subscription';\n\nexport function createUseSubscription(\n vue: VueLike,\n): (\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n) => UseSubscriptionReturn {\n return function useSubscription(\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n ): UseSubscriptionReturn {\n const adapter = createSubscriptionAdapter(database, filters, callback);\n\n // Automatic cleanup when the component unmounts.\n vue.onUnmounted(() => adapter.destroy());\n\n return {\n unsubscribe: () => adapter.destroy(),\n };\n };\n}\n","import type {\n VueLike,\n VueRef,\n UseConversationReturn,\n UseConversationListReturn,\n} from './types';\nimport {\n ConversationStore,\n type ConversationStoreOptions,\n type ConversationStoreSnapshot,\n} from '../../stores/conversation-store';\nimport {\n ConversationListStore,\n type ConversationListStoreOptions,\n type ConversationListSnapshot,\n} from '../../stores/conversation-list-store';\nimport { logger } from '../../logger';\n\nexport function createUseConversation(\n vue: VueLike,\n): (options: ConversationStoreOptions) => UseConversationReturn {\n return function useConversation(options: ConversationStoreOptions): UseConversationReturn {\n const store = new ConversationStore(options);\n const snapshot = vue.ref(store.getSnapshot()) as VueRef<ConversationStoreSnapshot>;\n const unsubscribe = store.subscribe((s) => { snapshot.value = s; });\n\n vue.onUnmounted(() => {\n unsubscribe();\n store.destroy();\n });\n\n return {\n conversation: vue.computed(() => snapshot.value.conversation),\n messages: vue.computed(() => snapshot.value.messages),\n isStreaming: vue.computed(() => snapshot.value.isStreaming),\n isWaiting: vue.computed(() => snapshot.value.isWaiting),\n streamingText: vue.computed(() => snapshot.value.streamingText),\n error: vue.computed(() => snapshot.value.error),\n activeToolCalls: vue.computed(() => snapshot.value.activeToolCalls),\n plans: vue.computed(() => snapshot.value.plans),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n conversationPath: vue.computed(() => snapshot.value.conversationPath),\n sendMessage: (content: string) => store.sendMessage(content),\n approvePlan: async (planPath: string) => { await store.approvePlan(planPath); },\n rejectPlan: async (planPath: string, feedback?: string) => { await store.rejectPlan(planPath, feedback); },\n stop: () => store.stop(),\n loadMessages: () => store.loadMessages(),\n store,\n };\n };\n}\n\nexport function createUseConversationList(\n vue: VueLike,\n): (options: ConversationListStoreOptions) => UseConversationListReturn {\n return function useConversationList(options: ConversationListStoreOptions): UseConversationListReturn {\n const store = new ConversationListStore(options);\n const snapshot = vue.ref(store.getSnapshot()) as VueRef<ConversationListSnapshot>;\n const unsubscribe = store.subscribe((s) => { snapshot.value = s; });\n\n // Initial load (same behavior as the React useConversationList hook).\n store.load().catch((err) => {\n logger.error('[useConversationList] Initial load failed:', err);\n });\n\n vue.onUnmounted(() => {\n unsubscribe();\n store.destroy();\n });\n\n return {\n conversations: vue.computed(() => snapshot.value.conversations),\n totalUnreadCount: vue.computed(() => snapshot.value.totalUnreadCount),\n isLoading: vue.computed(() => snapshot.value.isLoading),\n error: vue.computed(() => snapshot.value.error),\n createConversation: (opts) => store.createConversation(opts),\n deleteConversation: (conversationPath: string) => store.deleteConversation(conversationPath),\n markAsRead: (conversationPath: string) => store.markAsRead(conversationPath),\n refresh: () => store.load(),\n store,\n };\n };\n}\n","/**\n * Vue 3 integration layer for RaisinDB.\n *\n * Provides a `createRaisinVue(vue)` factory that returns composables for\n * auth, connection, SQL queries, node-event subscriptions, and the\n * conversation stores.\n *\n * Uses the same \"bring your own framework\" pattern as the React integration\n * (`createRaisinReact(React)`): the SDK never imports `vue`, so Vue stays\n * out of the SDK's dependency graph and the main `.` bundle. You pass the\n * Vue module (its `ref`, `computed`, and `onUnmounted` are all that is\n * needed) once at setup time.\n *\n * Each composable creates its underlying store/adapter when called and\n * destroys it automatically in `onUnmounted`, so call them from\n * `setup()` / `<script setup>`.\n *\n * @example\n * ```ts\n * // lib/raisin-vue.ts\n * import * as vue from 'vue';\n * import { RaisinClient, LocalStorageTokenStorage } from '@raisindb/client';\n * import { createRaisinVue } from '@raisindb/client/vue';\n *\n * export const client = new RaisinClient('ws://localhost:8081/sys/default/myrepo', {\n * tokenStorage: new LocalStorageTokenStorage('myapp'),\n * });\n * export const db = client.database('myrepo');\n *\n * export const {\n * useAuth, useConnection, useSql, useSubscription,\n * useConversation, useConversationList,\n * } = createRaisinVue(vue);\n * ```\n *\n * @example In a component:\n * ```vue\n * <script setup lang=\"ts\">\n * import { client, db, useConversation } from '@/lib/raisin-vue';\n *\n * const chat = useConversation({\n * database: db,\n * createOptions: { participant: '/agents/support' },\n * });\n * </script>\n *\n * <template>\n * <div v-for=\"(m, i) in chat.messages.value\" :key=\"i\">{{ m.content }}</div>\n * <p v-if=\"chat.isStreaming.value\">{{ chat.streamingText.value }}</p>\n * </template>\n * ```\n */\n\nimport type {\n VueLike,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlReturn,\n UseSubscriptionReturn,\n UseConversationReturn,\n UseConversationListReturn,\n} from './types';\nimport type { RaisinClient } from '../../client';\nimport type { Database } from '../../database';\nimport type { EventMessage, SubscriptionFilters } from '../../protocol';\nimport type { ConversationStoreOptions } from '../../stores/conversation-store';\nimport type { ConversationListStoreOptions } from '../../stores/conversation-list-store';\nimport type { SqlAdapterOptions } from '../svelte/svelte-sql';\n\nimport { createUseAuth } from './vue-auth';\nimport { createUseConnection } from './vue-connection';\nimport { createUseSql } from './vue-sql';\nimport { createUseSubscription } from './vue-subscription';\nimport { createUseConversation, createUseConversationList } from './vue-conversation';\n\nexport interface RaisinVue {\n /** Reactive auth state + login/register/logout/initSession actions */\n useAuth: (client: RaisinClient) => UseAuthReturn;\n /** Reactive connection state (state / isConnected / isReady) */\n useConnection: (client: RaisinClient) => UseConnectionReturn;\n /** Run a SQL query with reactive data/isLoading/error + optional realtime refetch */\n useSql: <T = Record<string, unknown>>(\n database: Database,\n sql: string,\n params?: unknown[],\n options?: SqlAdapterOptions,\n ) => UseSqlReturn<T>;\n /** Subscribe to node events; unsubscribes automatically on unmount */\n useSubscription: (\n database: Database,\n filters: SubscriptionFilters,\n callback: (event: EventMessage) => void,\n ) => UseSubscriptionReturn;\n /** Bind a ConversationStore (chat: messages, streaming, tool calls, plans) */\n useConversation: (options: ConversationStoreOptions) => UseConversationReturn;\n /** Bind a ConversationListStore (inbox-style conversation list) */\n useConversationList: (options: ConversationListStoreOptions) => UseConversationListReturn;\n}\n\n/**\n * Create the full Vue 3 integration for RaisinDB.\n *\n * @param vue - The Vue module (or any object providing `ref`, `computed`, `onUnmounted`)\n * @returns The set of composables\n */\nexport function createRaisinVue(vue: VueLike): RaisinVue {\n return {\n useAuth: createUseAuth(vue),\n useConnection: createUseConnection(vue),\n useSql: createUseSql(vue),\n useSubscription: createUseSubscription(vue),\n useConversation: createUseConversation(vue),\n useConversationList: createUseConversationList(vue),\n };\n}\n\n// Re-export types\nexport type {\n VueLike,\n VueRef,\n VueComputedRef,\n UseAuthReturn,\n UseConnectionReturn,\n UseSqlReturn,\n UseSubscriptionReturn,\n UseConversationReturn,\n UseConversationListReturn,\n} from './types';\nexport type { SqlAdapterOptions as UseSqlOptions } from '../svelte/svelte-sql';\n"],"mappings":"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","names":["import_events","LogLevel","ConnectionState","uuidv4","RequestType","ResponseStatus","payload","payload","scheduled","conversationId","import_events","UploadErrorCode","config","config","config","currentToken","config","config","rowsToObjects","rowsToObjects","useConversation","useConversationList","useFlow","createUseAuth","createUseConnection","createUseSql","createUseSubscription","useConversation","useConversationList","createUseAuth","createUseConnection","createUseSql","createUseSubscription"]}