holosphere 2.0.0-alpha8 → 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 (321) 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-CKffQDmQ.cjs → index-DDGt_V9o.cjs} +2 -2
  10. package/dist/{index-CKffQDmQ.cjs.map → index-DDGt_V9o.cjs.map} +1 -1
  11. package/dist/{index-4XHHKe6S.js → index-DJXftyvB.js} +1905 -337
  12. package/dist/index-DJXftyvB.js.map +1 -0
  13. package/dist/{index-Dz5kOZMI.cjs → index-DMbdcMtK.cjs} +17 -4
  14. package/dist/index-DMbdcMtK.cjs.map +1 -0
  15. package/dist/{index-BjP1TXGz.js → index-DeZ1xz_s.js} +2 -2
  16. package/dist/{index-BjP1TXGz.js.map → index-DeZ1xz_s.js.map} +1 -1
  17. package/dist/{indexeddb-storage-lExjjFlV.js → indexeddb-storage-BFt6hMeF.js} +48 -4
  18. package/dist/indexeddb-storage-BFt6hMeF.js.map +1 -0
  19. package/dist/{indexeddb-storage-DD7EFBVc.cjs → indexeddb-storage-BK5tv4Sh.cjs} +2 -2
  20. package/dist/indexeddb-storage-BK5tv4Sh.cjs.map +1 -0
  21. package/dist/{memory-storage-C68adso2.js → memory-storage-C9HuoL2E.js} +44 -4
  22. package/dist/memory-storage-C9HuoL2E.js.map +1 -0
  23. package/dist/{memory-storage-DD_6yyXT.cjs → memory-storage-Dao7jfYG.cjs} +2 -2
  24. package/dist/memory-storage-Dao7jfYG.cjs.map +1 -0
  25. package/dist/{secp256k1-DYELiqgx.cjs → secp256k1-BbKzbLtD.cjs} +2 -2
  26. package/dist/{secp256k1-DYELiqgx.cjs.map → secp256k1-BbKzbLtD.cjs.map} +1 -1
  27. package/dist/{secp256k1-OM8siPyy.js → secp256k1-CreY7Pcl.js} +2 -2
  28. package/dist/{secp256k1-OM8siPyy.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/jsdoc.json +26 -0
  247. package/package.json +14 -3
  248. package/src/ai/aggregation.js +13 -2
  249. package/src/ai/breakdown.js +12 -2
  250. package/src/ai/classifier.js +14 -3
  251. package/src/ai/council.js +22 -7
  252. package/src/ai/embeddings.js +37 -15
  253. package/src/ai/federation-ai.js +13 -2
  254. package/src/ai/h3-ai.js +14 -2
  255. package/src/ai/index.js +16 -7
  256. package/src/ai/json-ops.js +18 -5
  257. package/src/ai/llm-service.js +62 -31
  258. package/src/ai/nl-query.js +12 -2
  259. package/src/ai/relationships.js +13 -2
  260. package/src/ai/schema-extractor.js +24 -10
  261. package/src/ai/spatial.js +13 -2
  262. package/src/ai/tts.js +25 -8
  263. package/src/content/social-protocols.js +34 -25
  264. package/src/contracts/chain-manager.js +68 -40
  265. package/src/contracts/deployer.js +70 -42
  266. package/src/contracts/event-listener.js +61 -29
  267. package/src/contracts/holon-contracts.js +46 -31
  268. package/src/contracts/index.js +5 -6
  269. package/src/contracts/networks.js +19 -14
  270. package/src/contracts/operations.js +58 -41
  271. package/src/contracts/queries.js +54 -20
  272. package/src/core/holosphere.js +35 -6
  273. package/src/crypto/nostr-utils.js +82 -76
  274. package/src/crypto/secp256k1.js +7 -2
  275. package/src/federation/handshake.js +7 -7
  276. package/src/federation/hologram.js +9 -1
  277. package/src/hierarchical/upcast.js +34 -20
  278. package/src/index.js +655 -5
  279. package/src/lib/ai-methods.js +352 -3
  280. package/src/lib/contract-methods.js +152 -3
  281. package/src/lib/errors.js +31 -1
  282. package/src/lib/federation-methods.js +110 -3
  283. package/src/lib/index.js +9 -5
  284. package/src/schema/validator.js +22 -3
  285. package/src/spatial/h3-operations.js +17 -1
  286. package/src/storage/backend-factory.js +7 -2
  287. package/src/storage/backend-interface.js +21 -2
  288. package/src/storage/backends/activitypub/server.js +25 -3
  289. package/src/storage/backends/activitypub-backend.js +25 -2
  290. package/src/storage/backends/gundb-backend.js +29 -2
  291. package/src/storage/backends/nostr-backend.js +116 -1
  292. package/src/storage/filesystem-storage-browser.js +42 -2
  293. package/src/storage/filesystem-storage.js +72 -5
  294. package/src/storage/global-tables.js +7 -2
  295. package/src/storage/gun-async.js +20 -11
  296. package/src/storage/gun-auth.js +15 -4
  297. package/src/storage/gun-federation.js +14 -5
  298. package/src/storage/gun-references.js +16 -5
  299. package/src/storage/gun-schema.js +25 -10
  300. package/src/storage/gun-wrapper.js +99 -36
  301. package/src/storage/indexeddb-storage.js +65 -4
  302. package/src/storage/key-storage-simple.js +32 -9
  303. package/src/storage/key-storage.js +45 -13
  304. package/src/storage/memory-storage.js +65 -4
  305. package/src/storage/migration.js +20 -7
  306. package/src/storage/nostr-async.js +157 -67
  307. package/src/storage/nostr-client.js +173 -49
  308. package/src/storage/nostr-wrapper.js +6 -2
  309. package/src/storage/outbox-queue.js +55 -18
  310. package/src/storage/persistent-storage.js +56 -13
  311. package/src/storage/sync-service.js +51 -17
  312. package/src/storage/unified-storage.js +7 -2
  313. package/src/subscriptions/manager.js +33 -16
  314. package/dist/index-4XHHKe6S.js.map +0 -1
  315. package/dist/index-Dz5kOZMI.cjs.map +0 -1
  316. package/dist/indexeddb-storage-DD7EFBVc.cjs.map +0 -1
  317. package/dist/indexeddb-storage-lExjjFlV.js.map +0 -1
  318. package/dist/memory-storage-C68adso2.js.map +0 -1
  319. package/dist/memory-storage-DD_6yyXT.cjs.map +0 -1
  320. /package/{cleanup-test-data.js → scripts/cleanup-test-data.js} +0 -0
  321. /package/{test-ai-real-api.js → scripts/test-ai-real-api.js} +0 -0
@@ -1,13 +1,25 @@
1
1
  /**
2
- * Key Storage - Universal API
3
- * Automatically uses Node.js or Browser implementation
2
+ * @fileoverview Key Storage - Universal API.
3
+ *
4
+ * Automatically uses Node.js or Browser implementation for storing private keys.
5
+ * In Node.js, keys are stored in the filesystem (~/.config/holosphere/keys).
6
+ * In browsers, keys are stored in localStorage.
7
+ *
8
+ * @module storage/key-storage
4
9
  */
5
10
 
6
11
  /**
7
- * Lazy-loaded Node.js modules
12
+ * Lazy-loaded Node.js modules.
13
+ * @private
8
14
  */
9
15
  let nodeModules = null;
10
16
 
17
+ /**
18
+ * Get or initialize Node.js modules for filesystem access.
19
+ *
20
+ * @private
21
+ * @returns {Object|null} Node.js modules or null if unavailable
22
+ */
11
23
  function getNodeModules() {
12
24
  if (!nodeModules) {
13
25
  try {
@@ -36,10 +48,17 @@ function getNodeModules() {
36
48
  }
37
49
 
38
50
  /**
39
- * Load private key from storage
51
+ * Load private key from storage.
52
+ *
53
+ * Attempts to load from localStorage (browser) or filesystem (Node.js).
54
+ *
40
55
  * @param {string} appName - Application name
41
- * @param {Object} options - Options
42
- * @returns {string|null} Private key or null
56
+ * @param {Object} [options={}] - Options
57
+ * @param {string} [options.keyDir] - Custom key directory (Node.js only)
58
+ * @returns {string|null} Private key (hex) or null if not found
59
+ * @example
60
+ * const key = loadPrivateKey('myapp');
61
+ * if (key) console.log('Loaded existing key');
43
62
  */
44
63
  export function loadPrivateKey(appName, options = {}) {
45
64
  // Browser environment
@@ -70,11 +89,18 @@ export function loadPrivateKey(appName, options = {}) {
70
89
  }
71
90
 
72
91
  /**
73
- * Save private key to storage
92
+ * Save private key to storage.
93
+ *
94
+ * Saves to localStorage (browser) or filesystem (Node.js) with secure permissions.
95
+ *
74
96
  * @param {string} appName - Application name
75
- * @param {string} privateKey - Private key (hex)
76
- * @param {Object} options - Options
77
- * @returns {boolean} Success
97
+ * @param {string} privateKey - Private key (64-character hex string)
98
+ * @param {Object} [options={}] - Options
99
+ * @param {string} [options.keyDir] - Custom key directory (Node.js only)
100
+ * @returns {boolean} True if saved successfully
101
+ * @throws {Error} If private key format is invalid
102
+ * @example
103
+ * const success = savePrivateKey('myapp', '1a2b3c...');
78
104
  */
79
105
  export function savePrivateKey(appName, privateKey, options = {}) {
80
106
  if (!/^[0-9a-f]{64}$/i.test(privateKey)) {
@@ -113,11 +139,17 @@ export function savePrivateKey(appName, privateKey, options = {}) {
113
139
  }
114
140
 
115
141
  /**
116
- * Get or create private key for an app
142
+ * Get or create private key for an app.
143
+ *
144
+ * Loads existing key or generates and saves a new one.
145
+ *
117
146
  * @param {string} appName - Application name
118
- * @param {Function} generateFn - Function to generate new key
119
- * @param {Object} options - Options
147
+ * @param {Function} generateFn - Function to generate new key (returns hex string)
148
+ * @param {Object} [options={}] - Options
149
+ * @param {string} [options.keyDir] - Custom key directory (Node.js only)
120
150
  * @returns {string} Private key (hex)
151
+ * @example
152
+ * const key = getOrCreatePrivateKey('myapp', () => generateSecureKey());
121
153
  */
122
154
  export function getOrCreatePrivateKey(appName, generateFn, options = {}) {
123
155
  const existingKey = loadPrivateKey(appName, options);
@@ -1,16 +1,43 @@
1
1
  /**
2
- * Memory-only storage adapter (fallback, no actual persistence)
2
+ * @fileoverview Memory-only storage adapter (fallback, no actual persistence).
3
+ *
4
+ * Provides in-memory storage for testing or when persistent storage is unavailable.
5
+ * Data is shared across instances with the same namespace but lost on process restart.
6
+ *
7
+ * @module storage/memory-storage
3
8
  */
4
9
 
5
10
  import { PersistentStorage } from './persistent-storage.js';
6
11
 
12
+ /**
13
+ * Memory-only storage adapter.
14
+ *
15
+ * Stores data in memory with no persistence across restarts.
16
+ * Uses a global store to share data across instances with same namespace.
17
+ *
18
+ * @class MemoryStorage
19
+ * @extends PersistentStorage
20
+ * @example
21
+ * const storage = new MemoryStorage();
22
+ * await storage.init('myapp');
23
+ * await storage.put('key1', { id: 'event1' });
24
+ */
7
25
  export class MemoryStorage extends PersistentStorage {
26
+ /**
27
+ * Create a new MemoryStorage instance.
28
+ */
8
29
  constructor() {
9
30
  super();
10
31
  this.data = new Map();
11
32
  this.namespace = null;
12
33
  }
13
34
 
35
+ /**
36
+ * Initialize storage with namespace.
37
+ *
38
+ * @param {string} namespace - Storage namespace
39
+ * @returns {Promise<void>}
40
+ */
14
41
  async init(namespace) {
15
42
  this.namespace = namespace;
16
43
  // Check if there's existing data for this namespace
@@ -23,18 +50,33 @@ export class MemoryStorage extends PersistentStorage {
23
50
  this.data = MemoryStorage._globalStore.get(namespace);
24
51
  }
25
52
 
53
+ /**
54
+ * Store an event.
55
+ *
56
+ * @param {string} key - Storage key
57
+ * @param {Object} event - Event data
58
+ * @returns {Promise<void>}
59
+ */
26
60
  async put(key, event) {
27
61
  this.data.set(key, JSON.parse(JSON.stringify(event))); // Deep clone
28
62
  }
29
63
 
64
+ /**
65
+ * Retrieve an event.
66
+ *
67
+ * @param {string} key - Storage key
68
+ * @returns {Promise<Object|null>} Event data or null
69
+ */
30
70
  async get(key) {
31
71
  const data = this.data.get(key);
32
72
  return data ? JSON.parse(JSON.stringify(data)) : null; // Deep clone
33
73
  }
34
74
 
35
75
  /**
36
- * @param {string} prefix
37
- * @returns {Promise<any[]>}
76
+ * Retrieve all events matching a prefix.
77
+ *
78
+ * @param {string} prefix - Key prefix to match
79
+ * @returns {Promise<any[]>} Array of matching events
38
80
  */
39
81
  async getAll(prefix) {
40
82
  /** @type {any[]} */
@@ -47,18 +89,37 @@ export class MemoryStorage extends PersistentStorage {
47
89
  return results;
48
90
  }
49
91
 
92
+ /**
93
+ * Delete an event.
94
+ *
95
+ * @param {string} key - Storage key
96
+ * @returns {Promise<void>}
97
+ */
50
98
  async delete(key) {
51
99
  this.data.delete(key);
52
100
  }
53
101
 
102
+ /**
103
+ * Clear all stored events.
104
+ *
105
+ * @returns {Promise<void>}
106
+ */
54
107
  async clear() {
55
108
  this.data.clear();
56
109
  }
57
110
 
111
+ /**
112
+ * Close storage (no-op for memory storage).
113
+ *
114
+ * @returns {Promise<void>}
115
+ */
58
116
  async close() {
59
117
  // Nothing to close for memory storage
60
118
  }
61
119
  }
62
120
 
63
- // Global store shared across instances with same namespace
121
+ /**
122
+ * Global store shared across instances with same namespace.
123
+ * @private
124
+ */
64
125
  MemoryStorage._globalStore = null;
@@ -1,11 +1,8 @@
1
1
  /**
2
- * Migration Tool for HoloSphere Storage Backends
3
- *
4
- * Enables data migration between different storage backends:
5
- * - Export data from any backend to a portable format
6
- * - Import data to any backend from the portable format
7
- * - Direct migration between backends
8
- * - Validation of migrated data
2
+ * @fileoverview Migration tool for HoloSphere storage backends.
3
+ * Enables data migration between different storage backends (Nostr, GunDB, ActivityPub)
4
+ * with export/import functionality, direct migration, and validation.
5
+ * @module storage/migration
9
6
  */
10
7
 
11
8
  import { BackendFactory } from './backend-factory.js';
@@ -38,9 +35,25 @@ import { BackendFactory } from './backend-factory.js';
38
35
  * @property {Object[]} errors - Error details
39
36
  */
40
37
 
38
+ /**
39
+ * Migration tool for transferring data between HoloSphere storage backends.
40
+ * Supports export/import to portable format, direct migration, and validation.
41
+ *
42
+ * @class MigrationTool
43
+ * @example
44
+ * const tool = new MigrationTool();
45
+ * await tool.setSource('nostr', { relays: ['wss://...'] });
46
+ * await tool.setTarget('gundb', { peers: ['wss://...'] });
47
+ * const results = await tool.migrate();
48
+ */
41
49
  export class MigrationTool {
50
+ /**
51
+ * Create a new MigrationTool instance.
52
+ */
42
53
  constructor() {
54
+ /** @type {StorageBackend|null} */
43
55
  this.sourceBackend = null;
56
+ /** @type {StorageBackend|null} */
44
57
  this.targetBackend = null;
45
58
  }
46
59
 
@@ -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;
@@ -72,8 +98,8 @@ export async function nostrGet(client, path, kind = 30000, options = {}) {
72
98
  try {
73
99
  const data = JSON.parse(persistedEvent.content);
74
100
 
75
- // Skip deleted items
76
- if (data._deleted) {
101
+ // Skip null/undefined or deleted items
102
+ if (!data || data._deleted) {
77
103
  return null;
78
104
  }
79
105
 
@@ -128,8 +154,16 @@ export async function nostrGet(client, path, kind = 30000, options = {}) {
128
154
  }
129
155
 
130
156
  /**
131
- * Internal function to execute nostrGet query
157
+ * Internal function to execute nostrGet query.
158
+ *
132
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
133
167
  */
134
168
  async function _executeNostrGet(client, path, kind, authors, timeout, options) {
135
169
  const filter = {
@@ -153,8 +187,8 @@ async function _executeNostrGet(client, path, kind, authors, timeout, options) {
153
187
 
154
188
  try {
155
189
  const data = JSON.parse(event.content);
156
- // Skip deleted items
157
- if (data._deleted) {
190
+ // Skip null/undefined or deleted items
191
+ if (!data || data._deleted) {
158
192
  return null;
159
193
  }
160
194
  // Optionally include author information
@@ -169,17 +203,24 @@ async function _executeNostrGet(client, path, kind, authors, timeout, options) {
169
203
  }
170
204
 
171
205
  /**
172
- * Query all events under a path prefix
173
- * LOCAL-FIRST: Checks persistent storage first, never blocks on network
174
- * 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
+ *
175
211
  * @param {Object} client - NostrClient instance
176
212
  * @param {string} pathPrefix - Path prefix to match
177
- * @param {number} kind - Event kind (default: 30000)
178
- * @param {Object} options - Query options
179
- * @param {string[]} options.authors - Array of public keys to query (default: [client.publicKey])
180
- * @param {boolean} options.includeAuthor - If true, adds _author field to returned data
181
- * @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
182
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`);
183
224
  */
184
225
  export async function nostrGetAll(client, pathPrefix, kind = 30000, options = {}) {
185
226
  const timeout = options.timeout !== undefined ? options.timeout : 30000;
@@ -208,8 +249,8 @@ export async function nostrGetAll(client, pathPrefix, kind = 30000, options = {}
208
249
  try {
209
250
  const data = JSON.parse(event.content);
210
251
 
211
- // Handle deleted items - remove from map if this is newer
212
- if (data._deleted) {
252
+ // Handle null/undefined or deleted items - remove from map if this is newer
253
+ if (!data || data._deleted) {
213
254
  byPath.delete(path);
214
255
  continue;
215
256
  }
@@ -266,8 +307,17 @@ export async function nostrGetAll(client, pathPrefix, kind = 30000, options = {}
266
307
  }
267
308
 
268
309
  /**
269
- * Internal function to execute nostrGetAll query
310
+ * Internal function to execute nostrGetAll query.
311
+ *
270
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
271
321
  */
272
322
  async function _executeNostrGetAll(client, pathPrefix, kind, authors, timeout, limit, options) {
273
323
  const filter = {
@@ -296,8 +346,8 @@ async function _executeNostrGetAll(client, pathPrefix, kind, authors, timeout, l
296
346
  try {
297
347
  const data = JSON.parse(event.content);
298
348
 
299
- // Handle deleted items - remove from map if this is newer
300
- if (data._deleted) {
349
+ // Handle null/undefined or deleted items - remove from map if this is newer
350
+ if (!data || data._deleted) {
301
351
  byPath.delete(dTag);
302
352
  continue;
303
353
  }
@@ -318,14 +368,18 @@ async function _executeNostrGetAll(client, pathPrefix, kind, authors, timeout, l
318
368
  }
319
369
 
320
370
  /**
321
- * Query all events under a path prefix (HYBRID MODE - local + relay)
322
- * 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
+ *
323
375
  * @param {Object} client - NostrClient instance
324
376
  * @param {string} pathPrefix - Path prefix to match
325
- * @param {number} kind - Event kind (default: 30000)
326
- * @param {Object} options - Query options
327
- * @param {string[]} options.authors - Array of public keys to query (default: [client.publicKey])
328
- * @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
329
383
  * @returns {Promise<Array>} Array of data objects (merged from local + relay)
330
384
  */
331
385
  export async function nostrGetAllHybrid(client, pathPrefix, kind = 30000, options = {}) {
@@ -386,11 +440,19 @@ export async function nostrGetAllHybrid(client, pathPrefix, kind = 30000, option
386
440
  }
387
441
 
388
442
  /**
389
- * 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
+ *
390
447
  * @param {Object} client - NostrClient instance
391
448
  * @param {string} path - Path identifier
392
- * @param {number} kind - Original event kind (default: 30000)
393
- * @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
+ * }
394
456
  */
395
457
  export async function nostrDelete(client, path, kind = 30000) {
396
458
  // Read existing data first
@@ -447,11 +509,15 @@ export async function nostrDelete(client, path, kind = 30000) {
447
509
  }
448
510
 
449
511
  /**
450
- * Delete all data with path prefix (publish deletion events - NIP-09)
512
+ * Delete all data with path prefix (publish deletion events - NIP-09).
513
+ *
451
514
  * @param {Object} client - NostrClient instance
452
515
  * @param {string} pathPrefix - Path prefix to delete all items under
453
- * @param {number} kind - Original event kind (default: 30000)
454
- * @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`);
455
521
  */
456
522
  export async function nostrDeleteAll(client, pathPrefix, kind = 30000) {
457
523
  // Query events from relay
@@ -566,13 +632,21 @@ export async function nostrDeleteAll(client, pathPrefix, kind = 30000) {
566
632
  }
567
633
 
568
634
  /**
569
- * Subscribe to path changes
570
- * 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
+ *
571
639
  * @param {Object} client - NostrClient instance
572
640
  * @param {string} path - Path to subscribe to
573
641
  * @param {Function} callback - Callback function (data, event) => void
574
- * @param {Object} options - Subscription options
642
+ * @param {Object} [options={}] - Subscription options
643
+ * @param {number} [options.kind=30000] - Event kind to subscribe to
575
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();
576
650
  */
577
651
  export function nostrSubscribe(client, path, callback, options = {}) {
578
652
  const kind = options.kind || 30000;
@@ -631,8 +705,8 @@ export function nostrSubscribe(client, path, callback, options = {}) {
631
705
  try {
632
706
  const data = JSON.parse(event.content);
633
707
 
634
- // Skip deleted items - don't send tombstones to subscribers
635
- if (data._deleted) {
708
+ // Skip null/undefined or deleted items - don't send tombstones to subscribers
709
+ if (!data || data._deleted) {
636
710
  return;
637
711
  }
638
712
 
@@ -674,7 +748,7 @@ export function nostrSubscribe(client, path, callback, options = {}) {
674
748
  }
675
749
 
676
750
  /**
677
- * Subscribe to path prefix (multiple paths)
751
+ * Subscribe to path prefix (multiple paths).
678
752
  *
679
753
  * Subscribes to data events and uses Page Visibility API to refresh when tab becomes visible.
680
754
  * Note: Nostr relays do not broadcast replaceable event updates to active subscriptions.
@@ -682,8 +756,14 @@ export function nostrSubscribe(client, path, callback, options = {}) {
682
756
  * @param {Object} client - NostrClient instance
683
757
  * @param {string} pathPrefix - Path prefix to match
684
758
  * @param {Function} callback - Callback function (data, path, event) => void
685
- * @param {Object} options - Subscription options
759
+ * @param {Object} [options={}] - Subscription options
760
+ * @param {number} [options.kind=30000] - Event kind to subscribe to
686
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();
687
767
  */
688
768
  export async function nostrSubscribeMany(client, pathPrefix, callback, options = {}) {
689
769
  const kind = options.kind || 30000;
@@ -758,8 +838,8 @@ export async function nostrSubscribeMany(client, pathPrefix, callback, options =
758
838
  try {
759
839
  const data = JSON.parse(event.content);
760
840
 
761
- // Skip deleted items - don't send tombstones to subscribers
762
- if (data._deleted) {
841
+ // Skip null/undefined data or deleted items - don't send tombstones to subscribers
842
+ if (!data || data._deleted) {
763
843
  return;
764
844
  }
765
845
 
@@ -844,12 +924,16 @@ export async function nostrSubscribeMany(client, pathPrefix, callback, options =
844
924
  }
845
925
 
846
926
  /**
847
- * Update data (merge with existing)
927
+ * Update data (merge with existing).
928
+ *
848
929
  * @param {Object} client - NostrClient instance
849
930
  * @param {string} path - Path identifier
850
931
  * @param {Object} updates - Fields to update
851
- * @param {number} kind - Event kind (default: 30000)
932
+ * @param {number} [kind=30000] - Event kind (default: 30000)
852
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' });
853
937
  */
854
938
  export async function nostrUpdate(client, path, updates, kind = 30000) {
855
939
  // Read existing data
@@ -867,10 +951,11 @@ export async function nostrUpdate(client, path, updates, kind = 30000) {
867
951
  }
868
952
 
869
953
  /**
870
- * Batch read multiple paths
954
+ * Batch read multiple paths.
955
+ *
871
956
  * @param {Object} client - NostrClient instance
872
957
  * @param {string[]} paths - Array of paths
873
- * @param {number} kind - Event kind (default: 30000)
958
+ * @param {number} [kind=30000] - Event kind (default: 30000)
874
959
  * @returns {Promise<Object>} Object mapping paths to data
875
960
  */
876
961
  export async function nostrBatchGet(client, paths, kind = 30000) {
@@ -911,10 +996,11 @@ export async function nostrBatchGet(client, paths, kind = 30000) {
911
996
  }
912
997
 
913
998
  /**
914
- * Batch write multiple paths
999
+ * Batch write multiple paths.
1000
+ *
915
1001
  * @param {Object} client - NostrClient instance
916
1002
  * @param {Object} pathDataMap - Object mapping paths to data
917
- * @param {number} kind - Event kind (default: 30000)
1003
+ * @param {number} [kind=30000] - Event kind (default: 30000)
918
1004
  * @returns {Promise<Array>} Array of publish results
919
1005
  */
920
1006
  export async function nostrBatchPut(client, pathDataMap, kind = 30000) {
@@ -926,11 +1012,13 @@ export async function nostrBatchPut(client, pathDataMap, kind = 30000) {
926
1012
  }
927
1013
 
928
1014
  /**
929
- * Retry operation with exponential backoff
1015
+ * Retry operation with exponential backoff.
1016
+ *
930
1017
  * @param {Function} operation - Async function to retry
931
- * @param {number} maxRetries - Max retry attempts (default: 3)
932
- * @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
933
1020
  * @returns {Promise<any>} Promise resolving to operation result
1021
+ * @throws {Error} Last error if all retries fail
934
1022
  */
935
1023
  export async function nostrRetry(operation, maxRetries = 3, baseDelay = 100) {
936
1024
  let lastError;
@@ -951,12 +1039,14 @@ export async function nostrRetry(operation, maxRetries = 3, baseDelay = 100) {
951
1039
  }
952
1040
 
953
1041
  /**
954
- * Wait for specific condition on data
1042
+ * Wait for specific condition on data.
1043
+ *
955
1044
  * @param {Object} client - NostrClient instance
956
1045
  * @param {string} path - Path to watch
957
1046
  * @param {Function} predicate - Condition function (data) => boolean
958
- * @param {number} timeout - Timeout in ms (default: 5000ms)
1047
+ * @param {number} [timeout=5000] - Timeout in ms
959
1048
  * @returns {Promise<any>} Promise resolving when condition is met
1049
+ * @throws {Error} If timeout occurs before condition is met
960
1050
  */
961
1051
  export async function nostrWaitFor(client, path, predicate, timeout = 5000) {
962
1052
  return new Promise((resolve, reject) => {