@swal/edge-mesh 0.0.0-stage → 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 +128 -0
- package/NOTICE +37 -0
- package/README.md +470 -2
- package/dist/adapters/gpu-agent/index.d.ts +61 -0
- package/dist/adapters/gpu-agent/index.d.ts.map +1 -0
- package/dist/adapters/gpu-agent/index.js +364 -0
- package/dist/adapters/gpu-agent/index.js.map +1 -0
- package/dist/adapters/maloca-salud/citas-distribuidas.d.ts +19 -0
- package/dist/adapters/maloca-salud/citas-distribuidas.d.ts.map +1 -0
- package/dist/adapters/maloca-salud/citas-distribuidas.js +51 -0
- package/dist/adapters/maloca-salud/citas-distribuidas.js.map +1 -0
- package/dist/adapters/maloca-salud/eps-bridge.d.ts +15 -0
- package/dist/adapters/maloca-salud/eps-bridge.d.ts.map +1 -0
- package/dist/adapters/maloca-salud/eps-bridge.js +27 -0
- package/dist/adapters/maloca-salud/eps-bridge.js.map +1 -0
- package/dist/adapters/maloca-salud/patient-profile.d.ts +20 -0
- package/dist/adapters/maloca-salud/patient-profile.d.ts.map +1 -0
- package/dist/adapters/maloca-salud/patient-profile.js +36 -0
- package/dist/adapters/maloca-salud/patient-profile.js.map +1 -0
- package/dist/adapters/maloca-salud/types.d.ts +40 -0
- package/dist/adapters/maloca-salud/types.d.ts.map +1 -0
- package/dist/adapters/maloca-salud/types.js +2 -0
- package/dist/adapters/maloca-salud/types.js.map +1 -0
- package/dist/adapters/maloca-veeduria/contract-bridge.d.ts +31 -0
- package/dist/adapters/maloca-veeduria/contract-bridge.d.ts.map +1 -0
- package/dist/adapters/maloca-veeduria/contract-bridge.js +103 -0
- package/dist/adapters/maloca-veeduria/contract-bridge.js.map +1 -0
- package/dist/adapters/maloca-veeduria/evidentia-veeduria.d.ts +14 -0
- package/dist/adapters/maloca-veeduria/evidentia-veeduria.d.ts.map +1 -0
- package/dist/adapters/maloca-veeduria/evidentia-veeduria.js +40 -0
- package/dist/adapters/maloca-veeduria/evidentia-veeduria.js.map +1 -0
- package/dist/adapters/maloca-veeduria/licitante-profile.d.ts +21 -0
- package/dist/adapters/maloca-veeduria/licitante-profile.d.ts.map +1 -0
- package/dist/adapters/maloca-veeduria/licitante-profile.js +58 -0
- package/dist/adapters/maloca-veeduria/licitante-profile.js.map +1 -0
- package/dist/adapters/maloca-veeduria/types.d.ts +30 -0
- package/dist/adapters/maloca-veeduria/types.d.ts.map +1 -0
- package/dist/adapters/maloca-veeduria/types.js +2 -0
- package/dist/adapters/maloca-veeduria/types.js.map +1 -0
- package/dist/adapters/maloca-xavier/agent-profile.d.ts +32 -0
- package/dist/adapters/maloca-xavier/agent-profile.d.ts.map +1 -0
- package/dist/adapters/maloca-xavier/agent-profile.js +56 -0
- package/dist/adapters/maloca-xavier/agent-profile.js.map +1 -0
- package/dist/adapters/maloca-xavier/codegraph-bridge.d.ts +27 -0
- package/dist/adapters/maloca-xavier/codegraph-bridge.d.ts.map +1 -0
- package/dist/adapters/maloca-xavier/codegraph-bridge.js +58 -0
- package/dist/adapters/maloca-xavier/codegraph-bridge.js.map +1 -0
- package/dist/adapters/maloca-xavier/llm-router.d.ts +25 -0
- package/dist/adapters/maloca-xavier/llm-router.d.ts.map +1 -0
- package/dist/adapters/maloca-xavier/llm-router.js +58 -0
- package/dist/adapters/maloca-xavier/llm-router.js.map +1 -0
- package/dist/authz/index.d.ts +81 -0
- package/dist/authz/index.d.ts.map +1 -0
- package/dist/authz/index.js +271 -0
- package/dist/authz/index.js.map +1 -0
- package/dist/chat/index.d.ts +138 -0
- package/dist/chat/index.d.ts.map +1 -0
- package/dist/chat/index.js +394 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/offline-queue.d.ts +32 -0
- package/dist/chat/offline-queue.d.ts.map +1 -0
- package/dist/chat/offline-queue.js +93 -0
- package/dist/chat/offline-queue.js.map +1 -0
- package/dist/core/DefaultEdgeMeshNode.d.ts +17 -0
- package/dist/core/DefaultEdgeMeshNode.d.ts.map +1 -0
- package/dist/core/DefaultEdgeMeshNode.js +57 -0
- package/dist/core/DefaultEdgeMeshNode.js.map +1 -0
- package/dist/core/node.d.ts +26 -0
- package/dist/core/node.d.ts.map +1 -0
- package/dist/core/node.js +16 -0
- package/dist/core/node.js.map +1 -0
- package/dist/edge-mesh.d.ts +139 -0
- package/dist/edge-mesh.d.ts.map +1 -0
- package/dist/edge-mesh.js +1146 -0
- package/dist/edge-mesh.js.map +1 -0
- package/dist/gos/GosBridge.d.ts +49 -0
- package/dist/gos/GosBridge.d.ts.map +1 -0
- package/dist/gos/GosBridge.js +133 -0
- package/dist/gos/GosBridge.js.map +1 -0
- package/dist/governance/authority.d.ts +44 -0
- package/dist/governance/authority.d.ts.map +1 -0
- package/dist/governance/authority.js +123 -0
- package/dist/governance/authority.js.map +1 -0
- package/dist/governance/index.d.ts +66 -0
- package/dist/governance/index.d.ts.map +1 -0
- package/dist/governance/index.js +210 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/governance/merge.d.ts +31 -0
- package/dist/governance/merge.d.ts.map +1 -0
- package/dist/governance/merge.js +167 -0
- package/dist/governance/merge.js.map +1 -0
- package/dist/identity/index.d.ts +199 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +415 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/maloca/backoffice.d.ts +31 -0
- package/dist/maloca/backoffice.d.ts.map +1 -0
- package/dist/maloca/backoffice.js +40 -0
- package/dist/maloca/backoffice.js.map +1 -0
- package/dist/maloca/event-bus.d.ts +60 -0
- package/dist/maloca/event-bus.d.ts.map +1 -0
- package/dist/maloca/event-bus.js +175 -0
- package/dist/maloca/event-bus.js.map +1 -0
- package/dist/maloca/evidentia.d.ts +136 -0
- package/dist/maloca/evidentia.d.ts.map +1 -0
- package/dist/maloca/evidentia.js +447 -0
- package/dist/maloca/evidentia.js.map +1 -0
- package/dist/maloca/gateway/api.d.ts +146 -0
- package/dist/maloca/gateway/api.d.ts.map +1 -0
- package/dist/maloca/gateway/api.js +228 -0
- package/dist/maloca/gateway/api.js.map +1 -0
- package/dist/maloca/gateway/auth.d.ts +20 -0
- package/dist/maloca/gateway/auth.d.ts.map +1 -0
- package/dist/maloca/gateway/auth.js +115 -0
- package/dist/maloca/gateway/auth.js.map +1 -0
- package/dist/maloca/gateway/dashboard.d.ts +42 -0
- package/dist/maloca/gateway/dashboard.d.ts.map +1 -0
- package/dist/maloca/gateway/dashboard.js +67 -0
- package/dist/maloca/gateway/dashboard.js.map +1 -0
- package/dist/maloca/gateway/websocket.d.ts +34 -0
- package/dist/maloca/gateway/websocket.d.ts.map +1 -0
- package/dist/maloca/gateway/websocket.js +71 -0
- package/dist/maloca/gateway/websocket.js.map +1 -0
- package/dist/maloca/karma.d.ts +165 -0
- package/dist/maloca/karma.d.ts.map +1 -0
- package/dist/maloca/karma.js +307 -0
- package/dist/maloca/karma.js.map +1 -0
- package/dist/maloca/kernel.d.ts +20 -0
- package/dist/maloca/kernel.d.ts.map +1 -0
- package/dist/maloca/kernel.js +76 -0
- package/dist/maloca/kernel.js.map +1 -0
- package/dist/maloca/metadata.d.ts +30 -0
- package/dist/maloca/metadata.d.ts.map +1 -0
- package/dist/maloca/metadata.js +80 -0
- package/dist/maloca/metadata.js.map +1 -0
- package/dist/maloca/perfil.d.ts +57 -0
- package/dist/maloca/perfil.d.ts.map +1 -0
- package/dist/maloca/perfil.js +113 -0
- package/dist/maloca/perfil.js.map +1 -0
- package/dist/maloca/plugin-registry.d.ts +27 -0
- package/dist/maloca/plugin-registry.d.ts.map +1 -0
- package/dist/maloca/plugin-registry.js +76 -0
- package/dist/maloca/plugin-registry.js.map +1 -0
- package/dist/maloca/polygon-bridge.d.ts +63 -0
- package/dist/maloca/polygon-bridge.d.ts.map +1 -0
- package/dist/maloca/polygon-bridge.js +198 -0
- package/dist/maloca/polygon-bridge.js.map +1 -0
- package/dist/maloca/types.d.ts +44 -0
- package/dist/maloca/types.d.ts.map +1 -0
- package/dist/maloca/types.js +2 -0
- package/dist/maloca/types.js.map +1 -0
- package/dist/medico/aval.d.ts +149 -0
- package/dist/medico/aval.d.ts.map +1 -0
- package/dist/medico/aval.js +281 -0
- package/dist/medico/aval.js.map +1 -0
- package/dist/medico/canonica.d.ts +96 -0
- package/dist/medico/canonica.d.ts.map +1 -0
- package/dist/medico/canonica.js +148 -0
- package/dist/medico/canonica.js.map +1 -0
- package/dist/medico/credencial.d.ts +160 -0
- package/dist/medico/credencial.d.ts.map +1 -0
- package/dist/medico/credencial.js +240 -0
- package/dist/medico/credencial.js.map +1 -0
- package/dist/medico/index.d.ts +36 -0
- package/dist/medico/index.d.ts.map +1 -0
- package/dist/medico/index.js +39 -0
- package/dist/medico/index.js.map +1 -0
- package/dist/medico/malla.d.ts +218 -0
- package/dist/medico/malla.d.ts.map +1 -0
- package/dist/medico/malla.js +347 -0
- package/dist/medico/malla.js.map +1 -0
- package/dist/medico/registro-profesional.d.ts +84 -0
- package/dist/medico/registro-profesional.d.ts.map +1 -0
- package/dist/medico/registro-profesional.js +135 -0
- package/dist/medico/registro-profesional.js.map +1 -0
- package/dist/medico/registro.d.ts +149 -0
- package/dist/medico/registro.d.ts.map +1 -0
- package/dist/medico/registro.js +173 -0
- package/dist/medico/registro.js.map +1 -0
- package/dist/medico/types.d.ts +287 -0
- package/dist/medico/types.d.ts.map +1 -0
- package/dist/medico/types.js +135 -0
- package/dist/medico/types.js.map +1 -0
- package/dist/medico/verificacion-registro.d.ts +300 -0
- package/dist/medico/verificacion-registro.d.ts.map +1 -0
- package/dist/medico/verificacion-registro.js +319 -0
- package/dist/medico/verificacion-registro.js.map +1 -0
- package/dist/mesh/index.d.ts +457 -0
- package/dist/mesh/index.d.ts.map +1 -0
- package/dist/mesh/index.js +929 -0
- package/dist/mesh/index.js.map +1 -0
- package/dist/namespaces/encrypted-plugin.d.ts +56 -0
- package/dist/namespaces/encrypted-plugin.d.ts.map +1 -0
- package/dist/namespaces/encrypted-plugin.js +173 -0
- package/dist/namespaces/encrypted-plugin.js.map +1 -0
- package/dist/namespaces/index.d.ts +52 -0
- package/dist/namespaces/index.d.ts.map +1 -0
- package/dist/namespaces/index.js +134 -0
- package/dist/namespaces/index.js.map +1 -0
- package/dist/namespaces/ivn-proofs.d.ts +54 -0
- package/dist/namespaces/ivn-proofs.d.ts.map +1 -0
- package/dist/namespaces/ivn-proofs.js +162 -0
- package/dist/namespaces/ivn-proofs.js.map +1 -0
- package/dist/namespaces/offers-gossip.d.ts +95 -0
- package/dist/namespaces/offers-gossip.d.ts.map +1 -0
- package/dist/namespaces/offers-gossip.js +213 -0
- package/dist/namespaces/offers-gossip.js.map +1 -0
- package/dist/node-memory/idb-store.d.ts +22 -0
- package/dist/node-memory/idb-store.d.ts.map +1 -0
- package/dist/node-memory/idb-store.js +154 -0
- package/dist/node-memory/idb-store.js.map +1 -0
- package/dist/node-memory/index.d.ts +14 -0
- package/dist/node-memory/index.d.ts.map +1 -0
- package/dist/node-memory/index.js +159 -0
- package/dist/node-memory/index.js.map +1 -0
- package/dist/node-memory/sync-flush.d.ts +11 -0
- package/dist/node-memory/sync-flush.d.ts.map +1 -0
- package/dist/node-memory/sync-flush.js +37 -0
- package/dist/node-memory/sync-flush.js.map +1 -0
- package/dist/node-memory/types.d.ts +34 -0
- package/dist/node-memory/types.d.ts.map +1 -0
- package/dist/node-memory/types.js +2 -0
- package/dist/node-memory/types.js.map +1 -0
- package/dist/node-memory/xavier-store.d.ts +12 -0
- package/dist/node-memory/xavier-store.d.ts.map +1 -0
- package/dist/node-memory/xavier-store.js +75 -0
- package/dist/node-memory/xavier-store.js.map +1 -0
- package/dist/op-log/index.d.ts +49 -0
- package/dist/op-log/index.d.ts.map +1 -0
- package/dist/op-log/index.js +190 -0
- package/dist/op-log/index.js.map +1 -0
- package/dist/presence/health.d.ts +54 -0
- package/dist/presence/health.d.ts.map +1 -0
- package/dist/presence/health.js +139 -0
- package/dist/presence/health.js.map +1 -0
- package/dist/presence/index.d.ts +85 -0
- package/dist/presence/index.d.ts.map +1 -0
- package/dist/presence/index.js +255 -0
- package/dist/presence/index.js.map +1 -0
- package/dist/presence/peer-health.d.ts +40 -0
- package/dist/presence/peer-health.d.ts.map +1 -0
- package/dist/presence/peer-health.js +118 -0
- package/dist/presence/peer-health.js.map +1 -0
- package/dist/protocol/canonical.d.ts +10 -0
- package/dist/protocol/canonical.d.ts.map +1 -0
- package/dist/protocol/canonical.js +32 -0
- package/dist/protocol/canonical.js.map +1 -0
- package/dist/protocol/crypto.d.ts +299 -0
- package/dist/protocol/crypto.d.ts.map +1 -0
- package/dist/protocol/crypto.js +739 -0
- package/dist/protocol/crypto.js.map +1 -0
- package/dist/protocol/index.d.ts +30 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +116 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/utils.d.ts +5 -0
- package/dist/protocol/utils.d.ts.map +1 -0
- package/dist/protocol/utils.js +27 -0
- package/dist/protocol/utils.js.map +1 -0
- package/dist/salones/manager.d.ts +100 -0
- package/dist/salones/manager.d.ts.map +1 -0
- package/dist/salones/manager.js +240 -0
- package/dist/salones/manager.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +13 -0
- package/dist/security/rate-limiter.d.ts.map +1 -0
- package/dist/security/rate-limiter.js +32 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/snapshot/index.d.ts +90 -0
- package/dist/snapshot/index.d.ts.map +1 -0
- package/dist/snapshot/index.js +189 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/storage/index.d.ts +49 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +176 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/optimizer.d.ts +28 -0
- package/dist/storage/optimizer.d.ts.map +1 -0
- package/dist/storage/optimizer.js +50 -0
- package/dist/storage/optimizer.js.map +1 -0
- package/dist/storage/ydoc-persistence.d.ts +27 -0
- package/dist/storage/ydoc-persistence.d.ts.map +1 -0
- package/dist/storage/ydoc-persistence.js +128 -0
- package/dist/storage/ydoc-persistence.js.map +1 -0
- package/dist/sync/ChunkSyncManager.d.ts +41 -0
- package/dist/sync/ChunkSyncManager.d.ts.map +1 -0
- package/dist/sync/ChunkSyncManager.js +115 -0
- package/dist/sync/ChunkSyncManager.js.map +1 -0
- package/dist/sync/conflict-resolver.d.ts +33 -0
- package/dist/sync/conflict-resolver.d.ts.map +1 -0
- package/dist/sync/conflict-resolver.js +54 -0
- package/dist/sync/conflict-resolver.js.map +1 -0
- package/dist/sync/engine.d.ts +168 -0
- package/dist/sync/engine.d.ts.map +1 -0
- package/dist/sync/engine.js +315 -0
- package/dist/sync/engine.js.map +1 -0
- package/dist/sync/index.d.ts +3 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/transport/TorTransportAdapter.d.ts +70 -0
- package/dist/transport/TorTransportAdapter.d.ts.map +1 -0
- package/dist/transport/TorTransportAdapter.js +192 -0
- package/dist/transport/TorTransportAdapter.js.map +1 -0
- package/dist/transport/memory.d.ts +31 -0
- package/dist/transport/memory.d.ts.map +1 -0
- package/dist/transport/memory.js +114 -0
- package/dist/transport/memory.js.map +1 -0
- package/dist/transport/peerjs.d.ts +45 -0
- package/dist/transport/peerjs.d.ts.map +1 -0
- package/dist/transport/peerjs.js +301 -0
- package/dist/transport/peerjs.js.map +1 -0
- package/dist/transport/pqc-handshake.d.ts +72 -0
- package/dist/transport/pqc-handshake.d.ts.map +1 -0
- package/dist/transport/pqc-handshake.js +129 -0
- package/dist/transport/pqc-handshake.js.map +1 -0
- package/dist/transport/relay-config.d.ts +11 -0
- package/dist/transport/relay-config.d.ts.map +1 -0
- package/dist/transport/relay-config.js +48 -0
- package/dist/transport/relay-config.js.map +1 -0
- package/dist/transport/relay-server.d.ts +37 -0
- package/dist/transport/relay-server.d.ts.map +1 -0
- package/dist/transport/relay-server.js +230 -0
- package/dist/transport/relay-server.js.map +1 -0
- package/dist/transport/tor.d.ts +47 -0
- package/dist/transport/tor.d.ts.map +1 -0
- package/dist/transport/tor.js +158 -0
- package/dist/transport/tor.js.map +1 -0
- package/dist/transport/types.d.ts +34 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +2 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/types/index.d.ts +293 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +73 -0
- package/dist/types/index.js.map +1 -0
- package/dist/web/admission.d.ts +24 -0
- package/dist/web/admission.d.ts.map +1 -0
- package/dist/web/admission.js +41 -0
- package/dist/web/admission.js.map +1 -0
- package/dist/web/crypto.d.ts +18 -0
- package/dist/web/crypto.d.ts.map +1 -0
- package/dist/web/crypto.js +78 -0
- package/dist/web/crypto.js.map +1 -0
- package/dist/web/exchange.d.ts +23 -0
- package/dist/web/exchange.d.ts.map +1 -0
- package/dist/web/exchange.js +54 -0
- package/dist/web/exchange.js.map +1 -0
- package/dist/web/fragment.d.ts +58 -0
- package/dist/web/fragment.d.ts.map +1 -0
- package/dist/web/fragment.js +198 -0
- package/dist/web/fragment.js.map +1 -0
- package/dist/web/index.d.ts +25 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +14 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/merge/index.d.ts +104 -0
- package/dist/web/merge/index.d.ts.map +1 -0
- package/dist/web/merge/index.js +236 -0
- package/dist/web/merge/index.js.map +1 -0
- package/dist/web/oplog/hlc.d.ts +19 -0
- package/dist/web/oplog/hlc.d.ts.map +1 -0
- package/dist/web/oplog/hlc.js +39 -0
- package/dist/web/oplog/hlc.js.map +1 -0
- package/dist/web/oplog/index.d.ts +10 -0
- package/dist/web/oplog/index.d.ts.map +1 -0
- package/dist/web/oplog/index.js +6 -0
- package/dist/web/oplog/index.js.map +1 -0
- package/dist/web/oplog/log.d.ts +182 -0
- package/dist/web/oplog/log.d.ts.map +1 -0
- package/dist/web/oplog/log.js +693 -0
- package/dist/web/oplog/log.js.map +1 -0
- package/dist/web/oplog/store.d.ts +40 -0
- package/dist/web/oplog/store.d.ts.map +1 -0
- package/dist/web/oplog/store.js +85 -0
- package/dist/web/oplog/store.js.map +1 -0
- package/dist/web/oplog/sync.d.ts +54 -0
- package/dist/web/oplog/sync.d.ts.map +1 -0
- package/dist/web/oplog/sync.js +162 -0
- package/dist/web/oplog/sync.js.map +1 -0
- package/dist/web/oplog/types.d.ts +119 -0
- package/dist/web/oplog/types.d.ts.map +1 -0
- package/dist/web/oplog/types.js +2 -0
- package/dist/web/oplog/types.js.map +1 -0
- package/dist/web/pairing.d.ts +186 -0
- package/dist/web/pairing.d.ts.map +1 -0
- package/dist/web/pairing.js +395 -0
- package/dist/web/pairing.js.map +1 -0
- package/dist/web/pq.d.ts +36 -0
- package/dist/web/pq.d.ts.map +1 -0
- package/dist/web/pq.js +59 -0
- package/dist/web/pq.js.map +1 -0
- package/dist/web/provider.d.ts +188 -0
- package/dist/web/provider.d.ts.map +1 -0
- package/dist/web/provider.js +2042 -0
- package/dist/web/provider.js.map +1 -0
- package/dist/web/rooms.d.ts +20 -0
- package/dist/web/rooms.d.ts.map +1 -0
- package/dist/web/rooms.js +51 -0
- package/dist/web/rooms.js.map +1 -0
- package/dist/web/rotation.d.ts +73 -0
- package/dist/web/rotation.d.ts.map +1 -0
- package/dist/web/rotation.js +130 -0
- package/dist/web/rotation.js.map +1 -0
- package/dist/web/secstate.d.ts +213 -0
- package/dist/web/secstate.d.ts.map +1 -0
- package/dist/web/secstate.js +789 -0
- package/dist/web/secstate.js.map +1 -0
- package/dist/web/store.d.ts +9 -0
- package/dist/web/store.d.ts.map +1 -0
- package/dist/web/store.js +32 -0
- package/dist/web/store.js.map +1 -0
- package/dist/web/transports/loopback.d.ts +11 -0
- package/dist/web/transports/loopback.d.ts.map +1 -0
- package/dist/web/transports/loopback.js +97 -0
- package/dist/web/transports/loopback.js.map +1 -0
- package/dist/web/transports/qr-sdp.d.ts +27 -0
- package/dist/web/transports/qr-sdp.d.ts.map +1 -0
- package/dist/web/transports/qr-sdp.js +131 -0
- package/dist/web/transports/qr-sdp.js.map +1 -0
- package/dist/web/transports/ws.d.ts +12 -0
- package/dist/web/transports/ws.d.ts.map +1 -0
- package/dist/web/transports/ws.js +139 -0
- package/dist/web/transports/ws.js.map +1 -0
- package/dist/web/trust/canonical.d.ts +8 -0
- package/dist/web/trust/canonical.d.ts.map +1 -0
- package/dist/web/trust/canonical.js +27 -0
- package/dist/web/trust/canonical.js.map +1 -0
- package/dist/web/trust/docs.d.ts +51 -0
- package/dist/web/trust/docs.d.ts.map +1 -0
- package/dist/web/trust/docs.js +170 -0
- package/dist/web/trust/docs.js.map +1 -0
- package/dist/web/trust/index.d.ts +10 -0
- package/dist/web/trust/index.d.ts.map +1 -0
- package/dist/web/trust/index.js +7 -0
- package/dist/web/trust/index.js.map +1 -0
- package/dist/web/trust/keys.d.ts +37 -0
- package/dist/web/trust/keys.d.ts.map +1 -0
- package/dist/web/trust/keys.js +75 -0
- package/dist/web/trust/keys.js.map +1 -0
- package/dist/web/trust/store.d.ts +150 -0
- package/dist/web/trust/store.d.ts.map +1 -0
- package/dist/web/trust/store.js +587 -0
- package/dist/web/trust/store.js.map +1 -0
- package/dist/web/trust/types.d.ts +134 -0
- package/dist/web/trust/types.d.ts.map +1 -0
- package/dist/web/trust/types.js +4 -0
- package/dist/web/trust/types.js.map +1 -0
- package/dist/web/types.d.ts +115 -0
- package/dist/web/types.d.ts.map +1 -0
- package/dist/web/types.js +2 -0
- package/dist/web/types.js.map +1 -0
- package/dist/web/util.d.ts +12 -0
- package/dist/web/util.d.ts.map +1 -0
- package/dist/web/util.js +54 -0
- package/dist/web/util.js.map +1 -0
- package/dist/web/webrtc.d.ts +35 -0
- package/dist/web/webrtc.d.ts.map +1 -0
- package/dist/web/webrtc.js +304 -0
- package/dist/web/webrtc.js.map +1 -0
- package/package.json +138 -4
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { compress, decompress, init } from "@bokuweb/zstd-wasm";
|
|
2
|
+
import { decode, encode } from "cbor-x";
|
|
3
|
+
let isZstdInitialized = false;
|
|
4
|
+
/**
|
|
5
|
+
* Initializes the WASM module for Zstd.
|
|
6
|
+
* Must be called once before compressing or decompressing.
|
|
7
|
+
*/
|
|
8
|
+
export async function initializeOptimizer() {
|
|
9
|
+
if (!isZstdInitialized) {
|
|
10
|
+
await init();
|
|
11
|
+
isZstdInitialized = true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Utility class to compress large payloads before storing them in local databases (IndexedDB/OPFS)
|
|
16
|
+
* or broadcasting them across the P2P network.
|
|
17
|
+
*
|
|
18
|
+
* It serializes objects to CBOR (Concise Binary Object Representation) and then compresses
|
|
19
|
+
* the binary stream using Zstandard (Zstd), significantly reducing the required space.
|
|
20
|
+
*/
|
|
21
|
+
export class PayloadOptimizer {
|
|
22
|
+
/**
|
|
23
|
+
* Serializes an object to CBOR and compresses it with Zstd.
|
|
24
|
+
* @param payload Any serializable JavaScript object.
|
|
25
|
+
* @param level Compression level (default 10).
|
|
26
|
+
* @returns A Uint8Array containing the compressed binary data.
|
|
27
|
+
*/
|
|
28
|
+
static async compressPayload(payload, level = 10) {
|
|
29
|
+
await initializeOptimizer();
|
|
30
|
+
// 1. Serialize to CBOR
|
|
31
|
+
const cborBuffer = encode(payload);
|
|
32
|
+
// 2. Compress with Zstd
|
|
33
|
+
const compressed = compress(new Uint8Array(cborBuffer), level);
|
|
34
|
+
return compressed;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Decompresses Zstd data and deserializes it from CBOR back to the original object.
|
|
38
|
+
* @param buffer The compressed binary data (Uint8Array).
|
|
39
|
+
* @returns The original parsed object.
|
|
40
|
+
*/
|
|
41
|
+
static async decompressPayload(buffer) {
|
|
42
|
+
await initializeOptimizer();
|
|
43
|
+
// 1. Decompress from Zstd
|
|
44
|
+
const decompressed = decompress(buffer);
|
|
45
|
+
// 2. Deserialize from CBOR
|
|
46
|
+
const payload = decode(decompressed);
|
|
47
|
+
return payload;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=optimizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimizer.js","sourceRoot":"","sources":["../../src/storage/optimizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACxC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACxB,MAAM,IAAI,EAAE,CAAC;QACb,iBAAiB,GAAG,IAAI,CAAC;IAC1B,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IAC5B;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,eAAe,CAC3B,OAAU,EACV,KAAK,GAAW,EAAE;QAElB,MAAM,mBAAmB,EAAE,CAAC;QAE5B,uBAAuB;QACvB,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnC,wBAAwB;QACxB,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;QAE/D,OAAO,UAAU,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAI,MAAkB;QACnD,MAAM,mBAAmB,EAAE,CAAC;QAE5B,0BAA0B;QAC1B,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAExC,2BAA2B;QAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAM,CAAC;QAE1C,OAAO,OAAO,CAAC;IAChB,CAAC;CACD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import type { IStorage } from "./index.js";
|
|
3
|
+
export interface YDocPersistenceOptions {
|
|
4
|
+
/** Maximum number of incremental updates to keep before compaction. Default is 100. */
|
|
5
|
+
readonly maxUpdatesBeforeCompaction?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class YDocPersistence {
|
|
8
|
+
private readonly docName;
|
|
9
|
+
private readonly doc;
|
|
10
|
+
private readonly storage;
|
|
11
|
+
private readonly updateHandler;
|
|
12
|
+
private readonly maxUpdatesBeforeCompaction;
|
|
13
|
+
private updateCount;
|
|
14
|
+
/** Promise that resolves when the document is fully loaded and rehydrated from storage. */
|
|
15
|
+
readonly whenLoaded: Promise<void>;
|
|
16
|
+
constructor(docName: string, doc: Y.Doc, storage: IStorage, options?: YDocPersistenceOptions);
|
|
17
|
+
private load;
|
|
18
|
+
private toUint8Array;
|
|
19
|
+
private storeUpdate;
|
|
20
|
+
/**
|
|
21
|
+
* Compacts the incremental updates of the document into a single snapshot/update
|
|
22
|
+
* and clears previous individual incremental updates to save storage.
|
|
23
|
+
*/
|
|
24
|
+
compact(): Promise<void>;
|
|
25
|
+
destroy(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=ydoc-persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ydoc-persistence.d.ts","sourceRoot":"","sources":["../../src/storage/ydoc-persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,sBAAsB;IACtC,uFAAuF;IACvF,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;CAC7C;AAED,qBAAa,eAAe;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgD;IAC9E,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAS;IACpD,OAAO,CAAC,WAAW,CAAK;IAExB,2FAA2F;IAC3F,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC,YACC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,OAAO,EAAE,QAAQ,EACjB,OAAO,GAAE,sBAA2B,EAepC;YAEa,IAAI;IAwDlB,OAAO,CAAC,YAAY;YAgBN,WAAW;IAczB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CA4B7B;IAED,OAAO,IAAI,IAAI,CAEd;CACD"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
export class YDocPersistence {
|
|
3
|
+
docName;
|
|
4
|
+
doc;
|
|
5
|
+
storage;
|
|
6
|
+
updateHandler;
|
|
7
|
+
maxUpdatesBeforeCompaction;
|
|
8
|
+
updateCount = 0;
|
|
9
|
+
/** Promise that resolves when the document is fully loaded and rehydrated from storage. */
|
|
10
|
+
whenLoaded;
|
|
11
|
+
constructor(docName, doc, storage, options = {}) {
|
|
12
|
+
this.docName = docName;
|
|
13
|
+
this.doc = doc;
|
|
14
|
+
this.storage = storage;
|
|
15
|
+
this.maxUpdatesBeforeCompaction = options.maxUpdatesBeforeCompaction ?? 100;
|
|
16
|
+
this.updateHandler = (update, origin) => {
|
|
17
|
+
// Avoid saving updates that came from the persistence provider itself during rehydration.
|
|
18
|
+
if (origin === this)
|
|
19
|
+
return;
|
|
20
|
+
void this.storeUpdate(update);
|
|
21
|
+
};
|
|
22
|
+
this.doc.on("update", this.updateHandler);
|
|
23
|
+
this.whenLoaded = this.load();
|
|
24
|
+
}
|
|
25
|
+
async load() {
|
|
26
|
+
try {
|
|
27
|
+
// 1. Retrieve compaction records (if any)
|
|
28
|
+
const compacts = await this.storage.list({
|
|
29
|
+
prefijo: `ydoc:${this.docName}:compact:`,
|
|
30
|
+
});
|
|
31
|
+
let latestCompactTimestamp = 0;
|
|
32
|
+
let compactValue = null;
|
|
33
|
+
if (compacts.length > 0) {
|
|
34
|
+
// Since list returns entries sorted by timestamp, the last one is the latest
|
|
35
|
+
const latestCompact = compacts[compacts.length - 1];
|
|
36
|
+
latestCompactTimestamp = latestCompact.timestamp;
|
|
37
|
+
// Recover the compact value
|
|
38
|
+
if (latestCompact.valor) {
|
|
39
|
+
compactValue = this.toUint8Array(latestCompact.valor);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 2. Retrieve incremental updates
|
|
43
|
+
const updates = await this.storage.list({
|
|
44
|
+
prefijo: `ydoc:${this.docName}:update:`,
|
|
45
|
+
});
|
|
46
|
+
// Filter updates to apply only those that were saved after the latest compaction (or all if no compaction)
|
|
47
|
+
const updatesToApply = updates.filter((entry) => entry.timestamp >= latestCompactTimestamp);
|
|
48
|
+
this.updateCount = updatesToApply.length;
|
|
49
|
+
// 3. Apply updates transactionally with `this` origin to avoid echoing/double saving
|
|
50
|
+
this.doc.transact(() => {
|
|
51
|
+
if (compactValue && compactValue.length > 0) {
|
|
52
|
+
Y.applyUpdate(this.doc, compactValue);
|
|
53
|
+
}
|
|
54
|
+
for (const entry of updatesToApply) {
|
|
55
|
+
if (entry.valor) {
|
|
56
|
+
const updateBytes = this.toUint8Array(entry.valor);
|
|
57
|
+
if (updateBytes.length > 0) {
|
|
58
|
+
Y.applyUpdate(this.doc, updateBytes);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}, this);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error(`[YDocPersistence] Error loading Y.Doc "${this.docName}":`, error);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
toUint8Array(valor) {
|
|
70
|
+
if (valor instanceof Uint8Array) {
|
|
71
|
+
return valor;
|
|
72
|
+
}
|
|
73
|
+
if (Array.isArray(valor)) {
|
|
74
|
+
return new Uint8Array(valor);
|
|
75
|
+
}
|
|
76
|
+
if (typeof valor === "object" && valor !== null && "data" in valor) {
|
|
77
|
+
const arr = valor.data;
|
|
78
|
+
if (Array.isArray(arr)) {
|
|
79
|
+
return new Uint8Array(arr);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
throw new Error("Unsupported serialized update format");
|
|
83
|
+
}
|
|
84
|
+
async storeUpdate(update) {
|
|
85
|
+
const timestamp = Date.now();
|
|
86
|
+
const id = Math.random().toString(36).substring(2, 9);
|
|
87
|
+
const key = `ydoc:${this.docName}:update:${timestamp}:${id}`;
|
|
88
|
+
// Convert Uint8Array to Array to ensure compatibility with all serialization adapters
|
|
89
|
+
await this.storage.set(key, Array.from(update));
|
|
90
|
+
this.updateCount++;
|
|
91
|
+
if (this.updateCount >= this.maxUpdatesBeforeCompaction) {
|
|
92
|
+
void this.compact();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Compacts the incremental updates of the document into a single snapshot/update
|
|
97
|
+
* and clears previous individual incremental updates to save storage.
|
|
98
|
+
*/
|
|
99
|
+
async compact() {
|
|
100
|
+
await this.whenLoaded;
|
|
101
|
+
const state = Y.encodeStateAsUpdate(this.doc);
|
|
102
|
+
const timestamp = Date.now();
|
|
103
|
+
const compactKey = `ydoc:${this.docName}:compact:${timestamp}`;
|
|
104
|
+
await this.storage.set(compactKey, Array.from(state));
|
|
105
|
+
this.updateCount = 0;
|
|
106
|
+
// Clean up previous updates and compact records
|
|
107
|
+
const updates = await this.storage.list({
|
|
108
|
+
prefijo: `ydoc:${this.docName}:update:`,
|
|
109
|
+
});
|
|
110
|
+
const compacts = await this.storage.list({
|
|
111
|
+
prefijo: `ydoc:${this.docName}:compact:`,
|
|
112
|
+
});
|
|
113
|
+
for (const entry of updates) {
|
|
114
|
+
if (entry.timestamp < timestamp) {
|
|
115
|
+
await this.storage.delete(entry.key);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const entry of compacts) {
|
|
119
|
+
if (entry.timestamp < timestamp) {
|
|
120
|
+
await this.storage.delete(entry.key);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
destroy() {
|
|
125
|
+
this.doc.off("update", this.updateHandler);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=ydoc-persistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ydoc-persistence.js","sourceRoot":"","sources":["../../src/storage/ydoc-persistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { NodoId } from "../types/index.js";
|
|
2
|
+
export interface SyncChunk<T = unknown> {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly docId: string;
|
|
5
|
+
readonly payload: T;
|
|
6
|
+
readonly lamportTimestamp: number;
|
|
7
|
+
readonly nodeId: NodoId;
|
|
8
|
+
readonly version: number;
|
|
9
|
+
readonly createdAt: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ChunkConflictResolution<T = unknown> {
|
|
12
|
+
readonly winner: SyncChunk<T>;
|
|
13
|
+
readonly loser: SyncChunk<T>;
|
|
14
|
+
readonly resolutionStrategy: "lamport" | "node_tiebreak" | "manual";
|
|
15
|
+
}
|
|
16
|
+
export interface ChunkSyncConfig {
|
|
17
|
+
readonly nodeId: NodoId;
|
|
18
|
+
readonly maxRetries?: number;
|
|
19
|
+
readonly retryDelayMs?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare class ChunkSyncManager<T = unknown> {
|
|
22
|
+
readonly nodeId: NodoId;
|
|
23
|
+
private currentLamport;
|
|
24
|
+
private readonly chunks;
|
|
25
|
+
private readonly retryQueue;
|
|
26
|
+
private readonly maxRetries;
|
|
27
|
+
private readonly retryDelayMs;
|
|
28
|
+
constructor(config: ChunkSyncConfig);
|
|
29
|
+
getLamportTimestamp(): number;
|
|
30
|
+
tick(): number;
|
|
31
|
+
createChunk(docId: string, payload: T): SyncChunk<T>;
|
|
32
|
+
receiveChunk(incoming: SyncChunk<T>): {
|
|
33
|
+
accepted: boolean;
|
|
34
|
+
resolution?: ChunkConflictResolution<T>;
|
|
35
|
+
};
|
|
36
|
+
getChunk(docId: string): SyncChunk<T> | undefined;
|
|
37
|
+
enqueueRetry(chunk: SyncChunk<T>): void;
|
|
38
|
+
getPendingRetries(): SyncChunk<T>[];
|
|
39
|
+
clearQueue(): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=ChunkSyncManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChunkSyncManager.d.ts","sourceRoot":"","sources":["../../src/sync/ChunkSyncManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,GAAG,OAAO;IACnD,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,SAAS,GAAG,eAAe,GAAG,QAAQ,CAAC;CACpE;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,gBAAgB,CAAC,CAAC,GAAG,OAAO;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAInB;IACR,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,YAAY,MAAM,EAAE,eAAe,EAIlC;IAED,mBAAmB,IAAI,MAAM,CAE5B;IAED,IAAI,IAAI,MAAM,CAGb;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAenD;IAED,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG;QACrC,QAAQ,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;KACxC,CAsDA;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAEhD;IAED,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAMtC;IAED,iBAAiB,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAWlC;IAED,UAAU,IAAI,IAAI,CAEjB;CACD"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export class ChunkSyncManager {
|
|
2
|
+
nodeId;
|
|
3
|
+
currentLamport = 0;
|
|
4
|
+
chunks = new Map();
|
|
5
|
+
retryQueue = [];
|
|
6
|
+
maxRetries;
|
|
7
|
+
retryDelayMs;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.nodeId = config.nodeId;
|
|
10
|
+
this.maxRetries = config.maxRetries ?? 3;
|
|
11
|
+
this.retryDelayMs = config.retryDelayMs ?? 1000;
|
|
12
|
+
}
|
|
13
|
+
getLamportTimestamp() {
|
|
14
|
+
return this.currentLamport;
|
|
15
|
+
}
|
|
16
|
+
tick() {
|
|
17
|
+
this.currentLamport += 1;
|
|
18
|
+
return this.currentLamport;
|
|
19
|
+
}
|
|
20
|
+
createChunk(docId, payload) {
|
|
21
|
+
const ts = this.tick();
|
|
22
|
+
const chunkId = `${docId}_${this.nodeId}_${ts}_${Date.now()}`;
|
|
23
|
+
const chunk = {
|
|
24
|
+
id: chunkId,
|
|
25
|
+
docId,
|
|
26
|
+
payload,
|
|
27
|
+
lamportTimestamp: ts,
|
|
28
|
+
nodeId: this.nodeId,
|
|
29
|
+
version: 1,
|
|
30
|
+
createdAt: Date.now(),
|
|
31
|
+
};
|
|
32
|
+
this.chunks.set(docId, chunk);
|
|
33
|
+
return chunk;
|
|
34
|
+
}
|
|
35
|
+
receiveChunk(incoming) {
|
|
36
|
+
// Advance local Lamport clock
|
|
37
|
+
this.currentLamport =
|
|
38
|
+
Math.max(this.currentLamport, incoming.lamportTimestamp) + 1;
|
|
39
|
+
const existing = this.chunks.get(incoming.docId);
|
|
40
|
+
if (!existing) {
|
|
41
|
+
this.chunks.set(incoming.docId, incoming);
|
|
42
|
+
return { accepted: true };
|
|
43
|
+
}
|
|
44
|
+
// Conflict reconciliation using Lamport timestamps
|
|
45
|
+
if (incoming.lamportTimestamp > existing.lamportTimestamp) {
|
|
46
|
+
this.chunks.set(incoming.docId, incoming);
|
|
47
|
+
return {
|
|
48
|
+
accepted: true,
|
|
49
|
+
resolution: {
|
|
50
|
+
winner: incoming,
|
|
51
|
+
loser: existing,
|
|
52
|
+
resolutionStrategy: "lamport",
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
else if (incoming.lamportTimestamp < existing.lamportTimestamp) {
|
|
57
|
+
return {
|
|
58
|
+
accepted: false,
|
|
59
|
+
resolution: {
|
|
60
|
+
winner: existing,
|
|
61
|
+
loser: incoming,
|
|
62
|
+
resolutionStrategy: "lamport",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Deterministic tie-breaker: lex compare node IDs
|
|
68
|
+
if (incoming.nodeId > existing.nodeId) {
|
|
69
|
+
this.chunks.set(incoming.docId, incoming);
|
|
70
|
+
return {
|
|
71
|
+
accepted: true,
|
|
72
|
+
resolution: {
|
|
73
|
+
winner: incoming,
|
|
74
|
+
loser: existing,
|
|
75
|
+
resolutionStrategy: "node_tiebreak",
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return {
|
|
81
|
+
accepted: false,
|
|
82
|
+
resolution: {
|
|
83
|
+
winner: existing,
|
|
84
|
+
loser: incoming,
|
|
85
|
+
resolutionStrategy: "node_tiebreak",
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
getChunk(docId) {
|
|
92
|
+
return this.chunks.get(docId);
|
|
93
|
+
}
|
|
94
|
+
enqueueRetry(chunk) {
|
|
95
|
+
this.retryQueue.push({
|
|
96
|
+
chunk,
|
|
97
|
+
attempts: 0,
|
|
98
|
+
nextRetry: Date.now() + this.retryDelayMs,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
getPendingRetries() {
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
return this.retryQueue
|
|
104
|
+
.filter((item) => item.nextRetry <= now && item.attempts < this.maxRetries)
|
|
105
|
+
.map((item) => {
|
|
106
|
+
item.attempts += 1;
|
|
107
|
+
item.nextRetry = now + this.retryDelayMs * 2 ** item.attempts;
|
|
108
|
+
return item.chunk;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
clearQueue() {
|
|
112
|
+
this.retryQueue.length = 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=ChunkSyncManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChunkSyncManager.js","sourceRoot":"","sources":["../../src/sync/ChunkSyncManager.ts"],"names":[],"mappings":"AAwBA,MAAM,OAAO,gBAAgB;IACnB,MAAM,CAAS;IAChB,cAAc,GAAW,CAAC,CAAC;IAClB,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IACzC,UAAU,GAItB,EAAE,CAAC;IACS,UAAU,CAAS;IACnB,YAAY,CAAS;IAEtC,YAAY,MAAuB;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC;IACjD,CAAC;IAED,mBAAmB;QAClB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC5B,CAAC;IAED,IAAI;QACH,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC5B,CAAC;IAED,WAAW,CAAC,KAAa,EAAE,OAAU;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,GAAG,KAAK,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC9D,MAAM,KAAK,GAAiB;YAC3B,EAAE,EAAE,OAAO;YACX,KAAK;YACL,OAAO;YACP,gBAAgB,EAAE,EAAE;YACpB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,CAAC;YACV,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACrB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,YAAY,CAAC,QAAsB;QAIlC,8BAA8B;QAC9B,IAAI,CAAC,cAAc;YAClB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAE9D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC1C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,mDAAmD;QACnD,IAAI,QAAQ,CAAC,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAC3D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC1C,OAAO;gBACN,QAAQ,EAAE,IAAI;gBACd,UAAU,EAAE;oBACX,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,QAAQ;oBACf,kBAAkB,EAAE,SAAS;iBAC7B;aACD,CAAC;QACH,CAAC;aAAM,IAAI,QAAQ,CAAC,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAClE,OAAO;gBACN,QAAQ,EAAE,KAAK;gBACf,UAAU,EAAE;oBACX,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,QAAQ;oBACf,kBAAkB,EAAE,SAAS;iBAC7B;aACD,CAAC;QACH,CAAC;aAAM,CAAC;YACP,kDAAkD;YAClD,IAAI,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACvC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAC1C,OAAO;oBACN,QAAQ,EAAE,IAAI;oBACd,UAAU,EAAE;wBACX,MAAM,EAAE,QAAQ;wBAChB,KAAK,EAAE,QAAQ;wBACf,kBAAkB,EAAE,eAAe;qBACnC;iBACD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACP,OAAO;oBACN,QAAQ,EAAE,KAAK;oBACf,UAAU,EAAE;wBACX,MAAM,EAAE,QAAQ;wBAChB,KAAK,EAAE,QAAQ;wBACf,kBAAkB,EAAE,eAAe;qBACnC;iBACD,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC;IAED,QAAQ,CAAC,KAAa;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,YAAY,CAAC,KAAmB;QAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACpB,KAAK;YACL,QAAQ,EAAE,CAAC;YACX,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,YAAY;SACzC,CAAC,CAAC;IACJ,CAAC;IAED,iBAAiB;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,UAAU;aACpB,MAAM,CACN,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAClE;aACA,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;YACnB,IAAI,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC;YAC9D,OAAO,IAAI,CAAC,KAAK,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,UAAU;QACT,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,CAAC;CACD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conflict resolver for concurrent backlog updates.
|
|
3
|
+
* Implements last-writer-wins with vector clocks.
|
|
4
|
+
*/
|
|
5
|
+
export interface VectorClock {
|
|
6
|
+
[nodeId: string]: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ConflictEntry {
|
|
9
|
+
key: string;
|
|
10
|
+
localValue: unknown;
|
|
11
|
+
remoteValue: unknown;
|
|
12
|
+
localClock: VectorClock;
|
|
13
|
+
remoteClock: VectorClock;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Compare two vector clocks.
|
|
18
|
+
* Returns: -1 if a < b, 0 if concurrent, 1 if a > b
|
|
19
|
+
*/
|
|
20
|
+
export declare function compareClocks(a: VectorClock, b: VectorClock): number;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve conflict using last-writer-wins.
|
|
23
|
+
* If concurrent, use timestamp as tiebreaker.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveConflict(local: unknown, remote: unknown, localClock: VectorClock, remoteClock: VectorClock, localTimestamp: number, remoteTimestamp: number): {
|
|
26
|
+
winner: "local" | "remote";
|
|
27
|
+
reason: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Increment vector clock for a node.
|
|
31
|
+
*/
|
|
32
|
+
export declare function incrementClock(clock: VectorClock, nodeId: string): VectorClock;
|
|
33
|
+
//# sourceMappingURL=conflict-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conflict-resolver.d.ts","sourceRoot":"","sources":["../../src/sync/conflict-resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC3B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,CAepE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,WAAW,EACvB,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,GACrB;IAAE,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAehD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,GACZ,WAAW,CAKb"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conflict resolver for concurrent backlog updates.
|
|
3
|
+
* Implements last-writer-wins with vector clocks.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Compare two vector clocks.
|
|
7
|
+
* Returns: -1 if a < b, 0 if concurrent, 1 if a > b
|
|
8
|
+
*/
|
|
9
|
+
export function compareClocks(a, b) {
|
|
10
|
+
let aGreater = false;
|
|
11
|
+
let bGreater = false;
|
|
12
|
+
const allNodes = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
13
|
+
for (const node of allNodes) {
|
|
14
|
+
const aVal = a[node] ?? 0;
|
|
15
|
+
const bVal = b[node] ?? 0;
|
|
16
|
+
if (aVal > bVal)
|
|
17
|
+
aGreater = true;
|
|
18
|
+
if (bVal > aVal)
|
|
19
|
+
bGreater = true;
|
|
20
|
+
}
|
|
21
|
+
if (aGreater && !bGreater)
|
|
22
|
+
return 1;
|
|
23
|
+
if (bGreater && !aGreater)
|
|
24
|
+
return -1;
|
|
25
|
+
return 0; // concurrent
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve conflict using last-writer-wins.
|
|
29
|
+
* If concurrent, use timestamp as tiebreaker.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveConflict(local, remote, localClock, remoteClock, localTimestamp, remoteTimestamp) {
|
|
32
|
+
const cmp = compareClocks(localClock, remoteClock);
|
|
33
|
+
if (cmp === 1) {
|
|
34
|
+
return { winner: "local", reason: "local clock dominates" };
|
|
35
|
+
}
|
|
36
|
+
if (cmp === -1) {
|
|
37
|
+
return { winner: "remote", reason: "remote clock dominates" };
|
|
38
|
+
}
|
|
39
|
+
// Concurrent — use timestamp
|
|
40
|
+
if (localTimestamp >= remoteTimestamp) {
|
|
41
|
+
return { winner: "local", reason: "concurrent, local newer" };
|
|
42
|
+
}
|
|
43
|
+
return { winner: "remote", reason: "concurrent, remote newer" };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Increment vector clock for a node.
|
|
47
|
+
*/
|
|
48
|
+
export function incrementClock(clock, nodeId) {
|
|
49
|
+
return {
|
|
50
|
+
...clock,
|
|
51
|
+
[nodeId]: (clock[nodeId] ?? 0) + 1,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=conflict-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conflict-resolver.js","sourceRoot":"","sources":["../../src/sync/conflict-resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,CAAc,EAAE,CAAc;IAC3D,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,IAAI,GAAG,IAAI;YAAE,QAAQ,GAAG,IAAI,CAAC;QACjC,IAAI,IAAI,GAAG,IAAI;YAAE,QAAQ,GAAG,IAAI,CAAC;IAClC,CAAC;IAED,IAAI,QAAQ,IAAI,CAAC,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,IAAI,QAAQ,IAAI,CAAC,QAAQ;QAAE,OAAO,CAAC,CAAC,CAAC;IACrC,OAAO,CAAC,CAAC,CAAC,aAAa;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC9B,KAAc,EACd,MAAe,EACf,UAAuB,EACvB,WAAwB,EACxB,cAAsB,EACtB,eAAuB;IAEvB,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAEnD,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;IAC7D,CAAC;IACD,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAC/D,CAAC;IAED,6BAA6B;IAC7B,IAAI,cAAc,IAAI,eAAe,EAAE,CAAC;QACvC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAC7B,KAAkB,EAClB,MAAc;IAEd,OAAO;QACN,GAAG,KAAK;QACR,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;KAClC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { OpLog } from "../op-log/index.js";
|
|
2
|
+
import type { NodoId } from "../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Tope de operaciones que ponemos en el cable en un solo lote. Tambien se usa
|
|
5
|
+
* como tope de entrada por defecto (ver `maxBatchOperations`).
|
|
6
|
+
*
|
|
7
|
+
* Por que 500: un documento CRDT que se ha dividido de verdad en mas de unos
|
|
8
|
+
* pocos cientos de operaciones es un documento que hay que resyncar con un
|
|
9
|
+
* snapshot, no fusionar operacion a operacion. 500 operaciones de una nota
|
|
10
|
+
* clinica tipica (~600 bytes de payload mas una firma ML-DSA-65 de ~3.3 KB)
|
|
11
|
+
* caben de sobra en el presupuesto de un datagrama WebRTC, asi que un par
|
|
12
|
+
* conforme nunca necesita un frame mayor.
|
|
13
|
+
*/
|
|
14
|
+
export declare const MAX_BATCH_SIZE: 500;
|
|
15
|
+
/**
|
|
16
|
+
* Tope duro del tamano serializado de un sobre recibido.
|
|
17
|
+
*
|
|
18
|
+
* Por que 256 KiB: una operacion CRDT es una edicion (un campo de un registro),
|
|
19
|
+
* no un documento entero. Incluso una patologica — una insercion de texto completo
|
|
20
|
+
* o una referencia a un adjunto en base64 — queda muy por debajo de 256 KiB,
|
|
21
|
+
* mientras que algo mayor es mucho mas probable que un intento de agotamiento de
|
|
22
|
+
* memoria que datos clinicos reales. Tambien mantiene acotado el coste transitorio
|
|
23
|
+
* de validar un sobre, sea cual sea lo que el par haya puesto en `datos`.
|
|
24
|
+
*/
|
|
25
|
+
export declare const MAX_ENVELOPE_BYTES: 262144;
|
|
26
|
+
export type SyncDirection = "bidireccional" | "entrante" | "saliente";
|
|
27
|
+
export interface SyncEngineConfig {
|
|
28
|
+
readonly docId: string;
|
|
29
|
+
readonly opLog: OpLog;
|
|
30
|
+
readonly batchSize?: number;
|
|
31
|
+
readonly timeoutMs?: number;
|
|
32
|
+
readonly direction?: SyncDirection;
|
|
33
|
+
/**
|
|
34
|
+
* Tope duro del numero de operaciones aceptadas de un mismo par en una ronda
|
|
35
|
+
* de sync (por defecto: {@link MAX_BATCH_SIZE}).
|
|
36
|
+
*
|
|
37
|
+
* Ver {@link SyncEngine} para por que un lote sobredimensionado se rechaza
|
|
38
|
+
* entero en vez de aplicarse en trozos.
|
|
39
|
+
*/
|
|
40
|
+
readonly maxBatchOperations?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Tope duro del tamano en bytes serializados de un sobre recibido (por
|
|
43
|
+
* defecto: {@link MAX_ENVELOPE_BYTES}). Los sobres sobredimensionados se
|
|
44
|
+
* rechazan, nunca se truncan.
|
|
45
|
+
*/
|
|
46
|
+
readonly maxEnvelopeBytes?: number;
|
|
47
|
+
}
|
|
48
|
+
export interface SyncResult {
|
|
49
|
+
readonly docId: string;
|
|
50
|
+
readonly operacionesEnviadas: number;
|
|
51
|
+
readonly operacionesRecibidas: number;
|
|
52
|
+
readonly conflictos: number;
|
|
53
|
+
/**
|
|
54
|
+
* Operaciones rechazadas por los limites de recurso (sobre sobredimensionado,
|
|
55
|
+
* lote sobredimensionado). Un operador ve asi la basura de transporte en la
|
|
56
|
+
* misma cuenta que las demas senales de rechazo.
|
|
57
|
+
*/
|
|
58
|
+
readonly operacionesRechazadas: number;
|
|
59
|
+
readonly duracionMs: number;
|
|
60
|
+
readonly exito: boolean;
|
|
61
|
+
}
|
|
62
|
+
export interface SyncEngineEventMap {
|
|
63
|
+
syncIniciado: CustomEvent<{
|
|
64
|
+
readonly docId: string;
|
|
65
|
+
readonly peerId: NodoId;
|
|
66
|
+
readonly direction: SyncDirection;
|
|
67
|
+
}>;
|
|
68
|
+
syncCompletado: CustomEvent<{
|
|
69
|
+
readonly resultado: SyncResult;
|
|
70
|
+
readonly peerId: NodoId;
|
|
71
|
+
}>;
|
|
72
|
+
syncError: CustomEvent<{
|
|
73
|
+
readonly docId: string;
|
|
74
|
+
readonly peerId: NodoId;
|
|
75
|
+
readonly error: string;
|
|
76
|
+
}>;
|
|
77
|
+
conflictoDetectado: CustomEvent<{
|
|
78
|
+
readonly docId: string;
|
|
79
|
+
readonly operacionLocal: unknown;
|
|
80
|
+
readonly operacionRemota: unknown;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Un lote entrante excedia `maxBatchOperations` y se rechazo entero.
|
|
84
|
+
* `lotesOperaciones` es cuantas operaciones intento empujar el par.
|
|
85
|
+
*/
|
|
86
|
+
loteRechazado: CustomEvent<{
|
|
87
|
+
readonly docId: string;
|
|
88
|
+
readonly peerId: NodoId;
|
|
89
|
+
readonly lotesOperaciones: number;
|
|
90
|
+
readonly maximoPermitido: number;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Un sobre excedia `maxEnvelopeBytes` y fue rechazado. Los sobres nunca se
|
|
94
|
+
* truncan: una operacion partida a la mitad dejaria la secuencia en vuelo y el
|
|
95
|
+
* log inconsistente.
|
|
96
|
+
*/
|
|
97
|
+
sobreRechazadoPorTamano: CustomEvent<{
|
|
98
|
+
readonly docId: string;
|
|
99
|
+
readonly peerId: NodoId;
|
|
100
|
+
readonly secuencia: number;
|
|
101
|
+
readonly bytes: number;
|
|
102
|
+
readonly maximoPermitido: number;
|
|
103
|
+
}>;
|
|
104
|
+
}
|
|
105
|
+
export declare class SyncEngine {
|
|
106
|
+
readonly eventTarget: EventTarget;
|
|
107
|
+
readonly docId: string;
|
|
108
|
+
private readonly opLog;
|
|
109
|
+
private readonly batchSize;
|
|
110
|
+
private readonly timeoutMs;
|
|
111
|
+
private readonly _direction;
|
|
112
|
+
private readonly maxBatchOperations;
|
|
113
|
+
private readonly maxEnvelopeBytes;
|
|
114
|
+
private sincronizando;
|
|
115
|
+
private clockLocal;
|
|
116
|
+
private readonly clocksRemotos;
|
|
117
|
+
constructor(config: SyncEngineConfig);
|
|
118
|
+
sincronizar(peerId: NodoId, enviar: (ops: readonly unknown[]) => Promise<void>, recibir: () => Promise<readonly unknown[]>): Promise<SyncResult>;
|
|
119
|
+
/**
|
|
120
|
+
* Acota la memoria que un solo par puede hacer que este nodo asigne
|
|
121
|
+
* aplicando dos topes duros a un lote entrante.
|
|
122
|
+
*
|
|
123
|
+
* 1. **Tope de cantidad.** Un lote con mas de `maxBatchOperations` entradas se
|
|
124
|
+
* rechaza ENTERO, no en trozos. Esta comprobacion va primero, sobre el solo
|
|
125
|
+
* `length`, asi que un lote sobredimensionado se rechaza en tiempo constante.
|
|
126
|
+
*
|
|
127
|
+
* Compromiso, enunciado explicitamente porque es la decision discutible:
|
|
128
|
+
* - *Por que rechazar entero en vez de por trozos*: el rechazo es atomico y
|
|
129
|
+
* auditable. El par recibe un unico evento `loteRechazado` claro en vez de
|
|
130
|
+
* una fusion parcial silenciosa, el operador ve un solo rechazo contable en
|
|
131
|
+
* `operacionesRechazadas`, y `aplicarOperaciones` nunca se invoca con un
|
|
132
|
+
* array sin limite. Tambien significa que un par hostil no puede lograr una
|
|
133
|
+
* escritura parcial confirmada antes de descubrir que el resto es basura:
|
|
134
|
+
* trocear un lote envenenado aplicaria las primeras N operaciones y luego
|
|
135
|
+
* pararia, dejando en el log operaciones que ya le dijimos al par que no
|
|
136
|
+
* podemos verificar. Como el lote entero se descarta, la pasada por sobre
|
|
137
|
+
* se omite por completo: serializar 500k sobres solo para tirarlos seria
|
|
138
|
+
* justamente la tormenta de asignaciones que este tope existe para
|
|
139
|
+
* impedir.
|
|
140
|
+
* - *Que perdemos*: un par legitamente atrasado, con 800 operaciones
|
|
141
|
+
* pendientes, no obtiene nada esta ronda en vez de 500 de ellas. Eso es
|
|
142
|
+
* recuperable y correcto en el cable — `recibir()` es el closure de
|
|
143
|
+
* transporte del propio llamador, asi que un llamador conforme vuelve a
|
|
144
|
+
* ofrecer el resto desde el clock anunciado por el par, tal como ya debe
|
|
145
|
+
* hacer con los lotes salientes que troceamos en `batchSize`. No se pierde
|
|
146
|
+
* ninguna operacion; la puesta al dia simplemente tarda otra ronda. La
|
|
147
|
+
* siguiente ronda vuelve a estar acotada por el mismo tope, que es el punto.
|
|
148
|
+
*
|
|
149
|
+
* 2. **Tope de bytes por sobre.** Un sobre cuya forma serializada exceda
|
|
150
|
+
* `maxEnvelopeBytes` se descarta. NUNCA se trunca: un sobre truncado se
|
|
151
|
+
* parsea como una operacion parcial, lo que avanzaria la secuencia con un
|
|
152
|
+
* delta parcial y dejaria el log CRDT inconsistente. Rechazar es la unica
|
|
153
|
+
* opcion que mantiene el log entero.
|
|
154
|
+
*
|
|
155
|
+
* Los rechazos se cuentan en `SyncResult.operacionesRechazadas` para que un
|
|
156
|
+
* operador vea la basura junto a los rechazos de confianza.
|
|
157
|
+
*/
|
|
158
|
+
private aplicarLimitesDeRecurso;
|
|
159
|
+
actualizarClockLocal(clock: number): void;
|
|
160
|
+
actualizarClockRemoto(peerId: NodoId, clock: number): void;
|
|
161
|
+
obtenerClockLocal(): number;
|
|
162
|
+
obtenerClockRemoto(peerId: NodoId): number;
|
|
163
|
+
estaSincronizando(): boolean;
|
|
164
|
+
on<K extends keyof SyncEngineEventMap>(tipo: K, handler: (ev: SyncEngineEventMap[K]) => void): void;
|
|
165
|
+
off<K extends keyof SyncEngineEventMap>(tipo: K, handler: (ev: SyncEngineEventMap[K]) => void): void;
|
|
166
|
+
private emit;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=engine.d.ts.map
|