holosphere 2.0.0-alpha7 → 2.0.0-alpha9

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 (327) hide show
  1. package/CHANGELOG.md +446 -0
  2. package/FEATURES.md +431 -0
  3. package/LICENSE +29 -166
  4. package/LICENSE-AGPL.md +180 -0
  5. package/dist/cdn/holosphere.min.js +55 -0
  6. package/dist/cdn/holosphere.min.js.map +1 -0
  7. package/dist/cjs/holosphere.cjs +1 -1
  8. package/dist/esm/holosphere.js +1 -1
  9. package/dist/{index-C-IlLYlk.cjs → index-DDGt_V9o.cjs} +2 -2
  10. package/dist/{index-C-IlLYlk.cjs.map → index-DDGt_V9o.cjs.map} +1 -1
  11. package/dist/{index-d6f4RJBM.js → index-DJXftyvB.js} +2253 -387
  12. package/dist/index-DJXftyvB.js.map +1 -0
  13. package/dist/index-DMbdcMtK.cjs +18 -0
  14. package/dist/index-DMbdcMtK.cjs.map +1 -0
  15. package/dist/{index-jmTHEbR2.js → index-DeZ1xz_s.js} +2 -2
  16. package/dist/{index-jmTHEbR2.js.map → index-DeZ1xz_s.js.map} +1 -1
  17. package/dist/{indexeddb-storage-D8kOl0oK.js → indexeddb-storage-BFt6hMeF.js} +48 -4
  18. package/dist/indexeddb-storage-BFt6hMeF.js.map +1 -0
  19. package/dist/{indexeddb-storage-a8GipaDr.cjs → indexeddb-storage-BK5tv4Sh.cjs} +2 -2
  20. package/dist/indexeddb-storage-BK5tv4Sh.cjs.map +1 -0
  21. package/dist/{memory-storage-DBQK622V.js → memory-storage-C9HuoL2E.js} +44 -4
  22. package/dist/memory-storage-C9HuoL2E.js.map +1 -0
  23. package/dist/{memory-storage-gfRovk2O.cjs → memory-storage-Dao7jfYG.cjs} +2 -2
  24. package/dist/memory-storage-Dao7jfYG.cjs.map +1 -0
  25. package/dist/{secp256k1-BCAPF45D.cjs → secp256k1-BbKzbLtD.cjs} +2 -2
  26. package/dist/{secp256k1-BCAPF45D.cjs.map → secp256k1-BbKzbLtD.cjs.map} +1 -1
  27. package/dist/{secp256k1-DYm_CMqW.js → secp256k1-CreY7Pcl.js} +2 -2
  28. package/dist/{secp256k1-DYm_CMqW.js.map → secp256k1-CreY7Pcl.js.map} +1 -1
  29. package/docs/api/ai_aggregation.js.html +333 -0
  30. package/docs/api/ai_breakdown.js.html +524 -0
  31. package/docs/api/ai_classifier.js.html +231 -0
  32. package/docs/api/ai_council.js.html +246 -0
  33. package/docs/api/ai_embeddings.js.html +304 -0
  34. package/docs/api/ai_federation-ai.js.html +338 -0
  35. package/docs/api/ai_h3-ai.js.html +970 -0
  36. package/docs/api/ai_index.js.html +124 -0
  37. package/docs/api/ai_json-ops.js.html +241 -0
  38. package/docs/api/ai_llm-service.js.html +239 -0
  39. package/docs/api/ai_nl-query.js.html +236 -0
  40. package/docs/api/ai_relationships.js.html +367 -0
  41. package/docs/api/ai_schema-extractor.js.html +235 -0
  42. package/docs/api/ai_spatial.js.html +307 -0
  43. package/docs/api/ai_tts.js.html +214 -0
  44. package/docs/api/content_social-protocols.js.html +180 -0
  45. package/docs/api/core_holosphere.js.html +757 -0
  46. package/docs/api/crypto_nostr-utils.js.html +306 -0
  47. package/docs/api/crypto_secp256k1.js.html +267 -0
  48. package/docs/api/data/search.json +1 -0
  49. package/docs/api/federation_discovery.js.html +337 -0
  50. package/docs/api/federation_handshake.js.html +478 -0
  51. package/docs/api/federation_hologram.js.html +1053 -0
  52. package/docs/api/federation_registry.js.html +389 -0
  53. package/docs/api/fonts/Inconsolata-Regular.ttf +0 -0
  54. package/docs/api/fonts/OpenSans-Regular.ttf +0 -0
  55. package/docs/api/fonts/WorkSans-Bold.ttf +0 -0
  56. package/docs/api/global.html +3 -0
  57. package/docs/api/hierarchical_upcast.js.html +128 -0
  58. package/docs/api/index.html +265 -0
  59. package/docs/api/index.js.html +1868 -0
  60. package/docs/api/lib_ai-methods.js.html +660 -0
  61. package/docs/api/lib_contract-methods.js.html +445 -0
  62. package/docs/api/lib_errors.js.html +56 -0
  63. package/docs/api/lib_federation-methods.js.html +348 -0
  64. package/docs/api/lib_index.js.html +33 -0
  65. package/docs/api/module-ai.html +5 -0
  66. package/docs/api/module-ai_aggregation-SmartAggregation.html +6 -0
  67. package/docs/api/module-ai_aggregation.SmartAggregation.html +3 -0
  68. package/docs/api/module-ai_aggregation.html +3 -0
  69. package/docs/api/module-ai_breakdown-TaskBreakdown.html +5 -0
  70. package/docs/api/module-ai_breakdown.TaskBreakdown.html +3 -0
  71. package/docs/api/module-ai_breakdown.html +3 -0
  72. package/docs/api/module-ai_classifier-Classifier.html +6 -0
  73. package/docs/api/module-ai_classifier.Classifier.html +3 -0
  74. package/docs/api/module-ai_classifier.html +3 -0
  75. package/docs/api/module-ai_council-Council.html +6 -0
  76. package/docs/api/module-ai_council.Council.html +3 -0
  77. package/docs/api/module-ai_council.html +3 -0
  78. package/docs/api/module-ai_embeddings-Embeddings.html +5 -0
  79. package/docs/api/module-ai_embeddings.Embeddings.html +3 -0
  80. package/docs/api/module-ai_embeddings.html +3 -0
  81. package/docs/api/module-ai_federation-ai-FederationAdvisor.html +6 -0
  82. package/docs/api/module-ai_federation-ai.FederationAdvisor.html +3 -0
  83. package/docs/api/module-ai_federation-ai.html +3 -0
  84. package/docs/api/module-ai_h3-ai-H3AI.html +6 -0
  85. package/docs/api/module-ai_h3-ai.H3AI.html +3 -0
  86. package/docs/api/module-ai_h3-ai.html +3 -0
  87. package/docs/api/module-ai_json-ops-JSONOps.html +5 -0
  88. package/docs/api/module-ai_json-ops.JSONOps.html +3 -0
  89. package/docs/api/module-ai_json-ops.html +3 -0
  90. package/docs/api/module-ai_llm-service-LLMService.html +5 -0
  91. package/docs/api/module-ai_llm-service.LLMService.html +3 -0
  92. package/docs/api/module-ai_llm-service.html +3 -0
  93. package/docs/api/module-ai_nl-query-NLQuery.html +5 -0
  94. package/docs/api/module-ai_nl-query.NLQuery.html +3 -0
  95. package/docs/api/module-ai_nl-query.html +3 -0
  96. package/docs/api/module-ai_relationships-RelationshipDiscovery.html +6 -0
  97. package/docs/api/module-ai_relationships.RelationshipDiscovery.html +3 -0
  98. package/docs/api/module-ai_relationships.html +3 -0
  99. package/docs/api/module-ai_schema-extractor-SchemaExtractor.html +5 -0
  100. package/docs/api/module-ai_schema-extractor.SchemaExtractor.html +3 -0
  101. package/docs/api/module-ai_schema-extractor.html +3 -0
  102. package/docs/api/module-ai_spatial-SpatialAnalysis.html +6 -0
  103. package/docs/api/module-ai_spatial.SpatialAnalysis.html +3 -0
  104. package/docs/api/module-ai_spatial.html +3 -0
  105. package/docs/api/module-ai_tts-TTS.html +5 -0
  106. package/docs/api/module-ai_tts.TTS.html +3 -0
  107. package/docs/api/module-ai_tts.html +3 -0
  108. package/docs/api/module-content_social-protocols.html +3 -0
  109. package/docs/api/module-core_holosphere-HoloSphere.html +6 -0
  110. package/docs/api/module-core_holosphere.HoloSphere.html +3 -0
  111. package/docs/api/module-core_holosphere.html +3 -0
  112. package/docs/api/module-crypto_nostr-utils.html +3 -0
  113. package/docs/api/module-crypto_secp256k1.html +3 -0
  114. package/docs/api/module-federation_hologram.html +3 -0
  115. package/docs/api/module-hierarchical_upcast.html +3 -0
  116. package/docs/api/module-holosphere-HoloSphereBase.html +3 -0
  117. package/docs/api/module-holosphere.html +3 -0
  118. package/docs/api/module-lib_ai-methods.html +3 -0
  119. package/docs/api/module-lib_contract-methods.html +3 -0
  120. package/docs/api/module-lib_errors-AuthorizationError.html +3 -0
  121. package/docs/api/module-lib_errors-ValidationError.html +3 -0
  122. package/docs/api/module-lib_errors.AuthorizationError.html +3 -0
  123. package/docs/api/module-lib_errors.ValidationError.html +3 -0
  124. package/docs/api/module-lib_errors.html +3 -0
  125. package/docs/api/module-lib_federation-methods.html +3 -0
  126. package/docs/api/module-lib_index.html +3 -0
  127. package/docs/api/module-schema_validator-ValidationError.html +3 -0
  128. package/docs/api/module-schema_validator.ValidationError.html +3 -0
  129. package/docs/api/module-schema_validator.html +3 -0
  130. package/docs/api/module-spatial_h3-operations.html +4 -0
  131. package/docs/api/module-storage_backend-factory.BackendFactory.html +3 -0
  132. package/docs/api/module-storage_backend-factory.html +3 -0
  133. package/docs/api/module-storage_backend-interface-StorageBackend.html +3 -0
  134. package/docs/api/module-storage_backend-interface.StorageBackend.html +3 -0
  135. package/docs/api/module-storage_backend-interface.html +3 -0
  136. package/docs/api/module-storage_backends_activitypub-backend-ActivityPubBackend.html +7 -0
  137. package/docs/api/module-storage_backends_activitypub-backend.ActivityPubBackend.html +3 -0
  138. package/docs/api/module-storage_backends_activitypub-backend.html +3 -0
  139. package/docs/api/module-storage_backends_activitypub_server-ActivityPubServer.html +8 -0
  140. package/docs/api/module-storage_backends_activitypub_server.ActivityPubServer.html +3 -0
  141. package/docs/api/module-storage_backends_activitypub_server.html +3 -0
  142. package/docs/api/module-storage_backends_gundb-backend-GunDBBackend.html +7 -0
  143. package/docs/api/module-storage_backends_gundb-backend.GunDBBackend.html +3 -0
  144. package/docs/api/module-storage_backends_gundb-backend.html +3 -0
  145. package/docs/api/module-storage_backends_nostr-backend-NostrBackend.html +8 -0
  146. package/docs/api/module-storage_backends_nostr-backend.NostrBackend.html +3 -0
  147. package/docs/api/module-storage_backends_nostr-backend.html +3 -0
  148. package/docs/api/module-storage_filesystem-storage-FileSystemStorage.html +5 -0
  149. package/docs/api/module-storage_filesystem-storage-browser-FileSystemStorage.html +3 -0
  150. package/docs/api/module-storage_filesystem-storage-browser.FileSystemStorage.html +3 -0
  151. package/docs/api/module-storage_filesystem-storage-browser.html +3 -0
  152. package/docs/api/module-storage_filesystem-storage.FileSystemStorage.html +3 -0
  153. package/docs/api/module-storage_filesystem-storage.html +3 -0
  154. package/docs/api/module-storage_global-tables.html +3 -0
  155. package/docs/api/module-storage_gun-async.html +3 -0
  156. package/docs/api/module-storage_gun-auth-GunAuth.html +5 -0
  157. package/docs/api/module-storage_gun-auth.GunAuth.html +3 -0
  158. package/docs/api/module-storage_gun-auth.html +3 -0
  159. package/docs/api/module-storage_gun-federation.html +3 -0
  160. package/docs/api/module-storage_gun-references-GunReferenceHandler.html +5 -0
  161. package/docs/api/module-storage_gun-references.GunReferenceHandler.html +3 -0
  162. package/docs/api/module-storage_gun-references.html +3 -0
  163. package/docs/api/module-storage_gun-schema-GunSchemaValidator.html +5 -0
  164. package/docs/api/module-storage_gun-schema.GunSchemaValidator.html +3 -0
  165. package/docs/api/module-storage_gun-schema.html +3 -0
  166. package/docs/api/module-storage_gun-wrapper.html +11 -0
  167. package/docs/api/module-storage_indexeddb-storage-IndexedDBStorage.html +5 -0
  168. package/docs/api/module-storage_indexeddb-storage.IndexedDBStorage.html +3 -0
  169. package/docs/api/module-storage_indexeddb-storage.html +3 -0
  170. package/docs/api/module-storage_key-storage-simple.html +3 -0
  171. package/docs/api/module-storage_key-storage.html +4 -0
  172. package/docs/api/module-storage_memory-storage-MemoryStorage.html +5 -0
  173. package/docs/api/module-storage_memory-storage.MemoryStorage.html +3 -0
  174. package/docs/api/module-storage_memory-storage.html +3 -0
  175. package/docs/api/module-storage_migration-MigrationTool.html +6 -0
  176. package/docs/api/module-storage_migration.MigrationTool.html +3 -0
  177. package/docs/api/module-storage_migration.html +3 -0
  178. package/docs/api/module-storage_nostr-async.html +18 -0
  179. package/docs/api/module-storage_nostr-client-LRUCache.html +3 -0
  180. package/docs/api/module-storage_nostr-client-NostrClient.html +7 -0
  181. package/docs/api/module-storage_nostr-client.NostrClient.html +15 -0
  182. package/docs/api/module-storage_nostr-client.html +6 -0
  183. package/docs/api/module-storage_nostr-wrapper.html +3 -0
  184. package/docs/api/module-storage_outbox-queue-OutboxQueue.html +4 -0
  185. package/docs/api/module-storage_outbox-queue.OutboxQueue.html +3 -0
  186. package/docs/api/module-storage_outbox-queue.html +3 -0
  187. package/docs/api/module-storage_persistent-storage-PersistentStorage.html +3 -0
  188. package/docs/api/module-storage_persistent-storage.html +4 -0
  189. package/docs/api/module-storage_sync-service-SyncService.html +5 -0
  190. package/docs/api/module-storage_sync-service.SyncService.html +3 -0
  191. package/docs/api/module-storage_sync-service.html +3 -0
  192. package/docs/api/module-storage_unified-storage.html +3 -0
  193. package/docs/api/module-subscriptions_manager.SubscriptionRegistry.html +3 -0
  194. package/docs/api/module-subscriptions_manager.html +3 -0
  195. package/docs/api/schema_validator.js.html +113 -0
  196. package/docs/api/scripts/core.js +726 -0
  197. package/docs/api/scripts/core.min.js +23 -0
  198. package/docs/api/scripts/resize.js +90 -0
  199. package/docs/api/scripts/search.js +265 -0
  200. package/docs/api/scripts/search.min.js +6 -0
  201. package/docs/api/scripts/third-party/Apache-License-2.0.txt +202 -0
  202. package/docs/api/scripts/third-party/fuse.js +9 -0
  203. package/docs/api/scripts/third-party/hljs-line-num-original.js +369 -0
  204. package/docs/api/scripts/third-party/hljs-line-num.js +1 -0
  205. package/docs/api/scripts/third-party/hljs-original.js +5171 -0
  206. package/docs/api/scripts/third-party/hljs.js +1 -0
  207. package/docs/api/scripts/third-party/popper.js +5 -0
  208. package/docs/api/scripts/third-party/tippy.js +1 -0
  209. package/docs/api/scripts/third-party/tocbot.js +672 -0
  210. package/docs/api/scripts/third-party/tocbot.min.js +1 -0
  211. package/docs/api/spatial_h3-operations.js.html +129 -0
  212. package/docs/api/storage_backend-factory.js.html +133 -0
  213. package/docs/api/storage_backend-interface.js.html +164 -0
  214. package/docs/api/storage_backends_activitypub-backend.js.html +298 -0
  215. package/docs/api/storage_backends_activitypub_server.js.html +678 -0
  216. package/docs/api/storage_backends_gundb-backend.js.html +878 -0
  217. package/docs/api/storage_backends_nostr-backend.js.html +254 -0
  218. package/docs/api/storage_filesystem-storage-browser.js.html +83 -0
  219. package/docs/api/storage_filesystem-storage.js.html +207 -0
  220. package/docs/api/storage_global-tables.js.html +116 -0
  221. package/docs/api/storage_gun-async.js.html +344 -0
  222. package/docs/api/storage_gun-auth.js.html +376 -0
  223. package/docs/api/storage_gun-federation.js.html +788 -0
  224. package/docs/api/storage_gun-references.js.html +212 -0
  225. package/docs/api/storage_gun-schema.js.html +309 -0
  226. package/docs/api/storage_gun-wrapper.js.html +645 -0
  227. package/docs/api/storage_indexeddb-storage.js.html +224 -0
  228. package/docs/api/storage_key-storage-simple.js.html +102 -0
  229. package/docs/api/storage_key-storage.js.html +171 -0
  230. package/docs/api/storage_memory-storage.js.html +128 -0
  231. package/docs/api/storage_migration.js.html +354 -0
  232. package/docs/api/storage_nostr-async.js.html +1076 -0
  233. package/docs/api/storage_nostr-client.js.html +1598 -0
  234. package/docs/api/storage_nostr-wrapper.js.html +218 -0
  235. package/docs/api/storage_outbox-queue.js.html +248 -0
  236. package/docs/api/storage_persistent-storage.js.html +160 -0
  237. package/docs/api/storage_sync-service.js.html +201 -0
  238. package/docs/api/storage_unified-storage.js.html +157 -0
  239. package/docs/api/styles/clean-jsdoc-theme-base.css +1159 -0
  240. package/docs/api/styles/clean-jsdoc-theme-dark.css +412 -0
  241. package/docs/api/styles/clean-jsdoc-theme-light.css +482 -0
  242. package/docs/api/styles/clean-jsdoc-theme-scrollbar.css +30 -0
  243. package/docs/api/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
  244. package/docs/api/styles/clean-jsdoc-theme.min.css +1 -0
  245. package/docs/api/subscriptions_manager.js.html +162 -0
  246. package/examples/holosphere-widget.js +1242 -0
  247. package/examples/widget-demo.html +274 -0
  248. package/examples/widget.html +703 -0
  249. package/jsdoc.json +26 -0
  250. package/package.json +16 -3
  251. package/src/ai/aggregation.js +13 -2
  252. package/src/ai/breakdown.js +12 -2
  253. package/src/ai/classifier.js +14 -3
  254. package/src/ai/council.js +22 -7
  255. package/src/ai/embeddings.js +37 -15
  256. package/src/ai/federation-ai.js +13 -2
  257. package/src/ai/h3-ai.js +14 -2
  258. package/src/ai/index.js +16 -7
  259. package/src/ai/json-ops.js +18 -5
  260. package/src/ai/llm-service.js +62 -31
  261. package/src/ai/nl-query.js +12 -2
  262. package/src/ai/relationships.js +13 -2
  263. package/src/ai/schema-extractor.js +24 -10
  264. package/src/ai/spatial.js +13 -2
  265. package/src/ai/tts.js +25 -8
  266. package/src/cdn-entry.js +22 -0
  267. package/src/content/social-protocols.js +34 -25
  268. package/src/contracts/chain-manager.js +68 -40
  269. package/src/contracts/deployer.js +70 -42
  270. package/src/contracts/event-listener.js +61 -29
  271. package/src/contracts/holon-contracts.js +46 -31
  272. package/src/contracts/index.js +5 -6
  273. package/src/contracts/networks.js +19 -14
  274. package/src/contracts/operations.js +58 -41
  275. package/src/contracts/queries.js +70 -21
  276. package/src/core/holosphere.js +37 -8
  277. package/src/crypto/nostr-utils.js +105 -65
  278. package/src/crypto/secp256k1.js +7 -2
  279. package/src/federation/handshake.js +23 -11
  280. package/src/federation/hologram.js +9 -1
  281. package/src/hierarchical/upcast.js +34 -20
  282. package/src/index.js +671 -7
  283. package/src/lib/ai-methods.js +352 -3
  284. package/src/lib/contract-methods.js +152 -3
  285. package/src/lib/errors.js +31 -1
  286. package/src/lib/federation-methods.js +110 -3
  287. package/src/lib/index.js +9 -5
  288. package/src/schema/validator.js +22 -3
  289. package/src/spatial/h3-operations.js +17 -1
  290. package/src/storage/backend-factory.js +7 -2
  291. package/src/storage/backend-interface.js +21 -2
  292. package/src/storage/backends/activitypub/server.js +25 -3
  293. package/src/storage/backends/activitypub-backend.js +25 -2
  294. package/src/storage/backends/gundb-backend.js +322 -11
  295. package/src/storage/backends/nostr-backend.js +116 -1
  296. package/src/storage/filesystem-storage-browser.js +42 -2
  297. package/src/storage/filesystem-storage.js +72 -5
  298. package/src/storage/global-tables.js +7 -2
  299. package/src/storage/gun-async.js +20 -11
  300. package/src/storage/gun-auth.js +15 -4
  301. package/src/storage/gun-federation.js +14 -5
  302. package/src/storage/gun-references.js +16 -5
  303. package/src/storage/gun-schema.js +25 -10
  304. package/src/storage/gun-wrapper.js +160 -49
  305. package/src/storage/indexeddb-storage.js +65 -4
  306. package/src/storage/key-storage-simple.js +32 -9
  307. package/src/storage/key-storage.js +45 -13
  308. package/src/storage/memory-storage.js +65 -4
  309. package/src/storage/migration.js +20 -7
  310. package/src/storage/nostr-async.js +195 -90
  311. package/src/storage/nostr-client.js +173 -49
  312. package/src/storage/nostr-wrapper.js +6 -2
  313. package/src/storage/outbox-queue.js +55 -18
  314. package/src/storage/persistent-storage.js +56 -13
  315. package/src/storage/sync-service.js +51 -17
  316. package/src/storage/unified-storage.js +38 -3
  317. package/src/subscriptions/manager.js +33 -16
  318. package/vite.config.cdn.js +60 -0
  319. package/dist/index-Bvwyvd0T.cjs +0 -5
  320. package/dist/index-Bvwyvd0T.cjs.map +0 -1
  321. package/dist/index-d6f4RJBM.js.map +0 -1
  322. package/dist/indexeddb-storage-D8kOl0oK.js.map +0 -1
  323. package/dist/indexeddb-storage-a8GipaDr.cjs.map +0 -1
  324. package/dist/memory-storage-DBQK622V.js.map +0 -1
  325. package/dist/memory-storage-gfRovk2O.cjs.map +0 -1
  326. /package/{cleanup-test-data.js → scripts/cleanup-test-data.js} +0 -0
  327. /package/{test-ai-real-api.js → scripts/test-ai-real-api.js} +0 -0
