monorise 1.1.0-dev.1 → 1.1.0-dev.3

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.
Files changed (77) hide show
  1. package/dist/base/index.d.ts +53 -1
  2. package/dist/base/index.js +49 -1
  3. package/dist/base/index.js.map +1 -1
  4. package/dist/core/index.d.ts +3 -53
  5. package/dist/core/index.js +1 -1
  6. package/dist/core/index.js.map +1 -1
  7. package/dist/react/{chunk-DTRWUIDH.js → chunk-BIXAYYE4.js} +35 -5
  8. package/dist/react/{chunk-DTRWUIDH.js.map → chunk-BIXAYYE4.js.map} +1 -1
  9. package/dist/react/index.d.ts +1 -1
  10. package/dist/react/index.js +143 -10403
  11. package/dist/react/index.js.map +1 -1
  12. package/dist/react/websocket-7MZ3ENOC.js +9 -0
  13. package/package.json +2 -2
  14. package/dist/react/chunk-2QOYO3GF.js +0 -182
  15. package/dist/react/chunk-2QOYO3GF.js.map +0 -1
  16. package/dist/react/chunk-4WSYM746.js +0 -383
  17. package/dist/react/chunk-4WSYM746.js.map +0 -1
  18. package/dist/react/chunk-5XIRNUBL.js +0 -43
  19. package/dist/react/chunk-5XIRNUBL.js.map +0 -1
  20. package/dist/react/chunk-7JDOKZGQ.js +0 -172
  21. package/dist/react/chunk-7JDOKZGQ.js.map +0 -1
  22. package/dist/react/chunk-A5TI2FW3.js +0 -13
  23. package/dist/react/chunk-A5TI2FW3.js.map +0 -1
  24. package/dist/react/chunk-BJXCFDMF.js +0 -15
  25. package/dist/react/chunk-BJXCFDMF.js.map +0 -1
  26. package/dist/react/chunk-BUTF5RJU.js +0 -29
  27. package/dist/react/chunk-BUTF5RJU.js.map +0 -1
  28. package/dist/react/chunk-GFVCNWVT.js +0 -54
  29. package/dist/react/chunk-GFVCNWVT.js.map +0 -1
  30. package/dist/react/chunk-JT5EZZSL.js +0 -489
  31. package/dist/react/chunk-JT5EZZSL.js.map +0 -1
  32. package/dist/react/chunk-KJX5LOMN.js +0 -43
  33. package/dist/react/chunk-KJX5LOMN.js.map +0 -1
  34. package/dist/react/chunk-KLXK4V6G.js +0 -65
  35. package/dist/react/chunk-KLXK4V6G.js.map +0 -1
  36. package/dist/react/chunk-LJLMKEKI.js +0 -245
  37. package/dist/react/chunk-LJLMKEKI.js.map +0 -1
  38. package/dist/react/chunk-MIXAYX55.js +0 -147
  39. package/dist/react/chunk-RPNCWADG.js +0 -248
  40. package/dist/react/chunk-RPNCWADG.js.map +0 -1
  41. package/dist/react/chunk-S6RDMHHH.js +0 -47
  42. package/dist/react/chunk-S6RDMHHH.js.map +0 -1
  43. package/dist/react/chunk-U6RIOMF4.js +0 -893
  44. package/dist/react/chunk-U6RIOMF4.js.map +0 -1
  45. package/dist/react/chunk-WCRLJFBW.js +0 -5568
  46. package/dist/react/chunk-WCRLJFBW.js.map +0 -1
  47. package/dist/react/chunk-YF6S7S36.js +0 -588
  48. package/dist/react/chunk-YF6S7S36.js.map +0 -1
  49. package/dist/react/dist-es-5WYA7CWK.js +0 -379
  50. package/dist/react/dist-es-5WYA7CWK.js.map +0 -1
  51. package/dist/react/dist-es-CR5AOOCO.js +0 -333
  52. package/dist/react/dist-es-CR5AOOCO.js.map +0 -1
  53. package/dist/react/dist-es-KZ3GLAJI.js +0 -494
  54. package/dist/react/dist-es-KZ3GLAJI.js.map +0 -1
  55. package/dist/react/dist-es-R4TRTT45.js +0 -22
  56. package/dist/react/dist-es-R4TRTT45.js.map +0 -1
  57. package/dist/react/dist-es-SKDPAJEW.js +0 -169
  58. package/dist/react/dist-es-SKDPAJEW.js.map +0 -1
  59. package/dist/react/dist-es-TOHBZNTZ.js +0 -71
  60. package/dist/react/dist-es-TOHBZNTZ.js.map +0 -1
  61. package/dist/react/dist-es-XNAC47MK.js +0 -90
  62. package/dist/react/dist-es-XNAC47MK.js.map +0 -1
  63. package/dist/react/event-streams-WAZW4P3K.js +0 -277
  64. package/dist/react/event-streams-WAZW4P3K.js.map +0 -1
  65. package/dist/react/loadSso-KXVD6CBM.js +0 -556
  66. package/dist/react/loadSso-KXVD6CBM.js.map +0 -1
  67. package/dist/react/service.config-I7RKP6FE.js +0 -14
  68. package/dist/react/service.config-I7RKP6FE.js.map +0 -1
  69. package/dist/react/signin-SEY3FDQ5.js +0 -653
  70. package/dist/react/signin-SEY3FDQ5.js.map +0 -1
  71. package/dist/react/sso-oidc-REODVHH5.js +0 -786
  72. package/dist/react/sso-oidc-REODVHH5.js.map +0 -1
  73. package/dist/react/sts-I3M4QP37.js +0 -3948
  74. package/dist/react/sts-I3M4QP37.js.map +0 -1
  75. package/dist/react/websocket-OSLLJSNO.js +0 -10
  76. package/dist/react/websocket-OSLLJSNO.js.map +0 -1
  77. /package/dist/react/{chunk-MIXAYX55.js.map → websocket-7MZ3ENOC.js.map} +0 -0
