@openclaw/nostr 2026.7.2-beta.5 → 2026.7.33

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 (372) hide show
  1. package/dist/{channel-DNeI-LB-.js → .setup/channel-B4SX7Iq6.mjs} +552 -886
  2. package/dist/{config-schema-CelPzg1N.js → .setup/config-schema-DIiXiBKr.mjs} +1 -1
  3. package/dist/.setup/inbound-direct-dm-runtime-EdLLVtkh.mjs +2 -0
  4. package/dist/{setup-adapter-BjKmSwdW.js → .setup/setup-adapter-DEU3o8MF.mjs} +1 -31
  5. package/dist/.setup/setup-plugin-api-DzlCumkz.mjs +2 -0
  6. package/dist/.setup/setup-plugin-api-csfJrRxD.mjs +111 -0
  7. package/dist/{setup-surface-BJCFpe02.js → .setup/setup-surface-DWa6-9ku.mjs} +70 -41
  8. package/dist/api.js +70 -56
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/doctor-contract-api.js +3 -2
  11. package/dist/setup-api.js +1 -1
  12. package/dist/setup-entry.js +2 -1
  13. package/dist/setup-plugin-api.js +1 -112
  14. package/node_modules/nostr-tools/lib/cjs/abstract-pool.js +3 -35
  15. package/node_modules/nostr-tools/lib/cjs/abstract-pool.js.map +2 -2
  16. package/node_modules/nostr-tools/lib/cjs/abstract-relay.js +2 -30
  17. package/node_modules/nostr-tools/lib/cjs/abstract-relay.js.map +2 -2
  18. package/node_modules/nostr-tools/lib/cjs/index.js +3 -35
  19. package/node_modules/nostr-tools/lib/cjs/index.js.map +2 -2
  20. package/node_modules/nostr-tools/lib/cjs/nip46.js +3 -35
  21. package/node_modules/nostr-tools/lib/cjs/nip46.js.map +2 -2
  22. package/node_modules/nostr-tools/lib/cjs/nipb0.js +1 -4
  23. package/node_modules/nostr-tools/lib/cjs/nipb0.js.map +2 -2
  24. package/node_modules/nostr-tools/lib/cjs/pool.js +3 -35
  25. package/node_modules/nostr-tools/lib/cjs/pool.js.map +2 -2
  26. package/node_modules/nostr-tools/lib/cjs/relay.js +2 -30
  27. package/node_modules/nostr-tools/lib/cjs/relay.js.map +2 -2
  28. package/node_modules/nostr-tools/lib/esm/abstract-pool.js +3 -35
  29. package/node_modules/nostr-tools/lib/esm/abstract-pool.js.map +2 -2
  30. package/node_modules/nostr-tools/lib/esm/abstract-relay.js +2 -30
  31. package/node_modules/nostr-tools/lib/esm/abstract-relay.js.map +2 -2
  32. package/node_modules/nostr-tools/lib/esm/index.js +3 -35
  33. package/node_modules/nostr-tools/lib/esm/index.js.map +2 -2
  34. package/node_modules/nostr-tools/lib/esm/nip46.js +3 -35
  35. package/node_modules/nostr-tools/lib/esm/nip46.js.map +2 -2
  36. package/node_modules/nostr-tools/lib/esm/nipb0.js +1 -4
  37. package/node_modules/nostr-tools/lib/esm/nipb0.js.map +2 -2
  38. package/node_modules/nostr-tools/lib/esm/pool.js +3 -35
  39. package/node_modules/nostr-tools/lib/esm/pool.js.map +2 -2
  40. package/node_modules/nostr-tools/lib/esm/relay.js +2 -30
  41. package/node_modules/nostr-tools/lib/esm/relay.js.map +2 -2
  42. package/node_modules/nostr-tools/lib/nostr.bundle.js +3 -35
  43. package/node_modules/nostr-tools/lib/nostr.bundle.js.map +2 -2
  44. package/node_modules/nostr-tools/lib/types/abstract-pool.d.ts +0 -1
  45. package/node_modules/nostr-tools/lib/types/abstract-relay.d.ts +0 -5
  46. package/node_modules/nostr-tools/lib/types/relay.d.ts +2 -2
  47. package/node_modules/nostr-tools/package.json +1 -1
  48. package/openclaw.plugin.json +5 -0
  49. package/package.json +15 -41
  50. package/dist/inbound-direct-dm-runtime-DHn9NoYN.js +0 -2
  51. /package/dist/{state-account-id-CvBZ9s6P.js → .setup/state-account-id-CvBZ9s6P.mjs} +0 -0
  52. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/LICENSE +0 -0
  53. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/README.md +0 -0
  54. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_arx.d.ts +0 -0
  55. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_arx.d.ts.map +0 -0
  56. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_arx.js +0 -0
  57. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_arx.js.map +0 -0
  58. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_poly1305.d.ts +0 -0
  59. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_poly1305.d.ts.map +0 -0
  60. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_poly1305.js +0 -0
  61. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_poly1305.js.map +0 -0
  62. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_polyval.d.ts +0 -0
  63. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_polyval.d.ts.map +0 -0
  64. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_polyval.js +0 -0
  65. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/_polyval.js.map +0 -0
  66. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/aes.d.ts +0 -0
  67. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/aes.d.ts.map +0 -0
  68. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/aes.js +0 -0
  69. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/aes.js.map +0 -0
  70. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/chacha.d.ts +0 -0
  71. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/chacha.d.ts.map +0 -0
  72. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/chacha.js +0 -0
  73. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/chacha.js.map +0 -0
  74. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/ff1.d.ts +0 -0
  75. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/ff1.d.ts.map +0 -0
  76. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/ff1.js +0 -0
  77. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/ff1.js.map +0 -0
  78. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/index.d.ts +0 -0
  79. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/index.d.ts.map +0 -0
  80. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/index.js +0 -0
  81. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/index.js.map +0 -0
  82. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/package.json +0 -0
  83. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/salsa.d.ts +0 -0
  84. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/salsa.d.ts.map +0 -0
  85. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/salsa.js +0 -0
  86. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/salsa.js.map +0 -0
  87. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/_arx.ts +0 -0
  88. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/_poly1305.ts +0 -0
  89. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/_polyval.ts +0 -0
  90. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/aes.ts +0 -0
  91. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/chacha.ts +0 -0
  92. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/ff1.ts +0 -0
  93. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/index.ts +0 -0
  94. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/salsa.ts +0 -0
  95. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/utils.ts +0 -0
  96. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/src/webcrypto.ts +0 -0
  97. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/utils.d.ts +0 -0
  98. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/utils.d.ts.map +0 -0
  99. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/utils.js +0 -0
  100. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/utils.js.map +0 -0
  101. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/webcrypto.d.ts +0 -0
  102. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/webcrypto.d.ts.map +0 -0
  103. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/webcrypto.js +0 -0
  104. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/ciphers/webcrypto.js.map +0 -0
  105. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/LICENSE +0 -0
  106. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/README.md +0 -0
  107. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/bls.d.ts +0 -0
  108. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/bls.d.ts.map +0 -0
  109. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/bls.js +0 -0
  110. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/bls.js.map +0 -0
  111. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/curve.d.ts +0 -0
  112. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/curve.d.ts.map +0 -0
  113. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/curve.js +0 -0
  114. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/curve.js.map +0 -0
  115. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/edwards.d.ts +0 -0
  116. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/edwards.d.ts.map +0 -0
  117. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/edwards.js +0 -0
  118. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/edwards.js.map +0 -0
  119. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/fft.d.ts +0 -0
  120. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/fft.d.ts.map +0 -0
  121. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/fft.js +0 -0
  122. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/fft.js.map +0 -0
  123. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/hash-to-curve.d.ts +0 -0
  124. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/hash-to-curve.d.ts.map +0 -0
  125. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/hash-to-curve.js +0 -0
  126. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/hash-to-curve.js.map +0 -0
  127. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/modular.d.ts +0 -0
  128. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/modular.d.ts.map +0 -0
  129. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/modular.js +0 -0
  130. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/modular.js.map +0 -0
  131. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/montgomery.d.ts +0 -0
  132. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/montgomery.d.ts.map +0 -0
  133. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/montgomery.js +0 -0
  134. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/montgomery.js.map +0 -0
  135. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/oprf.d.ts +0 -0
  136. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/oprf.d.ts.map +0 -0
  137. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/oprf.js +0 -0
  138. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/oprf.js.map +0 -0
  139. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/poseidon.d.ts +0 -0
  140. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/poseidon.d.ts.map +0 -0
  141. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/poseidon.js +0 -0
  142. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/poseidon.js.map +0 -0
  143. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/tower.d.ts +0 -0
  144. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/tower.d.ts.map +0 -0
  145. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/tower.js +0 -0
  146. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/tower.js.map +0 -0
  147. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/weierstrass.d.ts +0 -0
  148. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/weierstrass.d.ts.map +0 -0
  149. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/weierstrass.js +0 -0
  150. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/abstract/weierstrass.js.map +0 -0
  151. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bls12-381.d.ts +0 -0
  152. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bls12-381.d.ts.map +0 -0
  153. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bls12-381.js +0 -0
  154. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bls12-381.js.map +0 -0
  155. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bn254.d.ts +0 -0
  156. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bn254.d.ts.map +0 -0
  157. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bn254.js +0 -0
  158. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/bn254.js.map +0 -0
  159. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed25519.d.ts +0 -0
  160. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed25519.d.ts.map +0 -0
  161. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed25519.js +0 -0
  162. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed25519.js.map +0 -0
  163. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed448.d.ts +0 -0
  164. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed448.d.ts.map +0 -0
  165. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed448.js +0 -0
  166. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/ed448.js.map +0 -0
  167. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/index.d.ts +0 -0
  168. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/index.d.ts.map +0 -0
  169. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/index.js +0 -0
  170. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/index.js.map +0 -0
  171. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/misc.d.ts +0 -0
  172. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/misc.d.ts.map +0 -0
  173. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/misc.js +0 -0
  174. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/misc.js.map +0 -0
  175. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/nist.d.ts +0 -0
  176. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/nist.d.ts.map +0 -0
  177. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/nist.js +0 -0
  178. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/nist.js.map +0 -0
  179. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/package.json +0 -0
  180. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/secp256k1.d.ts +0 -0
  181. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/secp256k1.d.ts.map +0 -0
  182. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/secp256k1.js +0 -0
  183. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/secp256k1.js.map +0 -0
  184. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/bls.ts +0 -0
  185. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/curve.ts +0 -0
  186. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/edwards.ts +0 -0
  187. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/fft.ts +0 -0
  188. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/hash-to-curve.ts +0 -0
  189. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/modular.ts +0 -0
  190. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/montgomery.ts +0 -0
  191. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/oprf.ts +0 -0
  192. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/poseidon.ts +0 -0
  193. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/tower.ts +0 -0
  194. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/abstract/weierstrass.ts +0 -0
  195. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/bls12-381.ts +0 -0
  196. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/bn254.ts +0 -0
  197. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/ed25519.ts +0 -0
  198. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/ed448.ts +0 -0
  199. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/index.ts +0 -0
  200. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/misc.ts +0 -0
  201. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/nist.ts +0 -0
  202. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/secp256k1.ts +0 -0
  203. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/utils.ts +0 -0
  204. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/src/webcrypto.ts +0 -0
  205. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/utils.d.ts +0 -0
  206. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/utils.d.ts.map +0 -0
  207. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/utils.js +0 -0
  208. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/utils.js.map +0 -0
  209. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/webcrypto.d.ts +0 -0
  210. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/webcrypto.d.ts.map +0 -0
  211. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/webcrypto.js +0 -0
  212. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/curves/webcrypto.js.map +0 -0
  213. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/LICENSE +0 -0
  214. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/README.md +0 -0
  215. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_blake.d.ts +0 -0
  216. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_blake.d.ts.map +0 -0
  217. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_blake.js +0 -0
  218. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_blake.js.map +0 -0
  219. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_md.d.ts +0 -0
  220. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_md.d.ts.map +0 -0
  221. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_md.js +0 -0
  222. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_md.js.map +0 -0
  223. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_u64.d.ts +0 -0
  224. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_u64.d.ts.map +0 -0
  225. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_u64.js +0 -0
  226. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/_u64.js.map +0 -0
  227. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/argon2.d.ts +0 -0
  228. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/argon2.d.ts.map +0 -0
  229. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/argon2.js +0 -0
  230. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/argon2.js.map +0 -0
  231. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake1.d.ts +0 -0
  232. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake1.d.ts.map +0 -0
  233. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake1.js +0 -0
  234. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake1.js.map +0 -0
  235. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake2.d.ts +0 -0
  236. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake2.d.ts.map +0 -0
  237. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake2.js +0 -0
  238. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake2.js.map +0 -0
  239. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake3.d.ts +0 -0
  240. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake3.d.ts.map +0 -0
  241. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake3.js +0 -0
  242. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/blake3.js.map +0 -0
  243. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/eskdf.d.ts +0 -0
  244. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/eskdf.d.ts.map +0 -0
  245. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/eskdf.js +0 -0
  246. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/eskdf.js.map +0 -0
  247. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hkdf.d.ts +0 -0
  248. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hkdf.d.ts.map +0 -0
  249. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hkdf.js +0 -0
  250. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hkdf.js.map +0 -0
  251. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hmac.d.ts +0 -0
  252. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hmac.d.ts.map +0 -0
  253. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hmac.js +0 -0
  254. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/hmac.js.map +0 -0
  255. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/index.d.ts +0 -0
  256. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/index.d.ts.map +0 -0
  257. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/index.js +0 -0
  258. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/index.js.map +0 -0
  259. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/legacy.d.ts +0 -0
  260. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/legacy.d.ts.map +0 -0
  261. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/legacy.js +0 -0
  262. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/legacy.js.map +0 -0
  263. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/package.json +0 -0
  264. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/pbkdf2.d.ts +0 -0
  265. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/pbkdf2.d.ts.map +0 -0
  266. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/pbkdf2.js +0 -0
  267. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/pbkdf2.js.map +0 -0
  268. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/scrypt.d.ts +0 -0
  269. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/scrypt.d.ts.map +0 -0
  270. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/scrypt.js +0 -0
  271. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/scrypt.js.map +0 -0
  272. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha2.d.ts +0 -0
  273. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha2.d.ts.map +0 -0
  274. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha2.js +0 -0
  275. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha2.js.map +0 -0
  276. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3-addons.d.ts +0 -0
  277. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3-addons.d.ts.map +0 -0
  278. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3-addons.js +0 -0
  279. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3-addons.js.map +0 -0
  280. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3.d.ts +0 -0
  281. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3.d.ts.map +0 -0
  282. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3.js +0 -0
  283. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/sha3.js.map +0 -0
  284. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/_blake.ts +0 -0
  285. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/_md.ts +0 -0
  286. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/_u64.ts +0 -0
  287. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/argon2.ts +0 -0
  288. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/blake1.ts +0 -0
  289. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/blake2.ts +0 -0
  290. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/blake3.ts +0 -0
  291. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/eskdf.ts +0 -0
  292. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/hkdf.ts +0 -0
  293. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/hmac.ts +0 -0
  294. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/index.ts +0 -0
  295. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/legacy.ts +0 -0
  296. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/pbkdf2.ts +0 -0
  297. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/scrypt.ts +0 -0
  298. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/sha2.ts +0 -0
  299. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/sha3-addons.ts +0 -0
  300. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/sha3.ts +0 -0
  301. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/utils.ts +0 -0
  302. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/src/webcrypto.ts +0 -0
  303. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/utils.d.ts +0 -0
  304. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/utils.d.ts.map +0 -0
  305. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/utils.js +0 -0
  306. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/utils.js.map +0 -0
  307. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/webcrypto.d.ts +0 -0
  308. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/webcrypto.d.ts.map +0 -0
  309. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/webcrypto.js +0 -0
  310. /package/node_modules/{@noble → nostr-tools/node_modules/@noble}/hashes/webcrypto.js.map +0 -0
  311. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/LICENSE +0 -0
  312. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/README.md +0 -0
  313. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/index.d.ts +0 -0
  314. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/index.d.ts.map +0 -0
  315. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/index.js +0 -0
  316. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/index.js.map +0 -0
  317. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/index.ts +0 -0
  318. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/base/package.json +0 -0
  319. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/LICENSE +0 -0
  320. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/README.md +0 -0
  321. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/index.d.ts +0 -0
  322. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/index.d.ts.map +0 -0
  323. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/index.js +0 -0
  324. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/index.js.map +0 -0
  325. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/index.ts +0 -0
  326. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip32/package.json +0 -0
  327. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/LICENSE +0 -0
  328. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/README.md +0 -0
  329. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/index.d.ts +0 -0
  330. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/index.js +0 -0
  331. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/package.json +0 -0
  332. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/src/index.ts +0 -0
  333. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/czech.d.ts +0 -0
  334. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/czech.js +0 -0
  335. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/english.d.ts +0 -0
  336. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/english.js +0 -0
  337. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/french.d.ts +0 -0
  338. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/french.js +0 -0
  339. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/italian.d.ts +0 -0
  340. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/italian.js +0 -0
  341. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/japanese.d.ts +0 -0
  342. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/japanese.js +0 -0
  343. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/korean.d.ts +0 -0
  344. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/korean.js +0 -0
  345. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/portuguese.d.ts +0 -0
  346. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/portuguese.js +0 -0
  347. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/simplified-chinese.d.ts +0 -0
  348. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/simplified-chinese.js +0 -0
  349. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/spanish.d.ts +0 -0
  350. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/spanish.js +0 -0
  351. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/traditional-chinese.d.ts +0 -0
  352. /package/node_modules/{@scure → nostr-tools/node_modules/@scure}/bip39/wordlists/traditional-chinese.js +0 -0
  353. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/README.md +0 -0
  354. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/api/emsimp.d.ts +0 -0
  355. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/api/nostr.d.ts +0 -0
  356. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/api/secp256k1-types.d.ts +0 -0
  357. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/api/secp256k1.d.ts +0 -0
  358. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/api/types.d.ts +0 -0
  359. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/api/wasm-env.d.ts +0 -0
  360. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/gen/wasm.d.ts +0 -0
  361. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/generate.d.ts +0 -0
  362. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/gzipped.d.ts +0 -0
  363. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/gzipped.js +0 -0
  364. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/headless.d.ts +0 -0
  365. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/main.d.ts +0 -0
  366. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/main.js +0 -0
  367. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/nostr.js +0 -0
  368. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/secp256k1.js +0 -0
  369. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/dist/types.d.ts +0 -0
  370. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/package.json +0 -0
  371. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/public/out/secp256k1.js +0 -0
  372. /package/node_modules/{nostr-wasm → nostr-tools/node_modules/nostr-wasm}/public/out/secp256k1.wasm +0 -0