@@ -1,34 +1,52 @@
1
1
  /**
2
- * Nostr Async Utilities
3
- * Provides Promise-based wrappers and async patterns for Nostr operations
2
+ * @fileoverview Nostr Async Utilities.
3
+ *
4
+ * Provides Promise-based wrappers and async patterns for Nostr operations.
5
+ * Includes local-first data access, query deduplication, subscription management,
6
+ * and background refresh capabilities for optimal performance.
7
+ *
8
+ * @module storage/nostr-async
4
9
  */
5
10
 
6
11
  /**
7
- * Global subscription manager to prevent duplicate subscriptions
12
+ * Global subscription manager to prevent duplicate subscriptions.
8
13
  * Maps: subscriptionKey -> subscription object
14
+ * @private
9
15
  */
10
16
  const globalSubscriptions = new Map();
11
17
 
12
18
  /**
13
- * Single-path subscription manager (for nostrSubscribe)
19
+ * Single-path subscription manager (for nostrSubscribe).
14
20
  * Maps: subscriptionKey -> { subscription, callbacks: [] }
21
+ * @private
15
22
  */
16
23
  const singlePathSubscriptions = new Map();
17
24
 
18
25
  /**
19
- * Query deduplication for nostrGet - prevents duplicate relay queries
26
+ * Query deduplication for nostrGet - prevents duplicate relay queries.
20
27
  * Maps: queryKey -> { promise, timestamp, callbacks: [] }
28
+ * @private
21
29
  */