@@ -1,7 +1,34 @@
1
- import {
2
- __spreadProps,
3
- __spreadValues
4
- } from "./chunk-MIXAYX55.js";
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
5
32
 
6
33
  // websocket/WebSocketManager.ts
7
34
  import { nanoid } from "nanoid";
@@ -396,7 +423,10 @@ var OptimisticEngine = class {
396
423
  };
397
424
 
398
425
  export {
426
+ __spreadValues,
427
+ __spreadProps,
428
+ __objRest,
399
429
  WebSocketManager,
400
430
  OptimisticEngine
401
431
  };
402
- //# sourceMappingURL=chunk-DTRWUIDH.js.map
432
+ //# sourceMappingURL=chunk-BIXAYYE4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../websocket/WebSocketManager.ts","../websocket/optimistic.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\n\nexport type ConnectionState =\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'disconnected';\n\nexport interface ClientMessage {\n action: 'subscribe' | 'unsubscribe' | 'ephemeral' | 'ping';\n id: string;\n payload: {\n // Entity subscription: subscribe to all changes of this entity type\n entityType?: string;\n // Mutual subscription: subscribe to all mutuals of this type for a byEntity\n byEntityType?: string;\n byEntityId?: string;\n mutualEntityType?: string;\n // Ephemeral channel\n channel?: string;\n // Ephemeral message data\n data?: unknown;\n };\n}\n\nexport interface ServerMessage {\n type:\n | 'entity.created'\n | 'entity.updated'\n | 'entity.deleted'\n | 'mutual.created'\n | 'mutual.updated'\n | 'mutual.deleted'\n | 'ephemeral'\n | 'ack'\n | 'error'\n | 'pong';\n id: string;\n payload: unknown;\n}\n\ntype MessageHandler = (message: ServerMessage) => void;\ntype ConnectionStateHandler = (state: ConnectionState) => void;\n\n// Entity type subscription: listen to ALL changes of this entity type\ninterface EntityTypeSubscription {\n entityType: string;\n}\n\n// Mutual type subscription: listen to ALL mutuals of this type for a byEntity\ninterface MutualTypeSubscription {\n byEntityType: string;\n byEntityId: string;\n mutualEntityType: string;\n}\n\n// Ephemeral channel subscription: listen to ephemeral messages on this channel\ninterface EphemeralSubscription {\n channel: string;\n}\n\nexport class WebSocketManager {\n private ws: WebSocket | null = null;\n private url: string;\n private token: string;\n private state: ConnectionState = 'disconnected';\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 10;\n private reconnectDelay = 1000;\n private maxReconnectDelay = 30000;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n private heartbeatTimeout: NodeJS.Timeout | null = null;\n private readonly heartbeatIntervalMs = 30000;\n private readonly heartbeatTimeoutMs = 10000;\n\n private messageHandlers: Set<MessageHandler> = new Set();\n private stateHandlers: Set<ConnectionStateHandler> = new Set();\n private entitySubscriptions: Map<string, EntityTypeSubscription> = new Map();\n private mutualSubscriptions: Map<string, MutualTypeSubscription> = new Map();\n private ephemeralSubscriptions: Map<string, EphemeralSubscription> = new Map();\n private pendingMessages: ClientMessage[] = [];\n\n public disableAutoReconnect = false;\n\n constructor(url: string, token: string) {\n this.url = url;\n this.token = token;\n }\n\n connect(): void {\n if (this.ws?.readyState === WebSocket.OPEN) return;\n\n this.setState('connecting');\n\n try {\n const connectUrl = this.token\n ? `${this.url}?token=${encodeURIComponent(this.token)}`\n : this.url;\n this.ws = new WebSocket(connectUrl);\n\n this.ws.onopen = this.handleOpen.bind(this);\n this.ws.onclose = this.handleClose.bind(this);\n this.ws.onerror = this.handleError.bind(this);\n this.ws.onmessage = this.handleMessage.bind(this);\n } catch (error) {\n console.error('WebSocket connection error:', error);\n this.scheduleReconnect();\n }\n }\n\n disconnect(): void {\n this.stopHeartbeat();\n this.reconnectAttempts = 0;\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.setState('disconnected');\n }\n\n // Subscribe to ALL changes of an entity type\n subscribeEntityType(entityType: string): string {\n const subKey = `entity:${entityType}`;\n\n if (!this.entitySubscriptions.has(subKey)) {\n this.entitySubscriptions.set(subKey, { entityType });\n }\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { entityType },\n };\n this.send(message);\n }\n\n return subKey;\n }\n\n unsubscribeEntityType(subKey: string): void {\n const subscription = this.entitySubscriptions.get(subKey);\n if (!subscription) return;\n\n this.entitySubscriptions.delete(subKey);\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'unsubscribe',\n id: nanoid(),\n payload: { entityType: subscription.entityType },\n };\n this.send(message);\n }\n }\n\n // Subscribe to ALL mutuals of a type for a specific byEntity\n subscribeMutualType(\n byEntityType: string,\n byEntityId: string,\n mutualEntityType: string,\n ): string {\n const subKey = `mutual:${byEntityType}:${byEntityId}:${mutualEntityType}`;\n\n if (!this.mutualSubscriptions.has(subKey)) {\n this.mutualSubscriptions.set(subKey, {\n byEntityType,\n byEntityId,\n mutualEntityType,\n });\n }\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { byEntityType, byEntityId, mutualEntityType },\n };\n this.send(message);\n }\n\n return subKey;\n }\n\n unsubscribeMutualType(subKey: string): void {\n const subscription = this.mutualSubscriptions.get(subKey);\n if (!subscription) return;\n\n this.mutualSubscriptions.delete(subKey);\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'unsubscribe',\n id: nanoid(),\n payload: {\n byEntityType: subscription.byEntityType,\n byEntityId: subscription.byEntityId,\n mutualEntityType: subscription.mutualEntityType,\n },\n };\n this.send(message);\n }\n }\n\n // Subscribe to ephemeral messages on a channel\n subscribeEphemeral(channel: string): string {\n const subKey = `ephemeral:${channel}`;\n\n if (!this.ephemeralSubscriptions.has(subKey)) {\n this.ephemeralSubscriptions.set(subKey, { channel });\n }\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { channel },\n };\n this.send(message);\n }\n\n return subKey;\n }\n\n unsubscribeEphemeral(subKey: string): void {\n const subscription = this.ephemeralSubscriptions.get(subKey);\n if (!subscription) return;\n\n this.ephemeralSubscriptions.delete(subKey);\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'unsubscribe',\n id: nanoid(),\n payload: { channel: subscription.channel },\n };\n this.send(message);\n }\n }\n\n // Send an ephemeral message to a channel\n sendEphemeral(channel: string, data: unknown): void {\n const message: ClientMessage = {\n action: 'ephemeral',\n id: nanoid(),\n payload: { channel, data },\n };\n this.send(message);\n }\n\n send(message: ClientMessage): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(message));\n } else {\n this.pendingMessages.push(message);\n }\n }\n\n onMessage(handler: MessageHandler): () => void {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n onStateChange(handler: ConnectionStateHandler): () => void {\n this.stateHandlers.add(handler);\n handler(this.state);\n return () => this.stateHandlers.delete(handler);\n }\n\n getState(): ConnectionState {\n return this.state;\n }\n\n private setState(newState: ConnectionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.stateHandlers.forEach((handler) => handler(newState));\n }\n }\n\n private handleOpen(): void {\n this.setState('connected');\n this.reconnectAttempts = 0;\n this.reconnectDelay = 1000;\n\n this.startHeartbeat();\n this.resubscribeAll();\n this.flushPendingMessages();\n }\n\n private handleClose(event: CloseEvent): void {\n this.stopHeartbeat();\n this.ws = null;\n\n if (this.disableAutoReconnect) {\n this.setState('disconnected');\n return;\n }\n\n if (this.reconnectAttempts < this.maxReconnectAttempts) {\n this.setState('reconnecting');\n this.scheduleReconnect();\n } else {\n this.setState('disconnected');\n }\n }\n\n private handleError(error: Event): void {\n console.error('WebSocket error:', error);\n }\n\n private handleMessage(event: MessageEvent): void {\n try {\n const message = JSON.parse(event.data) as ServerMessage;\n\n if (message.type === 'pong') {\n this.handlePong();\n return;\n }\n\n this.messageHandlers.forEach((handler) => handler(message));\n } catch (error) {\n console.error('Failed to parse WebSocket message:', error);\n }\n }\n\n private scheduleReconnect(): void {\n setTimeout(() => {\n this.reconnectAttempts++;\n this.reconnectDelay = Math.min(\n this.reconnectDelay * 2,\n this.maxReconnectDelay,\n );\n this.connect();\n }, this.reconnectDelay);\n }\n\n private resubscribeAll(): void {\n // Re-subscribe entity types\n for (const { entityType } of this.entitySubscriptions.values()) {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { entityType },\n };\n this.send(message);\n }\n\n // Re-subscribe mutual types\n for (const {\n byEntityType,\n byEntityId,\n mutualEntityType,\n } of this.mutualSubscriptions.values()) {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { byEntityType, byEntityId, mutualEntityType },\n };\n this.send(message);\n }\n\n // Re-subscribe ephemeral channels\n for (const { channel } of this.ephemeralSubscriptions.values()) {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { channel },\n };\n this.send(message);\n }\n }\n\n private flushPendingMessages(): void {\n while (this.pendingMessages.length > 0) {\n const message = this.pendingMessages.shift();\n if (message) {\n this.send(message);\n }\n }\n }\n\n private startHeartbeat(): void {\n this.heartbeatInterval = setInterval(() => {\n const pingMessage: ClientMessage = {\n action: 'ping',\n id: nanoid(),\n payload: {},\n };\n this.send(pingMessage);\n\n this.heartbeatTimeout = setTimeout(() => {\n this.ws?.close();\n }, this.heartbeatTimeoutMs);\n }, this.heartbeatIntervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = null;\n }\n }\n\n private handlePong(): void {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = null;\n }\n }\n}\n","import { nanoid } from 'nanoid';\n\nexport interface OptimisticOperation {\n id: string;\n type: 'create' | 'update' | 'delete';\n entityType: string;\n entityId: string;\n previousData?: unknown;\n optimisticData: unknown;\n timestamp: number;\n}\n\nexport class OptimisticEngine {\n private operations: Map<string, OptimisticOperation> = new Map();\n private onRollback?: (operation: OptimisticOperation) => void;\n private onConfirm?: (operation: OptimisticOperation) => void;\n\n constructor(options?: {\n onRollback?: (operation: OptimisticOperation) => void;\n onConfirm?: (operation: OptimisticOperation) => void;\n }) {\n this.onRollback = options?.onRollback;\n this.onConfirm = options?.onConfirm;\n }\n\n /**\n * Register an optimistic operation\n */\n register(operation: Omit<OptimisticOperation, 'id' | 'timestamp'>): string {\n const id = nanoid();\n const fullOperation: OptimisticOperation = {\n ...operation,\n id,\n timestamp: Date.now(),\n };\n\n this.operations.set(id, fullOperation);\n return id;\n }\n\n /**\n * Confirm an operation (server acknowledged)\n */\n confirm(mutationId: string): void {\n const operation = this.operations.get(mutationId);\n if (operation) {\n this.operations.delete(mutationId);\n this.onConfirm?.(operation);\n }\n }\n\n /**\n * Rollback an operation (server rejected or failed)\n */\n rollback(mutationId: string): OptimisticOperation | undefined {\n const operation = this.operations.get(mutationId);\n if (operation) {\n this.operations.delete(mutationId);\n this.onRollback?.(operation);\n return operation;\n }\n return undefined;\n }\n\n /**\n * Check if an entity has pending optimistic operations\n */\n hasPendingOperation(entityType: string, entityId: string): boolean {\n for (const op of this.operations.values()) {\n if (op.entityType === entityType && op.entityId === entityId) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get pending operation for an entity\n */\n getPendingOperation(\n entityType: string,\n entityId: string,\n ): OptimisticOperation | undefined {\n for (const op of this.operations.values()) {\n if (op.entityType === entityType && op.entityId === entityId) {\n return op;\n }\n }\n return undefined;\n }\n\n /**\n * Clear all operations (e.g., on disconnect)\n */\n clear(): OptimisticOperation[] {\n const allOperations = Array.from(this.operations.values());\n this.operations.clear();\n return allOperations;\n }\n\n /**\n * Get all pending operations\n */\n getAllPending(): OptimisticOperation[] {\n return Array.from(this.operations.values());\n }\n\n /**\n * Clean up old operations (older than specified ms)\n */\n cleanup(maxAgeMs: number = 5 * 60 * 1000): number {\n const now = Date.now();\n let cleaned = 0;\n\n for (const [id, operation] of this.operations) {\n if (now - operation.timestamp > maxAgeMs) {\n this.operations.delete(id);\n cleaned++;\n }\n }\n\n return cleaned;\n }\n}\n"],"mappings":"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","names":["nanoid","nanoid"]}
1
+ {"version":3,"sources":["../websocket/WebSocketManager.ts","../websocket/optimistic.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\n\nexport type ConnectionState =\n | 'connecting'\n | 'connected'\n | 'reconnecting'\n | 'disconnected';\n\nexport interface ClientMessage {\n action: 'subscribe' | 'unsubscribe' | 'ephemeral' | 'ping';\n id: string;\n payload: {\n // Entity subscription: subscribe to all changes of this entity type\n entityType?: string;\n // Mutual subscription: subscribe to all mutuals of this type for a byEntity\n byEntityType?: string;\n byEntityId?: string;\n mutualEntityType?: string;\n // Ephemeral channel\n channel?: string;\n // Ephemeral message data\n data?: unknown;\n };\n}\n\nexport interface ServerMessage {\n type:\n | 'entity.created'\n | 'entity.updated'\n | 'entity.deleted'\n | 'mutual.created'\n | 'mutual.updated'\n | 'mutual.deleted'\n | 'ephemeral'\n | 'ack'\n | 'error'\n | 'pong';\n id: string;\n payload: unknown;\n}\n\ntype MessageHandler = (message: ServerMessage) => void;\ntype ConnectionStateHandler = (state: ConnectionState) => void;\n\n// Entity type subscription: listen to ALL changes of this entity type\ninterface EntityTypeSubscription {\n entityType: string;\n}\n\n// Mutual type subscription: listen to ALL mutuals of this type for a byEntity\ninterface MutualTypeSubscription {\n byEntityType: string;\n byEntityId: string;\n mutualEntityType: string;\n}\n\n// Ephemeral channel subscription: listen to ephemeral messages on this channel\ninterface EphemeralSubscription {\n channel: string;\n}\n\nexport class WebSocketManager {\n private ws: WebSocket | null = null;\n private url: string;\n private token: string;\n private state: ConnectionState = 'disconnected';\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 10;\n private reconnectDelay = 1000;\n private maxReconnectDelay = 30000;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n private heartbeatTimeout: NodeJS.Timeout | null = null;\n private readonly heartbeatIntervalMs = 30000;\n private readonly heartbeatTimeoutMs = 10000;\n\n private messageHandlers: Set<MessageHandler> = new Set();\n private stateHandlers: Set<ConnectionStateHandler> = new Set();\n private entitySubscriptions: Map<string, EntityTypeSubscription> = new Map();\n private mutualSubscriptions: Map<string, MutualTypeSubscription> = new Map();\n private ephemeralSubscriptions: Map<string, EphemeralSubscription> = new Map();\n private pendingMessages: ClientMessage[] = [];\n\n public disableAutoReconnect = false;\n\n constructor(url: string, token: string) {\n this.url = url;\n this.token = token;\n }\n\n connect(): void {\n if (this.ws?.readyState === WebSocket.OPEN) return;\n\n this.setState('connecting');\n\n try {\n const connectUrl = this.token\n ? `${this.url}?token=${encodeURIComponent(this.token)}`\n : this.url;\n this.ws = new WebSocket(connectUrl);\n\n this.ws.onopen = this.handleOpen.bind(this);\n this.ws.onclose = this.handleClose.bind(this);\n this.ws.onerror = this.handleError.bind(this);\n this.ws.onmessage = this.handleMessage.bind(this);\n } catch (error) {\n console.error('WebSocket connection error:', error);\n this.scheduleReconnect();\n }\n }\n\n disconnect(): void {\n this.stopHeartbeat();\n this.reconnectAttempts = 0;\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.setState('disconnected');\n }\n\n // Subscribe to ALL changes of an entity type\n subscribeEntityType(entityType: string): string {\n const subKey = `entity:${entityType}`;\n\n if (!this.entitySubscriptions.has(subKey)) {\n this.entitySubscriptions.set(subKey, { entityType });\n }\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { entityType },\n };\n this.send(message);\n }\n\n return subKey;\n }\n\n unsubscribeEntityType(subKey: string): void {\n const subscription = this.entitySubscriptions.get(subKey);\n if (!subscription) return;\n\n this.entitySubscriptions.delete(subKey);\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'unsubscribe',\n id: nanoid(),\n payload: { entityType: subscription.entityType },\n };\n this.send(message);\n }\n }\n\n // Subscribe to ALL mutuals of a type for a specific byEntity\n subscribeMutualType(\n byEntityType: string,\n byEntityId: string,\n mutualEntityType: string,\n ): string {\n const subKey = `mutual:${byEntityType}:${byEntityId}:${mutualEntityType}`;\n\n if (!this.mutualSubscriptions.has(subKey)) {\n this.mutualSubscriptions.set(subKey, {\n byEntityType,\n byEntityId,\n mutualEntityType,\n });\n }\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { byEntityType, byEntityId, mutualEntityType },\n };\n this.send(message);\n }\n\n return subKey;\n }\n\n unsubscribeMutualType(subKey: string): void {\n const subscription = this.mutualSubscriptions.get(subKey);\n if (!subscription) return;\n\n this.mutualSubscriptions.delete(subKey);\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'unsubscribe',\n id: nanoid(),\n payload: {\n byEntityType: subscription.byEntityType,\n byEntityId: subscription.byEntityId,\n mutualEntityType: subscription.mutualEntityType,\n },\n };\n this.send(message);\n }\n }\n\n // Subscribe to ephemeral messages on a channel\n subscribeEphemeral(channel: string): string {\n const subKey = `ephemeral:${channel}`;\n\n if (!this.ephemeralSubscriptions.has(subKey)) {\n this.ephemeralSubscriptions.set(subKey, { channel });\n }\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { channel },\n };\n this.send(message);\n }\n\n return subKey;\n }\n\n unsubscribeEphemeral(subKey: string): void {\n const subscription = this.ephemeralSubscriptions.get(subKey);\n if (!subscription) return;\n\n this.ephemeralSubscriptions.delete(subKey);\n\n if (this.state === 'connected') {\n const message: ClientMessage = {\n action: 'unsubscribe',\n id: nanoid(),\n payload: { channel: subscription.channel },\n };\n this.send(message);\n }\n }\n\n // Send an ephemeral message to a channel\n sendEphemeral(channel: string, data: unknown): void {\n const message: ClientMessage = {\n action: 'ephemeral',\n id: nanoid(),\n payload: { channel, data },\n };\n this.send(message);\n }\n\n send(message: ClientMessage): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(message));\n } else {\n this.pendingMessages.push(message);\n }\n }\n\n onMessage(handler: MessageHandler): () => void {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n onStateChange(handler: ConnectionStateHandler): () => void {\n this.stateHandlers.add(handler);\n handler(this.state);\n return () => this.stateHandlers.delete(handler);\n }\n\n getState(): ConnectionState {\n return this.state;\n }\n\n private setState(newState: ConnectionState): void {\n if (this.state !== newState) {\n this.state = newState;\n this.stateHandlers.forEach((handler) => handler(newState));\n }\n }\n\n private handleOpen(): void {\n this.setState('connected');\n this.reconnectAttempts = 0;\n this.reconnectDelay = 1000;\n\n this.startHeartbeat();\n this.resubscribeAll();\n this.flushPendingMessages();\n }\n\n private handleClose(event: CloseEvent): void {\n this.stopHeartbeat();\n this.ws = null;\n\n if (this.disableAutoReconnect) {\n this.setState('disconnected');\n return;\n }\n\n if (this.reconnectAttempts < this.maxReconnectAttempts) {\n this.setState('reconnecting');\n this.scheduleReconnect();\n } else {\n this.setState('disconnected');\n }\n }\n\n private handleError(error: Event): void {\n console.error('WebSocket error:', error);\n }\n\n private handleMessage(event: MessageEvent): void {\n try {\n const message = JSON.parse(event.data) as ServerMessage;\n\n if (message.type === 'pong') {\n this.handlePong();\n return;\n }\n\n this.messageHandlers.forEach((handler) => handler(message));\n } catch (error) {\n console.error('Failed to parse WebSocket message:', error);\n }\n }\n\n private scheduleReconnect(): void {\n setTimeout(() => {\n this.reconnectAttempts++;\n this.reconnectDelay = Math.min(\n this.reconnectDelay * 2,\n this.maxReconnectDelay,\n );\n this.connect();\n }, this.reconnectDelay);\n }\n\n private resubscribeAll(): void {\n // Re-subscribe entity types\n for (const { entityType } of this.entitySubscriptions.values()) {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { entityType },\n };\n this.send(message);\n }\n\n // Re-subscribe mutual types\n for (const {\n byEntityType,\n byEntityId,\n mutualEntityType,\n } of this.mutualSubscriptions.values()) {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { byEntityType, byEntityId, mutualEntityType },\n };\n this.send(message);\n }\n\n // Re-subscribe ephemeral channels\n for (const { channel } of this.ephemeralSubscriptions.values()) {\n const message: ClientMessage = {\n action: 'subscribe',\n id: nanoid(),\n payload: { channel },\n };\n this.send(message);\n }\n }\n\n private flushPendingMessages(): void {\n while (this.pendingMessages.length > 0) {\n const message = this.pendingMessages.shift();\n if (message) {\n this.send(message);\n }\n }\n }\n\n private startHeartbeat(): void {\n this.heartbeatInterval = setInterval(() => {\n const pingMessage: ClientMessage = {\n action: 'ping',\n id: nanoid(),\n payload: {},\n };\n this.send(pingMessage);\n\n this.heartbeatTimeout = setTimeout(() => {\n this.ws?.close();\n }, this.heartbeatTimeoutMs);\n }, this.heartbeatIntervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = null;\n }\n }\n\n private handlePong(): void {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = null;\n }\n }\n}\n","import { nanoid } from 'nanoid';\n\nexport interface OptimisticOperation {\n id: string;\n type: 'create' | 'update' | 'delete';\n entityType: string;\n entityId: string;\n previousData?: unknown;\n optimisticData: unknown;\n timestamp: number;\n}\n\nexport class OptimisticEngine {\n private operations: Map<string, OptimisticOperation> = new Map();\n private onRollback?: (operation: OptimisticOperation) => void;\n private onConfirm?: (operation: OptimisticOperation) => void;\n\n constructor(options?: {\n onRollback?: (operation: OptimisticOperation) => void;\n onConfirm?: (operation: OptimisticOperation) => void;\n }) {\n this.onRollback = options?.onRollback;\n this.onConfirm = options?.onConfirm;\n }\n\n /**\n * Register an optimistic operation\n */\n register(operation: Omit<OptimisticOperation, 'id' | 'timestamp'>): string {\n const id = nanoid();\n const fullOperation: OptimisticOperation = {\n ...operation,\n id,\n timestamp: Date.now(),\n };\n\n this.operations.set(id, fullOperation);\n return id;\n }\n\n /**\n * Confirm an operation (server acknowledged)\n */\n confirm(mutationId: string): void {\n const operation = this.operations.get(mutationId);\n if (operation) {\n this.operations.delete(mutationId);\n this.onConfirm?.(operation);\n }\n }\n\n /**\n * Rollback an operation (server rejected or failed)\n */\n rollback(mutationId: string): OptimisticOperation | undefined {\n const operation = this.operations.get(mutationId);\n if (operation) {\n this.operations.delete(mutationId);\n this.onRollback?.(operation);\n return operation;\n }\n return undefined;\n }\n\n /**\n * Check if an entity has pending optimistic operations\n */\n hasPendingOperation(entityType: string, entityId: string): boolean {\n for (const op of this.operations.values()) {\n if (op.entityType === entityType && op.entityId === entityId) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get pending operation for an entity\n */\n getPendingOperation(\n entityType: string,\n entityId: string,\n ): OptimisticOperation | undefined {\n for (const op of this.operations.values()) {\n if (op.entityType === entityType && op.entityId === entityId) {\n return op;\n }\n }\n return undefined;\n }\n\n /**\n * Clear all operations (e.g., on disconnect)\n */\n clear(): OptimisticOperation[] {\n const allOperations = Array.from(this.operations.values());\n this.operations.clear();\n return allOperations;\n }\n\n /**\n * Get all pending operations\n */\n getAllPending(): OptimisticOperation[] {\n return Array.from(this.operations.values());\n }\n\n /**\n * Clean up old operations (older than specified ms)\n */\n cleanup(maxAgeMs: number = 5 * 60 * 1000): number {\n const now = Date.now();\n let cleaned = 0;\n\n for (const [id, operation] of this.operations) {\n if (now - operation.timestamp > maxAgeMs) {\n this.operations.delete(id);\n cleaned++;\n }\n }\n\n return cleaned;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,cAAc;AA6DhB,IAAM,mBAAN,MAAuB;AAAA,EAuB5B,YAAY,KAAa,OAAe;AAtBxC,SAAQ,KAAuB;AAG/B,SAAQ,QAAyB;AACjC,SAAQ,oBAAoB;AAC5B,SAAQ,uBAAuB;AAC/B,SAAQ,iBAAiB;AACzB,SAAQ,oBAAoB;AAC5B,SAAQ,oBAA2C;AACnD,SAAQ,mBAA0C;AAClD,SAAiB,sBAAsB;AACvC,SAAiB,qBAAqB;AAEtC,SAAQ,kBAAuC,oBAAI,IAAI;AACvD,SAAQ,gBAA6C,oBAAI,IAAI;AAC7D,SAAQ,sBAA2D,oBAAI,IAAI;AAC3E,SAAQ,sBAA2D,oBAAI,IAAI;AAC3E,SAAQ,yBAA6D,oBAAI,IAAI;AAC7E,SAAQ,kBAAmC,CAAC;AAE5C,SAAO,uBAAuB;AAG5B,SAAK,MAAM;AACX,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,UAAgB;AAzFlB;AA0FI,UAAI,UAAK,OAAL,mBAAS,gBAAe,UAAU,KAAM;AAE5C,SAAK,SAAS,YAAY;AAE1B,QAAI;AACF,YAAM,aAAa,KAAK,QACpB,GAAG,KAAK,GAAG,UAAU,mBAAmB,KAAK,KAAK,CAAC,KACnD,KAAK;AACT,WAAK,KAAK,IAAI,UAAU,UAAU;AAElC,WAAK,GAAG,SAAS,KAAK,WAAW,KAAK,IAAI;AAC1C,WAAK,GAAG,UAAU,KAAK,YAAY,KAAK,IAAI;AAC5C,WAAK,GAAG,UAAU,KAAK,YAAY,KAAK,IAAI;AAC5C,WAAK,GAAG,YAAY,KAAK,cAAc,KAAK,IAAI;AAAA,IAClD,SAAS,OAAO;AACd,cAAQ,MAAM,+BAA+B,KAAK;AAClD,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,aAAmB;AACjB,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAM;AACd,WAAK,KAAK;AAAA,IACZ;AAEA,SAAK,SAAS,cAAc;AAAA,EAC9B;AAAA;AAAA,EAGA,oBAAoB,YAA4B;AAC9C,UAAM,SAAS,UAAU,UAAU;AAEnC,QAAI,CAAC,KAAK,oBAAoB,IAAI,MAAM,GAAG;AACzC,WAAK,oBAAoB,IAAI,QAAQ,EAAE,WAAW,CAAC;AAAA,IACrD;AAEA,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,WAAW;AAAA,MACxB;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,sBAAsB,QAAsB;AAC1C,UAAM,eAAe,KAAK,oBAAoB,IAAI,MAAM;AACxD,QAAI,CAAC,aAAc;AAEnB,SAAK,oBAAoB,OAAO,MAAM;AAEtC,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,YAAY,aAAa,WAAW;AAAA,MACjD;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAAA,EACF;AAAA;AAAA,EAGA,oBACE,cACA,YACA,kBACQ;AACR,UAAM,SAAS,UAAU,YAAY,IAAI,UAAU,IAAI,gBAAgB;AAEvE,QAAI,CAAC,KAAK,oBAAoB,IAAI,MAAM,GAAG;AACzC,WAAK,oBAAoB,IAAI,QAAQ;AAAA,QACnC;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,cAAc,YAAY,iBAAiB;AAAA,MACxD;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,sBAAsB,QAAsB;AAC1C,UAAM,eAAe,KAAK,oBAAoB,IAAI,MAAM;AACxD,QAAI,CAAC,aAAc;AAEnB,SAAK,oBAAoB,OAAO,MAAM;AAEtC,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS;AAAA,UACP,cAAc,aAAa;AAAA,UAC3B,YAAY,aAAa;AAAA,UACzB,kBAAkB,aAAa;AAAA,QACjC;AAAA,MACF;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB,SAAyB;AAC1C,UAAM,SAAS,aAAa,OAAO;AAEnC,QAAI,CAAC,KAAK,uBAAuB,IAAI,MAAM,GAAG;AAC5C,WAAK,uBAAuB,IAAI,QAAQ,EAAE,QAAQ,CAAC;AAAA,IACrD;AAEA,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,QAAQ;AAAA,MACrB;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,qBAAqB,QAAsB;AACzC,UAAM,eAAe,KAAK,uBAAuB,IAAI,MAAM;AAC3D,QAAI,CAAC,aAAc;AAEnB,SAAK,uBAAuB,OAAO,MAAM;AAEzC,QAAI,KAAK,UAAU,aAAa;AAC9B,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,SAAS,aAAa,QAAQ;AAAA,MAC3C;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAAA,EACF;AAAA;AAAA,EAGA,cAAc,SAAiB,MAAqB;AAClD,UAAM,UAAyB;AAAA,MAC7B,QAAQ;AAAA,MACR,IAAI,OAAO;AAAA,MACX,SAAS,EAAE,SAAS,KAAK;AAAA,IAC3B;AACA,SAAK,KAAK,OAAO;AAAA,EACnB;AAAA,EAEA,KAAK,SAA8B;AA5PrC;AA6PI,UAAI,UAAK,OAAL,mBAAS,gBAAe,UAAU,MAAM;AAC1C,WAAK,GAAG,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,IACtC,OAAO;AACL,WAAK,gBAAgB,KAAK,OAAO;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,UAAU,SAAqC;AAC7C,SAAK,gBAAgB,IAAI,OAAO;AAChC,WAAO,MAAM,KAAK,gBAAgB,OAAO,OAAO;AAAA,EAClD;AAAA,EAEA,cAAc,SAA6C;AACzD,SAAK,cAAc,IAAI,OAAO;AAC9B,YAAQ,KAAK,KAAK;AAClB,WAAO,MAAM,KAAK,cAAc,OAAO,OAAO;AAAA,EAChD;AAAA,EAEA,WAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,SAAS,UAAiC;AAChD,QAAI,KAAK,UAAU,UAAU;AAC3B,WAAK,QAAQ;AACb,WAAK,cAAc,QAAQ,CAAC,YAAY,QAAQ,QAAQ,CAAC;AAAA,IAC3D;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,SAAK,SAAS,WAAW;AACzB,SAAK,oBAAoB;AACzB,SAAK,iBAAiB;AAEtB,SAAK,eAAe;AACpB,SAAK,eAAe;AACpB,SAAK,qBAAqB;AAAA,EAC5B;AAAA,EAEQ,YAAY,OAAyB;AAC3C,SAAK,cAAc;AACnB,SAAK,KAAK;AAEV,QAAI,KAAK,sBAAsB;AAC7B,WAAK,SAAS,cAAc;AAC5B;AAAA,IACF;AAEA,QAAI,KAAK,oBAAoB,KAAK,sBAAsB;AACtD,WAAK,SAAS,cAAc;AAC5B,WAAK,kBAAkB;AAAA,IACzB,OAAO;AACL,WAAK,SAAS,cAAc;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,YAAY,OAAoB;AACtC,YAAQ,MAAM,oBAAoB,KAAK;AAAA,EACzC;AAAA,EAEQ,cAAc,OAA2B;AAC/C,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,MAAM,IAAI;AAErC,UAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAK,WAAW;AAChB;AAAA,MACF;AAEA,WAAK,gBAAgB,QAAQ,CAAC,YAAY,QAAQ,OAAO,CAAC;AAAA,IAC5D,SAAS,OAAO;AACd,cAAQ,MAAM,sCAAsC,KAAK;AAAA,IAC3D;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,eAAW,MAAM;AACf,WAAK;AACL,WAAK,iBAAiB,KAAK;AAAA,QACzB,KAAK,iBAAiB;AAAA,QACtB,KAAK;AAAA,MACP;AACA,WAAK,QAAQ;AAAA,IACf,GAAG,KAAK,cAAc;AAAA,EACxB;AAAA,EAEQ,iBAAuB;AAE7B,eAAW,EAAE,WAAW,KAAK,KAAK,oBAAoB,OAAO,GAAG;AAC9D,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,WAAW;AAAA,MACxB;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAGA,eAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF,KAAK,KAAK,oBAAoB,OAAO,GAAG;AACtC,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,cAAc,YAAY,iBAAiB;AAAA,MACxD;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAGA,eAAW,EAAE,QAAQ,KAAK,KAAK,uBAAuB,OAAO,GAAG;AAC9D,YAAM,UAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,EAAE,QAAQ;AAAA,MACrB;AACA,WAAK,KAAK,OAAO;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,uBAA6B;AACnC,WAAO,KAAK,gBAAgB,SAAS,GAAG;AACtC,YAAM,UAAU,KAAK,gBAAgB,MAAM;AAC3C,UAAI,SAAS;AACX,aAAK,KAAK,OAAO;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,oBAAoB,YAAY,MAAM;AACzC,YAAM,cAA6B;AAAA,QACjC,QAAQ;AAAA,QACR,IAAI,OAAO;AAAA,QACX,SAAS,CAAC;AAAA,MACZ;AACA,WAAK,KAAK,WAAW;AAErB,WAAK,mBAAmB,WAAW,MAAM;AAzY/C;AA0YQ,mBAAK,OAAL,mBAAS;AAAA,MACX,GAAG,KAAK,kBAAkB;AAAA,IAC5B,GAAG,KAAK,mBAAmB;AAAA,EAC7B;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,mBAAmB;AAC1B,oBAAc,KAAK,iBAAiB;AACpC,WAAK,oBAAoB;AAAA,IAC3B;AACA,QAAI,KAAK,kBAAkB;AACzB,mBAAa,KAAK,gBAAgB;AAClC,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,QAAI,KAAK,kBAAkB;AACzB,mBAAa,KAAK,gBAAgB;AAClC,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AACF;;;AChaA,SAAS,UAAAA,eAAc;AAYhB,IAAM,mBAAN,MAAuB;AAAA,EAK5B,YAAY,SAGT;AAPH,SAAQ,aAA+C,oBAAI,IAAI;AAQ7D,SAAK,aAAa,mCAAS;AAC3B,SAAK,YAAY,mCAAS;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,WAAkE;AACzE,UAAM,KAAKC,QAAO;AAClB,UAAM,gBAAqC,iCACtC,YADsC;AAAA,MAEzC;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,WAAW,IAAI,IAAI,aAAa;AACrC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,YAA0B;AA3CpC;AA4CI,UAAM,YAAY,KAAK,WAAW,IAAI,UAAU;AAChD,QAAI,WAAW;AACb,WAAK,WAAW,OAAO,UAAU;AACjC,iBAAK,cAAL,8BAAiB;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,YAAqD;AAtDhE;AAuDI,UAAM,YAAY,KAAK,WAAW,IAAI,UAAU;AAChD,QAAI,WAAW;AACb,WAAK,WAAW,OAAO,UAAU;AACjC,iBAAK,eAAL,8BAAkB;AAClB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,YAAoB,UAA2B;AACjE,eAAW,MAAM,KAAK,WAAW,OAAO,GAAG;AACzC,UAAI,GAAG,eAAe,cAAc,GAAG,aAAa,UAAU;AAC5D,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,oBACE,YACA,UACiC;AACjC,eAAW,MAAM,KAAK,WAAW,OAAO,GAAG;AACzC,UAAI,GAAG,eAAe,cAAc,GAAG,aAAa,UAAU;AAC5D,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,QAA+B;AAC7B,UAAM,gBAAgB,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC;AACzD,SAAK,WAAW,MAAM;AACtB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAuC;AACrC,WAAO,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,WAAmB,IAAI,KAAK,KAAc;AAChD,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,UAAU;AAEd,eAAW,CAAC,IAAI,SAAS,KAAK,KAAK,YAAY;AAC7C,UAAI,MAAM,UAAU,YAAY,UAAU;AACxC,aAAK,WAAW,OAAO,EAAE;AACzB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;","names":["nanoid","nanoid"]}
@@ -1159,7 +1159,7 @@ declare const store: import("zustand").UseBoundStore<Omit<import("zustand").Stor
1159
1159
  }, useEntityFeed: (opts: import("./actions/websocket.action").UseEntityFeedOptions) => import("./actions/websocket.action").UseEntityFeedReturn;