@@ -1,82 +1,60 @@
1
- import { a as listNostrAccountIds, c as normalizePubkey, l as validatePrivateKey, n as nostrSetupContract, o as resolveDefaultNostrAccountId, r as nostrSetupWizard, s as resolveNostrAccount, t as nostrSetupAdapter } from "./setup-surface-BJCFpe02.js";
2
- import { a as collectStatusIssuesFromLastError, i as buildChannelConfigSchema, n as NostrProfileSchema, o as createDefaultChannelRuntimeState, r as DEFAULT_ACCOUNT_ID, s as formatPairingApproveHint, t as NostrConfigSchema } from "./config-schema-CelPzg1N.js";
3
- import { a as DEFAULT_RELAYS } from "./setup-adapter-BjKmSwdW.js";
4
- import { t as normalizeNostrStateAccountId } from "./state-account-id-CvBZ9s6P.js";
1
+ import { a as resolveDefaultNostrAccountId, c as validatePrivateKey, i as listNostrAccountIds, n as nostrSetupWizard, o as resolveNostrAccount, s as normalizePubkey, t as nostrSetupAdapter } from "./setup-surface-DWa6-9ku.mjs";
2
+ import { a as collectStatusIssuesFromLastError, i as buildChannelConfigSchema, n as NostrProfileSchema, o as createDefaultChannelRuntimeState, r as DEFAULT_ACCOUNT_ID, s as formatPairingApproveHint, t as NostrConfigSchema } from "./config-schema-DIiXiBKr.mjs";
3
+ import { i as DEFAULT_RELAYS } from "./setup-adapter-DEU3o8MF.mjs";
4
+ import { t as normalizeNostrStateAccountId } from "./state-account-id-CvBZ9s6P.mjs";
5
5
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
6
6
  import { createScopedDmSecurityResolver, createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
7
7
  import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
8
- import { missingTargetError } from "openclaw/plugin-sdk/channel-feedback";
9
- import { DEFAULT_INGRESS_ADOPTION_STALL_MS, bindIngressLifecycleToReplyOptions, createChannelIngressMonitor, createChannelMessageAdapterFromOutbound, runPassiveAccountLifecycle } from "openclaw/plugin-sdk/channel-outbound";
10
- import { buildPassiveChannelStatusSummary, buildTrafficStatusSummary } from "openclaw/plugin-sdk/extension-shared";
8
+ import { createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-outbound";
9
+ import { buildPassiveChannelStatusSummary, buildTrafficStatusSummary, runStoppablePassiveMonitor } from "openclaw/plugin-sdk/extension-shared";
11
10
  import { createComputedAccountStatusAdapter } from "openclaw/plugin-sdk/status-helpers";
12
11
  import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
13
12
  import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
14
13
  import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
15
14
  import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
16
- import { stripMarkdown } from "openclaw/plugin-sdk/text-chunking";
17
15
  import { SimplePool, finalizeEvent, getPublicKey, verifyEvent } from "nostr-tools";
18
16
  import { decrypt, encrypt } from "nostr-tools/nip04";
19
17
  import { createDirectDmPreCryptoGuardPolicy } from "openclaw/plugin-sdk/direct-dm-guard-policy";
20
18
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
21
19
  import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
20
+ import { resolveIntegerOption, resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
22
21
  import { buildChannelOutboundSessionRoute, stripChannelTargetPrefix } from "openclaw/plugin-sdk/core";
23
22
  //#region extensions/nostr/src/metrics.ts
24
- function createZeroMetricsState() {
25
- return {
26
- eventsReceived: 0,
27
- eventsProcessed: 0,
28
- eventsDuplicate: 0,
29
- eventsRejected: {
30
- invalidShape: 0,
31
- wrongKind: 0,
32
- stale: 0,
33
- future: 0,
34
- rateLimited: 0,
35
- invalidSignature: 0,
36
- oversizedCiphertext: 0,
37
- oversizedPlaintext: 0,
38
- decryptFailed: 0,
39
- selfMessage: 0
40
- },
41
- relays: /* @__PURE__ */ new Map(),
42
- rateLimiting: {
43
- perSenderHits: 0,
44
- globalHits: 0
45
- },
46
- decrypt: {
47
- success: 0,
48
- failure: 0
49
- },
50
- memory: {
51
- seenTrackerSize: 0,
52
- rateLimiterEntries: 0
53
- }
54
- };
55
- }
56
- function createMetricsSnapshot(state, snapshotAt) {
57
- const relays = {};
58
- for (const [url, stats] of state.relays) relays[url] = {
59
- ...stats,
60
- messagesReceived: { ...stats.messagesReceived }
61
- };
62
- return {
63
- ...state,
64
- eventsRejected: { ...state.eventsRejected },
65
- relays,
66
- rateLimiting: { ...state.rateLimiting },
67
- decrypt: { ...state.decrypt },
68
- memory: { ...state.memory },
69
- snapshotAt: snapshotAt ?? Date.now()
70
- };
71
- }
72
23
  /**
73
24
  * Create a metrics collector instance.
74
25
  * Optionally pass an onMetric callback to receive real-time metric events.
75
26
  */
76
27
  function createMetrics(onMetric) {
77
- let state = createZeroMetricsState();
28
+ let eventsReceived = 0;
29
+ let eventsProcessed = 0;
30
+ let eventsDuplicate = 0;
31
+ const eventsRejected = {
32
+ invalidShape: 0,
33
+ wrongKind: 0,
34
+ stale: 0,
35
+ future: 0,
36
+ rateLimited: 0,
37
+ invalidSignature: 0,
38
+ oversizedCiphertext: 0,
39
+ oversizedPlaintext: 0,
40
+ decryptFailed: 0,
41
+ selfMessage: 0
42
+ };
43
+ const relays = /* @__PURE__ */ new Map();
44
+ const rateLimiting = {
45
+ perSenderHits: 0,
46
+ globalHits: 0
47
+ };
48
+ const decrypt = {
49
+ success: 0,
50
+ failure: 0
51
+ };
52
+ const memory = {
53
+ seenTrackerSize: 0,
54
+ rateLimiterEntries: 0
55
+ };
78
56
  function getOrCreateRelay(url) {
79
- let relay = state.relays.get(url);
57
+ let relay = relays.get(url);
80
58
  if (!relay) {
81
59
  relay = {
82
60
  connects: 0,
@@ -95,7 +73,7 @@ function createMetrics(onMetric) {
95
73
  circuitBreakerOpens: 0,
96
74
  circuitBreakerCloses: 0
97
75
  };
98
- state.relays.set(url, relay);
76
+ relays.set(url, relay);
99
77
  }
100
78
  return relay;
101
79
  }
@@ -109,43 +87,43 @@ function createMetrics(onMetric) {
109
87
  const relayUrl = labels?.relay;
110
88
  switch (name) {
111
89
  case "event.received":
112
- state.eventsReceived += value;
90
+ eventsReceived += value;
113
91
  break;
114
92
  case "event.processed":
115
- state.eventsProcessed += value;
93
+ eventsProcessed += value;
116
94
  break;
117
95
  case "event.duplicate":
118
- state.eventsDuplicate += value;
96
+ eventsDuplicate += value;
119
97
  break;
120
98
  case "event.rejected.invalid_shape":
121
- state.eventsRejected.invalidShape += value;
99
+ eventsRejected.invalidShape += value;
122
100
  break;
123
101
  case "event.rejected.wrong_kind":
124
- state.eventsRejected.wrongKind += value;
102
+ eventsRejected.wrongKind += value;
125
103
  break;
126
104
  case "event.rejected.stale":
127
- state.eventsRejected.stale += value;
105
+ eventsRejected.stale += value;
128
106
  break;
129
107
  case "event.rejected.future":
130
- state.eventsRejected.future += value;
108
+ eventsRejected.future += value;
131
109
  break;
132
110
  case "event.rejected.rate_limited":
133
- state.eventsRejected.rateLimited += value;
111
+ eventsRejected.rateLimited += value;
134
112
  break;
135
113
  case "event.rejected.invalid_signature":
136
- state.eventsRejected.invalidSignature += value;
114
+ eventsRejected.invalidSignature += value;
137
115
  break;
138
116
  case "event.rejected.oversized_ciphertext":
139
- state.eventsRejected.oversizedCiphertext += value;
117
+ eventsRejected.oversizedCiphertext += value;
140
118
  break;
141
119
  case "event.rejected.oversized_plaintext":
142
- state.eventsRejected.oversizedPlaintext += value;
120
+ eventsRejected.oversizedPlaintext += value;
143
121
  break;
144
122
  case "event.rejected.decrypt_failed":
145
- state.eventsRejected.decryptFailed += value;
123
+ eventsRejected.decryptFailed += value;
146
124
  break;
147
125
  case "event.rejected.self_message":
148
- state.eventsRejected.selfMessage += value;
126
+ eventsRejected.selfMessage += value;
149
127
  break;
150
128
  case "relay.connect":
151
129
  if (relayUrl) getOrCreateRelay(relayUrl).connects += value;
@@ -195,30 +173,64 @@ function createMetrics(onMetric) {
195
173
  if (relayUrl) getOrCreateRelay(relayUrl).circuitBreakerState = "half_open";
196
174
  break;
197
175
  case "rate_limit.per_sender":
198
- state.rateLimiting.perSenderHits += value;
176
+ rateLimiting.perSenderHits += value;
199
177
  break;
200
178
  case "rate_limit.global":
201
- state.rateLimiting.globalHits += value;
179
+ rateLimiting.globalHits += value;
202
180
  break;
203
181
  case "decrypt.success":
204
- state.decrypt.success += value;
182
+ decrypt.success += value;
205
183
  break;
206
184
  case "decrypt.failure":
207
- state.decrypt.failure += value;
185
+ decrypt.failure += value;
208
186
  break;
209
187
  case "memory.seen_tracker_size":
210
- state.memory.seenTrackerSize = value;
211
- break;
212
- case "memory.rate_limiter_entries":
213
- state.memory.rateLimiterEntries = value;
188
+ memory.seenTrackerSize = value;
214
189
  break;
190
+ case "memory.rate_limiter_entries": memory.rateLimiterEntries = value;
215
191
  }
216
192
  }
217
193
  function getSnapshot() {
218
- return createMetricsSnapshot(state);
194
+ const relaysObj = {};
195
+ for (const [url, stats] of relays) relaysObj[url] = {
196
+ ...stats,
197
+ messagesReceived: { ...stats.messagesReceived }
198
+ };
199
+ return {
200
+ eventsReceived,
201
+ eventsProcessed,
202
+ eventsDuplicate,
203
+ eventsRejected: { ...eventsRejected },
204
+ relays: relaysObj,
205
+ rateLimiting: { ...rateLimiting },
206
+ decrypt: { ...decrypt },
207
+ memory: { ...memory },
208
+ snapshotAt: Date.now()
209
+ };
219
210
  }
220
211
  function reset() {
221
- state = createZeroMetricsState();
212
+ eventsReceived = 0;
213
+ eventsProcessed = 0;
214
+ eventsDuplicate = 0;
215
+ Object.assign(eventsRejected, {
216
+ invalidShape: 0,
217
+ wrongKind: 0,
218
+ stale: 0,
219
+ future: 0,
220
+ rateLimited: 0,
221
+ invalidSignature: 0,
222
+ oversizedCiphertext: 0,
223
+ oversizedPlaintext: 0,
224
+ decryptFailed: 0,
225
+ selfMessage: 0
226
+ });
227
+ relays.clear();
228
+ rateLimiting.perSenderHits = 0;
229
+ rateLimiting.globalHits = 0;
230
+ decrypt.success = 0;
231
+ decrypt.failure = 0;
232
+ memory.seenTrackerSize = 0;
233
+ memory.rateLimiterEntries = 0;
222
234
  }
223
235
  return {
224
236
  emit,
@@ -230,7 +242,37 @@ function createMetrics(onMetric) {
230
242
  * Create a no-op metrics instance (for when metrics are disabled).
231
243
  */
232
244
  function createNoopMetrics() {
233
- const emptySnapshot = createMetricsSnapshot(createZeroMetricsState(), 0);
245
+ const emptySnapshot = {
246
+ eventsReceived: 0,
247
+ eventsProcessed: 0,
248
+ eventsDuplicate: 0,
249
+ eventsRejected: {
250
+ invalidShape: 0,
251
+ wrongKind: 0,
252
+ stale: 0,
253
+ future: 0,
254
+ rateLimited: 0,
255
+ invalidSignature: 0,
256
+ oversizedCiphertext: 0,
257
+ oversizedPlaintext: 0,
258
+ decryptFailed: 0,
259
+ selfMessage: 0
260
+ },
261
+ relays: {},
262
+ rateLimiting: {
263
+ perSenderHits: 0,
264
+ globalHits: 0
265
+ },
266
+ decrypt: {
267
+ success: 0,
268
+ failure: 0
269
+ },
270
+ memory: {
271
+ seenTrackerSize: 0,
272
+ rateLimiterEntries: 0
273
+ },
274
+ snapshotAt: 0
275
+ };
234
276
  return {
235
277
  emit: () => {},
236
278
  getSnapshot: () => ({
@@ -241,395 +283,6 @@ function createNoopMetrics() {
241
283
  };
242
284
  }
243
285
  //#endregion
244
- //#region extensions/nostr/src/nostr-cursor.ts
245
- const CURSOR_WRITE_RETRY_MS = [
246
- 0,
247
- 100,
248
- 300
249
- ];
250
- const CURSOR_RECOVERY_RETRY_MS = 1e3;
251
- /** Tracks the largest EOSE-safe Nostr timestamp without skipping undurable relay events. */
252
- function createNostrDurableCursor(options) {
253
- const nowSec = options.nowSec ?? (() => Math.floor(Date.now() / 1e3));
254
- let durableCandidate;
255
- let transientReplayCeiling;
256
- let backfillComplete = false;
257
- const safeCandidate = () => {
258
- if (durableCandidate === void 0) return;
259
- return Math.min(durableCandidate, transientReplayCeiling ?? Number.MAX_SAFE_INTEGER);
260
- };
261
- return {
262
- recordDurableAppend: (event) => {
263
- if (!Number.isSafeInteger(event.created_at)) return;
264
- const previousSafeCandidate = safeCandidate();
265
- durableCandidate = Math.max(durableCandidate ?? 0, Math.min(event.created_at, nowSec()));
266
- const nextSafeCandidate = safeCandidate();
267
- return backfillComplete && nextSafeCandidate !== previousSafeCandidate ? nextSafeCandidate : void 0;
268
- },
269
- recordTransientRejection: (event) => {
270
- if (!Number.isSafeInteger(event.created_at) || event.created_at < options.since) return;
271
- const previousSafeCandidate = safeCandidate();
272
- transientReplayCeiling = Math.min(transientReplayCeiling ?? Number.MAX_SAFE_INTEGER, event.created_at + options.replayOverlapSec);
273
- const nextSafeCandidate = safeCandidate();
274
- return backfillComplete && nextSafeCandidate !== previousSafeCandidate ? nextSafeCandidate : void 0;
275
- },
276
- markBackfillComplete: () => {
277
- backfillComplete = true;
278
- return safeCandidate();
279
- }
280
- };
281
- }
282
- /** Serializes cursor writes so a safety rewind always lands after older progress writes. */
283
- function createNostrCursorStateWriter(options) {
284
- let desiredCursor = Math.max(options.minimumCursor, options.initialCursor);
285
- let dirty = false;
286
- let timer;
287
- let writeTail = Promise.resolve();
288
- let activeFlush;
289
- let recoveryFlush;
290
- const writeWithRetry = async (cursor) => {
291
- let lastError;
292
- for (const delayMs of CURSOR_WRITE_RETRY_MS) {
293
- if (delayMs > 0) await new Promise((resolve) => {
294
- setTimeout(resolve, delayMs);
295
- });
296
- try {
297
- await options.write(cursor);
298
- return;
299
- } catch (error) {
300
- lastError = error;
301
- }
302
- }
303
- throw new Error("Nostr cursor state write failed.", { cause: lastError });
304
- };
305
- const enqueueWrite = (cursor) => {
306
- const write = writeTail.then(() => writeWithRetry(cursor));
307
- writeTail = write.catch(() => void 0);
308
- return write;
309
- };
310
- const clearTimer = () => {
311
- if (timer) {
312
- clearTimeout(timer);
313
- timer = void 0;
314
- }
315
- };
316
- const runFlush = async () => {
317
- for (;;) {
318
- if (!dirty) {
319
- await writeTail;
320
- if (!dirty) return;
321
- }
322
- dirty = false;
323
- const cursor = desiredCursor;
324
- try {
325
- await enqueueWrite(cursor);
326
- } catch (error) {
327
- dirty = true;
328
- throw error;
329
- }
330
- }
331
- };
332
- const flush = () => {
333
- clearTimer();
334
- if (activeFlush) return activeFlush;
335
- const tracked = runFlush().finally(() => {
336
- if (activeFlush === tracked) activeFlush = void 0;
337
- });
338
- activeFlush = tracked;
339
- return tracked;
340
- };
341
- const setDesiredCursor = (cursor) => {
342
- desiredCursor = Math.max(options.minimumCursor, cursor);
343
- dirty = true;
344
- };
345
- return {
346
- schedule: (cursor) => {
347
- setDesiredCursor(cursor);
348
- clearTimer();
349
- timer = setTimeout(() => {
350
- timer = void 0;
351
- flush().catch((error) => options.onBackgroundError?.(error));
352
- }, options.debounceMs);
353
- timer.unref?.();
354
- },
355
- persistNow: async (cursor) => {
356
- setDesiredCursor(cursor);
357
- await flush();
358
- },
359
- flush,
360
- flushUntilSuccess: () => {
361
- recoveryFlush ??= (async () => {
362
- for (;;) try {
363
- await flush();
364
- return;
365
- } catch (error) {
366
- options.onBackgroundError?.(error);
367
- await new Promise((resolve) => {
368
- setTimeout(resolve, options.recoveryRetryMs ?? CURSOR_RECOVERY_RETRY_MS);
369
- });
370
- }
371
- })().finally(() => {
372
- recoveryFlush = void 0;
373
- });
374
- return recoveryFlush;
375
- }
376
- };
377
- }
378
- var NostrIngressPermanentError = class extends Error {
379
- constructor(reason, message, options) {
380
- super(message, options);
381
- this.name = "NostrIngressPermanentError";
382
- this.reason = reason;
383
- }
384
- };
385
- function isNostrIngressRecord(value) {
386
- return typeof value === "object" && value !== null && !Array.isArray(value);
387
- }
388
- function requiredString(value, field) {
389
- if (typeof value === "string" && value.trim()) return value;
390
- throw new NostrIngressPermanentError("invalid-event", `Nostr event is missing ${field}.`);
391
- }
392
- function inspectNostrIngressEvent(event) {
393
- if (!isNostrIngressRecord(event)) throw new NostrIngressPermanentError("invalid-event", "Nostr event must be an object.");
394
- return {
395
- eventId: requiredString(event.id, "id"),
396
- laneKey: `direct:${requiredString(event.pubkey, "pubkey")}`
397
- };
398
- }
399
- /** Convert the retired persisted LRU seed into durable completion tombstones. */
400
- async function migrateNostrLegacyRecentEventIds(params) {
401
- const migratedAt = params.migratedAt ?? Date.now();
402
- let migrated = 0;
403
- for (const eventId of new Set(params.eventIds)) {
404
- if (!eventId.trim()) continue;
405
- const result = await params.queue.enqueue(eventId, {
406
- version: 1,
407
- receivedAt: migratedAt,
408
- rawEvent: ""
409
- }, {
410
- receivedAt: migratedAt,
411
- laneKey: `legacy:${eventId}`
412
- });
413
- if (result.kind === "accepted" || result.kind === "pending" && result.record.payload.rawEvent === "") {
414
- if (!await params.queue.complete(eventId, { completedAt: migratedAt })) throw new Error(`Failed to migrate Nostr replay event ${eventId}.`);
415
- }
416
- migrated += 1;
417
- }
418
- return migrated;
419
- }
420
- //#endregion
421
- //#region extensions/nostr/src/runtime.ts
422
- const { setRuntime: setNostrRuntime, getRuntime: getNostrRuntime } = createPluginRuntimeStore({
423
- pluginId: "nostr",
424
- errorMessage: "Nostr runtime not initialized"
425
- });
426
- //#endregion
427
- //#region extensions/nostr/src/nostr-ingress.ts
428
- const NOSTR_INGRESS_POLL_INTERVAL_MS = 500;
429
- const NOSTR_INGRESS_PRUNE_INTERVAL_MS = 3600 * 1e3;
430
- const NOSTR_INGRESS_COMPLETED_TTL_MS = 720 * 60 * 60 * 1e3;
431
- const NOSTR_INGRESS_COMPLETED_MAX_ENTRIES = 1e5;
432
- const NOSTR_INGRESS_FAILED_TTL_MS = 720 * 60 * 60 * 1e3;
433
- const NOSTR_INGRESS_FAILED_MAX_ENTRIES = 1e5;
434
- const NOSTR_INGRESS_APPEND_RETRY_MS = [
435
- 0,
436
- 100,
437
- 300
438
- ];
439
- var NostrIngressAdmissionRejectedError = class extends Error {
440
- constructor(reason, message) {
441
- super(message);
442
- this.name = "NostrIngressAdmissionRejectedError";
443
- this.reason = reason;
444
- }
445
- };
446
- function deserializeNostrIngressEvent(rawEvent, claimedId) {
447
- let parsed;
448
- try {
449
- parsed = JSON.parse(rawEvent);
450
- } catch (error) {
451
- throw new NostrIngressPermanentError("invalid-event", `Nostr ingress row ${claimedId} contains invalid JSON.`, { cause: error });
452
- }
453
- if (!isNostrIngressRecord(parsed)) throw new NostrIngressPermanentError("invalid-event", `Nostr ingress row ${claimedId} has an invalid event shape.`);
454
- if (typeof parsed.kind !== "number" || typeof parsed.created_at !== "number" || typeof parsed.content !== "string" || typeof parsed.sig !== "string" || !Array.isArray(parsed.tags)) throw new NostrIngressPermanentError("invalid-event", `Nostr ingress row ${claimedId} has an invalid event shape.`);
455
- return parsed;
456
- }
457
- function createNostrIngress(options) {
458
- let queue = options.queue;
459
- let admissionFailure;
460
- let admissionWindowStartedAt = Date.now();
461
- let admissionWindowCount = 0;
462
- let queuedAdmissions = 0;
463
- let stopping = false;
464
- let stopTask;
465
- const createStoppedError = () => /* @__PURE__ */ new Error("Nostr ingress stopped");
466
- const getQueue = () => {
467
- queue ??= getNostrRuntime().state.openChannelIngressQueue({ accountId: options.accountId });
468
- return queue;
469
- };
470
- const legacyMigration = migrateNostrLegacyRecentEventIds({
471
- queue: getQueue(),
472
- eventIds: options.legacyEventIds ?? []
473
- });
474
- const monitor = createChannelIngressMonitor({
475
- queue: getQueue,
476
- inspect: (event) => {
477
- const facts = inspectNostrIngressEvent(event);
478
- return {
479
- eventId: facts.eventId,
480
- laneKey: facts.laneKey
481
- };
482
- },
483
- payload: {
484
- version: 1,
485
- serialize: (event, { receivedAt }) => ({
486
- receivedAt,
487
- rawEvent: JSON.stringify(event)
488
- }),
489
- deserialize: (body, { claim }) => deserializeNostrIngressEvent(body.rawEvent, claim.id),
490
- encode: ({ body }) => ({
491
- version: 1,
492
- ...body
493
- }),
494
- decode: (payload, { claim }) => {
495
- if (typeof payload !== "object" || payload === null || typeof payload.rawEvent !== "string") throw new NostrIngressPermanentError("invalid-event", `Nostr ingress row ${claim.id} has an invalid payload.`);
496
- return {
497
- version: payload.version,
498
- body: {
499
- receivedAt: typeof payload.receivedAt === "number" ? payload.receivedAt : 0,
500
- rawEvent: payload.rawEvent
501
- }
502
- };
503
- },
504
- createClaimError: (kind, claim) => new NostrIngressPermanentError("invalid-event", kind === "invalid-version" ? `Nostr ingress row ${claim.id} has an unsupported version.` : `Nostr ingress row ${claim.id} changed event identity.`)
505
- },
506
- deliver: (event, lifecycle) => options.deliver(event, lifecycle),
507
- pollIntervalMs: options.pollIntervalMs ?? NOSTR_INGRESS_POLL_INTERVAL_MS,
508
- retention: {
509
- pruneIntervalMs: NOSTR_INGRESS_PRUNE_INTERVAL_MS,
510
- completedTtlMs: NOSTR_INGRESS_COMPLETED_TTL_MS,
511
- completedMaxEntries: NOSTR_INGRESS_COMPLETED_MAX_ENTRIES,
512
- failedTtlMs: NOSTR_INGRESS_FAILED_TTL_MS,
513
- failedMaxEntries: NOSTR_INGRESS_FAILED_MAX_ENTRIES
514
- },
515
- drain: {
516
- adoptionStallTimeoutMs: options.adoptionStallTimeoutMs ?? DEFAULT_INGRESS_ADOPTION_STALL_MS,
517
- resolveNonRetryableFailure: (error) => error instanceof NostrIngressPermanentError ? {
518
- reason: error.reason,
519
- message: error.message
520
- } : null,
521
- onLog: (message) => options.onError?.(new Error(message), "ingress drain")
522
- },
523
- createStoppedError,
524
- onError: (error) => options.onError?.(error, "ingress drain")
525
- });
526
- const monitorStart = legacyMigration.then(() => {
527
- if (!stopping) monitor.start();
528
- });
529
- monitorStart.catch((error) => options.onError?.(error, "ingress drain"));
530
- let admissionTail = Promise.resolve();
531
- const prepareAdmission = (event) => {
532
- const facts = inspectNostrIngressEvent(event);
533
- const receivedAt = Date.now();
534
- if (receivedAt - admissionWindowStartedAt >= options.admissionRateLimit.windowMs) {
535
- admissionWindowStartedAt = receivedAt;
536
- admissionWindowCount = 0;
537
- }
538
- if (admissionWindowCount >= options.admissionRateLimit.maxEvents) throw new NostrIngressAdmissionRejectedError("rate-limited", "Nostr event exceeds the durable admission rate.");
539
- admissionWindowCount += 1;
540
- if (queuedAdmissions >= options.maxQueuedAdmissions) throw new NostrIngressAdmissionRejectedError("backpressure", "Nostr event exceeds the in-memory admission backlog.");
541
- let payload;
542
- let serializedPayload;
543
- try {
544
- payload = {
545
- version: 1,
546
- receivedAt,
547
- rawEvent: JSON.stringify(event)
548
- };
549
- serializedPayload = JSON.stringify(payload);
550
- } catch (error) {
551
- throw new NostrIngressPermanentError("invalid-event", "Nostr event could not be serialized for durable ingress.", { cause: error });
552
- }
553
- if (Buffer.byteLength(serializedPayload, "utf8") > options.maxSerializedPayloadBytes) throw new NostrIngressAdmissionRejectedError("oversized-event", "Nostr event exceeds the durable ingress size limit.");
554
- return {
555
- event,
556
- facts,
557
- receivedAt,
558
- payload
559
- };
560
- };
561
- const admitOnce = async (prepared) => {
562
- await legacyMigration;
563
- const pending = await getQueue().listPending({ limit: options.maxPendingEvents });
564
- const claims = await getQueue().listClaims();
565
- if (pending.length + claims.length >= options.maxPendingEvents) throw new NostrIngressAdmissionRejectedError("backpressure", "Nostr event exceeds the durable ingress backlog.");
566
- let lastError;
567
- for (const delayMs of NOSTR_INGRESS_APPEND_RETRY_MS) {
568
- if (delayMs > 0) await new Promise((resolve) => {
569
- setTimeout(resolve, delayMs);
570
- });
571
- try {
572
- const result = await getQueue().enqueue(prepared.facts.eventId, prepared.payload, {
573
- receivedAt: prepared.receivedAt,
574
- laneKey: prepared.facts.laneKey
575
- });
576
- options.afterDurableAppend(prepared.event);
577
- monitor.requestDrain();
578
- return result.kind === "accepted" ? "accepted" : "duplicate";
579
- } catch (error) {
580
- lastError = error;
581
- }
582
- }
583
- throw new Error(`Nostr durable admission failed: ${formatErrorMessage(lastError)}`, { cause: lastError });
584
- };
585
- return {
586
- ready: async () => {
587
- await monitorStart;
588
- },
589
- receive: (event) => {
590
- if (stopping) return Promise.reject(createStoppedError());
591
- let prepared;
592
- try {
593
- prepared = prepareAdmission(event);
594
- } catch (error) {
595
- return Promise.reject(error);
596
- }
597
- queuedAdmissions += 1;
598
- const settledAdmission = admissionTail.then(async () => {
599
- if (admissionFailure) throw admissionFailure;
600
- try {
601
- return await admitOnce(prepared);
602
- } catch (error) {
603
- if (error instanceof NostrIngressAdmissionRejectedError || error instanceof NostrIngressPermanentError) throw error;
604
- admissionFailure = error instanceof Error ? error : new Error(formatErrorMessage(error), { cause: error });
605
- throw admissionFailure;
606
- }
607
- }).finally(() => {
608
- queuedAdmissions -= 1;
609
- });
610
- admissionTail = settledAdmission.then(() => void 0, () => void 0);
611
- return settledAdmission;
612
- },
613
- stop: () => {
614
- if (stopTask) return stopTask;
615
- stopping = true;
616
- const pauseTask = monitor.pause();
617
- stopTask = (async () => {
618
- await admissionTail;
619
- await monitorStart.catch(() => void 0);
620
- await pauseTask;
621
- await monitor.stop();
622
- })();
623
- return stopTask;
624
- },
625
- waitForIdle: async () => {
626
- await admissionTail;
627
- await monitorStart;
628
- await monitor.waitForIdle();
629
- }
630
- };
631
- }
632
- //#endregion
633
286
  //#region extensions/nostr/src/nostr-profile-core.ts
634
287
  /**
635
288
  * Convert our config profile schema to NIP-01 content format.
@@ -665,16 +318,6 @@ function contentToProfile(content) {
665
318
  return profile;
666
319
  }
667
320
  //#endregion
668
- //#region extensions/nostr/src/relay-publish.ts
669
- const CONNECTION_FAILURE_PREFIX = "connection failure: ";
670
- async function publishNostrEventToRelay(pool, relay, event) {
671
- const publishPromise = pool.publish([relay], event)[0];
672
- if (!publishPromise) throw new Error(`Failed to create publish promise for relay ${relay}`);
673
- const result = await publishPromise;
674
- if (result.startsWith(CONNECTION_FAILURE_PREFIX)) throw new Error(result.slice(20));
675
- return result;
676
- }
677
- //#endregion
678
321
  //#region extensions/nostr/src/nostr-profile.ts
679
322
  /**
680
323
  * Nostr Profile Management (NIP-01 kind:0)
@@ -694,11 +337,12 @@ function createProfileEvent(sk, profile, lastPublishedAt) {
694
337
  const content = profileToContent(profile);
695
338
  const contentJson = JSON.stringify(content);
696
339
  const now = Math.floor(Date.now() / 1e3);
340
+ const createdAt = lastPublishedAt !== void 0 ? Math.max(now, lastPublishedAt + 1) : now;
697
341
  return finalizeEvent({
698
342
  kind: 0,
699
343
  content: contentJson,
700
344
  tags: [],
701
- created_at: lastPublishedAt !== void 0 ? Math.max(now, lastPublishedAt + 1) : now
345
+ created_at: createdAt
702
346
  }, sk);
703
347
  }
704
348
  /** Per-relay publish timeout (ms) */
@@ -723,7 +367,7 @@ async function publishProfileEvent(pool, relays, event) {
723
367
  const timeoutPromise = new Promise((_, reject) => {
724
368
  timer = setTimeout(() => reject(/* @__PURE__ */ new Error("timeout")), RELAY_PUBLISH_TIMEOUT_MS);
725
369
  });
726
- await Promise.race([publishNostrEventToRelay(pool, relay, event), timeoutPromise]);
370
+ await Promise.race([...pool.publish([relay], event), timeoutPromise]);
727
371
  successes.push(relay);
728
372
  } catch (err) {
729
373
  const errorMessage = formatErrorMessage(err);
@@ -757,111 +401,11 @@ async function publishProfile(pool, sk, relays, profile, lastPublishedAt) {
757
401
  return publishProfileEvent(pool, relays, createProfileEvent(sk, profile, lastPublishedAt));
758
402
  }
759
403
  //#endregion
760
- //#region extensions/nostr/src/nostr-rate-limiter.ts
761
- function createFixedWindowRateLimiter(params) {
762
- const windowMs = Math.max(1, Math.floor(params.windowMs));
763
- const maxRequests = Math.max(1, Math.floor(params.maxRequests));
764
- const maxTrackedKeys = Math.max(1, Math.floor(params.maxTrackedKeys));
765
- const state = /* @__PURE__ */ new Map();
766
- const touch = (key, value) => {
767
- state.delete(key);
768
- state.set(key, value);
769
- };
770
- const prune = (nowMs) => {
771
- for (const [key, entry] of state) if (nowMs - entry.windowStartMs >= windowMs) state.delete(key);
772
- while (state.size > maxTrackedKeys) {
773
- const oldest = state.keys().next().value;
774
- if (!oldest) break;
775
- state.delete(oldest);
776
- }
777
- };
778
- return {
779
- isRateLimited: (key, nowMs = Date.now()) => {
780
- if (!key) return false;
781
- prune(nowMs);
782
- const existing = state.get(key);
783
- if (!existing || nowMs - existing.windowStartMs >= windowMs) {
784
- touch(key, {
785
- count: 1,
786
- windowStartMs: nowMs
787
- });
788
- return false;
789
- }
790
- const nextCount = existing.count + 1;
791
- touch(key, {
792
- count: nextCount,
793
- windowStartMs: existing.windowStartMs
794
- });
795
- return nextCount > maxRequests;
796
- },
797
- size: () => state.size,
798
- clear: () => state.clear()
799
- };
800
- }
801
- //#endregion
802
- //#region extensions/nostr/src/nostr-relay-subscription.ts
803
- const DEFAULT_EOSE_CONFIRM_DEADLINE_MS = 1e4;
804
- const LIBRARY_EOSE_TIMEOUT_MARGIN_MS = 1e3;
805
- /** Separates real relay EOSE frames from nostr-tools timeout/close synthesis. */
806
- function createNostrRelaySubscriptionGroup(options) {
807
- const relays = [...new Set(options.relays)];
808
- const subscriptions = [];
809
- const deadlineTimers = /* @__PURE__ */ new Set();
810
- let locallyClosing = false;
811
- const backfillStatus = new Map(relays.map((relay) => [relay, "pending"]));
812
- const confirmDeadlineMs = options.eoseConfirmDeadlineMs ?? DEFAULT_EOSE_CONFIRM_DEADLINE_MS;
813
- const settleBackfill = (relay, status) => {
814
- if (backfillStatus.get(relay) !== "pending") return;
815
- backfillStatus.set(relay, status);
816
- if ([...backfillStatus.values()].some((value) => value === "pending")) return;
817
- if ([...backfillStatus.values()].every((value) => value === "confirmed")) options.onBackfillComplete(relays);
818
- };
819
- const clearDeadlines = () => {
820
- for (const timer of deadlineTimers) clearTimeout(timer);
821
- deadlineTimers.clear();
822
- };
823
- return {
824
- start: () => {
825
- for (const relay of relays) {
826
- let relayClosed = false;
827
- let deadlineReached = false;
828
- const deadlineTimer = setTimeout(() => {
829
- deadlineTimers.delete(deadlineTimer);
830
- deadlineReached = true;
831
- settleBackfill(relay, "incomplete");
832
- }, confirmDeadlineMs);
833
- deadlineTimer.unref?.();
834
- deadlineTimers.add(deadlineTimer);
835
- subscriptions.push(options.pool.subscribeMany([relay], options.filter, {
836
- onevent: options.onEvent,
837
- oneose: () => {
838
- queueMicrotask(() => {
839
- if (!relayClosed && !deadlineReached) {
840
- clearTimeout(deadlineTimer);
841
- deadlineTimers.delete(deadlineTimer);
842
- settleBackfill(relay, "confirmed");
843
- }
844
- });
845
- },
846
- onclose: (reasons) => {
847
- relayClosed = true;
848
- clearTimeout(deadlineTimer);
849
- deadlineTimers.delete(deadlineTimer);
850
- settleBackfill(relay, "incomplete");
851
- if (!locallyClosing && !options.abort.aborted) options.onClose(relay, reasons);
852
- },
853
- maxWait: confirmDeadlineMs + LIBRARY_EOSE_TIMEOUT_MARGIN_MS,
854
- abort: options.abort
855
- }));
856
- }
857
- },
858
- close: async (reason) => {
859
- locallyClosing = true;
860
- clearDeadlines();
861
- await Promise.all(subscriptions.map(async (subscription) => subscription.close(reason)));
862
- }
863
- };
864
- }
404
+ //#region extensions/nostr/src/runtime.ts
405
+ const { setRuntime: setNostrRuntime, getRuntime: getNostrRuntime } = createPluginRuntimeStore({
406
+ pluginId: "nostr",
407
+ errorMessage: "Nostr runtime not initialized"
408
+ });
865
409
  //#endregion
866
410
  //#region extensions/nostr/src/nostr-state-store.ts
867
411
  const STORE_VERSION = 2;
@@ -916,15 +460,213 @@ async function writeNostrProfileState(params) {
916
460
  await openNostrProfileStateStore(params.env).register(normalizeNostrStateAccountId(params.accountId), payload);
917
461
  }
918
462
  //#endregion
463
+ //#region extensions/nostr/src/seen-tracker.ts
464
+ /**
465
+ * LRU-based seen event tracker with TTL support.
466
+ * Prevents unbounded memory growth under high load or abuse.
467
+ */
468
+ /**
469
+ * Create a new seen tracker with LRU eviction and TTL expiration.
470
+ */
471
+ function createSeenTracker(options) {
472
+ const maxEntries = resolveIntegerOption(options?.maxEntries, 1e5, { min: 1 });
473
+ const ttlMs = resolvePositiveTimerTimeoutMs(options?.ttlMs, 36e5);
474
+ const pruneIntervalMs = resolvePositiveTimerTimeoutMs(options?.pruneIntervalMs, 6e5);
475
+ const entries = /* @__PURE__ */ new Map();
476
+ let head = null;
477
+ let tail = null;
478
+ function moveToFront(id) {
479
+ const entry = entries.get(id);
480
+ if (!entry) return;
481
+ if (head === id) return;
482
+ if (entry.prev) {
483
+ const prevEntry = entries.get(entry.prev);
484
+ if (prevEntry) prevEntry.next = entry.next;
485
+ }
486
+ if (entry.next) {
487
+ const nextEntry = entries.get(entry.next);
488
+ if (nextEntry) nextEntry.prev = entry.prev;
489
+ }
490
+ if (tail === id) tail = entry.prev;
491
+ entry.prev = null;
492
+ entry.next = head;
493
+ if (head) {
494
+ const headEntry = entries.get(head);
495
+ if (headEntry) headEntry.prev = id;
496
+ }
497
+ head = id;
498
+ if (!tail) tail = id;
499
+ }
500
+ function removeFromList(id) {
501
+ const entry = entries.get(id);
502
+ if (!entry) return;
503
+ if (entry.prev) {
504
+ const prevEntry = entries.get(entry.prev);
505
+ if (prevEntry) prevEntry.next = entry.next;
506
+ } else head = entry.next;
507
+ if (entry.next) {
508
+ const nextEntry = entries.get(entry.next);
509
+ if (nextEntry) nextEntry.prev = entry.prev;
510
+ } else tail = entry.prev;
511
+ }
512
+ function evictLRU() {
513
+ if (!tail) return;
514
+ const idToEvict = tail;
515
+ removeFromList(idToEvict);
516
+ entries.delete(idToEvict);
517
+ }
518
+ function insertAtFront(id, seenAt) {
519
+ const newEntry = {
520
+ seenAt,
521
+ prev: null,
522
+ next: head
523
+ };
524
+ if (head) {
525
+ const headEntry = entries.get(head);
526
+ if (headEntry) headEntry.prev = id;
527
+ }
528
+ entries.set(id, newEntry);
529
+ head = id;
530
+ if (!tail) tail = id;
531
+ }
532
+ function pruneExpired() {
533
+ const now = Date.now();
534
+ const toDelete = [];
535
+ for (const [id, entry] of entries) if (now - entry.seenAt > ttlMs) toDelete.push(id);
536
+ for (const id of toDelete) {
537
+ removeFromList(id);
538
+ entries.delete(id);
539
+ }
540
+ }
541
+ let pruneTimer;
542
+ if (pruneIntervalMs > 0) {
543
+ pruneTimer = setInterval(pruneExpired, pruneIntervalMs);
544
+ if (pruneTimer.unref) pruneTimer.unref();
545
+ }
546
+ function add(id) {
547
+ const now = Date.now();
548
+ const existing = entries.get(id);
549
+ if (existing) {
550
+ existing.seenAt = now;
551
+ moveToFront(id);
552
+ return;
553
+ }
554
+ while (entries.size >= maxEntries) evictLRU();
555
+ insertAtFront(id, now);
556
+ }
557
+ function has(id) {
558
+ const entry = entries.get(id);
559
+ if (!entry) {
560
+ add(id);
561
+ return false;
562
+ }
563
+ if (Date.now() - entry.seenAt > ttlMs) {
564
+ removeFromList(id);
565
+ entries.delete(id);
566
+ add(id);
567
+ return false;
568
+ }
569
+ entry.seenAt = Date.now();
570
+ moveToFront(id);
571
+ return true;
572
+ }
573
+ function peek(id) {
574
+ const entry = entries.get(id);
575
+ if (!entry) return false;
576
+ if (Date.now() - entry.seenAt > ttlMs) {
577
+ removeFromList(id);
578
+ entries.delete(id);
579
+ return false;
580
+ }
581
+ return true;
582
+ }
583
+ function deleteEntry(id) {
584
+ if (entries.has(id)) {
585
+ removeFromList(id);
586
+ entries.delete(id);
587
+ }
588
+ }
589
+ function clear() {
590
+ entries.clear();
591
+ head = null;
592
+ tail = null;
593
+ }
594
+ function size() {
595
+ return entries.size;
596
+ }
597
+ function stop() {
598
+ if (pruneTimer) {
599
+ clearInterval(pruneTimer);
600
+ pruneTimer = void 0;
601
+ }
602
+ }
603
+ function seed(ids) {
604
+ const now = Date.now();
605
+ for (let i = ids.length - 1; i >= 0; i--) {
606
+ const id = ids[i];
607
+ if (!entries.has(id) && entries.size < maxEntries) insertAtFront(id, now);
608
+ }
609
+ }
610
+ return {
611
+ has,
612
+ add,
613
+ peek,
614
+ delete: deleteEntry,
615
+ clear,
616
+ size,
617
+ stop,
618
+ seed
619
+ };
620
+ }
621
+ //#endregion
919
622
  //#region extensions/nostr/src/nostr-bus.ts
920
623
  const STARTUP_LOOKBACK_SEC = 120;
624
+ const MAX_PERSISTED_EVENT_IDS = 5e3;
921
625
  const STATE_PERSIST_DEBOUNCE_MS = 5e3;
922
- const NOSTR_INGRESS_ENVELOPE_OVERHEAD_BYTES = 16 * 1024;
923
- const NOSTR_INGRESS_MAX_PENDING_EVENTS = 1e3;
924
626
  const DEFAULT_INBOUND_GUARD_POLICY = createDirectDmPreCryptoGuardPolicy();
925
627
  const CIRCUIT_BREAKER_THRESHOLD = 5;
926
628
  const CIRCUIT_BREAKER_RESET_MS = 3e4;
927
629
  const HEALTH_WINDOW_MS = 6e4;
630
+ function createFixedWindowRateLimiter(params) {
631
+ const windowMs = Math.max(1, Math.floor(params.windowMs));
632
+ const maxRequests = Math.max(1, Math.floor(params.maxRequests));
633
+ const maxTrackedKeys = Math.max(1, Math.floor(params.maxTrackedKeys));
634
+ const state = /* @__PURE__ */ new Map();
635
+ const touch = (key, value) => {
636
+ state.delete(key);
637
+ state.set(key, value);
638
+ };
639
+ const prune = (nowMs) => {
640
+ for (const [key, entry] of state) if (nowMs - entry.windowStartMs >= windowMs) state.delete(key);
641
+ while (state.size > maxTrackedKeys) {
642
+ const oldest = state.keys().next().value;
643
+ if (!oldest) break;
644
+ state.delete(oldest);
645
+ }
646
+ };
647
+ return {
648
+ isRateLimited: (key, nowMs = Date.now()) => {
649
+ if (!key) return false;
650
+ prune(nowMs);
651
+ const existing = state.get(key);
652
+ if (!existing || nowMs - existing.windowStartMs >= windowMs) {
653
+ touch(key, {
654
+ count: 1,
655
+ windowStartMs: nowMs
656
+ });
657
+ return false;
658
+ }
659
+ const nextCount = existing.count + 1;
660
+ touch(key, {
661
+ count: nextCount,
662
+ windowStartMs: existing.windowStartMs
663
+ });
664
+ return nextCount > maxRequests;
665
+ },
666
+ size: () => state.size,
667
+ clear: () => state.clear()
668
+ };
669
+ }
928
670
  function createCircuitBreaker(relay, metrics, threshold = CIRCUIT_BREAKER_THRESHOLD, resetMs = CIRCUIT_BREAKER_RESET_MS) {
929
671
  const state = {
930
672
  state: "closed",
@@ -1020,11 +762,10 @@ function createRelayHealthTracker() {
1020
762
  * Start the Nostr DM bus - subscribes to NIP-04 encrypted DMs
1021
763
  */
1022
764
  async function startNostrBus(options) {
1023
- const { privateKey, relays = DEFAULT_RELAYS, onMessage, authorizeSender, onError, onEose, onMetric } = options;
765
+ const { privateKey, relays = DEFAULT_RELAYS, onMessage, authorizeSender, onError, onEose, onMetric, maxSeenEntries = 1e5, seenTtlMs = 36e5 } = options;
1024
766
  const sk = validatePrivateKey(privateKey);
1025
767
  const pk = getPublicKey(sk);
1026
768
  const pool = new SimplePool();
1027
- pool.onRelayConnectionSuccess = options.onConnect;
1028
769
  const accountId = options.accountId ?? pk.slice(0, 16);
1029
770
  const gatewayStartedAt = Math.floor(Date.now() / 1e3);
1030
771
  const guardPolicy = createDirectDmPreCryptoGuardPolicy({
@@ -1036,32 +777,41 @@ async function startNostrBus(options) {
1036
777
  }
1037
778
  });
1038
779
  const metrics = onMetric ? createMetrics(onMetric) : createNoopMetrics();
780
+ const seen = createSeenTracker({
781
+ maxEntries: maxSeenEntries,
782
+ ttlMs: seenTtlMs
783
+ });
1039
784
  const circuitBreakers = /* @__PURE__ */ new Map();
1040
785
  const healthTracker = createRelayHealthTracker();
1041
786
  for (const relay of relays) circuitBreakers.set(relay, createCircuitBreaker(relay, metrics));
1042
787
  const state = await readNostrBusState({ accountId });
1043
788
  const baseSince = computeSinceTimestamp(state, gatewayStartedAt);
1044
789
  const since = Math.max(0, baseSince - STARTUP_LOOKBACK_SEC);
1045
- const cursorStartedAt = state?.gatewayStartedAt ?? gatewayStartedAt;
1046
- const initialCursor = Math.max(baseSince, state?.lastProcessedAt ?? cursorStartedAt);
1047
- const cursorWriter = createNostrCursorStateWriter({
1048
- initialCursor,
1049
- minimumCursor: baseSince,
1050
- debounceMs: STATE_PERSIST_DEBOUNCE_MS,
1051
- write: async (cursor) => {
1052
- await writeNostrBusState({
1053
- accountId,
1054
- lastProcessedAt: cursor,
1055
- gatewayStartedAt: cursorStartedAt,
1056
- recentEventIds: []
1057
- });
1058
- },
1059
- onBackgroundError: (error) => onError?.(error, "persist state")
1060
- });
1061
- const durableCursor = createNostrDurableCursor({
1062
- since,
1063
- replayOverlapSec: STARTUP_LOOKBACK_SEC
790
+ if (state?.recentEventIds?.length) seen.seed(state.recentEventIds);
791
+ await writeNostrBusState({
792
+ accountId,
793
+ lastProcessedAt: state?.lastProcessedAt ?? gatewayStartedAt,
794
+ gatewayStartedAt,
795
+ recentEventIds: state?.recentEventIds ?? []
1064
796
  });
797
+ let pendingWrite;
798
+ let lastProcessedAt = state?.lastProcessedAt ?? gatewayStartedAt;
799
+ let recentEventIds = (state?.recentEventIds ?? []).slice(-5e3);
800
+ function scheduleStatePersist(eventCreatedAt, eventId) {
801
+ lastProcessedAt = Math.max(lastProcessedAt, eventCreatedAt);
802
+ recentEventIds.push(eventId);
803
+ if (recentEventIds.length > MAX_PERSISTED_EVENT_IDS) recentEventIds = recentEventIds.slice(-5e3);
804
+ if (pendingWrite) clearTimeout(pendingWrite);
805
+ pendingWrite = setTimeout(() => {
806
+ writeNostrBusState({
807
+ accountId,
808
+ lastProcessedAt,
809
+ gatewayStartedAt,
810
+ recentEventIds
811
+ }).catch((err) => onError?.(err, "persist state"));
812
+ }, STATE_PERSIST_DEBOUNCE_MS);
813
+ }
814
+ const inflight = /* @__PURE__ */ new Set();
1065
815
  const perSenderRateLimiter = createFixedWindowRateLimiter({
1066
816
  windowMs: guardPolicy.rateLimit.windowMs,
1067
817
  maxRequests: guardPolicy.rateLimit.maxPerSenderPerWindow,
@@ -1075,217 +825,147 @@ async function startNostrBus(options) {
1075
825
  const updateRateLimiterSizeMetric = () => {
1076
826
  metrics.emit("memory.rate_limiter_entries", perSenderRateLimiter.size() + globalRateLimiter.size());
1077
827
  };
1078
- const rejectIfGlobalRateLimited = () => {
1079
- updateRateLimiterSizeMetric();
1080
- if (globalRateLimiter.isRateLimited("global")) {
1081
- metrics.emit("rate_limit.global");
1082
- metrics.emit("event.rejected.rate_limited");
1083
- updateRateLimiterSizeMetric();
1084
- return true;
1085
- }
1086
- updateRateLimiterSizeMetric();
1087
- return false;
1088
- };
1089
- const rejectIfVerifiedSenderRateLimited = (senderPubkey) => {
1090
- updateRateLimiterSizeMetric();
1091
- if (perSenderRateLimiter.isRateLimited(senderPubkey)) {
1092
- metrics.emit("rate_limit.per_sender");
1093
- metrics.emit("event.rejected.rate_limited");
1094
- updateRateLimiterSizeMetric();
1095
- return true;
1096
- }
1097
- updateRateLimiterSizeMetric();
1098
- return false;
1099
- };
1100
- async function dispatchEvent(event, lifecycle) {
1101
- if (event.pubkey === pk) {
1102
- metrics.emit("event.rejected.self_message");
1103
- return;
1104
- }
1105
- if (event.created_at > Math.floor(Date.now() / 1e3) + guardPolicy.maxFutureSkewSec) {
1106
- metrics.emit("event.rejected.future");
1107
- throw new Error(`Nostr event ${event.id} is too far in the future.`);
1108
- }
1109
- if (!guardPolicy.allowedKinds.includes(event.kind)) {
1110
- metrics.emit("event.rejected.wrong_kind");
1111
- return;
1112
- }
1113
- let targetsUs = false;
1114
- for (const tag of event.tags) if (tag[0] === "p" && tag[1] === pk) {
1115
- targetsUs = true;
1116
- break;
1117
- }
1118
- if (!targetsUs) {
1119
- metrics.emit("event.rejected.wrong_kind");
1120
- return;
1121
- }
1122
- const replyTo = async (text) => {
1123
- await sendEncryptedDm(pool, sk, event.pubkey, text, relays, metrics, circuitBreakers, healthTracker, onError, event.id);
1124
- };
1125
- if (Buffer.byteLength(event.content, "utf8") > guardPolicy.maxCiphertextBytes) {
1126
- if (rejectIfGlobalRateLimited()) throw new Error(`Nostr event ${event.id} hit the global rate limit.`);
1127
- metrics.emit("event.rejected.oversized_ciphertext");
1128
- return;
1129
- }
1130
- if (rejectIfGlobalRateLimited()) throw new Error(`Nostr event ${event.id} hit the global rate limit.`);
1131
- if (!verifyEvent(event)) {
1132
- metrics.emit("event.rejected.invalid_signature");
1133
- const error = new NostrIngressPermanentError("invalid-signature", `Nostr event ${event.id} has an invalid signature.`);
1134
- onError?.(error, `event ${event.id}`);
1135
- throw error;
1136
- }
1137
- if (rejectIfVerifiedSenderRateLimited(event.pubkey)) throw new Error(`Nostr sender ${event.pubkey} hit the rate limit.`);
1138
- if (authorizeSender) {
1139
- if (await authorizeSender({
1140
- senderPubkey: event.pubkey,
1141
- reply: replyTo
1142
- }) !== "allow") return;
1143
- }
1144
- let plaintext;
828
+ async function handleEvent(event) {
1145
829
  try {
1146
- plaintext = decrypt(sk, event.pubkey, event.content);
1147
- metrics.emit("decrypt.success");
1148
- } catch (error) {
1149
- metrics.emit("decrypt.failure");
1150
- metrics.emit("event.rejected.decrypt_failed");
1151
- onError?.(error, `decrypt from ${event.pubkey}`);
1152
- throw new NostrIngressPermanentError("decrypt-failed", `Nostr event ${event.id} could not be decrypted.`, { cause: error });
1153
- }
1154
- if (Buffer.byteLength(plaintext, "utf8") > guardPolicy.maxPlaintextBytes) {
1155
- metrics.emit("event.rejected.oversized_plaintext");
1156
- return;
1157
- }
1158
- if (lifecycle.abortSignal.aborted) throw new Error(`Nostr event ${event.id} stopped before dispatch.`);
1159
- await onMessage(event.pubkey, plaintext, replyTo, {
1160
- eventId: event.id,
1161
- createdAt: event.created_at
1162
- }, lifecycle);
1163
- metrics.emit("event.processed");
1164
- }
1165
- const dmFilter = {
1166
- kinds: [4],
1167
- "#p": [pk],
1168
- since
1169
- };
1170
- const relayAbort = new AbortController();
1171
- let relaySubscriptions;
1172
- let relayStopPromise;
1173
- const stopRelays = (reason) => {
1174
- relayStopPromise ??= (async () => {
1175
- relayAbort.abort(reason);
1176
- try {
1177
- await relaySubscriptions?.close(reason);
1178
- } catch (error) {
1179
- onError?.(error, "close subscription");
1180
- } finally {
1181
- try {
1182
- pool.close(relays);
1183
- } catch (error) {
1184
- onError?.(error, "close relay pool");
1185
- }
830
+ metrics.emit("event.received");
831
+ if (seen.peek(event.id) || inflight.has(event.id)) {
832
+ metrics.emit("event.duplicate");
833
+ return;
1186
834
  }
1187
- })();
1188
- return relayStopPromise;
1189
- };
1190
- const ingress = createNostrIngress({
1191
- accountId,
1192
- legacyEventIds: state?.recentEventIds ?? [],
1193
- maxSerializedPayloadBytes: guardPolicy.maxCiphertextBytes + NOSTR_INGRESS_ENVELOPE_OVERHEAD_BYTES,
1194
- maxPendingEvents: NOSTR_INGRESS_MAX_PENDING_EVENTS,
1195
- maxQueuedAdmissions: guardPolicy.rateLimit.maxGlobalPerWindow,
1196
- admissionRateLimit: {
1197
- windowMs: guardPolicy.rateLimit.windowMs,
1198
- maxEvents: guardPolicy.rateLimit.maxGlobalPerWindow
1199
- },
1200
- afterDurableAppend: (event) => {
1201
- const cursor = durableCursor.recordDurableAppend(event);
1202
- if (cursor !== void 0) cursorWriter.schedule(cursor);
1203
- },
1204
- deliver: dispatchEvent,
1205
- onError
1206
- });
1207
- const persistTransientReplayCursor = async (event) => {
1208
- const cursor = durableCursor.recordTransientRejection(event);
1209
- if (cursor !== void 0) await cursorWriter.persistNow(cursor);
1210
- };
1211
- const recoverCursorPersistence = async () => {
1212
- await cursorWriter.flushUntilSuccess();
1213
- };
1214
- const handleRelayEvent = async (event) => {
1215
- metrics.emit("event.received");
1216
- if (typeof event.created_at === "number" && event.created_at < since) {
1217
- metrics.emit("event.rejected.stale");
1218
- return;
1219
- }
1220
- try {
1221
- if (await ingress.receive(event) === "duplicate") metrics.emit("event.duplicate");
1222
- } catch (error) {
1223
- onError?.(error, `durable admission for event ${event.id}`);
1224
- if (error instanceof NostrIngressAdmissionRejectedError) {
1225
- if (error.reason === "rate-limited") {
835
+ inflight.add(event.id);
836
+ const markSeen = () => {
837
+ seen.add(event.id);
838
+ metrics.emit("memory.seen_tracker_size", seen.size());
839
+ };
840
+ const rejectAndMarkSeen = (metric) => {
841
+ markSeen();
842
+ metrics.emit(metric);
843
+ };
844
+ if (event.pubkey === pk) {
845
+ rejectAndMarkSeen("event.rejected.self_message");
846
+ return;
847
+ }
848
+ if (event.created_at < since) {
849
+ rejectAndMarkSeen("event.rejected.stale");
850
+ return;
851
+ }
852
+ if (event.created_at > Math.floor(Date.now() / 1e3) + guardPolicy.maxFutureSkewSec) {
853
+ metrics.emit("event.rejected.future");
854
+ return;
855
+ }
856
+ if (!guardPolicy.allowedKinds.includes(event.kind)) {
857
+ rejectAndMarkSeen("event.rejected.wrong_kind");
858
+ return;
859
+ }
860
+ let targetsUs = false;
861
+ for (const t of event.tags) if (t[0] === "p" && t[1] === pk) {
862
+ targetsUs = true;
863
+ break;
864
+ }
865
+ if (!targetsUs) {
866
+ rejectAndMarkSeen("event.rejected.wrong_kind");
867
+ return;
868
+ }
869
+ const replyTo = async (text) => {
870
+ await sendEncryptedDm(pool, sk, event.pubkey, text, relays, metrics, circuitBreakers, healthTracker, onError);
871
+ };
872
+ const rejectIfGlobalRateLimited = () => {
873
+ updateRateLimiterSizeMetric();
874
+ if (globalRateLimiter.isRateLimited("global")) {
1226
875
  metrics.emit("rate_limit.global");
1227
876
  metrics.emit("event.rejected.rate_limited");
877
+ updateRateLimiterSizeMetric();
878
+ return true;
1228
879
  }
1229
- if (error.reason !== "oversized-event") try {
1230
- await persistTransientReplayCursor(event);
1231
- } catch (cursorError) {
1232
- onError?.(cursorError, "persist transient replay cursor");
1233
- await stopRelays("cursor persistence failed");
1234
- await recoverCursorPersistence();
880
+ updateRateLimiterSizeMetric();
881
+ return false;
882
+ };
883
+ const rejectIfVerifiedSenderRateLimited = () => {
884
+ updateRateLimiterSizeMetric();
885
+ if (perSenderRateLimiter.isRateLimited(event.pubkey)) {
886
+ metrics.emit("rate_limit.per_sender");
887
+ metrics.emit("event.rejected.rate_limited");
888
+ updateRateLimiterSizeMetric();
889
+ return true;
1235
890
  }
891
+ updateRateLimiterSizeMetric();
892
+ return false;
893
+ };
894
+ if (Buffer.byteLength(event.content, "utf8") > guardPolicy.maxCiphertextBytes) {
895
+ if (rejectIfGlobalRateLimited()) return;
896
+ rejectAndMarkSeen("event.rejected.oversized_ciphertext");
1236
897
  return;
1237
898
  }
1238
- if (error instanceof NostrIngressPermanentError) return;
1239
- let cursorPersistenceFailed = false;
899
+ if (rejectIfGlobalRateLimited()) return;
900
+ if (!verifyEvent(event)) {
901
+ rejectAndMarkSeen("event.rejected.invalid_signature");
902
+ onError?.(/* @__PURE__ */ new Error("Invalid signature"), `event ${event.id}`);
903
+ return;
904
+ }
905
+ if (rejectIfVerifiedSenderRateLimited()) return;
906
+ if (authorizeSender) {
907
+ if (await authorizeSender({
908
+ senderPubkey: event.pubkey,
909
+ reply: replyTo
910
+ }) !== "allow") {
911
+ markSeen();
912
+ return;
913
+ }
914
+ }
915
+ let plaintext;
1240
916
  try {
1241
- await persistTransientReplayCursor(event);
1242
- } catch (cursorError) {
1243
- onError?.(cursorError, "persist transient replay cursor");
1244
- cursorPersistenceFailed = true;
917
+ plaintext = decrypt(sk, event.pubkey, event.content);
918
+ metrics.emit("decrypt.success");
919
+ } catch (err) {
920
+ markSeen();
921
+ metrics.emit("decrypt.failure");
922
+ metrics.emit("event.rejected.decrypt_failed");
923
+ onError?.(err, `decrypt from ${event.pubkey}`);
924
+ return;
1245
925
  }
1246
- await stopRelays("durable admission failed");
1247
- if (cursorPersistenceFailed) await recoverCursorPersistence();
926
+ if (Buffer.byteLength(plaintext, "utf8") > guardPolicy.maxPlaintextBytes) {
927
+ markSeen();
928
+ metrics.emit("event.rejected.oversized_plaintext");
929
+ return;
930
+ }
931
+ await onMessage(event.pubkey, plaintext, replyTo, {
932
+ eventId: event.id,
933
+ createdAt: event.created_at
934
+ });
935
+ markSeen();
936
+ metrics.emit("event.processed");
937
+ scheduleStatePersist(event.created_at, event.id);
938
+ } catch (err) {
939
+ onError?.(err, `event ${event.id}`);
940
+ } finally {
941
+ inflight.delete(event.id);
1248
942
  }
943
+ }
944
+ const dmFilter = {
945
+ kinds: [4],
946
+ "#p": [pk],
947
+ since
1249
948
  };
1250
- let backfillFinalizePromise;
1251
- try {
1252
- await ingress.ready();
1253
- await writeNostrBusState({
1254
- accountId,
1255
- lastProcessedAt: initialCursor,
1256
- gatewayStartedAt: cursorStartedAt,
1257
- recentEventIds: []
1258
- });
1259
- relaySubscriptions = createNostrRelaySubscriptionGroup({
1260
- pool,
1261
- relays,
1262
- filter: dmFilter,
1263
- abort: relayAbort.signal,
1264
- onEvent: (event) => {
1265
- const task = handleRelayEvent(event);
1266
- if (options.trackIngressTask) options.trackIngressTask(task.then(() => ingress.waitForIdle()));
1267
- },
1268
- onBackfillComplete: (confirmedRelays) => {
1269
- backfillFinalizePromise ??= ingress.waitForIdle().then(() => {
1270
- const cursor = durableCursor.markBackfillComplete();
1271
- if (cursor !== void 0) cursorWriter.schedule(cursor);
1272
- for (const relay of confirmedRelays) metrics.emit("relay.message.eose", 1, { relay });
1273
- onEose?.(confirmedRelays.join(", "));
1274
- }).catch((error) => onError?.(error, "finalize relay backfill"));
1275
- },
1276
- onClose: (relay, reasons) => {
949
+ const relayAbort = new AbortController();
950
+ const sub = pool.subscribeMany(relays, dmFilter, {
951
+ onevent: (event) => {
952
+ handleEvent(event);
953
+ },
954
+ oneose: () => {
955
+ for (const relay of relays) metrics.emit("relay.message.eose", 1, { relay });
956
+ onEose?.(relays.join(", "));
957
+ },
958
+ onclose: (reason) => {
959
+ for (const relay of relays) {
1277
960
  metrics.emit("relay.message.closed", 1, { relay });
1278
961
  options.onDisconnect?.(relay);
1279
- onError?.(/* @__PURE__ */ new Error(`Subscription closed: ${reasons.join(", ")}`), "subscription");
1280
962
  }
1281
- });
1282
- relaySubscriptions.start();
1283
- } catch (error) {
1284
- await Promise.allSettled([stopRelays("startup failed"), ingress.stop()]);
1285
- throw error;
1286
- }
963
+ onError?.(/* @__PURE__ */ new Error(`Subscription closed: ${reason.join(", ")}`), "subscription");
964
+ },
965
+ abort: relayAbort.signal
966
+ });
1287
967
  const sendDm = async (toPubkey, text) => {
1288
- return await sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError);
968
+ await sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError);
1289
969
  };
1290
970
  const publishProfile$1 = async (profile) => {
1291
971
  const lastPublishedAt = (await readNostrProfileState({ accountId }))?.lastPublishedAt ?? void 0;
@@ -1309,20 +989,25 @@ async function startNostrBus(options) {
1309
989
  lastPublishResults: stateLocal?.lastPublishResults ?? null
1310
990
  };
1311
991
  };
1312
- let closePromise;
1313
- const close = () => {
1314
- closePromise ??= (async () => {
1315
- await stopRelays("closed by caller");
1316
- await ingress.stop();
1317
- await backfillFinalizePromise;
1318
- await cursorWriter.flushUntilSuccess();
992
+ return {
993
+ close: () => {
994
+ relayAbort.abort("closed by caller");
995
+ Promise.resolve(sub.close("closed by caller")).catch((err) => onError?.(err, "close subscription")).finally(() => {
996
+ pool.close(relays);
997
+ });
998
+ seen.stop();
1319
999
  perSenderRateLimiter.clear();
1320
1000
  globalRateLimiter.clear();
1321
- })();
1322
- return closePromise;
1323
- };
1324
- return {
1325
- close,
1001
+ if (pendingWrite) {
1002
+ clearTimeout(pendingWrite);
1003
+ writeNostrBusState({
1004
+ accountId,
1005
+ lastProcessedAt,
1006
+ gatewayStartedAt,
1007
+ recentEventIds
1008
+ }).catch((err) => onError?.(err, "persist state on close"));
1009
+ }
1010
+ },
1326
1011
  publicKey: pk,
1327
1012
  sendDm,
1328
1013
  getMetrics: () => metrics.getSnapshot(),
@@ -1333,14 +1018,12 @@ async function startNostrBus(options) {
1333
1018
  /**
1334
1019
  * Send an encrypted DM to a pubkey
1335
1020
  */
1336
- async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError, replyToEventId) {
1021
+ async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circuitBreakers, healthTracker, onError) {
1337
1022
  const ciphertext = encrypt(sk, toPubkey, text);
1338
- const tags = [["p", toPubkey]];
1339
- if (replyToEventId) tags.push(["e", replyToEventId]);
1340
1023
  const reply = finalizeEvent({
1341
1024
  kind: 4,
1342
1025
  content: ciphertext,
1343
- tags,
1026
+ tags: [["p", toPubkey]],
1344
1027
  created_at: Math.floor(Date.now() / 1e3)
1345
1028
  }, sk);
1346
1029
  const sortedRelays = healthTracker.getSortedRelays(relays);
@@ -1350,13 +1033,15 @@ async function sendEncryptedDm(pool, sk, toPubkey, text, relays, metrics, circui
1350
1033
  if (cb && !cb.canAttempt()) continue;
1351
1034
  const startTime = Date.now();
1352
1035
  try {
1353
- await publishNostrEventToRelay(pool, relay, reply);
1036
+ const publishPromises = pool.publish([relay], reply);
1037
+ if (publishPromises.length === 0) throw new Error(`Failed to create publish promise for relay ${relay}`);
1038
+ await publishPromises[0];
1354
1039
  const latency = Date.now() - startTime;
1355
1040
  cb?.recordSuccess();
1356
1041
  healthTracker.recordSuccess(relay, latency);
1357
- return reply.id;
1042
+ return;
1358
1043
  } catch (err) {
1359
- lastError = err instanceof Error ? err : new Error(String(err));
1044
+ lastError = err;
1360
1045
  const latency = Date.now() - startTime;
1361
1046
  cb?.recordFailure();
1362
1047
  healthTracker.recordFailure(relay);
@@ -1455,7 +1140,7 @@ const startNostrGatewayAccount = async (ctx) => {
1455
1140
  ctx.log?.debug?.(`[${account.accountId}] blocked Nostr sender ${input.senderId} (${resolved.senderAccess.reasonCode})`);
1456
1141
  return "block";
1457
1142
  };
1458
- await runPassiveAccountLifecycle({
1143
+ await runStoppablePassiveMonitor({
1459
1144
  abortSignal: ctx.abortSignal,
1460
1145
  start: async () => {
1461
1146
  const bus = await startNostrBus({
@@ -1466,15 +1151,16 @@ const startNostrGatewayAccount = async (ctx) => {
1466
1151
  senderId: senderPubkey,
1467
1152
  reply
1468
1153
  }),
1469
- onMessage: async (senderPubkey, text, reply, meta, lifecycle) => {
1154
+ onMessage: async (senderPubkey, text, reply, meta) => {
1470
1155
  const resolvedAccess = await resolveInboundAccess(senderPubkey, text);
1471
1156
  if (resolvedAccess.senderAccess.decision !== "allow") {
1472
1157
  ctx.log?.warn?.(`[${account.accountId}] dropping Nostr DM after preflight drift (${senderPubkey}, ${resolvedAccess.senderAccess.reasonCode})`);
1473
1158
  return;
1474
1159
  }
1475
- const { dispatchInboundDirectDm } = await import("./inbound-direct-dm-runtime-DHn9NoYN.js");
1476
- await dispatchInboundDirectDm({
1160
+ const { dispatchInboundDirectDmWithRuntime } = await import("./inbound-direct-dm-runtime-EdLLVtkh.mjs");
1161
+ await dispatchInboundDirectDmWithRuntime({
1477
1162
  cfg: ctx.cfg,
1163
+ runtime,
1478
1164
  channel: "nostr",
1479
1165
  channelLabel: "Nostr",
1480
1166
  accountId: account.accountId,
@@ -1490,7 +1176,6 @@ const startNostrGatewayAccount = async (ctx) => {
1490
1176
  messageId: meta.eventId,
1491
1177
  timestamp: meta.createdAt * 1e3,
1492
1178
  commandAuthorized: resolvedAccess.commandAccess.requested ? resolvedAccess.commandAccess.authorized : void 0,
1493
- turnAdoptionLifecycle: bindIngressLifecycleToReplyOptions(lifecycle).turnAdoptionLifecycle,
1494
1179
  deliver: async (payload) => {
1495
1180
  const outboundText = payload && typeof payload === "object" && "text" in payload ? payload.text ?? "" : "";
1496
1181
  if (!outboundText.trim()) return;
@@ -1499,8 +1184,7 @@ const startNostrGatewayAccount = async (ctx) => {
1499
1184
  channel: "nostr",
1500
1185
  accountId: account.accountId
1501
1186
  });
1502
- const message = stripMarkdown(runtime.channel.text.convertMarkdownTables(outboundText, tableMode));
1503
- if (message) await reply(message);
1187
+ await reply(runtime.channel.text.convertMarkdownTables(outboundText, tableMode));
1504
1188
  },
1505
1189
  onRecordError: (err) => {
1506
1190
  ctx.log?.error?.(`[${account.accountId}] failed recording Nostr inbound session: ${String(err)}`);
@@ -1530,19 +1214,19 @@ const startNostrGatewayAccount = async (ctx) => {
1530
1214
  if (busHandle) metricsSnapshots.set(account.accountId, busHandle.getMetrics());
1531
1215
  }
1532
1216
  });
1217
+ let stopped = false;
1533
1218
  busHandle = bus;
1534
1219
  activeBuses.set(account.accountId, bus);
1535
- ctx.log?.info?.(`[${account.accountId}] Nostr provider started with ${account.relays.length} configured relay(s)`);
1536
- return { stop: async () => {
1537
- await bus.close();
1220
+ ctx.log?.info?.(`[${account.accountId}] Nostr provider started, connected to ${account.relays.length} relay(s)`);
1221
+ return { stop: () => {
1222
+ if (stopped) return;
1223
+ stopped = true;
1224
+ bus.close();
1538
1225
  if (busHandle === bus) busHandle = null;
1539
1226
  if (activeBuses.get(account.accountId) === bus) activeBuses.delete(account.accountId);
1540
1227
  metricsSnapshots.delete(account.accountId);
1541
1228
  ctx.log?.info?.(`[${account.accountId}] Nostr provider stopped`);
1542
1229
  } };
1543
- },
1544
- stop: async (monitor) => {
1545
- await monitor.stop();
1546
1230
  }
1547
1231
  });
1548
1232
  };
@@ -1578,12 +1262,12 @@ const nostrOutboundAdapter = {
1578
1262
  channel: "nostr",
1579
1263
  accountId: aid
1580
1264
  });
1581
- const message = stripMarkdown(core.channel.text.convertMarkdownTables(text ?? "", tableMode));
1582
- if (!message) throw new Error("Nostr send requires non-empty text after markdown stripping.");
1265
+ const message = core.channel.text.convertMarkdownTables(text ?? "", tableMode);
1583
1266
  const normalizedTo = normalizePubkey(to);
1267
+ await bus.sendDm(normalizedTo, message);
1584
1268
  return attachChannelToResult("nostr", {
1585
1269
  to: normalizedTo,
1586
- messageId: await bus.sendDm(normalizedTo, message)
1270
+ messageId: `nostr-${Date.now()}`
1587
1271
  });
1588
1272
  }
1589
1273
  };
@@ -1617,18 +1301,6 @@ function resolveNostrOutboundSessionRoute(params) {
1617
1301
  }
1618
1302
  //#endregion
1619
1303
  //#region extensions/nostr/src/channel.ts
1620
- const NOSTR_TARGET_HINT = "<npub|hex pubkey|nostr:npub...>";
1621
- function stripNostrTargetPrefix(target) {
1622
- return target.trim().replace(/^nostr:/i, "");
1623
- }
1624
- function normalizeNostrTarget(target) {
1625
- const cleaned = stripNostrTargetPrefix(target);
1626
- try {
1627
- return normalizePubkey(cleaned);
1628
- } catch {
1629
- return target.trim();
1630
- }
1631
- }
1632
1304
  const resolveNostrDmPolicy = createScopedDmSecurityResolver({
1633
1305
  channelKey: "nostr",
1634
1306
  resolvePolicy: (account) => account.config.dmPolicy,
@@ -1636,7 +1308,13 @@ const resolveNostrDmPolicy = createScopedDmSecurityResolver({
1636
1308
  policyPathSuffix: "dmPolicy",
1637
1309
  defaultPolicy: "pairing",
1638
1310
  approveHint: formatPairingApproveHint("nostr"),
1639
- normalizeEntry: normalizeNostrTarget
1311
+ normalizeEntry: (raw) => {
1312
+ try {
1313
+ return normalizePubkey(raw.trim().replace(/^nostr:/i, ""));
1314
+ } catch {
1315
+ return raw.trim();
1316
+ }
1317
+ }
1640
1318
  });
1641
1319
  const nostrConfigAdapter = createTopLevelChannelConfigAdapter({
1642
1320
  sectionKey: "nostr",
@@ -1656,35 +1334,17 @@ const nostrConfigAdapter = createTopLevelChannelConfigAdapter({
1656
1334
  resolveAllowFrom: (account) => account.config.allowFrom,
1657
1335
  formatAllowFrom: (allowFrom) => normalizeStringEntries(allowFrom).map((entry) => {
1658
1336
  if (entry === "*") return "*";
1659
- return normalizeNostrTarget(entry);
1337
+ try {
1338
+ return normalizePubkey(entry);
1339
+ } catch {
1340
+ return entry;
1341
+ }
1660
1342
  }).filter(Boolean)
1661
1343
  });
1662
1344
  const nostrMessageAdapter = createChannelMessageAdapterFromOutbound({
1663
1345
  id: "nostr",
1664
1346
  outbound: nostrOutboundAdapter
1665
1347
  });
1666
- const nostrPluginOutboundAdapter = {
1667
- ...nostrOutboundAdapter,
1668
- resolveTarget: ({ to }) => {
1669
- const trimmed = to?.trim() ?? "";
1670
- if (!trimmed) return {
1671
- ok: false,
1672
- error: missingTargetError("Nostr", NOSTR_TARGET_HINT)
1673
- };
1674
- const normalized = normalizeNostrTarget(trimmed);
1675
- try {
1676
- return {
1677
- ok: true,
1678
- to: normalizePubkey(normalized)
1679
- };
1680
- } catch {
1681
- return {
1682
- ok: false,
1683
- error: /* @__PURE__ */ new Error("Nostr target must be a 64-character hex pubkey or npub value")
1684
- };
1685
- }
1686
- }
1687
- };
1688
1348
  const nostrPlugin = createChatChannelPlugin({
1689
1349
  base: {
1690
1350
  id: "nostr",
@@ -1704,7 +1364,6 @@ const nostrPlugin = createChatChannelPlugin({
1704
1364
  reload: { configPrefixes: ["channels.nostr"] },
1705
1365
  configSchema: buildChannelConfigSchema(NostrConfigSchema),
1706
1366
  setup: nostrSetupAdapter,
1707
- setupContract: nostrSetupContract,
1708
1367
  setupWizard: nostrSetupWizard,
1709
1368
  config: {
1710
1369
  ...nostrConfigAdapter,
@@ -1717,13 +1376,20 @@ const nostrPlugin = createChatChannelPlugin({
1717
1376
  },
1718
1377
  messaging: {
1719
1378
  targetPrefixes: ["nostr"],
1720
- normalizeTarget: normalizeNostrTarget,
1379
+ normalizeTarget: (target) => {
1380
+ const cleaned = target.trim().replace(/^nostr:/i, "");
1381
+ try {
1382
+ return normalizePubkey(cleaned);
1383
+ } catch {
1384
+ return cleaned;
1385
+ }
1386
+ },
1721
1387
  targetResolver: {
1722
- looksLikeId: (input, normalized) => {
1723
- const trimmed = normalized?.trim() || stripNostrTargetPrefix(input);
1724
- return trimmed.startsWith("npub1") || trimmed.startsWith("NPUB1") || /^[0-9a-fA-F]{64}$/.test(trimmed);
1388
+ looksLikeId: (input) => {
1389
+ const trimmed = input.trim();
1390
+ return trimmed.startsWith("npub1") || /^[0-9a-fA-F]{64}$/.test(trimmed);
1725
1391
  },
1726
- hint: NOSTR_TARGET_HINT
1392
+ hint: "<npub|hex pubkey|nostr:npub...>"
1727
1393
  },
1728
1394
  resolveOutboundSessionRoute: (params) => resolveNostrOutboundSessionRoute(params)
1729
1395
  },
@@ -1748,7 +1414,7 @@ const nostrPlugin = createChatChannelPlugin({
1748
1414
  },
1749
1415
  pairing: { text: nostrPairingTextAdapter },
1750
1416
  security: { resolveDmPolicy: resolveNostrDmPolicy },
1751
- outbound: nostrPluginOutboundAdapter
1417
+ outbound: nostrOutboundAdapter
1752
1418
  });
1753
1419
  /**
1754
1420
  * Publish a profile (kind:0) for a Nostr account.
@@ -1774,4 +1440,4 @@ async function getNostrProfileState(accountId = DEFAULT_ACCOUNT_ID) {
1774
1440
  return bus.getProfileState();
1775
1441
  }
1776
1442
  //#endregion
1777
- export { getNostrRuntime as a, contentToProfile as i, nostrPlugin as n, setNostrRuntime as o, publishNostrProfile as r, getNostrProfileState as t };
1443
+ export { setNostrRuntime as a, getNostrRuntime as i, nostrPlugin as n, contentToProfile as o, publishNostrProfile as r, getNostrProfileState as t };