holosphere 2.0.0-alpha0 → 2.0.0-alpha10
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/CHANGELOG.md +473 -0
- package/FEATURES.md +431 -0
- package/LICENSE +29 -42
- package/LICENSE-AGPL.md +180 -0
- package/README.md +97 -16
- package/dist/2019-D2OG2idw.js +6680 -0
- package/dist/2019-D2OG2idw.js.map +1 -0
- package/dist/2019-EION3wKo.cjs +8 -0
- package/dist/2019-EION3wKo.cjs.map +1 -0
- package/dist/_commonjsHelpers-C37NGDzP.cjs +2 -0
- package/dist/_commonjsHelpers-C37NGDzP.cjs.map +1 -0
- package/dist/_commonjsHelpers-CUmg6egw.js +7 -0
- package/dist/_commonjsHelpers-CUmg6egw.js.map +1 -0
- package/dist/browser-BSniCNqO.js +3058 -0
- package/dist/browser-BSniCNqO.js.map +1 -0
- package/dist/browser-Cq59Ij19.cjs +2 -0
- package/dist/browser-Cq59Ij19.cjs.map +1 -0
- package/dist/cdn/holosphere.min.js +55 -0
- package/dist/cdn/holosphere.min.js.map +1 -0
- package/dist/cjs/holosphere.cjs +2 -0
- package/dist/cjs/holosphere.cjs.map +1 -0
- package/dist/esm/holosphere.js +53 -0
- package/dist/esm/holosphere.js.map +1 -0
- package/dist/index-DDGt_V9o.cjs +12 -0
- package/dist/index-DDGt_V9o.cjs.map +1 -0
- package/dist/index-DJXftyvB.js +39841 -0
- package/dist/index-DJXftyvB.js.map +1 -0
- package/dist/index-DMbdcMtK.cjs +18 -0
- package/dist/index-DMbdcMtK.cjs.map +1 -0
- package/dist/index-DeZ1xz_s.js +15104 -0
- package/dist/index-DeZ1xz_s.js.map +1 -0
- package/dist/indexeddb-storage-BFt6hMeF.js +176 -0
- package/dist/indexeddb-storage-BFt6hMeF.js.map +1 -0
- package/dist/indexeddb-storage-BK5tv4Sh.cjs +2 -0
- package/dist/indexeddb-storage-BK5tv4Sh.cjs.map +1 -0
- package/dist/memory-storage-C9HuoL2E.js +91 -0
- package/dist/memory-storage-C9HuoL2E.js.map +1 -0
- package/dist/memory-storage-Dao7jfYG.cjs +2 -0
- package/dist/memory-storage-Dao7jfYG.cjs.map +1 -0
- package/dist/secp256k1-BbKzbLtD.cjs +12 -0
- package/dist/secp256k1-BbKzbLtD.cjs.map +1 -0
- package/dist/secp256k1-CreY7Pcl.js +1890 -0
- package/dist/secp256k1-CreY7Pcl.js.map +1 -0
- package/docs/CONTRACTS.md +797 -0
- package/docs/FOSDEM_PROPOSAL.md +388 -0
- package/docs/LOCALFIRST.md +266 -0
- package/docs/api/ai_aggregation.js.html +333 -0
- package/docs/api/ai_breakdown.js.html +524 -0
- package/docs/api/ai_classifier.js.html +231 -0
- package/docs/api/ai_council.js.html +246 -0
- package/docs/api/ai_embeddings.js.html +304 -0
- package/docs/api/ai_federation-ai.js.html +338 -0
- package/docs/api/ai_h3-ai.js.html +970 -0
- package/docs/api/ai_index.js.html +124 -0
- package/docs/api/ai_json-ops.js.html +241 -0
- package/docs/api/ai_llm-service.js.html +239 -0
- package/docs/api/ai_nl-query.js.html +236 -0
- package/docs/api/ai_relationships.js.html +367 -0
- package/docs/api/ai_schema-extractor.js.html +235 -0
- package/docs/api/ai_spatial.js.html +307 -0
- package/docs/api/ai_tts.js.html +214 -0
- package/docs/api/content_social-protocols.js.html +180 -0
- package/docs/api/core_holosphere.js.html +757 -0
- package/docs/api/crypto_nostr-utils.js.html +306 -0
- package/docs/api/crypto_secp256k1.js.html +267 -0
- package/docs/api/data/search.json +1 -0
- package/docs/api/federation_discovery.js.html +337 -0
- package/docs/api/federation_handshake.js.html +478 -0
- package/docs/api/federation_hologram.js.html +1053 -0
- package/docs/api/federation_registry.js.html +389 -0
- package/docs/api/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/api/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/api/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/api/global.html +3 -0
- package/docs/api/hierarchical_upcast.js.html +128 -0
- package/docs/api/index.html +265 -0
- package/docs/api/index.js.html +1868 -0
- package/docs/api/lib_ai-methods.js.html +660 -0
- package/docs/api/lib_contract-methods.js.html +445 -0
- package/docs/api/lib_errors.js.html +56 -0
- package/docs/api/lib_federation-methods.js.html +348 -0
- package/docs/api/lib_index.js.html +33 -0
- package/docs/api/module-ai.html +5 -0
- package/docs/api/module-ai_aggregation-SmartAggregation.html +6 -0
- package/docs/api/module-ai_aggregation.SmartAggregation.html +3 -0
- package/docs/api/module-ai_aggregation.html +3 -0
- package/docs/api/module-ai_breakdown-TaskBreakdown.html +5 -0
- package/docs/api/module-ai_breakdown.TaskBreakdown.html +3 -0
- package/docs/api/module-ai_breakdown.html +3 -0
- package/docs/api/module-ai_classifier-Classifier.html +6 -0
- package/docs/api/module-ai_classifier.Classifier.html +3 -0
- package/docs/api/module-ai_classifier.html +3 -0
- package/docs/api/module-ai_council-Council.html +6 -0
- package/docs/api/module-ai_council.Council.html +3 -0
- package/docs/api/module-ai_council.html +3 -0
- package/docs/api/module-ai_embeddings-Embeddings.html +5 -0
- package/docs/api/module-ai_embeddings.Embeddings.html +3 -0
- package/docs/api/module-ai_embeddings.html +3 -0
- package/docs/api/module-ai_federation-ai-FederationAdvisor.html +6 -0
- package/docs/api/module-ai_federation-ai.FederationAdvisor.html +3 -0
- package/docs/api/module-ai_federation-ai.html +3 -0
- package/docs/api/module-ai_h3-ai-H3AI.html +6 -0
- package/docs/api/module-ai_h3-ai.H3AI.html +3 -0
- package/docs/api/module-ai_h3-ai.html +3 -0
- package/docs/api/module-ai_json-ops-JSONOps.html +5 -0
- package/docs/api/module-ai_json-ops.JSONOps.html +3 -0
- package/docs/api/module-ai_json-ops.html +3 -0
- package/docs/api/module-ai_llm-service-LLMService.html +5 -0
- package/docs/api/module-ai_llm-service.LLMService.html +3 -0
- package/docs/api/module-ai_llm-service.html +3 -0
- package/docs/api/module-ai_nl-query-NLQuery.html +5 -0
- package/docs/api/module-ai_nl-query.NLQuery.html +3 -0
- package/docs/api/module-ai_nl-query.html +3 -0
- package/docs/api/module-ai_relationships-RelationshipDiscovery.html +6 -0
- package/docs/api/module-ai_relationships.RelationshipDiscovery.html +3 -0
- package/docs/api/module-ai_relationships.html +3 -0
- package/docs/api/module-ai_schema-extractor-SchemaExtractor.html +5 -0
- package/docs/api/module-ai_schema-extractor.SchemaExtractor.html +3 -0
- package/docs/api/module-ai_schema-extractor.html +3 -0
- package/docs/api/module-ai_spatial-SpatialAnalysis.html +6 -0
- package/docs/api/module-ai_spatial.SpatialAnalysis.html +3 -0
- package/docs/api/module-ai_spatial.html +3 -0
- package/docs/api/module-ai_tts-TTS.html +5 -0
- package/docs/api/module-ai_tts.TTS.html +3 -0
- package/docs/api/module-ai_tts.html +3 -0
- package/docs/api/module-content_social-protocols.html +3 -0
- package/docs/api/module-core_holosphere-HoloSphere.html +6 -0
- package/docs/api/module-core_holosphere.HoloSphere.html +3 -0
- package/docs/api/module-core_holosphere.html +3 -0
- package/docs/api/module-crypto_nostr-utils.html +3 -0
- package/docs/api/module-crypto_secp256k1.html +3 -0
- package/docs/api/module-federation_hologram.html +3 -0
- package/docs/api/module-hierarchical_upcast.html +3 -0
- package/docs/api/module-holosphere-HoloSphereBase.html +3 -0
- package/docs/api/module-holosphere.html +3 -0
- package/docs/api/module-lib_ai-methods.html +3 -0
- package/docs/api/module-lib_contract-methods.html +3 -0
- package/docs/api/module-lib_errors-AuthorizationError.html +3 -0
- package/docs/api/module-lib_errors-ValidationError.html +3 -0
- package/docs/api/module-lib_errors.AuthorizationError.html +3 -0
- package/docs/api/module-lib_errors.ValidationError.html +3 -0
- package/docs/api/module-lib_errors.html +3 -0
- package/docs/api/module-lib_federation-methods.html +3 -0
- package/docs/api/module-lib_index.html +3 -0
- package/docs/api/module-schema_validator-ValidationError.html +3 -0
- package/docs/api/module-schema_validator.ValidationError.html +3 -0
- package/docs/api/module-schema_validator.html +3 -0
- package/docs/api/module-spatial_h3-operations.html +4 -0
- package/docs/api/module-storage_backend-factory.BackendFactory.html +3 -0
- package/docs/api/module-storage_backend-factory.html +3 -0
- package/docs/api/module-storage_backend-interface-StorageBackend.html +3 -0
- package/docs/api/module-storage_backend-interface.StorageBackend.html +3 -0
- package/docs/api/module-storage_backend-interface.html +3 -0
- package/docs/api/module-storage_backends_activitypub-backend-ActivityPubBackend.html +7 -0
- package/docs/api/module-storage_backends_activitypub-backend.ActivityPubBackend.html +3 -0
- package/docs/api/module-storage_backends_activitypub-backend.html +3 -0
- package/docs/api/module-storage_backends_activitypub_server-ActivityPubServer.html +8 -0
- package/docs/api/module-storage_backends_activitypub_server.ActivityPubServer.html +3 -0
- package/docs/api/module-storage_backends_activitypub_server.html +3 -0
- package/docs/api/module-storage_backends_gundb-backend-GunDBBackend.html +7 -0
- package/docs/api/module-storage_backends_gundb-backend.GunDBBackend.html +3 -0
- package/docs/api/module-storage_backends_gundb-backend.html +3 -0
- package/docs/api/module-storage_backends_nostr-backend-NostrBackend.html +8 -0
- package/docs/api/module-storage_backends_nostr-backend.NostrBackend.html +3 -0
- package/docs/api/module-storage_backends_nostr-backend.html +3 -0
- package/docs/api/module-storage_filesystem-storage-FileSystemStorage.html +5 -0
- package/docs/api/module-storage_filesystem-storage-browser-FileSystemStorage.html +3 -0
- package/docs/api/module-storage_filesystem-storage-browser.FileSystemStorage.html +3 -0
- package/docs/api/module-storage_filesystem-storage-browser.html +3 -0
- package/docs/api/module-storage_filesystem-storage.FileSystemStorage.html +3 -0
- package/docs/api/module-storage_filesystem-storage.html +3 -0
- package/docs/api/module-storage_global-tables.html +3 -0
- package/docs/api/module-storage_gun-async.html +3 -0
- package/docs/api/module-storage_gun-auth-GunAuth.html +5 -0
- package/docs/api/module-storage_gun-auth.GunAuth.html +3 -0
- package/docs/api/module-storage_gun-auth.html +3 -0
- package/docs/api/module-storage_gun-federation.html +3 -0
- package/docs/api/module-storage_gun-references-GunReferenceHandler.html +5 -0
- package/docs/api/module-storage_gun-references.GunReferenceHandler.html +3 -0
- package/docs/api/module-storage_gun-references.html +3 -0
- package/docs/api/module-storage_gun-schema-GunSchemaValidator.html +5 -0
- package/docs/api/module-storage_gun-schema.GunSchemaValidator.html +3 -0
- package/docs/api/module-storage_gun-schema.html +3 -0
- package/docs/api/module-storage_gun-wrapper.html +11 -0
- package/docs/api/module-storage_indexeddb-storage-IndexedDBStorage.html +5 -0
- package/docs/api/module-storage_indexeddb-storage.IndexedDBStorage.html +3 -0
- package/docs/api/module-storage_indexeddb-storage.html +3 -0
- package/docs/api/module-storage_key-storage-simple.html +3 -0
- package/docs/api/module-storage_key-storage.html +4 -0
- package/docs/api/module-storage_memory-storage-MemoryStorage.html +5 -0
- package/docs/api/module-storage_memory-storage.MemoryStorage.html +3 -0
- package/docs/api/module-storage_memory-storage.html +3 -0
- package/docs/api/module-storage_migration-MigrationTool.html +6 -0
- package/docs/api/module-storage_migration.MigrationTool.html +3 -0
- package/docs/api/module-storage_migration.html +3 -0
- package/docs/api/module-storage_nostr-async.html +18 -0
- package/docs/api/module-storage_nostr-client-LRUCache.html +3 -0
- package/docs/api/module-storage_nostr-client-NostrClient.html +7 -0
- package/docs/api/module-storage_nostr-client.NostrClient.html +15 -0
- package/docs/api/module-storage_nostr-client.html +6 -0
- package/docs/api/module-storage_nostr-wrapper.html +3 -0
- package/docs/api/module-storage_outbox-queue-OutboxQueue.html +4 -0
- package/docs/api/module-storage_outbox-queue.OutboxQueue.html +3 -0
- package/docs/api/module-storage_outbox-queue.html +3 -0
- package/docs/api/module-storage_persistent-storage-PersistentStorage.html +3 -0
- package/docs/api/module-storage_persistent-storage.html +4 -0
- package/docs/api/module-storage_sync-service-SyncService.html +5 -0
- package/docs/api/module-storage_sync-service.SyncService.html +3 -0
- package/docs/api/module-storage_sync-service.html +3 -0
- package/docs/api/module-storage_unified-storage.html +3 -0
- package/docs/api/module-subscriptions_manager.SubscriptionRegistry.html +3 -0
- package/docs/api/module-subscriptions_manager.html +3 -0
- package/docs/api/schema_validator.js.html +113 -0
- package/docs/api/scripts/core.js +726 -0
- package/docs/api/scripts/core.min.js +23 -0
- package/docs/api/scripts/resize.js +90 -0
- package/docs/api/scripts/search.js +265 -0
- package/docs/api/scripts/search.min.js +6 -0
- package/docs/api/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/api/scripts/third-party/fuse.js +9 -0
- package/docs/api/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/api/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/api/scripts/third-party/hljs-original.js +5171 -0
- package/docs/api/scripts/third-party/hljs.js +1 -0
- package/docs/api/scripts/third-party/popper.js +5 -0
- package/docs/api/scripts/third-party/tippy.js +1 -0
- package/docs/api/scripts/third-party/tocbot.js +672 -0
- package/docs/api/scripts/third-party/tocbot.min.js +1 -0
- package/docs/api/spatial_h3-operations.js.html +129 -0
- package/docs/api/storage_backend-factory.js.html +133 -0
- package/docs/api/storage_backend-interface.js.html +164 -0
- package/docs/api/storage_backends_activitypub-backend.js.html +298 -0
- package/docs/api/storage_backends_activitypub_server.js.html +678 -0
- package/docs/api/storage_backends_gundb-backend.js.html +878 -0
- package/docs/api/storage_backends_nostr-backend.js.html +254 -0
- package/docs/api/storage_filesystem-storage-browser.js.html +83 -0
- package/docs/api/storage_filesystem-storage.js.html +207 -0
- package/docs/api/storage_global-tables.js.html +116 -0
- package/docs/api/storage_gun-async.js.html +344 -0
- package/docs/api/storage_gun-auth.js.html +376 -0
- package/docs/api/storage_gun-federation.js.html +788 -0
- package/docs/api/storage_gun-references.js.html +212 -0
- package/docs/api/storage_gun-schema.js.html +309 -0
- package/docs/api/storage_gun-wrapper.js.html +645 -0
- package/docs/api/storage_indexeddb-storage.js.html +224 -0
- package/docs/api/storage_key-storage-simple.js.html +102 -0
- package/docs/api/storage_key-storage.js.html +171 -0
- package/docs/api/storage_memory-storage.js.html +128 -0
- package/docs/api/storage_migration.js.html +354 -0
- package/docs/api/storage_nostr-async.js.html +1076 -0
- package/docs/api/storage_nostr-client.js.html +1598 -0
- package/docs/api/storage_nostr-wrapper.js.html +218 -0
- package/docs/api/storage_outbox-queue.js.html +248 -0
- package/docs/api/storage_persistent-storage.js.html +160 -0
- package/docs/api/storage_sync-service.js.html +201 -0
- package/docs/api/storage_unified-storage.js.html +157 -0
- package/docs/api/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/api/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/api/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/api/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/api/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/api/styles/clean-jsdoc-theme.min.css +1 -0
- package/docs/api/subscriptions_manager.js.html +162 -0
- package/docs/contracts/api-interface.md +793 -0
- package/docs/data-model.md +476 -0
- package/docs/gun-async-usage.md +338 -0
- package/docs/plan.md +349 -0
- package/docs/quickstart.md +674 -0
- package/docs/research.md +362 -0
- package/docs/spec.md +244 -0
- package/docs/storage-backends.md +326 -0
- package/docs/tasks.md +947 -0
- package/examples/demo.html +47 -0
- package/examples/holosphere-widget.js +1242 -0
- package/examples/widget-demo.html +274 -0
- package/examples/widget.html +703 -0
- package/jsdoc.json +26 -0
- package/package.json +25 -7
- package/src/ai/aggregation.js +13 -2
- package/src/ai/breakdown.js +12 -2
- package/src/ai/classifier.js +14 -3
- package/src/ai/council.js +22 -7
- package/src/ai/embeddings.js +37 -15
- package/src/ai/federation-ai.js +13 -2
- package/src/ai/h3-ai.js +14 -2
- package/src/ai/index.js +16 -7
- package/src/ai/json-ops.js +18 -5
- package/src/ai/llm-service.js +62 -31
- package/src/ai/nl-query.js +12 -2
- package/src/ai/relationships.js +13 -2
- package/src/ai/schema-extractor.js +24 -10
- package/src/ai/spatial.js +13 -2
- package/src/ai/tts.js +25 -8
- package/src/cdn-entry.js +22 -0
- package/src/content/social-protocols.js +34 -25
- package/src/contracts/abis/Appreciative.json +1280 -0
- package/src/contracts/abis/AppreciativeFactory.json +101 -0
- package/src/contracts/abis/Bundle.json +1438 -0
- package/src/contracts/abis/BundleFactory.json +106 -0
- package/src/contracts/abis/Holon.json +881 -0
- package/src/contracts/abis/Holons.json +330 -0
- package/src/contracts/abis/Managed.json +1262 -0
- package/src/contracts/abis/ManagedFactory.json +149 -0
- package/src/contracts/abis/Membrane.json +261 -0
- package/src/contracts/abis/Splitter.json +1624 -0
- package/src/contracts/abis/SplitterFactory.json +220 -0
- package/src/contracts/abis/TestToken.json +321 -0
- package/src/contracts/abis/Zoned.json +1461 -0
- package/src/contracts/abis/ZonedFactory.json +154 -0
- package/src/contracts/chain-manager.js +403 -0
- package/src/contracts/deployer.js +500 -0
- package/src/contracts/event-listener.js +539 -0
- package/src/contracts/holon-contracts.js +359 -0
- package/src/contracts/index.js +82 -0
- package/src/contracts/networks.js +229 -0
- package/src/contracts/operations.js +687 -0
- package/src/contracts/queries.js +638 -0
- package/src/core/holosphere.js +487 -6
- package/src/crypto/nostr-utils.js +303 -0
- package/src/crypto/secp256k1.js +7 -2
- package/src/federation/handshake.js +475 -0
- package/src/federation/hologram.js +117 -3
- package/src/hierarchical/upcast.js +40 -25
- package/src/index.js +1501 -1909
- package/src/lib/ai-methods.js +657 -0
- package/src/lib/contract-methods.js +442 -0
- package/src/lib/errors.js +53 -0
- package/src/lib/federation-methods.js +345 -0
- package/src/lib/index.js +30 -0
- package/src/schema/validator.js +22 -3
- package/src/spatial/h3-operations.js +19 -3
- package/src/storage/backend-factory.js +7 -2
- package/src/storage/backend-interface.js +21 -2
- package/src/storage/backends/activitypub/server.js +25 -3
- package/src/storage/backends/activitypub-backend.js +25 -2
- package/src/storage/backends/gundb-backend.js +692 -50
- package/src/storage/backends/nostr-backend.js +116 -1
- package/src/storage/filesystem-storage-browser.js +42 -2
- package/src/storage/filesystem-storage.js +72 -5
- package/src/storage/global-tables.js +35 -3
- package/src/storage/gun-async.js +75 -15
- package/src/storage/gun-auth.js +373 -0
- package/src/storage/gun-federation.js +785 -0
- package/src/storage/gun-references.js +209 -0
- package/src/storage/gun-schema.js +306 -0
- package/src/storage/gun-wrapper.js +475 -54
- package/src/storage/indexeddb-storage.js +112 -13
- package/src/storage/key-storage-simple.js +32 -9
- package/src/storage/key-storage.js +45 -13
- package/src/storage/memory-storage.js +68 -2
- package/src/storage/migration.js +20 -7
- package/src/storage/nostr-async.js +412 -122
- package/src/storage/nostr-client.js +749 -76
- package/src/storage/nostr-wrapper.js +6 -2
- package/src/storage/outbox-queue.js +55 -18
- package/src/storage/persistent-storage.js +62 -14
- package/src/storage/sync-service.js +51 -17
- package/src/storage/unified-storage.js +154 -0
- package/src/subscriptions/manager.js +34 -17
- package/types/index.d.ts +133 -0
- package/vite.config.cdn.js +60 -0
- package/tests/unit/ai/aggregation.test.js +0 -295
- package/tests/unit/ai/breakdown.test.js +0 -446
- package/tests/unit/ai/classifier.test.js +0 -294
- package/tests/unit/ai/council.test.js +0 -262
- package/tests/unit/ai/embeddings.test.js +0 -384
- package/tests/unit/ai/federation-ai.test.js +0 -344
- package/tests/unit/ai/h3-ai.test.js +0 -458
- package/tests/unit/ai/index.test.js +0 -304
- package/tests/unit/ai/json-ops.test.js +0 -307
- package/tests/unit/ai/llm-service.test.js +0 -390
- package/tests/unit/ai/nl-query.test.js +0 -383
- package/tests/unit/ai/relationships.test.js +0 -311
- package/tests/unit/ai/schema-extractor.test.js +0 -384
- package/tests/unit/ai/spatial.test.js +0 -279
- package/tests/unit/ai/tts.test.js +0 -279
- package/tests/unit/content.test.js +0 -332
- package/tests/unit/contract/core.test.js +0 -88
- package/tests/unit/contract/crypto.test.js +0 -198
- package/tests/unit/contract/data.test.js +0 -223
- package/tests/unit/contract/federation.test.js +0 -181
- package/tests/unit/contract/hierarchical.test.js +0 -113
- package/tests/unit/contract/schema.test.js +0 -114
- package/tests/unit/contract/social.test.js +0 -217
- package/tests/unit/contract/spatial.test.js +0 -110
- package/tests/unit/contract/subscriptions.test.js +0 -128
- package/tests/unit/contract/utils.test.js +0 -159
- package/tests/unit/core.test.js +0 -152
- package/tests/unit/crypto.test.js +0 -328
- package/tests/unit/federation.test.js +0 -234
- package/tests/unit/gun-async.test.js +0 -252
- package/tests/unit/hierarchical.test.js +0 -399
- package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
- package/tests/unit/integration/scenario-02-federation.test.js +0 -76
- package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
- package/tests/unit/integration/scenario-04-validation.test.js +0 -129
- package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
- package/tests/unit/integration/scenario-06-social.test.js +0 -135
- package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
- package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
- package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
- package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
- package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
- package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
- package/tests/unit/performance/benchmark.test.js +0 -85
- package/tests/unit/schema.test.js +0 -213
- package/tests/unit/spatial.test.js +0 -158
- package/tests/unit/storage.test.js +0 -195
- package/tests/unit/subscriptions.test.js +0 -328
- package/tests/unit/test-data-permanence-debug.js +0 -197
- package/tests/unit/test-data-permanence.js +0 -340
- package/tests/unit/test-key-persistence-fixed.js +0 -148
- package/tests/unit/test-key-persistence.js +0 -172
- package/tests/unit/test-relay-permanence.js +0 -376
- package/tests/unit/test-second-node.js +0 -95
- package/tests/unit/test-simple-write.js +0 -89
- /package/{cleanup-test-data.js → scripts/cleanup-test-data.js} +0 -0
- /package/{test-ai-real-api.js → scripts/test-ai-real-api.js} +0 -0
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GunDB Storage Wrapper with radisk persistence
|
|
3
|
-
*
|
|
2
|
+
* @fileoverview GunDB Storage Wrapper with radisk persistence.
|
|
3
|
+
*
|
|
4
|
+
* Handles path construction and CRUD operations for GunDB storage backend.
|
|
5
|
+
* Note: GunDB doesn't handle nested objects well, so we store data as JSON strings.
|
|
6
|
+
* Provides both holon-specific paths and global table operations.
|
|
7
|
+
*
|
|
8
|
+
* @module storage/gun-wrapper
|
|
4
9
|
*/
|
|
5
10
|
|
|
6
11
|
import { gunPromise, gunPut, gunCollect } from './gun-async.js';
|
|
7
12
|
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// PATH BUILDERS
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
8
17
|
/**
|
|
9
|
-
* Build Gun path from components
|
|
18
|
+
* Build Gun path from components.
|
|
19
|
+
*
|
|
10
20
|
* @param {string} appname - Application namespace
|
|
11
21
|
* @param {string} holon - Holon ID (H3 or URI)
|
|
12
22
|
* @param {string} lens - Lens name
|
|
13
|
-
* @param {string} key - Data key (optional)
|
|
23
|
+
* @param {string} [key=null] - Data key (optional)
|
|
14
24
|
* @returns {string} Gun path
|
|
25
|
+
* @example
|
|
26
|
+
* const path = buildPath('myapp', 'holon123', 'items', 'item1');
|
|
27
|
+
* // Returns: 'myapp/holon123/items/item1'
|
|
15
28
|
*/
|
|
16
29
|
export function buildPath(appname, holon, lens, key = null) {
|
|
17
30
|
// Encode components to handle special characters
|
|
@@ -26,39 +39,207 @@ export function buildPath(appname, holon, lens, key = null) {
|
|
|
26
39
|
}
|
|
27
40
|
|
|
28
41
|
/**
|
|
29
|
-
*
|
|
42
|
+
* Build Gun path for global tables (app-wide data not tied to holons).
|
|
43
|
+
*
|
|
44
|
+
* @param {string} appname - Application namespace
|
|
45
|
+
* @param {string} tableName - Global table name (e.g., 'schemas', 'federation')
|
|
46
|
+
* @param {string} [key=null] - Data key (optional)
|
|
47
|
+
* @returns {string} Gun path
|
|
48
|
+
* @example
|
|
49
|
+
* const path = buildGlobalPath('myapp', 'schemas', 'user');
|
|
50
|
+
* // Returns: 'myapp/schemas/user'
|
|
51
|
+
*/
|
|
52
|
+
export function buildGlobalPath(appname, tableName, key = null) {
|
|
53
|
+
const encodedTable = encodePathComponent(tableName);
|
|
54
|
+
if (key) {
|
|
55
|
+
const encodedKey = encodePathComponent(key);
|
|
56
|
+
return `${appname}/${encodedTable}/${encodedKey}`;
|
|
57
|
+
}
|
|
58
|
+
return `${appname}/${encodedTable}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Encode path component to handle special characters.
|
|
63
|
+
*
|
|
30
64
|
* @private
|
|
65
|
+
* @param {string} component - Component to encode
|
|
66
|
+
* @returns {string} Encoded component
|
|
31
67
|
*/
|
|
32
68
|
function encodePathComponent(component) {
|
|
33
69
|
return encodeURIComponent(component).replace(/%2F/g, '/');
|
|
34
70
|
}
|
|
35
71
|
|
|
36
72
|
/**
|
|
37
|
-
*
|
|
73
|
+
* Navigate to a Gun path using chained .get() calls.
|
|
74
|
+
*
|
|
75
|
+
* Gun treats 'a/b/c' as a literal key, not a path.
|
|
76
|
+
* This function splits the path and chains .get() calls properly.
|
|
77
|
+
*
|
|
78
|
+
* @private
|
|
79
|
+
* @param {Object} gun - Gun instance
|
|
80
|
+
* @param {string} path - Path string like "appname/holon/lens/key"
|
|
81
|
+
* @returns {Object} Gun chain reference at the path
|
|
82
|
+
*/
|
|
83
|
+
function getGunPath(gun, path) {
|
|
84
|
+
const parts = path.split('/').filter(p => p.length > 0);
|
|
85
|
+
let ref = gun;
|
|
86
|
+
for (const part of parts) {
|
|
87
|
+
ref = ref.get(part);
|
|
88
|
+
}
|
|
89
|
+
return ref;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Serialize data for GunDB storage.
|
|
94
|
+
*
|
|
95
|
+
* Stores data as raw JSON string for compatibility with holosphere original.
|
|
96
|
+
* This matches the format used in holosphere v1 for better interoperability.
|
|
97
|
+
*
|
|
98
|
+
* @private
|
|
99
|
+
* @param {Object} data - Data to serialize
|
|
100
|
+
* @returns {string} JSON string
|
|
101
|
+
*/
|
|
102
|
+
function serializeForGun(data) {
|
|
103
|
+
return JSON.stringify(data);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Deserialize data from GunDB storage.
|
|
108
|
+
*
|
|
109
|
+
* Handles multiple formats:
|
|
110
|
+
* - Direct JSON string (holosphere original - now default)
|
|
111
|
+
* - _json wrapped format (holosphere2 legacy)
|
|
112
|
+
* - Gun internal references (_["#"])
|
|
113
|
+
* - Gun node data (_[">"])
|
|
114
|
+
* - Plain objects
|
|
115
|
+
*
|
|
116
|
+
* @private
|
|
117
|
+
* @param {*} data - Raw data from Gun
|
|
118
|
+
* @returns {Object|null} Parsed data or null
|
|
119
|
+
*/
|
|
120
|
+
function deserializeFromGun(data) {
|
|
121
|
+
if (!data) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// Format 1: String data (holosphere original stores JSON as string directly)
|
|
127
|
+
if (typeof data === 'string') {
|
|
128
|
+
try {
|
|
129
|
+
return JSON.parse(data);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
// Not JSON, return as-is
|
|
132
|
+
return data;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Format 2: _json wrapped format (holosphere2 default)
|
|
137
|
+
if (data._json && typeof data._json === 'string') {
|
|
138
|
+
try {
|
|
139
|
+
return JSON.parse(data._json);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
console.warn('Failed to parse _json field:', e);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Format 3: Gun internal reference (_["#"]) - this indicates a Gun reference
|
|
147
|
+
// The actual data retrieval should happen via resolveReference, we just identify it here
|
|
148
|
+
if (data._ && data._['#']) {
|
|
149
|
+
// This is a Gun reference - return as-is for reference resolution
|
|
150
|
+
// The caller should check isReference() and handle appropriately
|
|
151
|
+
return data;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Format 4: Gun node data with timestamps (_[">"])
|
|
155
|
+
// Gun stores metadata in _.> - find the actual value
|
|
156
|
+
if (data._ && data._['>']) {
|
|
157
|
+
const nodeValue = Object.entries(data).find(([k, v]) => k !== '_' && typeof v === 'string');
|
|
158
|
+
if (nodeValue) {
|
|
159
|
+
try {
|
|
160
|
+
return JSON.parse(nodeValue[1]);
|
|
161
|
+
} catch (e) {
|
|
162
|
+
return nodeValue[1];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Format 5: Plain object - clean Gun metadata and return
|
|
168
|
+
if (typeof data === 'object' && data !== null) {
|
|
169
|
+
const cleaned = { ...data };
|
|
170
|
+
delete cleaned['_'];
|
|
171
|
+
|
|
172
|
+
// Check if any remaining keys - if empty after removing _, return null
|
|
173
|
+
if (Object.keys(cleaned).length === 0) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return cleaned;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return data;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.warn('Error deserializing Gun data:', error);
|
|
183
|
+
return data; // Return raw data as fallback
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Write data to Gun with radisk persistence.
|
|
189
|
+
*
|
|
38
190
|
* @param {Object} gun - Gun instance
|
|
39
191
|
* @param {string} path - Gun path
|
|
40
192
|
* @param {Object} data - Data to write
|
|
41
|
-
* @returns {Promise<
|
|
193
|
+
* @returns {Promise<Object>} Success object with ok and timeout flags
|
|
194
|
+
* @example
|
|
195
|
+
* const result = await write(gun, 'myapp/holon1/items/item1', { name: 'Test' });
|
|
196
|
+
* if (result.timeout) console.warn('Write may not be persisted');
|
|
42
197
|
*/
|
|
43
198
|
export async function write(gun, path, data) {
|
|
44
199
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
200
|
+
const serialized = serializeForGun(data);
|
|
201
|
+
const parts = path.split('/').filter(p => p.length > 0);
|
|
202
|
+
console.log('[gun-wrapper] write:', { path, parts, dataId: data?.id });
|
|
203
|
+
const ref = getGunPath(gun, path);
|
|
204
|
+
console.log('[gun-wrapper] write ref soul:', ref?._.get);
|
|
205
|
+
const ack = await gunPut(ref, serialized, 5000); // Increased timeout from 2s to 5s
|
|
206
|
+
console.log('[gun-wrapper] write ack:', { ok: ack.ok, timeout: ack.timeout });
|
|
207
|
+
if (ack.timeout) {
|
|
208
|
+
console.warn('[gun-wrapper] write timed out (data may not be persisted):', path);
|
|
209
|
+
}
|
|
210
|
+
console.log('[gun-wrapper] write complete:', path);
|
|
211
|
+
|
|
212
|
+
// Return ack info so caller can handle timeouts
|
|
213
|
+
return { ok: true, timeout: ack.timeout || false };
|
|
49
214
|
} catch (error) {
|
|
215
|
+
console.error('[gun-wrapper] write error:', error);
|
|
50
216
|
throw error;
|
|
51
217
|
}
|
|
52
218
|
}
|
|
53
219
|
|
|
54
220
|
/**
|
|
55
|
-
* Read data from Gun
|
|
221
|
+
* Read data from Gun.
|
|
222
|
+
*
|
|
56
223
|
* @param {Object} gun - Gun instance
|
|
57
224
|
* @param {string} path - Gun path
|
|
58
|
-
* @returns {Promise<Object|null>} Data or null if not found
|
|
225
|
+
* @returns {Promise<Object|null>} Data or null if not found or deleted
|
|
226
|
+
* @example
|
|
227
|
+
* const data = await read(gun, 'myapp/holon1/items/item1');
|
|
228
|
+
* if (data) console.log(data.name);
|
|
59
229
|
*/
|
|
60
230
|
export async function read(gun, path) {
|
|
61
|
-
const
|
|
231
|
+
const parts = path.split('/').filter(p => p.length > 0);
|
|
232
|
+
console.log('[gun-wrapper] read:', { path, parts });
|
|
233
|
+
const ref = getGunPath(gun, path);
|
|
234
|
+
console.log('[gun-wrapper] read ref soul:', ref?._.get);
|
|
235
|
+
const rawData = await gunPromise(ref, 2000);
|
|
236
|
+
console.log('[gun-wrapper] read rawData:', rawData ? (typeof rawData === 'string' ? rawData.substring(0, 100) : 'object') : 'null');
|
|
237
|
+
|
|
238
|
+
if (!rawData) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const data = deserializeFromGun(rawData);
|
|
62
243
|
|
|
63
244
|
// Return null if deleted or not found
|
|
64
245
|
if (!data || data._deleted) {
|
|
@@ -69,48 +250,158 @@ export async function read(gun, path) {
|
|
|
69
250
|
}
|
|
70
251
|
|
|
71
252
|
/**
|
|
72
|
-
* Read all data under a path (lens query)
|
|
253
|
+
* Read all data under a path (lens query).
|
|
254
|
+
*
|
|
255
|
+
* First gets the count of expected items, then collects until count is reached.
|
|
256
|
+
*
|
|
73
257
|
* @param {Object} gun - Gun instance
|
|
74
258
|
* @param {string} path - Gun path
|
|
259
|
+
* @param {number} [timeout=5000] - Maximum timeout in ms
|
|
75
260
|
* @returns {Promise<Object[]>} Array of data objects
|
|
261
|
+
* @example
|
|
262
|
+
* const items = await readAll(gun, 'myapp/holon1/items');
|
|
263
|
+
* console.log(`Found ${items.length} items`);
|
|
76
264
|
*/
|
|
77
|
-
export async function readAll(gun, path) {
|
|
78
|
-
const
|
|
265
|
+
export async function readAll(gun, path, timeout = 5000) {
|
|
266
|
+
const parts = path.split('/').filter(p => p.length > 0);
|
|
267
|
+
console.log('[gun-wrapper] readAll:', { path, parts });
|
|
268
|
+
|
|
269
|
+
return new Promise((resolve) => {
|
|
270
|
+
const output = new Map();
|
|
271
|
+
let settled = false;
|
|
272
|
+
let expectedCount = 0;
|
|
273
|
+
let receivedCount = 0;
|
|
274
|
+
|
|
275
|
+
const ref = getGunPath(gun, path);
|
|
276
|
+
console.log('[gun-wrapper] readAll ref soul:', ref?._.get);
|
|
277
|
+
|
|
278
|
+
const tryResolve = () => {
|
|
279
|
+
if (settled) return;
|
|
280
|
+
if (expectedCount > 0 && receivedCount >= expectedCount) {
|
|
281
|
+
settled = true;
|
|
282
|
+
console.log('[gun-wrapper] readAll resolved with', output.size, 'items');
|
|
283
|
+
resolve(Array.from(output.values()));
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const parseItem = (data) => {
|
|
288
|
+
return deserializeFromGun(data);
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// Step 1: Get the parent data to count expected items
|
|
292
|
+
ref.once((parentData) => {
|
|
293
|
+
if (settled) return;
|
|
294
|
+
console.log('[gun-wrapper] readAll parentData:', parentData);
|
|
295
|
+
console.log('[gun-wrapper] readAll parentData keys:', parentData ? Object.keys(parentData).filter(k => k !== '_') : 'null');
|
|
296
|
+
console.log('[gun-wrapper] readAll parentData type:', typeof parentData);
|
|
297
|
+
|
|
298
|
+
if (!parentData) {
|
|
299
|
+
settled = true;
|
|
300
|
+
console.log('[gun-wrapper] readAll: no parent data, returning empty');
|
|
301
|
+
resolve([]);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Get all keys except Gun metadata
|
|
306
|
+
const keys = Object.keys(parentData).filter(k => k !== '_');
|
|
307
|
+
console.log('[gun-wrapper] readAll keys:', keys);
|
|
308
|
+
|
|
309
|
+
if (keys.length === 0) {
|
|
310
|
+
settled = true;
|
|
311
|
+
console.log('[gun-wrapper] readAll: no keys, returning empty');
|
|
312
|
+
resolve([]);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Count expected items and check for inline data
|
|
317
|
+
const referenceKeys = [];
|
|
318
|
+
|
|
319
|
+
for (const key of keys) {
|
|
320
|
+
const rawItem = parentData[key];
|
|
321
|
+
if (!rawItem) continue;
|
|
322
|
+
|
|
323
|
+
// Check if it's a Gun reference (soul) - need to fetch separately
|
|
324
|
+
if (typeof rawItem === 'object' && rawItem['#']) {
|
|
325
|
+
referenceKeys.push(key);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Try to parse inline data (don't count yet - will count in map().once() phase)
|
|
330
|
+
const item = parseItem(rawItem);
|
|
331
|
+
if (item && item.id && !item._deleted) {
|
|
332
|
+
output.set(item.id, item);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Set expected count: ALL keys that could have data (references + inline)
|
|
337
|
+
// We use total keys because map().once() will fire for all of them
|
|
338
|
+
expectedCount = keys.length;
|
|
339
|
+
|
|
340
|
+
// If no keys, we're done (shouldn't happen but be safe)
|
|
341
|
+
if (expectedCount === 0) {
|
|
342
|
+
settled = true;
|
|
343
|
+
resolve(Array.from(output.values()));
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Step 2: Use map().once() to resolve all items, counting as we go
|
|
348
|
+
ref.map().once((data, key) => {
|
|
349
|
+
if (settled || !data || key === '_') return;
|
|
350
|
+
|
|
351
|
+
const item = parseItem(data);
|
|
352
|
+
if (item && item.id && !item._deleted) {
|
|
353
|
+
// Add to output if not already there (inline items already added)
|
|
354
|
+
if (!output.has(item.id)) {
|
|
355
|
+
output.set(item.id, item);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Count every item received (inline or reference)
|
|
359
|
+
receivedCount++;
|
|
360
|
+
tryResolve();
|
|
361
|
+
});
|
|
362
|
+
});
|
|
79
363
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.map(({ data }) => data);
|
|
364
|
+
// Fallback timeout in case count-based resolution fails
|
|
365
|
+
setTimeout(() => {
|
|
366
|
+
if (!settled) {
|
|
367
|
+
settled = true;
|
|
368
|
+
resolve(Array.from(output.values()));
|
|
369
|
+
}
|
|
370
|
+
}, timeout);
|
|
371
|
+
});
|
|
89
372
|
}
|
|
90
373
|
|
|
91
374
|
/**
|
|
92
|
-
* Update data (merge fields)
|
|
375
|
+
* Update data (merge fields).
|
|
376
|
+
*
|
|
93
377
|
* @param {Object} gun - Gun instance
|
|
94
378
|
* @param {string} path - Gun path
|
|
95
379
|
* @param {Object} updates - Fields to update
|
|
96
380
|
* @returns {Promise<boolean>} Success indicator
|
|
381
|
+
* @example
|
|
382
|
+
* const success = await update(gun, 'myapp/holon1/items/item1', { status: 'active' });
|
|
97
383
|
*/
|
|
98
384
|
export async function update(gun, path, updates) {
|
|
99
|
-
const
|
|
385
|
+
const rawData = await gunPromise(getGunPath(gun, path));
|
|
100
386
|
|
|
101
|
-
if (!
|
|
102
|
-
return false; // Not found
|
|
387
|
+
if (!rawData) {
|
|
388
|
+
return false; // Not found
|
|
103
389
|
}
|
|
104
390
|
|
|
105
|
-
//
|
|
106
|
-
const
|
|
107
|
-
|
|
391
|
+
// Deserialize existing data
|
|
392
|
+
const existing = deserializeFromGun(rawData);
|
|
393
|
+
if (!existing || !existing.id || existing._deleted) {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
108
396
|
|
|
109
397
|
// Merge updates
|
|
110
|
-
const merged = { ...
|
|
398
|
+
const merged = { ...existing, ...updates };
|
|
111
399
|
|
|
112
400
|
try {
|
|
113
|
-
|
|
401
|
+
const serialized = serializeForGun(merged);
|
|
402
|
+
await gunPut(getGunPath(gun, path), serialized, 2000);
|
|
403
|
+
// Add delay for propagation
|
|
404
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
114
405
|
return true;
|
|
115
406
|
} catch (error) {
|
|
116
407
|
throw error;
|
|
@@ -118,28 +409,34 @@ export async function update(gun, path, updates) {
|
|
|
118
409
|
}
|
|
119
410
|
|
|
120
411
|
/**
|
|
121
|
-
* Delete data (tombstone)
|
|
412
|
+
* Delete data (tombstone).
|
|
413
|
+
*
|
|
122
414
|
* @param {Object} gun - Gun instance
|
|
123
415
|
* @param {string} path - Gun path
|
|
124
416
|
* @returns {Promise<boolean>} Success indicator
|
|
417
|
+
* @example
|
|
418
|
+
* const deleted = await deleteData(gun, 'myapp/holon1/items/item1');
|
|
125
419
|
*/
|
|
126
420
|
export async function deleteData(gun, path) {
|
|
127
421
|
try {
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (!existing) {
|
|
422
|
+
// First read existing data to get the id
|
|
423
|
+
const rawData = await gunPromise(getGunPath(gun, path));
|
|
424
|
+
if (!rawData) {
|
|
132
425
|
return true; // Already deleted/doesn't exist
|
|
133
426
|
}
|
|
134
427
|
|
|
135
|
-
|
|
428
|
+
const existing = deserializeFromGun(rawData);
|
|
429
|
+
|
|
430
|
+
// Create tombstone object and serialize it
|
|
136
431
|
const tombstone = {
|
|
137
|
-
id: existing
|
|
432
|
+
id: existing?.id,
|
|
138
433
|
_deleted: true,
|
|
139
434
|
_deletedAt: Date.now()
|
|
140
435
|
};
|
|
141
436
|
|
|
142
|
-
await gunPut(gun
|
|
437
|
+
await gunPut(getGunPath(gun, path), serializeForGun(tombstone), 2000);
|
|
438
|
+
// Add delay for propagation
|
|
439
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
143
440
|
return true;
|
|
144
441
|
} catch (error) {
|
|
145
442
|
throw error;
|
|
@@ -147,7 +444,8 @@ export async function deleteData(gun, path) {
|
|
|
147
444
|
}
|
|
148
445
|
|
|
149
446
|
/**
|
|
150
|
-
* Delete all data under path prefix (tombstone)
|
|
447
|
+
* Delete all data under path prefix (tombstone).
|
|
448
|
+
*
|
|
151
449
|
* @param {Object} gun - Gun instance
|
|
152
450
|
* @param {string} path - Gun path prefix
|
|
153
451
|
* @returns {Promise<Object>} Deletion results { success: boolean, count: number }
|
|
@@ -168,13 +466,19 @@ export async function deleteAll(gun, path) {
|
|
|
168
466
|
}
|
|
169
467
|
|
|
170
468
|
/**
|
|
171
|
-
* Subscribe to data changes
|
|
469
|
+
* Subscribe to data changes.
|
|
470
|
+
*
|
|
172
471
|
* @param {Object} gun - Gun instance
|
|
173
472
|
* @param {string} path - Gun path
|
|
174
|
-
* @param {Function} callback - Called on data changes
|
|
175
|
-
* @param {Object} options - Subscription options
|
|
176
|
-
* @param {boolean} options.prefix - Subscribe to all items under path (default: auto-detect)
|
|
473
|
+
* @param {Function} callback - Called on data changes (data, key) => void
|
|
474
|
+
* @param {Object} [options={}] - Subscription options
|
|
475
|
+
* @param {boolean} [options.prefix] - Subscribe to all items under path (default: auto-detect)
|
|
177
476
|
* @returns {Object} Subscription object with unsubscribe method
|
|
477
|
+
* @example
|
|
478
|
+
* const sub = subscribe(gun, 'myapp/holon1/items', (data, key) => {
|
|
479
|
+
* console.log('Item changed:', key, data);
|
|
480
|
+
* });
|
|
481
|
+
* // Later: sub.unsubscribe();
|
|
178
482
|
*/
|
|
179
483
|
export function subscribe(gun, path, callback, options = {}) {
|
|
180
484
|
// Detect if this is a prefix subscription
|
|
@@ -183,11 +487,14 @@ export function subscribe(gun, path, callback, options = {}) {
|
|
|
183
487
|
|
|
184
488
|
if (isPrefix) {
|
|
185
489
|
// Subscribe to all items under this prefix
|
|
186
|
-
const ref = gun
|
|
490
|
+
const ref = getGunPath(gun, path);
|
|
187
491
|
|
|
188
492
|
ref.map().on((data, key) => {
|
|
189
|
-
if (data && !key.startsWith('_')
|
|
190
|
-
|
|
493
|
+
if (data && !key.startsWith('_')) {
|
|
494
|
+
const deserialized = deserializeFromGun(data);
|
|
495
|
+
if (deserialized && !deserialized._deleted) {
|
|
496
|
+
callback(deserialized, key);
|
|
497
|
+
}
|
|
191
498
|
}
|
|
192
499
|
});
|
|
193
500
|
|
|
@@ -202,9 +509,12 @@ export function subscribe(gun, path, callback, options = {}) {
|
|
|
202
509
|
};
|
|
203
510
|
} else {
|
|
204
511
|
// Subscribe to single item
|
|
205
|
-
const listener = gun
|
|
206
|
-
if (data
|
|
207
|
-
|
|
512
|
+
const listener = getGunPath(gun, path).on((data, key) => {
|
|
513
|
+
if (data) {
|
|
514
|
+
const deserialized = deserializeFromGun(data);
|
|
515
|
+
if (deserialized && !deserialized._deleted) {
|
|
516
|
+
callback(deserialized, key);
|
|
517
|
+
}
|
|
208
518
|
}
|
|
209
519
|
});
|
|
210
520
|
|
|
@@ -219,3 +529,114 @@ export function subscribe(gun, path, callback, options = {}) {
|
|
|
219
529
|
};
|
|
220
530
|
}
|
|
221
531
|
}
|
|
532
|
+
|
|
533
|
+
// ============================================================================
|
|
534
|
+
// GLOBAL TABLE OPERATIONS
|
|
535
|
+
// ============================================================================
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Write data to a global table.
|
|
539
|
+
*
|
|
540
|
+
* Global tables are app-wide data not tied to specific holons (e.g., schemas, federation).
|
|
541
|
+
*
|
|
542
|
+
* @param {Object} gun - Gun instance
|
|
543
|
+
* @param {string} appname - Application namespace
|
|
544
|
+
* @param {string} tableName - Global table name
|
|
545
|
+
* @param {Object} data - Data to write (must have 'id' field)
|
|
546
|
+
* @returns {Promise<Object>} Success object with ok and timeout flags
|
|
547
|
+
* @throws {Error} If data doesn't have an id field
|
|
548
|
+
* @example
|
|
549
|
+
* await writeGlobal(gun, 'myapp', 'schemas', { id: 'user', type: 'object' });
|
|
550
|
+
*/
|
|
551
|
+
export async function writeGlobal(gun, appname, tableName, data) {
|
|
552
|
+
if (!data || !data.id) {
|
|
553
|
+
throw new Error('writeGlobal: data must have an id field');
|
|
554
|
+
}
|
|
555
|
+
const path = buildGlobalPath(appname, tableName, data.id);
|
|
556
|
+
// Use write function which includes the propagation delay
|
|
557
|
+
return write(gun, path, data);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Read data from a global table.
|
|
562
|
+
*
|
|
563
|
+
* @param {Object} gun - Gun instance
|
|
564
|
+
* @param {string} appname - Application namespace
|
|
565
|
+
* @param {string} tableName - Global table name
|
|
566
|
+
* @param {string} key - Data key
|
|
567
|
+
* @returns {Promise<Object|null>} Data or null if not found
|
|
568
|
+
*/
|
|
569
|
+
export async function readGlobal(gun, appname, tableName, key) {
|
|
570
|
+
const path = buildGlobalPath(appname, tableName, key);
|
|
571
|
+
return read(gun, path);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Read all data from a global table.
|
|
576
|
+
*
|
|
577
|
+
* Uses same approach as readAll.
|
|
578
|
+
*
|
|
579
|
+
* @param {Object} gun - Gun instance
|
|
580
|
+
* @param {string} appname - Application namespace
|
|
581
|
+
* @param {string} tableName - Global table name
|
|
582
|
+
* @param {number} [timeout=2000] - Timeout in ms
|
|
583
|
+
* @returns {Promise<Object[]>} Array of data objects
|
|
584
|
+
*/
|
|
585
|
+
export async function readAllGlobal(gun, appname, tableName, timeout = 2000) {
|
|
586
|
+
const path = buildGlobalPath(appname, tableName);
|
|
587
|
+
return readAll(gun, path);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Delete data from a global table
|
|
592
|
+
* @param {Object} gun - Gun instance
|
|
593
|
+
* @param {string} appname - Application namespace
|
|
594
|
+
* @param {string} tableName - Global table name
|
|
595
|
+
* @param {string} key - Data key
|
|
596
|
+
* @returns {Promise<boolean>} Success indicator
|
|
597
|
+
*/
|
|
598
|
+
export async function deleteGlobal(gun, appname, tableName, key) {
|
|
599
|
+
const path = buildGlobalPath(appname, tableName, key);
|
|
600
|
+
return deleteData(gun, path);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Delete all data from a global table
|
|
605
|
+
* @param {Object} gun - Gun instance
|
|
606
|
+
* @param {string} appname - Application namespace
|
|
607
|
+
* @param {string} tableName - Global table name
|
|
608
|
+
* @returns {Promise<Object>} Deletion results { success: boolean, count: number }
|
|
609
|
+
*/
|
|
610
|
+
export async function deleteAllGlobal(gun, appname, tableName) {
|
|
611
|
+
const path = buildGlobalPath(appname, tableName);
|
|
612
|
+
return deleteAll(gun, path);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// ============================================================================
|
|
616
|
+
// DATA PARSING UTILITIES
|
|
617
|
+
// ============================================================================
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Parse data from Gun storage, handling various formats.
|
|
621
|
+
*
|
|
622
|
+
* Handles:
|
|
623
|
+
* - JSON string in _json field
|
|
624
|
+
* - Legacy object format
|
|
625
|
+
* - Gun references
|
|
626
|
+
*
|
|
627
|
+
* @param {*} rawData - Raw data from Gun
|
|
628
|
+
* @returns {Object|null} Parsed data or null
|
|
629
|
+
*/
|
|
630
|
+
export function parse(rawData) {
|
|
631
|
+
return deserializeFromGun(rawData);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Serialize data for Gun storage.
|
|
636
|
+
*
|
|
637
|
+
* @param {Object} data - Data to serialize
|
|
638
|
+
* @returns {string} JSON string
|
|
639
|
+
*/
|
|
640
|
+
export function serialize(data) {
|
|
641
|
+
return serializeForGun(data);
|
|
642
|
+
}
|