22
30
  const pendingQueries = new Map();
23
- const QUERY_DEDUP_WINDOW = 2000; // 2 second window for deduplication
24
31
 
25
32
  /**
26
- * Write data as Nostr event (parameterized replaceable event)
33
+ * Time window for query deduplication (2 seconds).
34
+ * @private
35
+ * @constant {number}
36
+ */
37
+ const QUERY_DEDUP_WINDOW = 2000;
38
+
39
+ /**
40
+ * Write data as Nostr event (parameterized replaceable event).
41
+ *
27
42
  * @param {Object} client - NostrClient instance
28
43
  * @param {string} path - Path identifier (encoded in d-tag)
29
44
  * @param {Object} data - Data to store
30
- * @param {number} kind - Event kind (default: 30000 for parameterized replaceable)
31
- * @returns {Promise<Object>} Published event result
45
+ * @param {number} [kind=30000] - Event kind (default: 30000 for parameterized replaceable)
46
+ * @returns {Promise<Object>} Published event result with relay responses
47
+ * @example
48
+ * const result = await nostrPut(client, 'myapp/holon123/items/item1', { name: 'Test' });
49
+ * console.log(result.event.id); // Event ID
32
50
  */
33
51
  export async function nostrPut(client, path, data, kind = 30000) {
34
52
  const dataEvent = {
@@ -45,17 +63,25 @@ export async function nostrPut(client, path, data, kind = 30000) {
45
63
  }
46
64
 
47
65
  /**
48
- * Read data from Nostr (query by d-tag)
49
- * LOCAL-FIRST: Checks persistent storage first, never blocks on network
50
- * Uses query deduplication to prevent duplicate relay queries within a time window
66
+ * Read data from Nostr (query by d-tag).
67
+ *
68
+ * LOCAL-FIRST: Checks persistent storage first, never blocks on network.
69
+ * Uses query deduplication to prevent duplicate relay queries within a time window.
70
+ *
51
71
  * @param {Object} client - NostrClient instance
52
72
  * @param {string} path - Path identifier
53
- * @param {number} kind - Event kind (default: 30000)
54
- * @param {Object} options - Query options
55
- * @param {string[]} options.authors - Array of public keys to query (default: [client.publicKey])
56
- * @param {boolean} options.includeAuthor - If true, adds _author field to returned data
57
- * @param {boolean} options.skipPersistent - If true, skip persistent storage check (default: false)
73
+ * @param {number} [kind=30000] - Event kind (default: 30000)
74
+ * @param {Object} [options={}] - Query options
75
+ * @param {string[]} [options.authors] - Array of public keys to query (default: [client.publicKey])
76
+ * @param {boolean} [options.includeAuthor=false] - If true, adds _author field to returned data
77
+ * @param {boolean} [options.skipPersistent=false] - If true, skip persistent storage check
78
+ * @param {number} [options.timeout=30000] - Query timeout in milliseconds
58
79
  * @returns {Promise<Object|null>} Data or null if not found
80
+ * @example
81
+ * const data = await nostrGet(client, 'myapp/holon1/items/item1');
82
+ * if (data) {
83
+ * console.log(data.name);
84
+ * }
59
85
  */
60
86
  export async function nostrGet(client, path, kind = 30000, options = {}) {
61
87
  const timeout = options.timeout !== undefined ? options.timeout : 30000;
@@ -65,28 +91,33 @@ export async function nostrGet(client, path, kind = 30000, options = {}) {
65
91
  if (!options.skipPersistent && client.persistentGet) {
66
92
  const persistedEvent = await client.persistentGet(path);
67
93
  if (persistedEvent && persistedEvent.content) {
68
- try {
69
- const data = JSON.parse(persistedEvent.content);
94
+ // Verify author is in requested authors list (persistent storage may have cached events from other authors)
95
+ if (!authors.includes(persistedEvent.pubkey)) {
96
+ // Author mismatch - fall through to relay query
97
+ } else {
98
+ try {
99
+ const data = JSON.parse(persistedEvent.content);
70
100
 
71
- // Skip deleted items
72
- if (data._deleted) {
73
- return null;
74
- }
101
+ // Skip null/undefined or deleted items
102
+ if (!data || data._deleted) {
103
+ return null;
104
+ }
75
105
 
76
- // Optionally include author information
77
- if (options.includeAuthor) {
78
- data._author = persistedEvent.pubkey;
79
- }
106
+ // Optionally include author information
107
+ if (options.includeAuthor) {
108
+ data._author = persistedEvent.pubkey;
109
+ }
80
110
 
81
- // Trigger background refresh from relays (fire-and-forget)
82
- if (client.refreshPathInBackground) {
83
- client.refreshPathInBackground(path, kind, { authors, timeout });
84
- }
111
+ // Trigger background refresh from relays (fire-and-forget)
112
+ if (client.refreshPathInBackground) {
113
+ client.refreshPathInBackground(path, kind, { authors, timeout });
114
+ }
85
115
 
86
- return data;
87
- } catch (error) {
88
- // Fall through to relay query if parsing fails
89
- console.warn('[nostrGet] Failed to parse persisted event:', error);
116
+ return data;
117
+ } catch (error) {
118
+ // Fall through to relay query if parsing fails
119
+ console.warn('[nostrGet] Failed to parse persisted event:', error);
120
+ }
90
121
  }
91
122
  }
92
123
  }
@@ -123,8 +154,16 @@ export async function nostrGet(client, path, kind = 30000, options = {}) {
123
154
  }
124
155
 
125
156
  /**
126
- * Internal function to execute nostrGet query
157
+ * Internal function to execute nostrGet query.
158
+ *
127
159
  * @private
160
+ * @param {Object} client - NostrClient instance
161
+ * @param {string} path - Path identifier
162
+ * @param {number} kind - Event kind
163
+ * @param {string[]} authors - Array of author public keys
164
+ * @param {number} timeout - Query timeout
165
+ * @param {Object} options - Query options
166
+ * @returns {Promise<Object|null>} Data or null
128
167
  */
129
168
  async function _executeNostrGet(client, path, kind, authors, timeout, options) {
130
169
  const filter = {
@@ -136,17 +175,20 @@ async function _executeNostrGet(client, path, kind, authors, timeout, options) {
136
175
 
137
176
  const events = await client.query(filter, { timeout });
138
177
 
139
- if (events.length === 0) {
178
+ // Filter by author (relays may not respect authors filter)
179
+ const authoredEvents = events.filter(event => authors.includes(event.pubkey));
180
+
181
+ if (authoredEvents.length === 0) {
140
182
  return null;
141
183
  }
142
184
 
143
- // Get most recent event (across all authors)
144
- const event = events.sort((a, b) => b.created_at - a.created_at)[0];
185
+ // Get most recent event (across allowed authors)
186
+ const event = authoredEvents.sort((a, b) => b.created_at - a.created_at)[0];
145
187
 
146
188
  try {
147
189
  const data = JSON.parse(event.content);
148
- // Skip deleted items
149
- if (data._deleted) {
190
+ // Skip null/undefined or deleted items
191
+ if (!data || data._deleted) {
150
192
  return null;
151
193
  }
152
194
  // Optionally include author information
@@ -161,17 +203,24 @@ async function _executeNostrGet(client, path, kind, authors, timeout, options) {
161
203
  }
162
204
 
163
205
  /**
164
- * Query all events under a path prefix
165
- * LOCAL-FIRST: Checks persistent storage first, never blocks on network
166
- * Uses query deduplication to prevent duplicate relay queries within a time window
206
+ * Query all events under a path prefix.
207
+ *
208
+ * LOCAL-FIRST: Checks persistent storage first, never blocks on network.
209
+ * Uses query deduplication to prevent duplicate relay queries within a time window.
210
+ *
167
211
  * @param {Object} client - NostrClient instance
168
212
  * @param {string} pathPrefix - Path prefix to match
169
- * @param {number} kind - Event kind (default: 30000)
170
- * @param {Object} options - Query options
171
- * @param {string[]} options.authors - Array of public keys to query (default: [client.publicKey])
172
- * @param {boolean} options.includeAuthor - If true, adds _author field to returned data
173
- * @param {boolean} options.skipPersistent - If true, skip persistent storage check (default: false)
213
+ * @param {number} [kind=30000] - Event kind (default: 30000)
214
+ * @param {Object} [options={}] - Query options
215
+ * @param {string[]} [options.authors] - Array of public keys to query (default: [client.publicKey])
216
+ * @param {boolean} [options.includeAuthor=false] - If true, adds _author field to returned data
217
+ * @param {boolean} [options.skipPersistent=false] - If true, skip persistent storage check
218
+ * @param {number} [options.timeout=30000] - Query timeout in milliseconds
219
+ * @param {number} [options.limit=1000] - Maximum number of events to retrieve
174
220
  * @returns {Promise<Array>} Array of data objects
221
+ * @example
222
+ * const items = await nostrGetAll(client, 'myapp/holon1/items/');
223
+ * console.log(`Found ${items.length} items`);
175
224
  */
176
225
  export async function nostrGetAll(client, pathPrefix, kind = 30000, options = {}) {
177
226
  const timeout = options.timeout !== undefined ? options.timeout : 30000;
@@ -187,6 +236,9 @@ export async function nostrGetAll(client, pathPrefix, kind = 30000, options = {}
187
236
  for (const event of persistedEvents) {
188
237
  if (!event || !event.tags) continue;
189
238
 
239
+ // Verify author is in requested authors list (persistent storage may have cached events from other authors)
240
+ if (!authors.includes(event.pubkey)) continue;
241
+
190
242
  const dTag = event.tags.find(t => t[0] === 'd');
191
243
  if (!dTag || !dTag[1] || !dTag[1].startsWith(pathPrefix)) continue;
192
244
 
@@ -197,8 +249,8 @@ export async function nostrGetAll(client, pathPrefix, kind = 30000, options = {}
197
249
  try {
198
250
  const data = JSON.parse(event.content);
199
251
 
200
- // Handle deleted items - remove from map if this is newer
201
- if (data._deleted) {
252
+ // Handle null/undefined or deleted items - remove from map if this is newer
253
+ if (!data || data._deleted) {
202
254
  byPath.delete(path);
203
255
  continue;
204
256
  }
@@ -255,8 +307,17 @@ export async function nostrGetAll(client, pathPrefix, kind = 30000, options = {}
255
307
  }
256
308
 
257
309
  /**
258
- * Internal function to execute nostrGetAll query
310
+ * Internal function to execute nostrGetAll query.
311
+ *
259
312
  * @private
313
+ * @param {Object} client - NostrClient instance
314
+ * @param {string} pathPrefix - Path prefix to match
315
+ * @param {number} kind - Event kind
316
+ * @param {string[]} authors - Array of author public keys
317
+ * @param {number} timeout - Query timeout
318
+ * @param {number} limit - Maximum results
319
+ * @param {Object} options - Query options
320
+ * @returns {Promise<Array>} Array of data objects
260
321
  */
261
322
  async function _executeNostrGetAll(client, pathPrefix, kind, authors, timeout, limit, options) {
262
323
  const filter = {
@@ -267,10 +328,12 @@ async function _executeNostrGetAll(client, pathPrefix, kind, authors, timeout, l
267
328
 
268
329
  const events = await client.query(filter, { timeout });
269
330
 
270
- // Filter by path prefix in application layer
331
+ // Filter by path prefix AND verify author (relays may not respect authors filter)
271
332
  const matching = events.filter(event => {
272
333
  const dTag = event.tags.find(t => t[0] === 'd');
273
- return dTag && dTag[1] && dTag[1].startsWith(pathPrefix);
334
+ const pathMatches = dTag && dTag[1] && dTag[1].startsWith(pathPrefix);
335
+ const authorAllowed = authors.includes(event.pubkey);
336
+ return pathMatches && authorAllowed;
274
337
  });
275
338
 
276
339
  // Parse content and group by d-tag (keep latest only, across all authors)
@@ -283,8 +346,8 @@ async function _executeNostrGetAll(client, pathPrefix, kind, authors, timeout, l
283
346
  try {
284
347
  const data = JSON.parse(event.content);
285
348
 
286
- // Handle deleted items - remove from map if this is newer
287
- if (data._deleted) {
349
+ // Handle null/undefined or deleted items - remove from map if this is newer
350
+ if (!data || data._deleted) {
288
351
  byPath.delete(dTag);
289
352
  continue;
290
353
  }
@@ -305,14 +368,18 @@ async function _executeNostrGetAll(client, pathPrefix, kind, authors, timeout, l
305
368
  }
306
369
 
307
370
  /**
308
- * Query all events under a path prefix (HYBRID MODE - local + relay)
309
- * Checks local cache first, then merges with relay data
371
+ * Query all events under a path prefix (HYBRID MODE - local + relay).
372
+ *
373
+ * Checks local cache first, then merges with relay data.
374
+ *
310
375
  * @param {Object} client - NostrClient instance
311
376
  * @param {string} pathPrefix - Path prefix to match
312
- * @param {number} kind - Event kind (default: 30000)
313
- * @param {Object} options - Query options
314
- * @param {string[]} options.authors - Array of public keys to query (default: [client.publicKey])
315
- * @param {boolean} options.includeAuthor - If true, adds _author field to returned data
377
+ * @param {number} [kind=30000] - Event kind (default: 30000)
378
+ * @param {Object} [options={}] - Query options
379
+ * @param {string[]} [options.authors] - Array of public keys to query (default: [client.publicKey])
380
+ * @param {boolean} [options.includeAuthor=false] - If true, adds _author field to returned data
381
+ * @param {number} [options.timeout=30000] - Query timeout in milliseconds
382
+ * @param {number} [options.limit=1000] - Maximum number of events to retrieve
316
383
  * @returns {Promise<Array>} Array of data objects (merged from local + relay)
317
384
  */
318
385
  export async function nostrGetAllHybrid(client, pathPrefix, kind = 30000, options = {}) {
@@ -331,10 +398,12 @@ export async function nostrGetAllHybrid(client, pathPrefix, kind = 30000, option
331
398
 
332
399
  const events = await queryMethod.call(client, filter, { timeout });
333
400
 
334
- // Filter by path prefix in application layer
401
+ // Filter by path prefix AND verify author (relays may not respect authors filter)
335
402
  const matching = events.filter(event => {
336
403
  const dTag = event.tags.find(t => t[0] === 'd');
337
- return dTag && dTag[1] && dTag[1].startsWith(pathPrefix);
404
+ const pathMatches = dTag && dTag[1] && dTag[1].startsWith(pathPrefix);
405
+ const authorAllowed = authors.includes(event.pubkey);
406
+ return pathMatches && authorAllowed;
338
407
  });
339
408
 
340
409
  // Parse content and group by d-tag (keep latest only)
@@ -371,11 +440,19 @@ export async function nostrGetAllHybrid(client, pathPrefix, kind = 30000, option
371
440
  }
372
441
 
373
442
  /**
374
- * Delete data (publish deletion event - NIP-09)
443
+ * Delete data (publish deletion event - NIP-09).
444
+ *
445
+ * Publishes a tombstone event and a NIP-09 deletion event to mark data as deleted.
446
+ *
375
447
  * @param {Object} client - NostrClient instance
376
448
  * @param {string} path - Path identifier
377
- * @param {number} kind - Original event kind (default: 30000)
378
- * @returns {Promise<Object>} Deletion event result
449
+ * @param {number} [kind=30000] - Original event kind (default: 30000)
450
+ * @returns {Promise<Object>} Deletion event result with status
451
+ * @example
452
+ * const result = await nostrDelete(client, 'myapp/holon1/items/item1');
453
+ * if (result.reason !== 'not_found') {
454
+ * console.log('Item deleted successfully');
455
+ * }
379
456
  */
380
457
  export async function nostrDelete(client, path, kind = 30000) {
381
458
  // Read existing data first
@@ -432,11 +509,15 @@ export async function nostrDelete(client, path, kind = 30000) {
432
509
  }
433
510
 
434
511
  /**
435
- * Delete all data with path prefix (publish deletion events - NIP-09)
512
+ * Delete all data with path prefix (publish deletion events - NIP-09).
513
+ *
436
514
  * @param {Object} client - NostrClient instance
437
515
  * @param {string} pathPrefix - Path prefix to delete all items under
438
- * @param {number} kind - Original event kind (default: 30000)
439
- * @returns {Promise<Object>} Deletion results
516
+ * @param {number} [kind=30000] - Original event kind (default: 30000)
517
+ * @returns {Promise<Object>} Deletion results with success count
518
+ * @example
519
+ * const result = await nostrDeleteAll(client, 'myapp/holon1/items/');
520
+ * console.log(`Deleted ${result.count} items`);
440
521
  */
441
522
  export async function nostrDeleteAll(client, pathPrefix, kind = 30000) {
442
523
  // Query events from relay
@@ -551,13 +632,21 @@ export async function nostrDeleteAll(client, pathPrefix, kind = 30000) {
551
632
  }
552
633
 
553
634
  /**
554
- * Subscribe to path changes
555
- * Uses subscription deduplication - multiple subscribers to same path share one relay subscription
635
+ * Subscribe to path changes.
636
+ *
637
+ * Uses subscription deduplication - multiple subscribers to same path share one relay subscription.
638
+ *
556
639
  * @param {Object} client - NostrClient instance
557
640
  * @param {string} path - Path to subscribe to
558
641
  * @param {Function} callback - Callback function (data, event) => void
559
- * @param {Object} options - Subscription options
642
+ * @param {Object} [options={}] - Subscription options
643
+ * @param {number} [options.kind=30000] - Event kind to subscribe to
560
644
  * @returns {Object} Subscription object with unsubscribe method
645
+ * @example
646
+ * const sub = nostrSubscribe(client, 'myapp/holon1/items/item1', (data, event) => {
647
+ * console.log('Item updated:', data);
648
+ * });
649
+ * // Later: sub.unsubscribe();
561
650
  */
562
651
  export function nostrSubscribe(client, path, callback, options = {}) {
563
652
  const kind = options.kind || 30000;
@@ -616,8 +705,8 @@ export function nostrSubscribe(client, path, callback, options = {}) {
616
705
  try {
617
706
  const data = JSON.parse(event.content);
618
707
 
619
- // Skip deleted items - don't send tombstones to subscribers
620
- if (data._deleted) {
708
+ // Skip null/undefined or deleted items - don't send tombstones to subscribers
709
+ if (!data || data._deleted) {
621
710
  return;
622
711
  }
623
712
 
@@ -659,7 +748,7 @@ export function nostrSubscribe(client, path, callback, options = {}) {
659
748
  }
660
749
 
661
750
  /**
662
- * Subscribe to path prefix (multiple paths)
751
+ * Subscribe to path prefix (multiple paths).
663
752
  *
664
753
  * Subscribes to data events and uses Page Visibility API to refresh when tab becomes visible.
665
754
  * Note: Nostr relays do not broadcast replaceable event updates to active subscriptions.
@@ -667,8 +756,14 @@ export function nostrSubscribe(client, path, callback, options = {}) {
667
756
  * @param {Object} client - NostrClient instance
668
757
  * @param {string} pathPrefix - Path prefix to match
669
758
  * @param {Function} callback - Callback function (data, path, event) => void
670
- * @param {Object} options - Subscription options
759
+ * @param {Object} [options={}] - Subscription options
760
+ * @param {number} [options.kind=30000] - Event kind to subscribe to
671
761
  * @returns {Promise<Object>} Subscription object with unsubscribe method
762
+ * @example
763
+ * const sub = await nostrSubscribeMany(client, 'myapp/holon1/items/', (data, path, event) => {
764
+ * console.log('Item event:', data);
765
+ * });
766
+ * // Later: sub.unsubscribe();
672
767
  */
673
768
  export async function nostrSubscribeMany(client, pathPrefix, callback, options = {}) {
674
769
  const kind = options.kind || 30000;
@@ -743,8 +838,8 @@ export async function nostrSubscribeMany(client, pathPrefix, callback, options =
743
838
  try {
744
839
  const data = JSON.parse(event.content);
745
840
 
746
- // Skip deleted items - don't send tombstones to subscribers
747
- if (data._deleted) {
841
+ // Skip null/undefined data or deleted items - don't send tombstones to subscribers
842
+ if (!data || data._deleted) {
748
843
  return;
749
844
  }
750
845
 
@@ -829,12 +924,16 @@ export async function nostrSubscribeMany(client, pathPrefix, callback, options =
829
924
  }
830
925
 
831
926
  /**
832
- * Update data (merge with existing)
927
+ * Update data (merge with existing).
928
+ *
833
929
  * @param {Object} client - NostrClient instance
834
930
  * @param {string} path - Path identifier
835
931
  * @param {Object} updates - Fields to update
836
- * @param {number} kind - Event kind (default: 30000)
932
+ * @param {number} [kind=30000] - Event kind (default: 30000)
837
933
  * @returns {Promise<Object>} Updated event result
934
+ * @throws {Error} If no data found at path
935
+ * @example
936
+ * await nostrUpdate(client, 'myapp/holon1/items/item1', { status: 'completed' });
838
937
  */
839
938
  export async function nostrUpdate(client, path, updates, kind = 30000) {
840
939
  // Read existing data
@@ -852,10 +951,11 @@ export async function nostrUpdate(client, path, updates, kind = 30000) {
852
951
  }
853
952
 
854
953
  /**
855
- * Batch read multiple paths
954
+ * Batch read multiple paths.
955
+ *
856
956
  * @param {Object} client - NostrClient instance
857
957
  * @param {string[]} paths - Array of paths
858
- * @param {number} kind - Event kind (default: 30000)
958
+ * @param {number} [kind=30000] - Event kind (default: 30000)
859
959
  * @returns {Promise<Object>} Object mapping paths to data
860
960
  */
861
961
  export async function nostrBatchGet(client, paths, kind = 30000) {
@@ -896,10 +996,11 @@ export async function nostrBatchGet(client, paths, kind = 30000) {
896
996
  }
897
997
 
898
998
  /**
899
- * Batch write multiple paths
999
+ * Batch write multiple paths.
1000
+ *
900
1001
  * @param {Object} client - NostrClient instance
901
1002
  * @param {Object} pathDataMap - Object mapping paths to data
902
- * @param {number} kind - Event kind (default: 30000)
1003
+ * @param {number} [kind=30000] - Event kind (default: 30000)
903
1004
  * @returns {Promise<Array>} Array of publish results
904
1005
  */
905
1006
  export async function nostrBatchPut(client, pathDataMap, kind = 30000) {
@@ -911,11 +1012,13 @@ export async function nostrBatchPut(client, pathDataMap, kind = 30000) {
911
1012
  }
912
1013
 
913
1014
  /**
914
- * Retry operation with exponential backoff
1015
+ * Retry operation with exponential backoff.
1016
+ *
915
1017
  * @param {Function} operation - Async function to retry
916
- * @param {number} maxRetries - Max retry attempts (default: 3)
917
- * @param {number} baseDelay - Base delay in ms (default: 100ms)
1018
+ * @param {number} [maxRetries=3] - Max retry attempts
1019
+ * @param {number} [baseDelay=100] - Base delay in ms
918
1020
  * @returns {Promise<any>} Promise resolving to operation result
1021
+ * @throws {Error} Last error if all retries fail
919
1022
  */
920
1023
  export async function nostrRetry(operation, maxRetries = 3, baseDelay = 100) {
921
1024
  let lastError;
@@ -936,12 +1039,14 @@ export async function nostrRetry(operation, maxRetries = 3, baseDelay = 100) {
936
1039
  }
937
1040
 
938
1041
  /**
939
- * Wait for specific condition on data
1042
+ * Wait for specific condition on data.
1043
+ *
940
1044
  * @param {Object} client - NostrClient instance
941
1045
  * @param {string} path - Path to watch
942
1046
  * @param {Function} predicate - Condition function (data) => boolean
943
- * @param {number} timeout - Timeout in ms (default: 5000ms)
1047
+ * @param {number} [timeout=5000] - Timeout in ms
944
1048
  * @returns {Promise<any>} Promise resolving when condition is met
1049
+ * @throws {Error} If timeout occurs before condition is met
945
1050
  */
946
1051
  export async function nostrWaitFor(client, path, predicate, timeout = 5000) {
947
1052
  return new Promise((resolve, reject) => {