@revealui/ai 0.1.0
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/LICENSE +22 -0
- package/LICENSE.commercial +112 -0
- package/README.md +314 -0
- package/dist/a2a/card.d.ts +26 -0
- package/dist/a2a/card.d.ts.map +1 -0
- package/dist/a2a/card.js +173 -0
- package/dist/a2a/handler.d.ts +26 -0
- package/dist/a2a/handler.d.ts.map +1 -0
- package/dist/a2a/handler.js +170 -0
- package/dist/a2a/index.d.ts +10 -0
- package/dist/a2a/index.d.ts.map +1 -0
- package/dist/a2a/index.js +9 -0
- package/dist/a2a/task-store.d.ts +42 -0
- package/dist/a2a/task-store.d.ts.map +1 -0
- package/dist/a2a/task-store.js +99 -0
- package/dist/audit/emitter.d.ts +34 -0
- package/dist/audit/emitter.d.ts.map +1 -0
- package/dist/audit/emitter.js +34 -0
- package/dist/audit/index.d.ts +44 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +48 -0
- package/dist/audit/observer.d.ts +108 -0
- package/dist/audit/observer.d.ts.map +1 -0
- package/dist/audit/observer.js +271 -0
- package/dist/audit/policy.d.ts +70 -0
- package/dist/audit/policy.d.ts.map +1 -0
- package/dist/audit/policy.js +209 -0
- package/dist/audit/store.d.ts +42 -0
- package/dist/audit/store.d.ts.map +1 -0
- package/dist/audit/store.js +80 -0
- package/dist/audit/types.d.ts +169 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/audit/types.js +80 -0
- package/dist/client/hooks/index.d.ts +22 -0
- package/dist/client/hooks/index.d.ts.map +1 -0
- package/dist/client/hooks/index.js +21 -0
- package/dist/client/hooks/useAgentContext.d.ts +30 -0
- package/dist/client/hooks/useAgentContext.d.ts.map +1 -0
- package/dist/client/hooks/useAgentContext.js +161 -0
- package/dist/client/hooks/useAgentEvents.d.ts +126 -0
- package/dist/client/hooks/useAgentEvents.d.ts.map +1 -0
- package/dist/client/hooks/useAgentEvents.js +232 -0
- package/dist/client/hooks/useAgentStream.d.ts +44 -0
- package/dist/client/hooks/useAgentStream.d.ts.map +1 -0
- package/dist/client/hooks/useAgentStream.js +101 -0
- package/dist/client/hooks/useEpisodicMemory.d.ts +25 -0
- package/dist/client/hooks/useEpisodicMemory.d.ts.map +1 -0
- package/dist/client/hooks/useEpisodicMemory.js +174 -0
- package/dist/client/hooks/useWorkingMemory.d.ts +57 -0
- package/dist/client/hooks/useWorkingMemory.d.ts.map +1 -0
- package/dist/client/hooks/useWorkingMemory.js +276 -0
- package/dist/client/index.d.ts +14 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +13 -0
- package/dist/embeddings/index.d.ts +51 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +73 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +103 -0
- package/dist/inference/context-assembly.d.ts +27 -0
- package/dist/inference/context-assembly.d.ts.map +1 -0
- package/dist/inference/context-assembly.js +81 -0
- package/dist/inference/overflow-compressor.d.ts +17 -0
- package/dist/inference/overflow-compressor.d.ts.map +1 -0
- package/dist/inference/overflow-compressor.js +40 -0
- package/dist/inference/runRag.d.ts +35 -0
- package/dist/inference/runRag.d.ts.map +1 -0
- package/dist/inference/runRag.js +53 -0
- package/dist/ingestion/bm25.d.ts +29 -0
- package/dist/ingestion/bm25.d.ts.map +1 -0
- package/dist/ingestion/bm25.js +161 -0
- package/dist/ingestion/cms-indexer.d.ts +39 -0
- package/dist/ingestion/cms-indexer.d.ts.map +1 -0
- package/dist/ingestion/cms-indexer.js +74 -0
- package/dist/ingestion/file-parsers.d.ts +51 -0
- package/dist/ingestion/file-parsers.d.ts.map +1 -0
- package/dist/ingestion/file-parsers.js +247 -0
- package/dist/ingestion/hybrid-search.d.ts +22 -0
- package/dist/ingestion/hybrid-search.d.ts.map +1 -0
- package/dist/ingestion/hybrid-search.js +63 -0
- package/dist/ingestion/index.d.ts +9 -0
- package/dist/ingestion/index.d.ts.map +1 -0
- package/dist/ingestion/index.js +8 -0
- package/dist/ingestion/pipeline.d.ts +35 -0
- package/dist/ingestion/pipeline.d.ts.map +1 -0
- package/dist/ingestion/pipeline.js +114 -0
- package/dist/ingestion/rag-vector-service.d.ts +34 -0
- package/dist/ingestion/rag-vector-service.d.ts.map +1 -0
- package/dist/ingestion/rag-vector-service.js +98 -0
- package/dist/ingestion/reranker.d.ts +10 -0
- package/dist/ingestion/reranker.d.ts.map +1 -0
- package/dist/ingestion/reranker.js +41 -0
- package/dist/ingestion/text-splitter.d.ts +25 -0
- package/dist/ingestion/text-splitter.d.ts.map +1 -0
- package/dist/ingestion/text-splitter.js +119 -0
- package/dist/llm/cache-utils.d.ts +146 -0
- package/dist/llm/cache-utils.d.ts.map +1 -0
- package/dist/llm/cache-utils.js +204 -0
- package/dist/llm/client.d.ts +134 -0
- package/dist/llm/client.d.ts.map +1 -0
- package/dist/llm/client.js +497 -0
- package/dist/llm/key-validator.d.ts +25 -0
- package/dist/llm/key-validator.d.ts.map +1 -0
- package/dist/llm/key-validator.js +101 -0
- package/dist/llm/provider-health.d.ts +40 -0
- package/dist/llm/provider-health.d.ts.map +1 -0
- package/dist/llm/provider-health.js +97 -0
- package/dist/llm/providers/anthropic.d.ts +31 -0
- package/dist/llm/providers/anthropic.d.ts.map +1 -0
- package/dist/llm/providers/anthropic.js +248 -0
- package/dist/llm/providers/base.d.ts +111 -0
- package/dist/llm/providers/base.d.ts.map +1 -0
- package/dist/llm/providers/base.js +6 -0
- package/dist/llm/providers/groq.d.ts +23 -0
- package/dist/llm/providers/groq.d.ts.map +1 -0
- package/dist/llm/providers/groq.js +27 -0
- package/dist/llm/providers/ollama.d.ts +27 -0
- package/dist/llm/providers/ollama.d.ts.map +1 -0
- package/dist/llm/providers/ollama.js +48 -0
- package/dist/llm/providers/openai.d.ts +19 -0
- package/dist/llm/providers/openai.d.ts.map +1 -0
- package/dist/llm/providers/openai.js +245 -0
- package/dist/llm/providers/vultr.d.ts +18 -0
- package/dist/llm/providers/vultr.d.ts.map +1 -0
- package/dist/llm/providers/vultr.js +168 -0
- package/dist/llm/response-cache.d.ts +166 -0
- package/dist/llm/response-cache.d.ts.map +1 -0
- package/dist/llm/response-cache.js +233 -0
- package/dist/llm/semantic-cache.d.ts +179 -0
- package/dist/llm/semantic-cache.d.ts.map +1 -0
- package/dist/llm/semantic-cache.js +306 -0
- package/dist/llm/server.d.ts +14 -0
- package/dist/llm/server.d.ts.map +1 -0
- package/dist/llm/server.js +15 -0
- package/dist/llm/token-counter.d.ts +48 -0
- package/dist/llm/token-counter.d.ts.map +1 -0
- package/dist/llm/token-counter.js +77 -0
- package/dist/llm/workspace-provider-config.d.ts +38 -0
- package/dist/llm/workspace-provider-config.d.ts.map +1 -0
- package/dist/llm/workspace-provider-config.js +47 -0
- package/dist/memory/agent/context-manager.d.ts +148 -0
- package/dist/memory/agent/context-manager.d.ts.map +1 -0
- package/dist/memory/agent/context-manager.js +284 -0
- package/dist/memory/agent/index.d.ts +7 -0
- package/dist/memory/agent/index.d.ts.map +1 -0
- package/dist/memory/agent/index.js +6 -0
- package/dist/memory/crdt/index.d.ts +13 -0
- package/dist/memory/crdt/index.d.ts.map +1 -0
- package/dist/memory/crdt/index.js +12 -0
- package/dist/memory/crdt/lww-register.d.ts +108 -0
- package/dist/memory/crdt/lww-register.d.ts.map +1 -0
- package/dist/memory/crdt/lww-register.js +169 -0
- package/dist/memory/crdt/or-set.d.ts +141 -0
- package/dist/memory/crdt/or-set.d.ts.map +1 -0
- package/dist/memory/crdt/or-set.js +291 -0
- package/dist/memory/crdt/pn-counter.d.ts +116 -0
- package/dist/memory/crdt/pn-counter.d.ts.map +1 -0
- package/dist/memory/crdt/pn-counter.js +174 -0
- package/dist/memory/crdt/vector-clock.d.ts +115 -0
- package/dist/memory/crdt/vector-clock.d.ts.map +1 -0
- package/dist/memory/crdt/vector-clock.js +179 -0
- package/dist/memory/errors/index.d.ts +56 -0
- package/dist/memory/errors/index.d.ts.map +1 -0
- package/dist/memory/errors/index.js +85 -0
- package/dist/memory/index.d.ts +21 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +20 -0
- package/dist/memory/persistence/crdt-persistence.d.ts +85 -0
- package/dist/memory/persistence/crdt-persistence.d.ts.map +1 -0
- package/dist/memory/persistence/crdt-persistence.js +204 -0
- package/dist/memory/persistence/index.d.ts +7 -0
- package/dist/memory/persistence/index.d.ts.map +1 -0
- package/dist/memory/persistence/index.js +6 -0
- package/dist/memory/preferences/index.d.ts +7 -0
- package/dist/memory/preferences/index.d.ts.map +1 -0
- package/dist/memory/preferences/index.js +6 -0
- package/dist/memory/preferences/user-preferences-manager.d.ts +133 -0
- package/dist/memory/preferences/user-preferences-manager.d.ts.map +1 -0
- package/dist/memory/preferences/user-preferences-manager.js +342 -0
- package/dist/memory/services/index.d.ts +8 -0
- package/dist/memory/services/index.d.ts.map +1 -0
- package/dist/memory/services/index.js +6 -0
- package/dist/memory/services/node-id-service.d.ts +75 -0
- package/dist/memory/services/node-id-service.d.ts.map +1 -0
- package/dist/memory/services/node-id-service.js +190 -0
- package/dist/memory/stores/episodic-memory.d.ts +182 -0
- package/dist/memory/stores/episodic-memory.d.ts.map +1 -0
- package/dist/memory/stores/episodic-memory.js +378 -0
- package/dist/memory/stores/index.d.ts +16 -0
- package/dist/memory/stores/index.d.ts.map +1 -0
- package/dist/memory/stores/index.js +15 -0
- package/dist/memory/stores/procedural-memory.d.ts +89 -0
- package/dist/memory/stores/procedural-memory.d.ts.map +1 -0
- package/dist/memory/stores/procedural-memory.js +152 -0
- package/dist/memory/stores/semantic-memory.d.ts +92 -0
- package/dist/memory/stores/semantic-memory.d.ts.map +1 -0
- package/dist/memory/stores/semantic-memory.js +155 -0
- package/dist/memory/stores/working-memory.d.ts +225 -0
- package/dist/memory/stores/working-memory.d.ts.map +1 -0
- package/dist/memory/stores/working-memory.js +336 -0
- package/dist/memory/utils/deep-clone.d.ts +10 -0
- package/dist/memory/utils/deep-clone.d.ts.map +1 -0
- package/dist/memory/utils/deep-clone.js +9 -0
- package/dist/memory/utils/index.d.ts +8 -0
- package/dist/memory/utils/index.d.ts.map +1 -0
- package/dist/memory/utils/index.js +7 -0
- package/dist/memory/utils/logger.d.ts +21 -0
- package/dist/memory/utils/logger.d.ts.map +1 -0
- package/dist/memory/utils/logger.js +62 -0
- package/dist/memory/utils/sql-helpers.d.ts +97 -0
- package/dist/memory/utils/sql-helpers.d.ts.map +1 -0
- package/dist/memory/utils/sql-helpers.js +214 -0
- package/dist/memory/utils/validation.d.ts +62 -0
- package/dist/memory/utils/validation.d.ts.map +1 -0
- package/dist/memory/utils/validation.js +244 -0
- package/dist/memory/vector/index.d.ts +12 -0
- package/dist/memory/vector/index.d.ts.map +1 -0
- package/dist/memory/vector/index.js +14 -0
- package/dist/memory/vector/vector-memory-service.d.ts +88 -0
- package/dist/memory/vector/vector-memory-service.d.ts.map +1 -0
- package/dist/memory/vector/vector-memory-service.js +335 -0
- package/dist/observability/logger.d.ts +79 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +165 -0
- package/dist/observability/metrics.d.ts +43 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +197 -0
- package/dist/observability/query.d.ts +150 -0
- package/dist/observability/query.d.ts.map +1 -0
- package/dist/observability/query.js +339 -0
- package/dist/observability/types.d.ts +140 -0
- package/dist/observability/types.d.ts.map +1 -0
- package/dist/observability/types.js +6 -0
- package/dist/orchestration/agent.d.ts +98 -0
- package/dist/orchestration/agent.d.ts.map +1 -0
- package/dist/orchestration/agent.js +6 -0
- package/dist/orchestration/defaults.d.ts +21 -0
- package/dist/orchestration/defaults.d.ts.map +1 -0
- package/dist/orchestration/defaults.js +22 -0
- package/dist/orchestration/memory-integration.d.ts +58 -0
- package/dist/orchestration/memory-integration.d.ts.map +1 -0
- package/dist/orchestration/memory-integration.js +130 -0
- package/dist/orchestration/orchestrator.d.ts +67 -0
- package/dist/orchestration/orchestrator.d.ts.map +1 -0
- package/dist/orchestration/orchestrator.js +174 -0
- package/dist/orchestration/runtime.d.ts +82 -0
- package/dist/orchestration/runtime.d.ts.map +1 -0
- package/dist/orchestration/runtime.js +251 -0
- package/dist/orchestration/streaming-runtime.d.ts +36 -0
- package/dist/orchestration/streaming-runtime.d.ts.map +1 -0
- package/dist/orchestration/streaming-runtime.js +175 -0
- package/dist/orchestration/ticket-agent.d.ts +70 -0
- package/dist/orchestration/ticket-agent.d.ts.map +1 -0
- package/dist/orchestration/ticket-agent.js +146 -0
- package/dist/skills/activation/index.d.ts +7 -0
- package/dist/skills/activation/index.d.ts.map +1 -0
- package/dist/skills/activation/index.js +6 -0
- package/dist/skills/activation/skill-activator.d.ts +68 -0
- package/dist/skills/activation/skill-activator.d.ts.map +1 -0
- package/dist/skills/activation/skill-activator.js +224 -0
- package/dist/skills/catalog/catalog-search.d.ts +55 -0
- package/dist/skills/catalog/catalog-search.d.ts.map +1 -0
- package/dist/skills/catalog/catalog-search.js +111 -0
- package/dist/skills/catalog/catalog-types.d.ts +81 -0
- package/dist/skills/catalog/catalog-types.d.ts.map +1 -0
- package/dist/skills/catalog/catalog-types.js +66 -0
- package/dist/skills/catalog/index.d.ts +9 -0
- package/dist/skills/catalog/index.d.ts.map +1 -0
- package/dist/skills/catalog/index.js +7 -0
- package/dist/skills/catalog/vercel-catalog.d.ts +42 -0
- package/dist/skills/catalog/vercel-catalog.d.ts.map +1 -0
- package/dist/skills/catalog/vercel-catalog.js +189 -0
- package/dist/skills/compat/index.d.ts +9 -0
- package/dist/skills/compat/index.d.ts.map +1 -0
- package/dist/skills/compat/index.js +8 -0
- package/dist/skills/compat/skill-enhancer.d.ts +37 -0
- package/dist/skills/compat/skill-enhancer.d.ts.map +1 -0
- package/dist/skills/compat/skill-enhancer.js +76 -0
- package/dist/skills/compat/tool-mapper.d.ts +61 -0
- package/dist/skills/compat/tool-mapper.d.ts.map +1 -0
- package/dist/skills/compat/tool-mapper.js +168 -0
- package/dist/skills/compat/vercel-compat.d.ts +33 -0
- package/dist/skills/compat/vercel-compat.d.ts.map +1 -0
- package/dist/skills/compat/vercel-compat.js +132 -0
- package/dist/skills/index.d.ts +40 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +47 -0
- package/dist/skills/integration/agent-skill-provider.d.ts +94 -0
- package/dist/skills/integration/agent-skill-provider.d.ts.map +1 -0
- package/dist/skills/integration/agent-skill-provider.js +161 -0
- package/dist/skills/integration/index.d.ts +7 -0
- package/dist/skills/integration/index.d.ts.map +1 -0
- package/dist/skills/integration/index.js +6 -0
- package/dist/skills/loader/github-loader.d.ts +61 -0
- package/dist/skills/loader/github-loader.d.ts.map +1 -0
- package/dist/skills/loader/github-loader.js +176 -0
- package/dist/skills/loader/index.d.ts +10 -0
- package/dist/skills/loader/index.d.ts.map +1 -0
- package/dist/skills/loader/index.js +9 -0
- package/dist/skills/loader/local-loader.d.ts +56 -0
- package/dist/skills/loader/local-loader.d.ts.map +1 -0
- package/dist/skills/loader/local-loader.js +186 -0
- package/dist/skills/loader/vercel-loader.d.ts +64 -0
- package/dist/skills/loader/vercel-loader.d.ts.map +1 -0
- package/dist/skills/loader/vercel-loader.js +313 -0
- package/dist/skills/loader/vercel-types.d.ts +64 -0
- package/dist/skills/loader/vercel-types.d.ts.map +1 -0
- package/dist/skills/loader/vercel-types.js +55 -0
- package/dist/skills/parser/index.d.ts +7 -0
- package/dist/skills/parser/index.d.ts.map +1 -0
- package/dist/skills/parser/index.js +6 -0
- package/dist/skills/parser/skill-md-parser.d.ts +64 -0
- package/dist/skills/parser/skill-md-parser.d.ts.map +1 -0
- package/dist/skills/parser/skill-md-parser.js +242 -0
- package/dist/skills/registry/index.d.ts +7 -0
- package/dist/skills/registry/index.d.ts.map +1 -0
- package/dist/skills/registry/index.js +6 -0
- package/dist/skills/registry/skill-registry.d.ts +133 -0
- package/dist/skills/registry/skill-registry.d.ts.map +1 -0
- package/dist/skills/registry/skill-registry.js +373 -0
- package/dist/skills/types.d.ts +216 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +176 -0
- package/dist/templates/agent-spec.d.ts +138 -0
- package/dist/templates/agent-spec.d.ts.map +1 -0
- package/dist/templates/agent-spec.js +138 -0
- package/dist/templates/index.d.ts +56 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +58 -0
- package/dist/templates/prompt-spec.d.ts +140 -0
- package/dist/templates/prompt-spec.d.ts.map +1 -0
- package/dist/templates/prompt-spec.js +210 -0
- package/dist/templates/skill-spec.d.ts +106 -0
- package/dist/templates/skill-spec.d.ts.map +1 -0
- package/dist/templates/skill-spec.js +119 -0
- package/dist/tools/base.d.ts +74 -0
- package/dist/tools/base.d.ts.map +1 -0
- package/dist/tools/base.js +6 -0
- package/dist/tools/cms/collection-tools.d.ts +36 -0
- package/dist/tools/cms/collection-tools.d.ts.map +1 -0
- package/dist/tools/cms/collection-tools.js +178 -0
- package/dist/tools/cms/factory.d.ts +89 -0
- package/dist/tools/cms/factory.d.ts.map +1 -0
- package/dist/tools/cms/factory.js +462 -0
- package/dist/tools/cms/global-tools.d.ts +21 -0
- package/dist/tools/cms/global-tools.d.ts.map +1 -0
- package/dist/tools/cms/global-tools.js +92 -0
- package/dist/tools/cms/index.d.ts +11 -0
- package/dist/tools/cms/index.d.ts.map +1 -0
- package/dist/tools/cms/index.js +11 -0
- package/dist/tools/cms/media-tools.d.ts +31 -0
- package/dist/tools/cms/media-tools.d.ts.map +1 -0
- package/dist/tools/cms/media-tools.js +140 -0
- package/dist/tools/cms/user-tools.d.ts +31 -0
- package/dist/tools/cms/user-tools.d.ts.map +1 -0
- package/dist/tools/cms/user-tools.js +135 -0
- package/dist/tools/deduplicator.d.ts +19 -0
- package/dist/tools/deduplicator.d.ts.map +1 -0
- package/dist/tools/deduplicator.js +53 -0
- package/dist/tools/document-summarizer.d.ts +11 -0
- package/dist/tools/document-summarizer.d.ts.map +1 -0
- package/dist/tools/document-summarizer.js +82 -0
- package/dist/tools/mcp-adapter.d.ts +66 -0
- package/dist/tools/mcp-adapter.d.ts.map +1 -0
- package/dist/tools/mcp-adapter.js +152 -0
- package/dist/tools/memory/index.d.ts +3 -0
- package/dist/tools/memory/index.d.ts.map +1 -0
- package/dist/tools/memory/index.js +1 -0
- package/dist/tools/memory/store-memory.d.ts +39 -0
- package/dist/tools/memory/store-memory.d.ts.map +1 -0
- package/dist/tools/memory/store-memory.js +94 -0
- package/dist/tools/registry.d.ts +14 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +48 -0
- package/dist/tools/ticket-tools.d.ts +31 -0
- package/dist/tools/ticket-tools.d.ts.map +1 -0
- package/dist/tools/ticket-tools.js +74 -0
- package/dist/tools/web/duck-duck-go.d.ts +52 -0
- package/dist/tools/web/duck-duck-go.d.ts.map +1 -0
- package/dist/tools/web/duck-duck-go.js +202 -0
- package/dist/tools/web/exa.d.ts +34 -0
- package/dist/tools/web/exa.d.ts.map +1 -0
- package/dist/tools/web/exa.js +80 -0
- package/dist/tools/web/index.d.ts +6 -0
- package/dist/tools/web/index.d.ts.map +1 -0
- package/dist/tools/web/index.js +4 -0
- package/dist/tools/web/scraper.d.ts +9 -0
- package/dist/tools/web/scraper.d.ts.map +1 -0
- package/dist/tools/web/scraper.js +118 -0
- package/dist/tools/web/tavily.d.ts +32 -0
- package/dist/tools/web/tavily.d.ts.map +1 -0
- package/dist/tools/web/tavily.js +73 -0
- package/dist/tools/web/types.d.ts +31 -0
- package/dist/tools/web/types.d.ts.map +1 -0
- package/dist/tools/web/types.js +9 -0
- package/package.json +143 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Last-Writer-Wins Register (LWW-Register)
|
|
3
|
+
*
|
|
4
|
+
* A CRDT that stores a single value where the most recent write wins.
|
|
5
|
+
* Uses timestamps and node IDs to determine ordering when timestamps are equal.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: This register deep clones object/array values to prevent external mutations.
|
|
8
|
+
* Primitives (strings, numbers, booleans, null) are stored as-is for performance.
|
|
9
|
+
*
|
|
10
|
+
* Use cases:
|
|
11
|
+
* - User preferences
|
|
12
|
+
* - Agent configurations
|
|
13
|
+
* - Any single-valued state
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const reg1 = new LWWRegister<string>('node-a', 'initial')
|
|
18
|
+
* const reg2 = new LWWRegister<string>('node-b', 'initial')
|
|
19
|
+
*
|
|
20
|
+
* reg1.set('value-from-a')
|
|
21
|
+
* reg2.set('value-from-b')
|
|
22
|
+
*
|
|
23
|
+
* // Merge resolves to most recent write
|
|
24
|
+
* const merged = reg1.merge(reg2)
|
|
25
|
+
* const value = merged.get() // 'value-from-b' (if reg2 was set later)
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
import { randomUUID } from 'node:crypto';
|
|
29
|
+
import { deepClone } from '../utils/deep-clone.js';
|
|
30
|
+
export class LWWRegister {
|
|
31
|
+
value;
|
|
32
|
+
timestamp;
|
|
33
|
+
nodeId;
|
|
34
|
+
version;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new LWW-Register.
|
|
37
|
+
* @param nodeId - Unique identifier for this node
|
|
38
|
+
* @param initialValue - The initial value
|
|
39
|
+
* @param timestamp - Optional initial timestamp (defaults to now)
|
|
40
|
+
*/
|
|
41
|
+
constructor(nodeId, initialValue, timestamp) {
|
|
42
|
+
this.nodeId = nodeId;
|
|
43
|
+
// Deep clone object/array values to prevent external mutations
|
|
44
|
+
this.value = this.shouldClone(initialValue) ? deepClone(initialValue) : initialValue;
|
|
45
|
+
this.timestamp = timestamp ?? Date.now();
|
|
46
|
+
this.version = 1;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Determines if a value should be deep cloned.
|
|
50
|
+
* Only objects and arrays need cloning; primitives are safe to store directly.
|
|
51
|
+
*/
|
|
52
|
+
shouldClone(value) {
|
|
53
|
+
return value !== null && typeof value === 'object';
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sets a new value with the current timestamp.
|
|
57
|
+
* Deep clones object/array values to prevent external mutations.
|
|
58
|
+
* @param value - The new value to set
|
|
59
|
+
* @param timestamp - Optional explicit timestamp (defaults to now)
|
|
60
|
+
*/
|
|
61
|
+
set(value, timestamp) {
|
|
62
|
+
const newTimestamp = timestamp ?? Date.now();
|
|
63
|
+
// For local sets, always update (increment timestamp if necessary)
|
|
64
|
+
// This ensures local writes always succeed
|
|
65
|
+
if (newTimestamp <= this.timestamp) {
|
|
66
|
+
this.timestamp = this.timestamp + 1;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.timestamp = newTimestamp;
|
|
70
|
+
}
|
|
71
|
+
// Deep clone object/array values to prevent external mutations
|
|
72
|
+
this.value = this.shouldClone(value) ? deepClone(value) : value;
|
|
73
|
+
this.version++;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Gets the current value.
|
|
77
|
+
* Returns a deep clone of object/array values to prevent external mutations.
|
|
78
|
+
* @returns The current value stored in the register (cloned if object/array)
|
|
79
|
+
*/
|
|
80
|
+
get() {
|
|
81
|
+
// Deep clone object/array values before returning to prevent external mutations
|
|
82
|
+
return this.shouldClone(this.value) ? deepClone(this.value) : this.value;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Gets the timestamp of the last update.
|
|
86
|
+
* @returns The timestamp when the value was last set
|
|
87
|
+
*/
|
|
88
|
+
getTimestamp() {
|
|
89
|
+
return this.timestamp;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Gets the current version number.
|
|
93
|
+
* @returns The number of times this register has been updated
|
|
94
|
+
*/
|
|
95
|
+
getVersion() {
|
|
96
|
+
return this.version;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Merges another LWW-Register into this one.
|
|
100
|
+
* The value with the most recent timestamp wins.
|
|
101
|
+
* @param other - The register to merge
|
|
102
|
+
* @returns A new merged LWWRegister
|
|
103
|
+
*/
|
|
104
|
+
merge(other) {
|
|
105
|
+
const merged = this.clone();
|
|
106
|
+
if (other.timestamp > merged.timestamp) {
|
|
107
|
+
// Deep clone the winning value to prevent mutations
|
|
108
|
+
merged.value = this.shouldClone(other.value) ? deepClone(other.value) : other.value;
|
|
109
|
+
merged.timestamp = other.timestamp;
|
|
110
|
+
merged.version = Math.max(merged.version, other.version) + 1;
|
|
111
|
+
}
|
|
112
|
+
else if (other.timestamp === merged.timestamp && other.nodeId > merged.nodeId) {
|
|
113
|
+
// Tie-break: lexicographically greater node ID wins
|
|
114
|
+
// Deep clone the winning value to prevent mutations
|
|
115
|
+
merged.value = this.shouldClone(other.value) ? deepClone(other.value) : other.value;
|
|
116
|
+
merged.nodeId = other.nodeId;
|
|
117
|
+
merged.version = Math.max(merged.version, other.version) + 1;
|
|
118
|
+
}
|
|
119
|
+
return merged;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Creates a deep copy of this register.
|
|
123
|
+
* @returns A new LWWRegister with the same state
|
|
124
|
+
*/
|
|
125
|
+
clone() {
|
|
126
|
+
const cloned = new LWWRegister(this.nodeId, this.value, this.timestamp);
|
|
127
|
+
cloned.version = this.version;
|
|
128
|
+
return cloned;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Serializes the register to a plain object.
|
|
132
|
+
* @returns A serializable representation
|
|
133
|
+
*/
|
|
134
|
+
toData() {
|
|
135
|
+
// Deep clone the value to prevent external mutations of serialized data
|
|
136
|
+
// This ensures the returned data structure is safe to modify without affecting internal state
|
|
137
|
+
return {
|
|
138
|
+
value: this.shouldClone(this.value) ? deepClone(this.value) : this.value,
|
|
139
|
+
timestamp: this.timestamp,
|
|
140
|
+
nodeId: this.nodeId,
|
|
141
|
+
version: this.version,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Deserializes a register from serialized data.
|
|
146
|
+
* @param data - The serialized register data
|
|
147
|
+
* @returns A new LWWRegister instance
|
|
148
|
+
*/
|
|
149
|
+
static fromData(data) {
|
|
150
|
+
// Constructor will deep clone object/array values automatically
|
|
151
|
+
const register = new LWWRegister(data.nodeId, data.value, data.timestamp);
|
|
152
|
+
register.version = data.version;
|
|
153
|
+
return register;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Creates a new register with a generated node ID.
|
|
157
|
+
* @param initialValue - The initial value
|
|
158
|
+
* @returns A new LWWRegister with a UUID node ID
|
|
159
|
+
*/
|
|
160
|
+
static create(initialValue) {
|
|
161
|
+
return new LWWRegister(randomUUID(), initialValue);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Returns a string representation for debugging.
|
|
165
|
+
*/
|
|
166
|
+
toString() {
|
|
167
|
+
return `LWWRegister(value=${JSON.stringify(this.value)}, ts=${this.timestamp}, node=${this.nodeId.slice(0, 8)})`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observed-Removed Set (OR-Set)
|
|
3
|
+
*
|
|
4
|
+
* A CRDT that supports both add and remove operations on a set.
|
|
5
|
+
* Uses unique tags for each element addition to handle concurrent operations.
|
|
6
|
+
*
|
|
7
|
+
* Use cases:
|
|
8
|
+
* - Collections of memories
|
|
9
|
+
* - Tags and categories
|
|
10
|
+
* - Active agent lists
|
|
11
|
+
* - User sessions
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const set1 = new ORSet<string>('node-a')
|
|
16
|
+
* const set2 = new ORSet<string>('node-b')
|
|
17
|
+
*
|
|
18
|
+
* set1.add('item1')
|
|
19
|
+
* set2.add('item2')
|
|
20
|
+
* set1.remove('item1')
|
|
21
|
+
*
|
|
22
|
+
* const merged = set1.merge(set2)
|
|
23
|
+
* merged.values() // ['item2']
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { type VectorClockData } from './vector-clock.js';
|
|
27
|
+
export interface ORSetEntry<T> {
|
|
28
|
+
value: T;
|
|
29
|
+
tag: string;
|
|
30
|
+
clock: VectorClockData;
|
|
31
|
+
}
|
|
32
|
+
export interface ORSetData<T> {
|
|
33
|
+
nodeId: string;
|
|
34
|
+
added: Record<string, ORSetEntry<T>>;
|
|
35
|
+
removed: string[];
|
|
36
|
+
}
|
|
37
|
+
export declare class ORSet<T> {
|
|
38
|
+
private nodeId;
|
|
39
|
+
private added;
|
|
40
|
+
private removed;
|
|
41
|
+
private clock;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new OR-Set.
|
|
44
|
+
* @param nodeId - Unique identifier for this node
|
|
45
|
+
*/
|
|
46
|
+
constructor(nodeId: string);
|
|
47
|
+
/**
|
|
48
|
+
* Adds an element to the set.
|
|
49
|
+
* @param element - The element to add
|
|
50
|
+
* @returns The unique tag for this addition
|
|
51
|
+
*/
|
|
52
|
+
add(element: T): string;
|
|
53
|
+
/**
|
|
54
|
+
* Removes an element by its tag.
|
|
55
|
+
* @param tag - The unique tag of the element to remove
|
|
56
|
+
* @returns true if the element was removed
|
|
57
|
+
*/
|
|
58
|
+
remove(tag: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Removes an element by value (removes all instances).
|
|
61
|
+
* @param element - The element value to remove
|
|
62
|
+
* @returns Number of instances removed
|
|
63
|
+
*/
|
|
64
|
+
removeByValue(element: T): number;
|
|
65
|
+
/**
|
|
66
|
+
* Checks if a tag is in the set.
|
|
67
|
+
* @param tag - The unique tag to check
|
|
68
|
+
* @returns true if the tag exists and hasn't been removed
|
|
69
|
+
*/
|
|
70
|
+
has(tag: string): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Checks if a value exists in the set.
|
|
73
|
+
* @param element - The element value to check
|
|
74
|
+
* @returns true if the value exists
|
|
75
|
+
*/
|
|
76
|
+
hasValue(element: T): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Gets all tags for a given value.
|
|
79
|
+
* @param element - The element value to find tags for
|
|
80
|
+
* @returns Array of tags for the value
|
|
81
|
+
*/
|
|
82
|
+
getTags(element: T): string[];
|
|
83
|
+
/**
|
|
84
|
+
* Gets all current values in the set.
|
|
85
|
+
* @returns Array of all non-removed values
|
|
86
|
+
*/
|
|
87
|
+
values(): T[];
|
|
88
|
+
/**
|
|
89
|
+
* Gets all entries (with tags) in the set.
|
|
90
|
+
* @returns Array of [tag, value] tuples
|
|
91
|
+
*/
|
|
92
|
+
entries(): Array<[string, T]>;
|
|
93
|
+
/**
|
|
94
|
+
* Gets the number of elements in the set.
|
|
95
|
+
*/
|
|
96
|
+
get size(): number;
|
|
97
|
+
/**
|
|
98
|
+
* Checks if the set is empty.
|
|
99
|
+
*/
|
|
100
|
+
get isEmpty(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Merges another OR-Set into this one.
|
|
103
|
+
* @param other - The set to merge
|
|
104
|
+
* @returns A new merged ORSet
|
|
105
|
+
*/
|
|
106
|
+
merge(other: ORSet<T>): ORSet<T>;
|
|
107
|
+
/**
|
|
108
|
+
* Clears all elements from the set.
|
|
109
|
+
*/
|
|
110
|
+
clear(): void;
|
|
111
|
+
/**
|
|
112
|
+
* Creates a copy of this set.
|
|
113
|
+
* @returns A new ORSet with the same state
|
|
114
|
+
*/
|
|
115
|
+
clone(): ORSet<T>;
|
|
116
|
+
/**
|
|
117
|
+
* Serializes the set to a plain object.
|
|
118
|
+
* @returns A serializable representation
|
|
119
|
+
*/
|
|
120
|
+
toData(): ORSetData<T>;
|
|
121
|
+
/**
|
|
122
|
+
* Deserializes a set from serialized data.
|
|
123
|
+
* @param data - The serialized set data
|
|
124
|
+
* @returns A new ORSet instance
|
|
125
|
+
*/
|
|
126
|
+
static fromData<T>(data: ORSetData<T>): ORSet<T>;
|
|
127
|
+
/**
|
|
128
|
+
* Creates a new OR-Set with a generated node ID.
|
|
129
|
+
* @returns A new ORSet with a UUID node ID
|
|
130
|
+
*/
|
|
131
|
+
static create<T>(): ORSet<T>;
|
|
132
|
+
/**
|
|
133
|
+
* Deep equality check for complex objects.
|
|
134
|
+
*/
|
|
135
|
+
private deepEquals;
|
|
136
|
+
/**
|
|
137
|
+
* Returns a string representation for debugging.
|
|
138
|
+
*/
|
|
139
|
+
toString(): string;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=or-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"or-set.d.ts","sourceRoot":"","sources":["../../../src/memory/crdt/or-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAErE,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAA;IACR,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IACpC,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,qBAAa,KAAK,CAAC,CAAC;IAClB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,KAAK,CAAa;IAE1B;;;OAGG;gBACS,MAAM,EAAE,MAAM;IAO1B;;;;OAIG;IACH,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM;IAUvB;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAS5B;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM;IAcjC;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO;IAS7B;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM,EAAE;IAU7B;;;OAGG;IACH,MAAM,IAAI,CAAC,EAAE;IAUb;;;OAGG;IACH,OAAO,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAU7B;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAQjB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAkChC;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;;OAGG;IACH,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC;IAkBjB;;;OAGG;IACH,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC;IAkBtB;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAiBhD;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC;IAI5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;OAEG;IACH,QAAQ,IAAI,MAAM;CAInB"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observed-Removed Set (OR-Set)
|
|
3
|
+
*
|
|
4
|
+
* A CRDT that supports both add and remove operations on a set.
|
|
5
|
+
* Uses unique tags for each element addition to handle concurrent operations.
|
|
6
|
+
*
|
|
7
|
+
* Use cases:
|
|
8
|
+
* - Collections of memories
|
|
9
|
+
* - Tags and categories
|
|
10
|
+
* - Active agent lists
|
|
11
|
+
* - User sessions
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const set1 = new ORSet<string>('node-a')
|
|
16
|
+
* const set2 = new ORSet<string>('node-b')
|
|
17
|
+
*
|
|
18
|
+
* set1.add('item1')
|
|
19
|
+
* set2.add('item2')
|
|
20
|
+
* set1.remove('item1')
|
|
21
|
+
*
|
|
22
|
+
* const merged = set1.merge(set2)
|
|
23
|
+
* merged.values() // ['item2']
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { randomUUID } from 'node:crypto';
|
|
27
|
+
import { VectorClock } from './vector-clock.js';
|
|
28
|
+
export class ORSet {
|
|
29
|
+
nodeId;
|
|
30
|
+
added;
|
|
31
|
+
removed;
|
|
32
|
+
clock;
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new OR-Set.
|
|
35
|
+
* @param nodeId - Unique identifier for this node
|
|
36
|
+
*/
|
|
37
|
+
constructor(nodeId) {
|
|
38
|
+
this.nodeId = nodeId;
|
|
39
|
+
this.added = new Map();
|
|
40
|
+
this.removed = new Set();
|
|
41
|
+
this.clock = new VectorClock(nodeId);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Adds an element to the set.
|
|
45
|
+
* @param element - The element to add
|
|
46
|
+
* @returns The unique tag for this addition
|
|
47
|
+
*/
|
|
48
|
+
add(element) {
|
|
49
|
+
const tag = `${this.nodeId}:${randomUUID()}`;
|
|
50
|
+
this.clock.tick();
|
|
51
|
+
this.added.set(tag, {
|
|
52
|
+
value: element,
|
|
53
|
+
clock: this.clock.clone(),
|
|
54
|
+
});
|
|
55
|
+
return tag;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Removes an element by its tag.
|
|
59
|
+
* @param tag - The unique tag of the element to remove
|
|
60
|
+
* @returns true if the element was removed
|
|
61
|
+
*/
|
|
62
|
+
remove(tag) {
|
|
63
|
+
if (this.added.has(tag) && !this.removed.has(tag)) {
|
|
64
|
+
this.removed.add(tag);
|
|
65
|
+
this.clock.tick();
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Removes an element by value (removes all instances).
|
|
72
|
+
* @param element - The element value to remove
|
|
73
|
+
* @returns Number of instances removed
|
|
74
|
+
*/
|
|
75
|
+
removeByValue(element) {
|
|
76
|
+
let count = 0;
|
|
77
|
+
for (const [tag, entry] of this.added) {
|
|
78
|
+
if (this.deepEquals(entry.value, element) && !this.removed.has(tag)) {
|
|
79
|
+
this.removed.add(tag);
|
|
80
|
+
count++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (count > 0) {
|
|
84
|
+
this.clock.tick();
|
|
85
|
+
}
|
|
86
|
+
return count;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Checks if a tag is in the set.
|
|
90
|
+
* @param tag - The unique tag to check
|
|
91
|
+
* @returns true if the tag exists and hasn't been removed
|
|
92
|
+
*/
|
|
93
|
+
has(tag) {
|
|
94
|
+
return this.added.has(tag) && !this.removed.has(tag);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Checks if a value exists in the set.
|
|
98
|
+
* @param element - The element value to check
|
|
99
|
+
* @returns true if the value exists
|
|
100
|
+
*/
|
|
101
|
+
hasValue(element) {
|
|
102
|
+
for (const [tag, entry] of this.added) {
|
|
103
|
+
if (this.deepEquals(entry.value, element) && !this.removed.has(tag)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Gets all tags for a given value.
|
|
111
|
+
* @param element - The element value to find tags for
|
|
112
|
+
* @returns Array of tags for the value
|
|
113
|
+
*/
|
|
114
|
+
getTags(element) {
|
|
115
|
+
const tags = [];
|
|
116
|
+
for (const [tag, entry] of this.added) {
|
|
117
|
+
if (this.deepEquals(entry.value, element) && !this.removed.has(tag)) {
|
|
118
|
+
tags.push(tag);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return tags;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Gets all current values in the set.
|
|
125
|
+
* @returns Array of all non-removed values
|
|
126
|
+
*/
|
|
127
|
+
values() {
|
|
128
|
+
const values = [];
|
|
129
|
+
for (const [tag, entry] of this.added) {
|
|
130
|
+
if (!this.removed.has(tag)) {
|
|
131
|
+
values.push(entry.value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return values;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Gets all entries (with tags) in the set.
|
|
138
|
+
* @returns Array of [tag, value] tuples
|
|
139
|
+
*/
|
|
140
|
+
entries() {
|
|
141
|
+
const entries = [];
|
|
142
|
+
for (const [tag, entry] of this.added) {
|
|
143
|
+
if (!this.removed.has(tag)) {
|
|
144
|
+
entries.push([tag, entry.value]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return entries;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Gets the number of elements in the set.
|
|
151
|
+
*/
|
|
152
|
+
get size() {
|
|
153
|
+
let count = 0;
|
|
154
|
+
for (const tag of this.added.keys()) {
|
|
155
|
+
if (!this.removed.has(tag)) {
|
|
156
|
+
count++;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return count;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Checks if the set is empty.
|
|
163
|
+
*/
|
|
164
|
+
get isEmpty() {
|
|
165
|
+
return this.size === 0;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Merges another OR-Set into this one.
|
|
169
|
+
* @param other - The set to merge
|
|
170
|
+
* @returns A new merged ORSet
|
|
171
|
+
*/
|
|
172
|
+
merge(other) {
|
|
173
|
+
const merged = new ORSet(this.nodeId);
|
|
174
|
+
// Merge clocks
|
|
175
|
+
merged.clock = this.clock.clone();
|
|
176
|
+
merged.clock.merge(other.clock);
|
|
177
|
+
// Union of added elements
|
|
178
|
+
for (const [tag, entry] of this.added) {
|
|
179
|
+
merged.added.set(tag, {
|
|
180
|
+
value: entry.value,
|
|
181
|
+
clock: entry.clock.clone(),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
for (const [tag, entry] of other.added) {
|
|
185
|
+
if (!merged.added.has(tag)) {
|
|
186
|
+
merged.added.set(tag, {
|
|
187
|
+
value: entry.value,
|
|
188
|
+
clock: entry.clock.clone(),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Union of removed tags
|
|
193
|
+
for (const tag of this.removed) {
|
|
194
|
+
merged.removed.add(tag);
|
|
195
|
+
}
|
|
196
|
+
for (const tag of other.removed) {
|
|
197
|
+
merged.removed.add(tag);
|
|
198
|
+
}
|
|
199
|
+
return merged;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Clears all elements from the set.
|
|
203
|
+
*/
|
|
204
|
+
clear() {
|
|
205
|
+
for (const tag of this.added.keys()) {
|
|
206
|
+
this.removed.add(tag);
|
|
207
|
+
}
|
|
208
|
+
this.clock.tick();
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Creates a copy of this set.
|
|
212
|
+
* @returns A new ORSet with the same state
|
|
213
|
+
*/
|
|
214
|
+
clone() {
|
|
215
|
+
const cloned = new ORSet(this.nodeId);
|
|
216
|
+
cloned.clock = this.clock.clone();
|
|
217
|
+
for (const [tag, entry] of this.added) {
|
|
218
|
+
cloned.added.set(tag, {
|
|
219
|
+
value: entry.value,
|
|
220
|
+
clock: entry.clock.clone(),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
for (const tag of this.removed) {
|
|
224
|
+
cloned.removed.add(tag);
|
|
225
|
+
}
|
|
226
|
+
return cloned;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Serializes the set to a plain object.
|
|
230
|
+
* @returns A serializable representation
|
|
231
|
+
*/
|
|
232
|
+
toData() {
|
|
233
|
+
const added = {};
|
|
234
|
+
for (const [tag, entry] of this.added) {
|
|
235
|
+
added[tag] = {
|
|
236
|
+
value: entry.value,
|
|
237
|
+
tag,
|
|
238
|
+
clock: entry.clock.toData(),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
nodeId: this.nodeId,
|
|
243
|
+
added,
|
|
244
|
+
removed: Array.from(this.removed),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Deserializes a set from serialized data.
|
|
249
|
+
* @param data - The serialized set data
|
|
250
|
+
* @returns A new ORSet instance
|
|
251
|
+
*/
|
|
252
|
+
static fromData(data) {
|
|
253
|
+
const set = new ORSet(data.nodeId);
|
|
254
|
+
for (const [tag, entry] of Object.entries(data.added)) {
|
|
255
|
+
set.added.set(tag, {
|
|
256
|
+
value: entry.value,
|
|
257
|
+
clock: VectorClock.fromData(entry.clock, data.nodeId),
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
for (const tag of data.removed) {
|
|
261
|
+
set.removed.add(tag);
|
|
262
|
+
}
|
|
263
|
+
return set;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Creates a new OR-Set with a generated node ID.
|
|
267
|
+
* @returns A new ORSet with a UUID node ID
|
|
268
|
+
*/
|
|
269
|
+
static create() {
|
|
270
|
+
return new ORSet(randomUUID());
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Deep equality check for complex objects.
|
|
274
|
+
*/
|
|
275
|
+
deepEquals(a, b) {
|
|
276
|
+
if (a === b)
|
|
277
|
+
return true;
|
|
278
|
+
if (typeof a !== typeof b)
|
|
279
|
+
return false;
|
|
280
|
+
if (typeof a !== 'object' || a === null)
|
|
281
|
+
return false;
|
|
282
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Returns a string representation for debugging.
|
|
286
|
+
*/
|
|
287
|
+
toString() {
|
|
288
|
+
const values = this.values();
|
|
289
|
+
return `ORSet(size=${this.size}, values=[${values.map((v) => JSON.stringify(v)).join(', ')}])`;
|
|
290
|
+
}
|
|
291
|
+
}
|