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.
Files changed (418) hide show
  1. package/CHANGELOG.md +473 -0
  2. package/FEATURES.md +431 -0
  3. package/LICENSE +29 -42
  4. package/LICENSE-AGPL.md +180 -0
  5. package/README.md +97 -16
  6. package/dist/2019-D2OG2idw.js +6680 -0
  7. package/dist/2019-D2OG2idw.js.map +1 -0
  8. package/dist/2019-EION3wKo.cjs +8 -0
  9. package/dist/2019-EION3wKo.cjs.map +1 -0
  10. package/dist/_commonjsHelpers-C37NGDzP.cjs +2 -0
  11. package/dist/_commonjsHelpers-C37NGDzP.cjs.map +1 -0
  12. package/dist/_commonjsHelpers-CUmg6egw.js +7 -0
  13. package/dist/_commonjsHelpers-CUmg6egw.js.map +1 -0
  14. package/dist/browser-BSniCNqO.js +3058 -0
  15. package/dist/browser-BSniCNqO.js.map +1 -0
  16. package/dist/browser-Cq59Ij19.cjs +2 -0
  17. package/dist/browser-Cq59Ij19.cjs.map +1 -0
  18. package/dist/cdn/holosphere.min.js +55 -0
  19. package/dist/cdn/holosphere.min.js.map +1 -0
  20. package/dist/cjs/holosphere.cjs +2 -0
  21. package/dist/cjs/holosphere.cjs.map +1 -0
  22. package/dist/esm/holosphere.js +53 -0
  23. package/dist/esm/holosphere.js.map +1 -0
  24. package/dist/index-DDGt_V9o.cjs +12 -0
  25. package/dist/index-DDGt_V9o.cjs.map +1 -0
  26. package/dist/index-DJXftyvB.js +39841 -0
  27. package/dist/index-DJXftyvB.js.map +1 -0
  28. package/dist/index-DMbdcMtK.cjs +18 -0
  29. package/dist/index-DMbdcMtK.cjs.map +1 -0
  30. package/dist/index-DeZ1xz_s.js +15104 -0
  31. package/dist/index-DeZ1xz_s.js.map +1 -0
  32. package/dist/indexeddb-storage-BFt6hMeF.js +176 -0
  33. package/dist/indexeddb-storage-BFt6hMeF.js.map +1 -0
  34. package/dist/indexeddb-storage-BK5tv4Sh.cjs +2 -0
  35. package/dist/indexeddb-storage-BK5tv4Sh.cjs.map +1 -0
  36. package/dist/memory-storage-C9HuoL2E.js +91 -0
  37. package/dist/memory-storage-C9HuoL2E.js.map +1 -0
  38. package/dist/memory-storage-Dao7jfYG.cjs +2 -0
  39. package/dist/memory-storage-Dao7jfYG.cjs.map +1 -0
  40. package/dist/secp256k1-BbKzbLtD.cjs +12 -0
  41. package/dist/secp256k1-BbKzbLtD.cjs.map +1 -0
  42. package/dist/secp256k1-CreY7Pcl.js +1890 -0
  43. package/dist/secp256k1-CreY7Pcl.js.map +1 -0
  44. package/docs/CONTRACTS.md +797 -0
  45. package/docs/FOSDEM_PROPOSAL.md +388 -0
  46. package/docs/LOCALFIRST.md +266 -0
  47. package/docs/api/ai_aggregation.js.html +333 -0
  48. package/docs/api/ai_breakdown.js.html +524 -0
  49. package/docs/api/ai_classifier.js.html +231 -0
  50. package/docs/api/ai_council.js.html +246 -0
  51. package/docs/api/ai_embeddings.js.html +304 -0
  52. package/docs/api/ai_federation-ai.js.html +338 -0
  53. package/docs/api/ai_h3-ai.js.html +970 -0
  54. package/docs/api/ai_index.js.html +124 -0
  55. package/docs/api/ai_json-ops.js.html +241 -0
  56. package/docs/api/ai_llm-service.js.html +239 -0
  57. package/docs/api/ai_nl-query.js.html +236 -0
  58. package/docs/api/ai_relationships.js.html +367 -0
  59. package/docs/api/ai_schema-extractor.js.html +235 -0
  60. package/docs/api/ai_spatial.js.html +307 -0
  61. package/docs/api/ai_tts.js.html +214 -0
  62. package/docs/api/content_social-protocols.js.html +180 -0
  63. package/docs/api/core_holosphere.js.html +757 -0
  64. package/docs/api/crypto_nostr-utils.js.html +306 -0
  65. package/docs/api/crypto_secp256k1.js.html +267 -0
  66. package/docs/api/data/search.json +1 -0
  67. package/docs/api/federation_discovery.js.html +337 -0
  68. package/docs/api/federation_handshake.js.html +478 -0
  69. package/docs/api/federation_hologram.js.html +1053 -0
  70. package/docs/api/federation_registry.js.html +389 -0
  71. package/docs/api/fonts/Inconsolata-Regular.ttf +0 -0
  72. package/docs/api/fonts/OpenSans-Regular.ttf +0 -0
  73. package/docs/api/fonts/WorkSans-Bold.ttf +0 -0
  74. package/docs/api/global.html +3 -0
  75. package/docs/api/hierarchical_upcast.js.html +128 -0
  76. package/docs/api/index.html +265 -0
  77. package/docs/api/index.js.html +1868 -0
  78. package/docs/api/lib_ai-methods.js.html +660 -0
  79. package/docs/api/lib_contract-methods.js.html +445 -0
  80. package/docs/api/lib_errors.js.html +56 -0
  81. package/docs/api/lib_federation-methods.js.html +348 -0
  82. package/docs/api/lib_index.js.html +33 -0
  83. package/docs/api/module-ai.html +5 -0
  84. package/docs/api/module-ai_aggregation-SmartAggregation.html +6 -0
  85. package/docs/api/module-ai_aggregation.SmartAggregation.html +3 -0
  86. package/docs/api/module-ai_aggregation.html +3 -0
  87. package/docs/api/module-ai_breakdown-TaskBreakdown.html +5 -0
  88. package/docs/api/module-ai_breakdown.TaskBreakdown.html +3 -0
  89. package/docs/api/module-ai_breakdown.html +3 -0
  90. package/docs/api/module-ai_classifier-Classifier.html +6 -0
  91. package/docs/api/module-ai_classifier.Classifier.html +3 -0
  92. package/docs/api/module-ai_classifier.html +3 -0
  93. package/docs/api/module-ai_council-Council.html +6 -0
  94. package/docs/api/module-ai_council.Council.html +3 -0
  95. package/docs/api/module-ai_council.html +3 -0
  96. package/docs/api/module-ai_embeddings-Embeddings.html +5 -0
  97. package/docs/api/module-ai_embeddings.Embeddings.html +3 -0
  98. package/docs/api/module-ai_embeddings.html +3 -0
  99. package/docs/api/module-ai_federation-ai-FederationAdvisor.html +6 -0
  100. package/docs/api/module-ai_federation-ai.FederationAdvisor.html +3 -0
  101. package/docs/api/module-ai_federation-ai.html +3 -0
  102. package/docs/api/module-ai_h3-ai-H3AI.html +6 -0
  103. package/docs/api/module-ai_h3-ai.H3AI.html +3 -0
  104. package/docs/api/module-ai_h3-ai.html +3 -0
  105. package/docs/api/module-ai_json-ops-JSONOps.html +5 -0
  106. package/docs/api/module-ai_json-ops.JSONOps.html +3 -0
  107. package/docs/api/module-ai_json-ops.html +3 -0
  108. package/docs/api/module-ai_llm-service-LLMService.html +5 -0
  109. package/docs/api/module-ai_llm-service.LLMService.html +3 -0
  110. package/docs/api/module-ai_llm-service.html +3 -0
  111. package/docs/api/module-ai_nl-query-NLQuery.html +5 -0
  112. package/docs/api/module-ai_nl-query.NLQuery.html +3 -0
  113. package/docs/api/module-ai_nl-query.html +3 -0
  114. package/docs/api/module-ai_relationships-RelationshipDiscovery.html +6 -0
  115. package/docs/api/module-ai_relationships.RelationshipDiscovery.html +3 -0
  116. package/docs/api/module-ai_relationships.html +3 -0
  117. package/docs/api/module-ai_schema-extractor-SchemaExtractor.html +5 -0
  118. package/docs/api/module-ai_schema-extractor.SchemaExtractor.html +3 -0
  119. package/docs/api/module-ai_schema-extractor.html +3 -0
  120. package/docs/api/module-ai_spatial-SpatialAnalysis.html +6 -0
  121. package/docs/api/module-ai_spatial.SpatialAnalysis.html +3 -0
  122. package/docs/api/module-ai_spatial.html +3 -0
  123. package/docs/api/module-ai_tts-TTS.html +5 -0
  124. package/docs/api/module-ai_tts.TTS.html +3 -0
  125. package/docs/api/module-ai_tts.html +3 -0
  126. package/docs/api/module-content_social-protocols.html +3 -0
  127. package/docs/api/module-core_holosphere-HoloSphere.html +6 -0
  128. package/docs/api/module-core_holosphere.HoloSphere.html +3 -0
  129. package/docs/api/module-core_holosphere.html +3 -0
  130. package/docs/api/module-crypto_nostr-utils.html +3 -0
  131. package/docs/api/module-crypto_secp256k1.html +3 -0
  132. package/docs/api/module-federation_hologram.html +3 -0
  133. package/docs/api/module-hierarchical_upcast.html +3 -0
  134. package/docs/api/module-holosphere-HoloSphereBase.html +3 -0
  135. package/docs/api/module-holosphere.html +3 -0
  136. package/docs/api/module-lib_ai-methods.html +3 -0
  137. package/docs/api/module-lib_contract-methods.html +3 -0
  138. package/docs/api/module-lib_errors-AuthorizationError.html +3 -0
  139. package/docs/api/module-lib_errors-ValidationError.html +3 -0
  140. package/docs/api/module-lib_errors.AuthorizationError.html +3 -0
  141. package/docs/api/module-lib_errors.ValidationError.html +3 -0
  142. package/docs/api/module-lib_errors.html +3 -0
  143. package/docs/api/module-lib_federation-methods.html +3 -0
  144. package/docs/api/module-lib_index.html +3 -0
  145. package/docs/api/module-schema_validator-ValidationError.html +3 -0
  146. package/docs/api/module-schema_validator.ValidationError.html +3 -0
  147. package/docs/api/module-schema_validator.html +3 -0
  148. package/docs/api/module-spatial_h3-operations.html +4 -0
  149. package/docs/api/module-storage_backend-factory.BackendFactory.html +3 -0
  150. package/docs/api/module-storage_backend-factory.html +3 -0
  151. package/docs/api/module-storage_backend-interface-StorageBackend.html +3 -0
  152. package/docs/api/module-storage_backend-interface.StorageBackend.html +3 -0
  153. package/docs/api/module-storage_backend-interface.html +3 -0
  154. package/docs/api/module-storage_backends_activitypub-backend-ActivityPubBackend.html +7 -0
  155. package/docs/api/module-storage_backends_activitypub-backend.ActivityPubBackend.html +3 -0
  156. package/docs/api/module-storage_backends_activitypub-backend.html +3 -0
  157. package/docs/api/module-storage_backends_activitypub_server-ActivityPubServer.html +8 -0
  158. package/docs/api/module-storage_backends_activitypub_server.ActivityPubServer.html +3 -0
  159. package/docs/api/module-storage_backends_activitypub_server.html +3 -0
  160. package/docs/api/module-storage_backends_gundb-backend-GunDBBackend.html +7 -0
  161. package/docs/api/module-storage_backends_gundb-backend.GunDBBackend.html +3 -0
  162. package/docs/api/module-storage_backends_gundb-backend.html +3 -0
  163. package/docs/api/module-storage_backends_nostr-backend-NostrBackend.html +8 -0
  164. package/docs/api/module-storage_backends_nostr-backend.NostrBackend.html +3 -0
  165. package/docs/api/module-storage_backends_nostr-backend.html +3 -0
  166. package/docs/api/module-storage_filesystem-storage-FileSystemStorage.html +5 -0
  167. package/docs/api/module-storage_filesystem-storage-browser-FileSystemStorage.html +3 -0
  168. package/docs/api/module-storage_filesystem-storage-browser.FileSystemStorage.html +3 -0
  169. package/docs/api/module-storage_filesystem-storage-browser.html +3 -0
  170. package/docs/api/module-storage_filesystem-storage.FileSystemStorage.html +3 -0
  171. package/docs/api/module-storage_filesystem-storage.html +3 -0
  172. package/docs/api/module-storage_global-tables.html +3 -0
  173. package/docs/api/module-storage_gun-async.html +3 -0
  174. package/docs/api/module-storage_gun-auth-GunAuth.html +5 -0
  175. package/docs/api/module-storage_gun-auth.GunAuth.html +3 -0
  176. package/docs/api/module-storage_gun-auth.html +3 -0
  177. package/docs/api/module-storage_gun-federation.html +3 -0
  178. package/docs/api/module-storage_gun-references-GunReferenceHandler.html +5 -0
  179. package/docs/api/module-storage_gun-references.GunReferenceHandler.html +3 -0
  180. package/docs/api/module-storage_gun-references.html +3 -0
  181. package/docs/api/module-storage_gun-schema-GunSchemaValidator.html +5 -0
  182. package/docs/api/module-storage_gun-schema.GunSchemaValidator.html +3 -0
  183. package/docs/api/module-storage_gun-schema.html +3 -0
  184. package/docs/api/module-storage_gun-wrapper.html +11 -0
  185. package/docs/api/module-storage_indexeddb-storage-IndexedDBStorage.html +5 -0
  186. package/docs/api/module-storage_indexeddb-storage.IndexedDBStorage.html +3 -0
  187. package/docs/api/module-storage_indexeddb-storage.html +3 -0
  188. package/docs/api/module-storage_key-storage-simple.html +3 -0
  189. package/docs/api/module-storage_key-storage.html +4 -0
  190. package/docs/api/module-storage_memory-storage-MemoryStorage.html +5 -0
  191. package/docs/api/module-storage_memory-storage.MemoryStorage.html +3 -0
  192. package/docs/api/module-storage_memory-storage.html +3 -0
  193. package/docs/api/module-storage_migration-MigrationTool.html +6 -0
  194. package/docs/api/module-storage_migration.MigrationTool.html +3 -0
  195. package/docs/api/module-storage_migration.html +3 -0
  196. package/docs/api/module-storage_nostr-async.html +18 -0
  197. package/docs/api/module-storage_nostr-client-LRUCache.html +3 -0
  198. package/docs/api/module-storage_nostr-client-NostrClient.html +7 -0
  199. package/docs/api/module-storage_nostr-client.NostrClient.html +15 -0
  200. package/docs/api/module-storage_nostr-client.html +6 -0
  201. package/docs/api/module-storage_nostr-wrapper.html +3 -0
  202. package/docs/api/module-storage_outbox-queue-OutboxQueue.html +4 -0
  203. package/docs/api/module-storage_outbox-queue.OutboxQueue.html +3 -0
  204. package/docs/api/module-storage_outbox-queue.html +3 -0
  205. package/docs/api/module-storage_persistent-storage-PersistentStorage.html +3 -0
  206. package/docs/api/module-storage_persistent-storage.html +4 -0
  207. package/docs/api/module-storage_sync-service-SyncService.html +5 -0
  208. package/docs/api/module-storage_sync-service.SyncService.html +3 -0
  209. package/docs/api/module-storage_sync-service.html +3 -0
  210. package/docs/api/module-storage_unified-storage.html +3 -0
  211. package/docs/api/module-subscriptions_manager.SubscriptionRegistry.html +3 -0
  212. package/docs/api/module-subscriptions_manager.html +3 -0
  213. package/docs/api/schema_validator.js.html +113 -0
  214. package/docs/api/scripts/core.js +726 -0
  215. package/docs/api/scripts/core.min.js +23 -0
  216. package/docs/api/scripts/resize.js +90 -0
  217. package/docs/api/scripts/search.js +265 -0
  218. package/docs/api/scripts/search.min.js +6 -0
  219. package/docs/api/scripts/third-party/Apache-License-2.0.txt +202 -0
  220. package/docs/api/scripts/third-party/fuse.js +9 -0
  221. package/docs/api/scripts/third-party/hljs-line-num-original.js +369 -0
  222. package/docs/api/scripts/third-party/hljs-line-num.js +1 -0
  223. package/docs/api/scripts/third-party/hljs-original.js +5171 -0
  224. package/docs/api/scripts/third-party/hljs.js +1 -0
  225. package/docs/api/scripts/third-party/popper.js +5 -0
  226. package/docs/api/scripts/third-party/tippy.js +1 -0
  227. package/docs/api/scripts/third-party/tocbot.js +672 -0
  228. package/docs/api/scripts/third-party/tocbot.min.js +1 -0
  229. package/docs/api/spatial_h3-operations.js.html +129 -0
  230. package/docs/api/storage_backend-factory.js.html +133 -0
  231. package/docs/api/storage_backend-interface.js.html +164 -0
  232. package/docs/api/storage_backends_activitypub-backend.js.html +298 -0
  233. package/docs/api/storage_backends_activitypub_server.js.html +678 -0
  234. package/docs/api/storage_backends_gundb-backend.js.html +878 -0
  235. package/docs/api/storage_backends_nostr-backend.js.html +254 -0
  236. package/docs/api/storage_filesystem-storage-browser.js.html +83 -0
  237. package/docs/api/storage_filesystem-storage.js.html +207 -0
  238. package/docs/api/storage_global-tables.js.html +116 -0
  239. package/docs/api/storage_gun-async.js.html +344 -0
  240. package/docs/api/storage_gun-auth.js.html +376 -0
  241. package/docs/api/storage_gun-federation.js.html +788 -0
  242. package/docs/api/storage_gun-references.js.html +212 -0
  243. package/docs/api/storage_gun-schema.js.html +309 -0
  244. package/docs/api/storage_gun-wrapper.js.html +645 -0
  245. package/docs/api/storage_indexeddb-storage.js.html +224 -0
  246. package/docs/api/storage_key-storage-simple.js.html +102 -0
  247. package/docs/api/storage_key-storage.js.html +171 -0
  248. package/docs/api/storage_memory-storage.js.html +128 -0
  249. package/docs/api/storage_migration.js.html +354 -0
  250. package/docs/api/storage_nostr-async.js.html +1076 -0
  251. package/docs/api/storage_nostr-client.js.html +1598 -0
  252. package/docs/api/storage_nostr-wrapper.js.html +218 -0
  253. package/docs/api/storage_outbox-queue.js.html +248 -0
  254. package/docs/api/storage_persistent-storage.js.html +160 -0
  255. package/docs/api/storage_sync-service.js.html +201 -0
  256. package/docs/api/storage_unified-storage.js.html +157 -0
  257. package/docs/api/styles/clean-jsdoc-theme-base.css +1159 -0
  258. package/docs/api/styles/clean-jsdoc-theme-dark.css +412 -0
  259. package/docs/api/styles/clean-jsdoc-theme-light.css +482 -0
  260. package/docs/api/styles/clean-jsdoc-theme-scrollbar.css +30 -0
  261. package/docs/api/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
  262. package/docs/api/styles/clean-jsdoc-theme.min.css +1 -0
  263. package/docs/api/subscriptions_manager.js.html +162 -0
  264. package/docs/contracts/api-interface.md +793 -0
  265. package/docs/data-model.md +476 -0
  266. package/docs/gun-async-usage.md +338 -0
  267. package/docs/plan.md +349 -0
  268. package/docs/quickstart.md +674 -0
  269. package/docs/research.md +362 -0
  270. package/docs/spec.md +244 -0
  271. package/docs/storage-backends.md +326 -0
  272. package/docs/tasks.md +947 -0
  273. package/examples/demo.html +47 -0
  274. package/examples/holosphere-widget.js +1242 -0
  275. package/examples/widget-demo.html +274 -0
  276. package/examples/widget.html +703 -0
  277. package/jsdoc.json +26 -0
  278. package/package.json +25 -7
  279. package/src/ai/aggregation.js +13 -2
  280. package/src/ai/breakdown.js +12 -2
  281. package/src/ai/classifier.js +14 -3
  282. package/src/ai/council.js +22 -7
  283. package/src/ai/embeddings.js +37 -15
  284. package/src/ai/federation-ai.js +13 -2
  285. package/src/ai/h3-ai.js +14 -2
  286. package/src/ai/index.js +16 -7
  287. package/src/ai/json-ops.js +18 -5
  288. package/src/ai/llm-service.js +62 -31
  289. package/src/ai/nl-query.js +12 -2
  290. package/src/ai/relationships.js +13 -2
  291. package/src/ai/schema-extractor.js +24 -10
  292. package/src/ai/spatial.js +13 -2
  293. package/src/ai/tts.js +25 -8
  294. package/src/cdn-entry.js +22 -0
  295. package/src/content/social-protocols.js +34 -25
  296. package/src/contracts/abis/Appreciative.json +1280 -0
  297. package/src/contracts/abis/AppreciativeFactory.json +101 -0
  298. package/src/contracts/abis/Bundle.json +1438 -0
  299. package/src/contracts/abis/BundleFactory.json +106 -0
  300. package/src/contracts/abis/Holon.json +881 -0
  301. package/src/contracts/abis/Holons.json +330 -0
  302. package/src/contracts/abis/Managed.json +1262 -0
  303. package/src/contracts/abis/ManagedFactory.json +149 -0
  304. package/src/contracts/abis/Membrane.json +261 -0
  305. package/src/contracts/abis/Splitter.json +1624 -0
  306. package/src/contracts/abis/SplitterFactory.json +220 -0
  307. package/src/contracts/abis/TestToken.json +321 -0
  308. package/src/contracts/abis/Zoned.json +1461 -0
  309. package/src/contracts/abis/ZonedFactory.json +154 -0
  310. package/src/contracts/chain-manager.js +403 -0
  311. package/src/contracts/deployer.js +500 -0
  312. package/src/contracts/event-listener.js +539 -0
  313. package/src/contracts/holon-contracts.js +359 -0
  314. package/src/contracts/index.js +82 -0
  315. package/src/contracts/networks.js +229 -0
  316. package/src/contracts/operations.js +687 -0
  317. package/src/contracts/queries.js +638 -0
  318. package/src/core/holosphere.js +487 -6
  319. package/src/crypto/nostr-utils.js +303 -0
  320. package/src/crypto/secp256k1.js +7 -2
  321. package/src/federation/handshake.js +475 -0
  322. package/src/federation/hologram.js +117 -3
  323. package/src/hierarchical/upcast.js +40 -25
  324. package/src/index.js +1501 -1909
  325. package/src/lib/ai-methods.js +657 -0
  326. package/src/lib/contract-methods.js +442 -0
  327. package/src/lib/errors.js +53 -0
  328. package/src/lib/federation-methods.js +345 -0
  329. package/src/lib/index.js +30 -0
  330. package/src/schema/validator.js +22 -3
  331. package/src/spatial/h3-operations.js +19 -3
  332. package/src/storage/backend-factory.js +7 -2
  333. package/src/storage/backend-interface.js +21 -2
  334. package/src/storage/backends/activitypub/server.js +25 -3
  335. package/src/storage/backends/activitypub-backend.js +25 -2
  336. package/src/storage/backends/gundb-backend.js +692 -50
  337. package/src/storage/backends/nostr-backend.js +116 -1
  338. package/src/storage/filesystem-storage-browser.js +42 -2
  339. package/src/storage/filesystem-storage.js +72 -5
  340. package/src/storage/global-tables.js +35 -3
  341. package/src/storage/gun-async.js +75 -15
  342. package/src/storage/gun-auth.js +373 -0
  343. package/src/storage/gun-federation.js +785 -0
  344. package/src/storage/gun-references.js +209 -0
  345. package/src/storage/gun-schema.js +306 -0
  346. package/src/storage/gun-wrapper.js +475 -54
  347. package/src/storage/indexeddb-storage.js +112 -13
  348. package/src/storage/key-storage-simple.js +32 -9
  349. package/src/storage/key-storage.js +45 -13
  350. package/src/storage/memory-storage.js +68 -2
  351. package/src/storage/migration.js +20 -7
  352. package/src/storage/nostr-async.js +412 -122
  353. package/src/storage/nostr-client.js +749 -76
  354. package/src/storage/nostr-wrapper.js +6 -2
  355. package/src/storage/outbox-queue.js +55 -18
  356. package/src/storage/persistent-storage.js +62 -14
  357. package/src/storage/sync-service.js +51 -17
  358. package/src/storage/unified-storage.js +154 -0
  359. package/src/subscriptions/manager.js +34 -17
  360. package/types/index.d.ts +133 -0
  361. package/vite.config.cdn.js +60 -0
  362. package/tests/unit/ai/aggregation.test.js +0 -295
  363. package/tests/unit/ai/breakdown.test.js +0 -446
  364. package/tests/unit/ai/classifier.test.js +0 -294
  365. package/tests/unit/ai/council.test.js +0 -262
  366. package/tests/unit/ai/embeddings.test.js +0 -384
  367. package/tests/unit/ai/federation-ai.test.js +0 -344
  368. package/tests/unit/ai/h3-ai.test.js +0 -458
  369. package/tests/unit/ai/index.test.js +0 -304
  370. package/tests/unit/ai/json-ops.test.js +0 -307
  371. package/tests/unit/ai/llm-service.test.js +0 -390
  372. package/tests/unit/ai/nl-query.test.js +0 -383
  373. package/tests/unit/ai/relationships.test.js +0 -311
  374. package/tests/unit/ai/schema-extractor.test.js +0 -384
  375. package/tests/unit/ai/spatial.test.js +0 -279
  376. package/tests/unit/ai/tts.test.js +0 -279
  377. package/tests/unit/content.test.js +0 -332
  378. package/tests/unit/contract/core.test.js +0 -88
  379. package/tests/unit/contract/crypto.test.js +0 -198
  380. package/tests/unit/contract/data.test.js +0 -223
  381. package/tests/unit/contract/federation.test.js +0 -181
  382. package/tests/unit/contract/hierarchical.test.js +0 -113
  383. package/tests/unit/contract/schema.test.js +0 -114
  384. package/tests/unit/contract/social.test.js +0 -217
  385. package/tests/unit/contract/spatial.test.js +0 -110
  386. package/tests/unit/contract/subscriptions.test.js +0 -128
  387. package/tests/unit/contract/utils.test.js +0 -159
  388. package/tests/unit/core.test.js +0 -152
  389. package/tests/unit/crypto.test.js +0 -328
  390. package/tests/unit/federation.test.js +0 -234
  391. package/tests/unit/gun-async.test.js +0 -252
  392. package/tests/unit/hierarchical.test.js +0 -399
  393. package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
  394. package/tests/unit/integration/scenario-02-federation.test.js +0 -76
  395. package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
  396. package/tests/unit/integration/scenario-04-validation.test.js +0 -129
  397. package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
  398. package/tests/unit/integration/scenario-06-social.test.js +0 -135
  399. package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
  400. package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
  401. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
  402. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
  403. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
  404. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
  405. package/tests/unit/performance/benchmark.test.js +0 -85
  406. package/tests/unit/schema.test.js +0 -213
  407. package/tests/unit/spatial.test.js +0 -158
  408. package/tests/unit/storage.test.js +0 -195
  409. package/tests/unit/subscriptions.test.js +0 -328
  410. package/tests/unit/test-data-permanence-debug.js +0 -197
  411. package/tests/unit/test-data-permanence.js +0 -340
  412. package/tests/unit/test-key-persistence-fixed.js +0 -148
  413. package/tests/unit/test-key-persistence.js +0 -172
  414. package/tests/unit/test-relay-permanence.js +0 -376
  415. package/tests/unit/test-second-node.js +0 -95
  416. package/tests/unit/test-simple-write.js +0 -89
  417. /package/{cleanup-test-data.js → scripts/cleanup-test-data.js} +0 -0
  418. /package/{test-ai-real-api.js → scripts/test-ai-real-api.js} +0 -0