1160
1160
  export { store, axios, authService, filestoreService, coreService, setConfig, getConfig, useConfig, startLoading, endLoading, setError, getError, clearError, openModal, closeModal, useLoadStore, useInterruptiveLoadStore, useErrorStore, useModalStore, requestLogin, useProfile, getProfile, useIsUnauthorized, setIsUnauthorized, logout, listMoreEntities, createEntity, upsertEntity, editEntity, adjustEntity, updateLocalEntity, deleteEntity, getMutual, createMutual, createLocalMutual, upsertLocalMutual, editMutual, deleteMutual, deleteLocalMutual, useEntity, useEntityByUniqueField, useEntities, useMutual, useMutuals, useTaggedEntities, useEntityState, getEntityRequestKey, getMutualRequestKey, getTagRequestKey, getUniqueFieldRequestKey, getEntity, updateLocalTaggedEntity, deleteLocalTaggedEntity, useEntitySocket, useMutualSocket, useEphemeralSocket, useEntityFeed, initializeWebSocketManager, getWebSocketManager, WebSocketManager, type ConnectionState, type ClientMessage, type ServerMessage, };
1161
1161
  export default Monorise;
1162
- export { transactional } from '../core/index';
1162
+ export { transactional } from '../base/index';
1163
1163
  export { MutualDataWithIndex, MutualDataMapping, MutualData, Mutual };
1164
1164
  export type { CreatedEntity, DraftEntity, Entity, EntitySchemaMap, NumericFields, } from '../base/index';
1165
1165
  //# sourceMappingURL=index.d.ts.map