@@ -0,0 +1,475 @@
1
+ /**
2
+ * Federation Handshake Protocol
3
+ *
4
+ * Uses NIP-44 encrypted DMs (kind 4) for bidirectional federation request/response.
5
+ * Falls back to NIP-04 for backward compatibility when receiving messages.
6
+ * When user A federates with user B's pubkey, a DM is sent to B.
7
+ * B can accept/reject, creating a matching federation on their side.
8
+ */
9
+
10
+ import {
11
+ encryptNIP44,
12
+ decryptNIP44,
13
+ encryptNIP04,
14
+ decryptNIP04,
15
+ createDMEvent,
16
+ hexToNpub,
17
+ generateNonce,
18
+ } from '../crypto/nostr-utils.js';
19
+ import { addFederatedPartner, storeInboundCapability } from './registry.js';
20
+
21
+ // ============================================================================
22
+ // Types (documented for reference)
23
+ // ============================================================================
24
+
25
+ /**
26
+ * @typedef {Object} FederationRequestPayload
27
+ * @property {'federation_request'} type
28
+ * @property {'1.0'} version
29
+ * @property {string} requestId - Unique request ID
30
+ * @property {number} timestamp
31
+ * @property {string} senderHolonId - Holon ID of the sender
32
+ * @property {string} senderHolonName - Human-readable holon name
33
+ * @property {string} senderNpub - Sender's npub
34
+ * @property {Object} lensConfig - Lens configuration
35
+ * @property {string[]} lensConfig.inbound - Lenses sender will accept
36
+ * @property {string[]} lensConfig.outbound - Lenses sender will share
37
+ * @property {Array} capabilities - Capability tokens
38
+ * @property {string} [message] - Optional personal message
39
+ */
40
+
41
+ /**
42
+ * @typedef {Object} FederationResponsePayload
43
+ * @property {'federation_response'} type
44
+ * @property {'1.0'} version
45
+ * @property {string} requestId - References original request
46
+ * @property {number} timestamp
47
+ * @property {'accepted'|'rejected'} status
48
+ * @property {string} [responderHolonId]
49
+ * @property {string} [responderHolonName]
50
+ * @property {string} [responderNpub]
51
+ * @property {Object} [lensConfig]
52
+ * @property {Array} [capabilities]
53
+ * @property {string} [message]
54
+ */
55
+
56
+ // ============================================================================
57
+ // Request/Response Creation
58
+ // ============================================================================
59
+
60
+ /**
61
+ * Create a federation request payload
62
+ * @param {Object} params
63
+ * @param {string} params.senderHolonId
64
+ * @param {string} params.senderHolonName
65
+ * @param {string} params.senderPubKey - Hex public key
66
+ * @param {Object} params.lensConfig - { inbound: string[], outbound: string[] }
67
+ * @param {Array} [params.capabilities] - Capability tokens to include
68
+ * @param {string} [params.message] - Optional message
69
+ * @returns {FederationRequestPayload}
70
+ */
71
+ export function createFederationRequest({
72
+ senderHolonId,
73
+ senderHolonName,
74
+ senderPubKey,
75
+ lensConfig = { inbound: [], outbound: [] },
76
+ capabilities = [],
77
+ message,
78
+ }) {
79
+ return {
80
+ type: 'federation_request',
81
+ version: '1.0',
82
+ requestId: generateNonce(),
83
+ timestamp: Date.now(),
84
+ senderHolonId,
85
+ senderHolonName,
86
+ senderNpub: hexToNpub(senderPubKey),
87
+ lensConfig,
88
+ capabilities,
89
+ message,
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Create a federation response payload
95
+ * @param {Object} params
96
+ * @param {string} params.requestId - Original request ID
97
+ * @param {'accepted'|'rejected'} params.status
98
+ * @param {string} [params.responderHolonId]
99
+ * @param {string} [params.responderHolonName]
100
+ * @param {string} [params.responderPubKey] - Hex public key
101
+ * @param {Object} [params.lensConfig]
102
+ * @param {Array} [params.capabilities]
103
+ * @param {string} [params.message]
104
+ * @returns {FederationResponsePayload}
105
+ */
106
+ export function createFederationResponse({
107
+ requestId,
108
+ status,
109
+ responderHolonId,
110
+ responderHolonName,
111
+ responderPubKey,
112
+ lensConfig,
113
+ capabilities,
114
+ message,
115
+ }) {
116
+ return {
117
+ type: 'federation_response',
118
+ version: '1.0',
119
+ requestId,
120
+ timestamp: Date.now(),
121
+ status,
122
+ responderHolonId,
123
+ responderHolonName,
124
+ responderNpub: responderPubKey ? hexToNpub(responderPubKey) : undefined,
125
+ lensConfig,
126
+ capabilities,
127
+ message,
128
+ };
129
+ }
130
+
131
+ // ============================================================================
132
+ // DM Sending
133
+ // ============================================================================
134
+
135
+ /**
136
+ * Send a federation request DM
137
+ * @param {Object} client - NostrClient instance with publish method
138
+ * @param {string} privateKey - Sender's hex private key
139
+ * @param {string} recipientPubKey - Recipient's hex public key
140
+ * @param {FederationRequestPayload} request - Request payload
141
+ * @returns {Promise<boolean>} Success indicator
142
+ */
143
+ export async function sendFederationRequest(client, privateKey, recipientPubKey, request) {
144
+ try {
145
+ const content = JSON.stringify(request);
146
+ const encrypted = encryptNIP44(privateKey, recipientPubKey, content);
147
+ const event = createDMEvent(recipientPubKey, encrypted, privateKey);
148
+
149
+ if (client?.publish) {
150
+ await client.publish(event);
151
+ console.log('[Handshake] Federation request sent to:', recipientPubKey.substring(0, 8) + '...');
152
+ return true;
153
+ } else {
154
+ console.error('[Handshake] No publish method on client');
155
+ return false;
156
+ }
157
+ } catch (error) {
158
+ console.error('[Handshake] Failed to send federation request:', error);
159
+ return false;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Send a federation response DM
165
+ * @param {Object} client - NostrClient instance with publish method
166
+ * @param {string} privateKey - Sender's hex private key
167
+ * @param {string} recipientPubKey - Recipient's hex public key
168
+ * @param {FederationResponsePayload} response - Response payload
169
+ * @returns {Promise<boolean>} Success indicator
170
+ */
171
+ export async function sendFederationResponse(client, privateKey, recipientPubKey, response) {
172
+ try {
173
+ const content = JSON.stringify(response);
174
+ const encrypted = encryptNIP44(privateKey, recipientPubKey, content);
175
+ const event = createDMEvent(recipientPubKey, encrypted, privateKey);
176
+
177
+ if (client?.publish) {
178
+ await client.publish(event);
179
+ console.log('[Handshake] Federation response sent to:', recipientPubKey.substring(0, 8) + '...');
180
+ return true;
181
+ } else {
182
+ console.error('[Handshake] No publish method on client');
183
+ return false;
184
+ }
185
+ } catch (error) {
186
+ console.error('[Handshake] Failed to send federation response:', error);
187
+ return false;
188
+ }
189
+ }
190
+
191
+ // ============================================================================
192
+ // DM Subscription
193
+ // ============================================================================
194
+
195
+ /**
196
+ * Subscribe to incoming federation DMs
197
+ * @param {Object} client - NostrClient instance with subscribe method
198
+ * @param {string} privateKey - Recipient's hex private key
199
+ * @param {string} publicKey - Recipient's hex public key
200
+ * @param {Object} handlers
201
+ * @param {Function} handlers.onRequest - Called with (request, senderPubKey)
202
+ * @param {Function} handlers.onResponse - Called with (response, senderPubKey)
203
+ * @returns {Function} Unsubscribe function
204
+ */
205
+ export function subscribeToFederationDMs(client, privateKey, publicKey, handlers) {
206
+ const { onRequest, onResponse } = handlers;
207
+ let isActive = true;
208
+ const processedEventIds = new Set();
209
+
210
+ const handleEvent = async (event) => {
211
+ if (!isActive) return;
212
+
213
+ // Skip duplicates
214
+ if (processedEventIds.has(event.id)) return;
215
+ processedEventIds.add(event.id);
216
+
217
+ // Only kind 4 (encrypted DM) events tagged to us
218
+ if (event.kind !== 4) return;
219
+
220
+ const pTag = event.tags?.find((t) => t[0] === 'p');
221
+ if (!pTag || pTag[1] !== publicKey) return;
222
+
223
+ try {
224
+ let decrypted;
225
+
226
+ // Try NIP-44 first (modern encryption)
227
+ try {
228
+ decrypted = decryptNIP44(privateKey, event.pubkey, event.content);
229
+ } catch (nip44Error) {
230
+ // Fall back to NIP-04 for backward compatibility with older clients
231
+ decrypted = await decryptNIP04(privateKey, event.pubkey, event.content);
232
+ }
233
+
234
+ const payload = JSON.parse(decrypted);
235
+
236
+ if (payload.type === 'federation_request' && payload.version === '1.0') {
237
+ console.log('[Handshake] Received federation request from:', event.pubkey.substring(0, 8) + '...');
238
+ onRequest?.(payload, event.pubkey);
239
+ } else if (payload.type === 'federation_response' && payload.version === '1.0') {
240
+ console.log('[Handshake] Received federation response from:', event.pubkey.substring(0, 8) + '...');
241
+ onResponse?.(payload, event.pubkey);
242
+ }
243
+ } catch (error) {
244
+ // Silently ignore non-federation DMs
245
+ }
246
+ };
247
+
248
+ // Subscribe via client
249
+ // Note: client is the HoloSphere instance, client.client is the NostrClient
250
+ let subscription = null;
251
+
252
+ const startSubscription = async () => {
253
+ // Get the NostrClient from HoloSphere instance
254
+ const nostrClient = client?.client;
255
+ if (!nostrClient?.subscribe) {
256
+ console.warn('[Handshake] No NostrClient subscribe method available');
257
+ return;
258
+ }
259
+
260
+ const filter = {
261
+ kinds: [4],
262
+ '#p': [publicKey],
263
+ since: Math.floor(Date.now() / 1000) - 86400, // Last 24 hours
264
+ };
265
+
266
+ try {
267
+ // NostrClient.subscribe(filter, onEvent, options) returns { unsubscribe }
268
+ subscription = await nostrClient.subscribe(filter, handleEvent, {});
269
+ console.log('[Handshake] Federation DM subscription started');
270
+ } catch (error) {
271
+ console.error('[Handshake] Failed to subscribe:', error);
272
+ }
273
+ };
274
+
275
+ startSubscription();
276
+
277
+ // Return unsubscribe function
278
+ return () => {
279
+ isActive = false;
280
+ if (subscription?.unsubscribe) {
281
+ subscription.unsubscribe();
282
+ } else if (subscription?.close) {
283
+ subscription.close();
284
+ }
285
+ };
286
+ }
287
+
288
+ // ============================================================================
289
+ // High-Level Handshake Operations
290
+ // ============================================================================
291
+
292
+ /**
293
+ * Initiate a federation handshake with a partner
294
+ * Creates local federation record and sends DM to partner
295
+ * @param {Object} holosphere - HoloSphere instance
296
+ * @param {string} privateKey - Sender's hex private key
297
+ * @param {Object} params
298
+ * @param {string} params.partnerPubKey - Partner's hex public key
299
+ * @param {string} params.holonId - Current holon ID
300
+ * @param {string} params.holonName - Current holon name
301
+ * @param {Object} [params.lensConfig] - Lens configuration
302
+ * @param {string} [params.message] - Optional message
303
+ * @returns {Promise<Object>} Result with success, requestId (if successful), error (if failed)
304
+ */
305
+ export async function initiateFederationHandshake(holosphere, privateKey, params) {
306
+ const {
307
+ partnerPubKey,
308
+ holonId,
309
+ holonName,
310
+ lensConfig = { inbound: [], outbound: [] },
311
+ message,
312
+ } = params;
313
+
314
+ try {
315
+ // Get sender's public key
316
+ const { getPublicKey } = await import('../crypto/nostr-utils.js');
317
+ const senderPubKey = getPublicKey(privateKey);
318
+
319
+ // Create federation request
320
+ const request = createFederationRequest({
321
+ senderHolonId: holonId,
322
+ senderHolonName: holonName,
323
+ senderPubKey,
324
+ lensConfig,
325
+ capabilities: [],
326
+ message,
327
+ });
328
+
329
+ // Add partner to local registry (status: pending)
330
+ if (holosphere.client) {
331
+ await addFederatedPartner(holosphere.client, holosphere.config.appName, partnerPubKey, {
332
+ alias: null,
333
+ addedVia: 'handshake_initiated',
334
+ });
335
+ }
336
+
337
+ // Send DM to partner
338
+ const sent = await sendFederationRequest(holosphere.client, privateKey, partnerPubKey, request);
339
+
340
+ if (sent) {
341
+ return { success: true, requestId: request.requestId };
342
+ } else {
343
+ return { success: false, error: 'Failed to send DM' };
344
+ }
345
+ } catch (error) {
346
+ return { success: false, error: error.message };
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Accept a federation request
352
+ * Creates local federation record and sends acceptance DM
353
+ * @param {Object} holosphere - HoloSphere instance
354
+ * @param {string} privateKey - Responder's hex private key
355
+ * @param {Object} params
356
+ * @param {FederationRequestPayload} params.request - Original request
357
+ * @param {string} params.senderPubKey - Original sender's public key
358
+ * @param {string} params.holonId - Current holon ID
359
+ * @param {string} params.holonName - Current holon name
360
+ * @param {Object} [params.lensConfig] - Our lens configuration
361
+ * @param {string} [params.message] - Optional message
362
+ * @returns {Promise<Object>} Result with success and optional error
363
+ */
364
+ export async function acceptFederationRequest(holosphere, privateKey, params) {
365
+ const {
366
+ request,
367
+ senderPubKey,
368
+ holonId,
369
+ holonName,
370
+ lensConfig = { inbound: [], outbound: [] },
371
+ message,
372
+ } = params;
373
+
374
+ try {
375
+ // Get responder's public key
376
+ const { getPublicKey } = await import('../crypto/nostr-utils.js');
377
+ const responderPubKey = getPublicKey(privateKey);
378
+
379
+ // Add sender as federated partner in Nostr registry
380
+ if (holosphere.client) {
381
+ await addFederatedPartner(holosphere.client, holosphere.config.appName, senderPubKey, {
382
+ alias: request.senderHolonName,
383
+ addedVia: 'handshake_accepted',
384
+ });
385
+
386
+ // Store any capabilities they sent
387
+ if (request.capabilities && request.capabilities.length > 0) {
388
+ for (const cap of request.capabilities) {
389
+ await storeInboundCapability(holosphere.client, holosphere.config.appName, senderPubKey, cap);
390
+ }
391
+ }
392
+ }
393
+
394
+ // Create the actual federation record in GunDB storage
395
+ // This is what makes the partner appear in getFederation() / loadFederationData()
396
+ // Store the sender's name so we can display it without reading their settings
397
+ await holosphere.federateHolon(holonId, senderPubKey, {
398
+ lensConfig,
399
+ partnerName: request.senderHolonName
400
+ });
401
+
402
+ // Create and send response
403
+ const response = createFederationResponse({
404
+ requestId: request.requestId,
405
+ status: 'accepted',
406
+ responderHolonId: holonId,
407
+ responderHolonName: holonName,
408
+ responderPubKey,
409
+ lensConfig,
410
+ capabilities: [],
411
+ message,
412
+ });
413
+
414
+ const sent = await sendFederationResponse(holosphere.client, privateKey, senderPubKey, response);
415
+
416
+ if (sent) {
417
+ return { success: true };
418
+ } else {
419
+ return { success: false, error: 'Failed to send response DM' };
420
+ }
421
+ } catch (error) {
422
+ return { success: false, error: error.message };
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Reject a federation request
428
+ * Sends rejection DM without creating local federation
429
+ * @param {Object} holosphere - HoloSphere instance
430
+ * @param {string} privateKey - Responder's hex private key
431
+ * @param {Object} params
432
+ * @param {string} params.requestId - Original request ID
433
+ * @param {string} params.senderPubKey - Original sender's public key
434
+ * @param {string} [params.message] - Optional rejection message
435
+ * @returns {Promise<Object>} Result with success and optional error
436
+ */
437
+ export async function rejectFederationRequest(holosphere, privateKey, params) {
438
+ const { requestId, senderPubKey, message } = params;
439
+
440
+ try {
441
+ const response = createFederationResponse({
442
+ requestId,
443
+ status: 'rejected',
444
+ message,
445
+ });
446
+
447
+ const sent = await sendFederationResponse(holosphere.client, privateKey, senderPubKey, response);
448
+
449
+ return { success: sent, error: sent ? undefined : 'Failed to send response DM' };
450
+ } catch (error) {
451
+ return { success: false, error: error.message };
452
+ }
453
+ }
454
+
455
+ // ============================================================================
456
+ // Payload Validation
457
+ // ============================================================================
458
+
459
+ /**
460
+ * Check if payload is a federation request
461
+ * @param {*} payload - Payload to check
462
+ * @returns {boolean} True if payload is a FederationRequestPayload
463
+ */
464
+ export function isFederationRequest(payload) {
465
+ return payload?.type === 'federation_request' && payload?.version === '1.0';
466
+ }
467
+
468
+ /**
469
+ * Check if payload is a federation response
470
+ * @param {*} payload - Payload to check
471
+ * @returns {boolean} True if payload is a FederationResponsePayload
472
+ */
473
+ export function isFederationResponse(payload) {
474
+ return payload?.type === 'federation_response' && payload?.version === '1.0';
475
+ }
@@ -1,11 +1,19 @@
1
1
  /**
2
- * Federation and Hologram (reference) Management
2
+ * @fileoverview Federation and Hologram (Reference) Management.
3
+ *
4
+ * Provides hologram (lightweight reference) creation, resolution, and management.
5
+ * Holograms enable data to appear in multiple holons while maintaining a single
6
+ * source of truth. Supports circular reference detection and cross-holosphere
7
+ * federation with capability-based access control.
8
+ *
9
+ * @module federation/hologram
3
10
  */
4
11
 
5
- import { buildPath, write, read, update } from '../storage/nostr-wrapper.js';
12
+ import { buildPath, write, read, update } from '../storage/unified-storage.js';
6
13
  import { verifyCapability } from '../crypto/secp256k1.js';
7
14
  import { getCapabilityForAuthor } from './registry.js';
8
15
 
16
+ /** @constant {number} Maximum depth for hologram resolution chain */
9
17
  const MAX_RESOLUTION_DEPTH = 10;
10
18
 
11
19
  /**
@@ -652,7 +660,8 @@ export async function addActiveHologram(client, appname, sourceHolon, lensName,
652
660
  sourceData._meta.activeHolograms.push({
653
661
  targetHolon,
654
662
  created: now,
655
- lastUpdated: now
663
+ lastUpdated: now,
664
+ platforms: {} // Platform-specific data (e.g., telegram: { messageId: 123 })
656
665
  });
657
666
  }
658
667
 
@@ -718,6 +727,111 @@ export async function removeActiveHologram(client, appname, sourceHolon, lensNam
718
727
  return false;
719
728
  }
720
729
 
730
+ /**
731
+ * Update platform-specific data for an active hologram entry
732
+ * Used by platform clients (Telegram, Discord, etc.) to store their message IDs
733
+ * @param {Object} client - Nostr client instance
734
+ * @param {string} appname - Application namespace
735
+ * @param {string} sourceHolon - Source holon ID
736
+ * @param {string} lensName - Lens name
737
+ * @param {string} dataId - Data ID
738
+ * @param {string} targetHolon - Target holon ID
739
+ * @param {string} platform - Platform name (e.g., 'telegram', 'discord')
740
+ * @param {Object} platformData - Platform-specific data (e.g., { messageId: 123 })
741
+ * @returns {Promise<boolean>} Success indicator
742
+ */
743
+ export async function updateActiveHologramPlatform(client, appname, sourceHolon, lensName, dataId, targetHolon, platform, platformData) {
744
+ let currentAppname = appname;
745
+ let currentHolon = sourceHolon;
746
+ let currentLens = lensName;
747
+ let currentDataId = dataId;
748
+ let sourcePath = buildPath(currentAppname, currentHolon, currentLens, currentDataId);
749
+
750
+ // Read existing source data
751
+ let sourceData = await read(client, sourcePath);
752
+ if (!sourceData) {
753
+ console.warn(`Source data not found at ${sourcePath}`);
754
+ return false;
755
+ }
756
+
757
+ // If source is a hologram, follow the chain to find the real source
758
+ let depth = 0;
759
+ const maxDepth = 10;
760
+ while (sourceData.hologram === true && sourceData.target && depth < maxDepth) {
761
+ depth++;
762
+ currentAppname = sourceData.target.appname || currentAppname;
763
+ currentHolon = sourceData.target.holonId;
764
+ currentLens = sourceData.target.lensName || currentLens;
765
+ currentDataId = sourceData.target.dataId || currentDataId;
766
+ sourcePath = buildPath(currentAppname, currentHolon, currentLens, currentDataId);
767
+
768
+ sourceData = await read(client, sourcePath);
769
+ if (!sourceData) {
770
+ console.warn(`Real source data not found at ${sourcePath}`);
771
+ return false;
772
+ }
773
+ }
774
+
775
+ if (!sourceData._meta || !Array.isArray(sourceData._meta.activeHolograms)) {
776
+ console.warn(`No activeHolograms found for ${sourcePath}`);
777
+ return false;
778
+ }
779
+
780
+ // Find the hologram entry for this target
781
+ const hologramEntry = sourceData._meta.activeHolograms.find(
782
+ h => h.targetHolon === targetHolon
783
+ );
784
+
785
+ if (!hologramEntry) {
786
+ console.warn(`No hologram entry found for target ${targetHolon}`);
787
+ return false;
788
+ }
789
+
790
+ // Initialize platforms object if needed
791
+ if (!hologramEntry.platforms) {
792
+ hologramEntry.platforms = {};
793
+ }
794
+
795
+ // Update platform-specific data
796
+ hologramEntry.platforms[platform] = {
797
+ ...hologramEntry.platforms[platform],
798
+ ...platformData,
799
+ lastUpdated: Date.now()
800
+ };
801
+ hologramEntry.lastUpdated = Date.now();
802
+
803
+ // Write back to source
804
+ return write(client, sourcePath, sourceData);
805
+ }
806
+
807
+ /**
808
+ * Get active holograms for a data item, optionally filtered by platform
809
+ * @param {Object} client - Nostr client instance
810
+ * @param {string} appname - Application namespace
811
+ * @param {string} sourceHolon - Source holon ID
812
+ * @param {string} lensName - Lens name
813
+ * @param {string} dataId - Data ID
814
+ * @param {string} [platform] - Optional platform filter (e.g., 'telegram')
815
+ * @returns {Promise<Array>} Array of hologram entries
816
+ */
817
+ export async function getActiveHolograms(client, appname, sourceHolon, lensName, dataId, platform = null) {
818
+ const sourcePath = buildPath(appname, sourceHolon, lensName, dataId);
819
+ const sourceData = await read(client, sourcePath);
820
+
821
+ if (!sourceData?._meta?.activeHolograms) {
822
+ return [];
823
+ }
824
+
825
+ let holograms = sourceData._meta.activeHolograms;
826
+
827
+ // Filter by platform if specified
828
+ if (platform) {
829
+ holograms = holograms.filter(h => h.platforms?.[platform]);
830
+ }
831
+
832
+ return holograms;
833
+ }
834
+
721
835
  /**
722
836
  * Refresh lastUpdated timestamps on all activeHolograms in source data
723
837
  * Also updates the hologram objects in target holons