@serfab/cadre-core 0.7.1 → 0.8.1

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 (166) hide show
  1. package/README.md +9 -8
  2. package/dist/authority-key.d.ts +41 -0
  3. package/dist/authority-key.js +52 -0
  4. package/dist/authority-key.js.map +1 -0
  5. package/dist/cadre-node.d.ts +770 -11
  6. package/dist/cadre-node.js +1900 -88
  7. package/dist/cadre-node.js.map +1 -1
  8. package/dist/canonical-datetime.d.ts +33 -0
  9. package/dist/canonical-datetime.js +38 -0
  10. package/dist/canonical-datetime.js.map +1 -0
  11. package/dist/canonical-json.d.ts +12 -0
  12. package/dist/canonical-json.js +33 -0
  13. package/dist/canonical-json.js.map +1 -0
  14. package/dist/control-cohort.d.ts +63 -0
  15. package/dist/control-cohort.js +80 -0
  16. package/dist/control-cohort.js.map +1 -0
  17. package/dist/control-database.d.ts +259 -5
  18. package/dist/control-database.js +541 -128
  19. package/dist/control-database.js.map +1 -1
  20. package/dist/control-formation-recorder.d.ts +89 -0
  21. package/dist/control-formation-recorder.js +139 -0
  22. package/dist/control-formation-recorder.js.map +1 -0
  23. package/dist/control-schema.d.ts +12 -0
  24. package/dist/control-schema.js +199 -0
  25. package/dist/control-schema.js.map +1 -0
  26. package/dist/control-stream.d.ts +54 -0
  27. package/dist/control-stream.js +104 -0
  28. package/dist/control-stream.js.map +1 -0
  29. package/dist/device-token.d.ts +50 -0
  30. package/dist/device-token.js +66 -0
  31. package/dist/device-token.js.map +1 -0
  32. package/dist/diagnostics/connection-path.d.ts +118 -0
  33. package/dist/diagnostics/connection-path.js +204 -0
  34. package/dist/diagnostics/connection-path.js.map +1 -0
  35. package/dist/diagnostics/webrtc-turn-tracker.d.ts +50 -0
  36. package/dist/diagnostics/webrtc-turn-tracker.js +196 -0
  37. package/dist/diagnostics/webrtc-turn-tracker.js.map +1 -0
  38. package/dist/hibernation-manager.d.ts +79 -0
  39. package/dist/hibernation-manager.js +173 -23
  40. package/dist/hibernation-manager.js.map +1 -1
  41. package/dist/index.d.ts +25 -4
  42. package/dist/index.js +59 -4
  43. package/dist/index.js.map +1 -1
  44. package/dist/key-store-file.d.ts +52 -0
  45. package/dist/key-store-file.js +194 -0
  46. package/dist/key-store-file.js.map +1 -0
  47. package/dist/key-store.d.ts +75 -0
  48. package/dist/key-store.js +66 -0
  49. package/dist/key-store.js.map +1 -0
  50. package/dist/peer-authorization.d.ts +26 -0
  51. package/dist/peer-authorization.js +40 -0
  52. package/dist/peer-authorization.js.map +1 -0
  53. package/dist/peer-record.d.ts +89 -0
  54. package/dist/peer-record.js +117 -0
  55. package/dist/peer-record.js.map +1 -0
  56. package/dist/push-credentials.d.ts +34 -0
  57. package/dist/push-credentials.js +81 -0
  58. package/dist/push-credentials.js.map +1 -0
  59. package/dist/push-fanout.d.ts +137 -0
  60. package/dist/push-fanout.js +197 -0
  61. package/dist/push-fanout.js.map +1 -0
  62. package/dist/push-notifier-apns.d.ts +53 -0
  63. package/dist/push-notifier-apns.js +195 -0
  64. package/dist/push-notifier-apns.js.map +1 -0
  65. package/dist/push-notifier-fcm.d.ts +38 -0
  66. package/dist/push-notifier-fcm.js +183 -0
  67. package/dist/push-notifier-fcm.js.map +1 -0
  68. package/dist/push-notifier-shared.d.ts +18 -0
  69. package/dist/push-notifier-shared.js +25 -0
  70. package/dist/push-notifier-shared.js.map +1 -0
  71. package/dist/push-notifier.d.ts +71 -0
  72. package/dist/push-notifier.js +50 -0
  73. package/dist/push-notifier.js.map +1 -0
  74. package/dist/schema-verification.d.ts +11 -2
  75. package/dist/schema-verification.js +15 -4
  76. package/dist/schema-verification.js.map +1 -1
  77. package/dist/seed-bootstrap.d.ts +197 -9
  78. package/dist/seed-bootstrap.js +396 -137
  79. package/dist/seed-bootstrap.js.map +1 -1
  80. package/dist/seed-trust-policy.d.ts +63 -0
  81. package/dist/seed-trust-policy.js +56 -0
  82. package/dist/seed-trust-policy.js.map +1 -0
  83. package/dist/strand-addr-protocol.d.ts +132 -0
  84. package/dist/strand-addr-protocol.js +313 -0
  85. package/dist/strand-addr-protocol.js.map +1 -0
  86. package/dist/strand-cohort.d.ts +54 -0
  87. package/dist/strand-cohort.js +38 -0
  88. package/dist/strand-cohort.js.map +1 -0
  89. package/dist/strand-database.d.ts +54 -6
  90. package/dist/strand-database.js +88 -100
  91. package/dist/strand-database.js.map +1 -1
  92. package/dist/strand-formation-manager.d.ts +79 -19
  93. package/dist/strand-formation-manager.js +196 -104
  94. package/dist/strand-formation-manager.js.map +1 -1
  95. package/dist/strand-formation-protocol.d.ts +162 -0
  96. package/dist/strand-formation-protocol.js +279 -0
  97. package/dist/strand-formation-protocol.js.map +1 -0
  98. package/dist/strand-instance-manager.d.ts +73 -4
  99. package/dist/strand-instance-manager.js +167 -41
  100. package/dist/strand-instance-manager.js.map +1 -1
  101. package/dist/strand-member-key.d.ts +29 -0
  102. package/dist/strand-member-key.js +38 -0
  103. package/dist/strand-member-key.js.map +1 -0
  104. package/dist/strand-member-registry.d.ts +98 -0
  105. package/dist/strand-member-registry.js +129 -0
  106. package/dist/strand-member-registry.js.map +1 -0
  107. package/dist/strand-membership-writer.d.ts +361 -0
  108. package/dist/strand-membership-writer.js +449 -0
  109. package/dist/strand-membership-writer.js.map +1 -0
  110. package/dist/strand-solicitation.d.ts +77 -2
  111. package/dist/strand-solicitation.js +25 -4
  112. package/dist/strand-solicitation.js.map +1 -1
  113. package/dist/strand-wake-payload.d.ts +30 -0
  114. package/dist/strand-wake-payload.js +20 -0
  115. package/dist/strand-wake-payload.js.map +1 -0
  116. package/dist/strand-wake-protocol.d.ts +114 -0
  117. package/dist/strand-wake-protocol.js +257 -0
  118. package/dist/strand-wake-protocol.js.map +1 -0
  119. package/dist/strand-watcher.d.ts +6 -2
  120. package/dist/strand-watcher.js +57 -17
  121. package/dist/strand-watcher.js.map +1 -1
  122. package/dist/types.d.ts +406 -23
  123. package/dist/types.js +22 -5
  124. package/dist/types.js.map +1 -1
  125. package/package.json +14 -8
  126. package/src/authority-key.ts +68 -0
  127. package/src/cadre-node.ts +2937 -948
  128. package/src/canonical-datetime.ts +39 -0
  129. package/src/canonical-json.ts +30 -0
  130. package/src/control-cohort.ts +103 -0
  131. package/src/control-database.ts +931 -383
  132. package/src/control-formation-recorder.ts +151 -0
  133. package/src/control-schema.ts +198 -0
  134. package/src/control-stream.ts +128 -0
  135. package/src/device-token.ts +89 -0
  136. package/src/diagnostics/connection-path.ts +277 -0
  137. package/src/diagnostics/webrtc-turn-tracker.ts +222 -0
  138. package/src/hibernation-manager.ts +197 -28
  139. package/src/index.ts +273 -79
  140. package/src/key-store-file.ts +203 -0
  141. package/src/key-store.ts +99 -0
  142. package/src/peer-authorization.ts +53 -0
  143. package/src/peer-record.ts +146 -0
  144. package/src/push-credentials.ts +84 -0
  145. package/src/push-fanout.ts +272 -0
  146. package/src/push-notifier-apns.ts +243 -0
  147. package/src/push-notifier-fcm.ts +221 -0
  148. package/src/push-notifier-shared.ts +28 -0
  149. package/src/push-notifier.ts +93 -0
  150. package/src/schema-verification.ts +18 -4
  151. package/src/seed-bootstrap.ts +464 -188
  152. package/src/seed-trust-policy.ts +107 -0
  153. package/src/strand-addr-protocol.ts +410 -0
  154. package/src/strand-cohort.ts +77 -0
  155. package/src/strand-database.ts +113 -141
  156. package/src/strand-formation-manager.ts +233 -142
  157. package/src/strand-formation-protocol.ts +391 -0
  158. package/src/strand-instance-manager.ts +207 -56
  159. package/src/strand-member-key.ts +39 -0
  160. package/src/strand-member-registry.ts +177 -0
  161. package/src/strand-membership-writer.ts +640 -0
  162. package/src/strand-solicitation.ts +93 -4
  163. package/src/strand-wake-payload.ts +32 -0
  164. package/src/strand-wake-protocol.ts +331 -0
  165. package/src/strand-watcher.ts +61 -17
  166. package/src/types.ts +1012 -582
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strand-addr-protocol.js","sourceRoot":"","sources":["../src/strand-addr-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAsB,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEnG,MAAM,GAAG,GAAG,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAE9C,wGAAwG;AACxG,MAAM,CAAC,MAAM,oBAAoB,GAAG,2BAA2B,CAAC;AAEhE;;;;GAIG;AACH,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,CAAC;AAEhC,uFAAuF;AACvF,MAAM,uBAAuB,GAAG,KAAM,CAAC;AAEvC,yFAAyF;AACzF,MAAM,4BAA4B,GAAG,KAAM,CAAC;AAE5C,wFAAwF;AACxF,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEzC;;;;;GAKG;AACH,KAAK,UAAU,SAAS,CAAI,MAAqB,EAAE,SAAiB;IAClE,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;IACzG,MAAM,IAAI,GAAG,yBAAyB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAM,CAAC;AACzD,CAAC;AAED,yFAAyF;AACzF,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;AACtC,CAAC;AA8BD;;;;;GAKG;AACH,MAAM,OAAO,iBAAiB;IAQ5B,YAAY,OAAiC;QAJrC,SAAI,GAAkB,IAAI,CAAC;QACnC,oFAAoF;QAC5E,kBAAa,GAAG,CAAC,CAAC;QAGxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,4BAA4B,CAAC;QAC3E,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,4BAA4B,CAAC;IAC7E,CAAC;IAED,uDAAuD;IACvD,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,qEAAqE;IACrE,UAAU,CAAC,IAAY;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,yEAAyE;QACzE,yEAAyE;QACzE,0EAA0E;QAC1E,4EAA4E;QAC5E,iEAAiE;QACjE,yBAAyB;QACzB,KAAK,IAAI,CAAC,MAAM,CAAC,oBAAoB,EAAE,KAAK,EAAE,SAAkB,EAAE,aAAsB,EAAE,EAAE;YAC1F,MAAM,YAAY,GAAI,aAA4B,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YACzE,MAAM,IAAI,CAAC,YAAY,CAAC,SAA0B,EAAE,YAAY,CAAC,CAAC;QACpE,CAAC,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,GAAG,CAAC,0CAA0C,EAAE,oBAAoB,CAAC,CAAC;IACxE,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,QAAQ;QACZ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;YAC/C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,GAAG,CAAC,4BAA4B,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,YAAY,CAAC,MAAqB,EAAE,YAAoB;QACpE,GAAG,CAAC,uCAAuC,EAAE,YAAY,CAAC,CAAC;QAE3D,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC7C,GAAG,CAAC,gEAAgE,EAAE,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5H,wEAAwE;YACxE,2EAA2E;YAC3E,iDAAiD;YACjD,IAAI,CAAC;gBACH,UAAU,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,yCAAyC;YAC3C,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,SAAS,CAAoB,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YAC/E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACtE,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,gDAAgD,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC;YACzE,wEAAwE;YACxE,mEAAmE;YACnE,IAAI,CAAC;gBACH,UAAU,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,wCAAwC;YAC1C,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,kBAAkB,CAAC,OAA0B,EAAE,YAAoB;QACvE,wEAAwE;QACxE,+CAA+C;QAC/C,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YACjD,GAAG,CAAC,yCAAyC,EAAE,YAAY,CAAC,CAAC;YAC7D,OAAO,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtE,GAAG,CAAC,iCAAiC,EAAE,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5E,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;IACpD,CAAC;CACF;AAsBD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,KAAuB,EACvB,QAAgB,EAChB,UAAqC,EAAE;IAEvC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtC,MAAM,OAAO,GAAsB,EAAE,QAAQ,EAAE,CAAC;IAChD,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAE1D,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CACrE,CAAC;IAEF,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,cAAc,CAC3B,IAAY,EACZ,IAAoB,EACpB,OAA0B,EAC1B,OAAkC;IAElC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,oBAAoB,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,uBAAuB,CAAC;IAC/D,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAElC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,GAAG,CAAC,+BAA+B,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,6EAA6E;QAC7E,8EAA8E;QAC9E,8EAA8E;QAC9E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,SAAS,EACT,oBAAoB,IAAI,CAAC,MAAM,EAAE,EACjC,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,EACrF,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CACzB,CAAC;YACF,OAAO,QAAQ,CAAC,UAAU,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,0CAA0C,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,IAAoB;IACvC,MAAM,OAAO,GAA8B,EAAE,CAAC;IAC9C,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,kDAAkD,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,uEAAuE;AACvE,SAAS,cAAc,CAAC,MAA0B;IAChD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,cAAc,CAC3B,IAAY,EACZ,MAA0B,EAC1B,UAAkB,EAClB,OAA0B,EAC1B,SAAiB,EACjB,MAAmB;IAEnB,2EAA2E;IAC3E,0EAA0E;IAC1E,4EAA4E;IAC5E,6EAA6E;IAC7E,oDAAoD;IACpD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACxG,MAAM,MAAM,GAAG,SAAqC,CAAC;IAErD,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,GAAS,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACnD,sFAAsF;IACtF,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;QACV,MAAM,QAAQ,CAAC;IACjB,CAAC;IACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,IAAI,CAAC;QACH,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5B,4EAA4E;QAC5E,oEAAoE;QACpE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAqB,MAAM,EAAE,SAAS,CAAC,CAAC;QACxE,GAAG,CAAC,yCAAyC,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC9F,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { StrandMode } from './types.js';
2
+ /**
3
+ * A single CadrePeer membership row, as returned by
4
+ * `ControlDatabase.queryCadrePeers()`.
5
+ */
6
+ export interface CohortPeerRow {
7
+ peerId: string;
8
+ /** Comma-joined list of multiaddr strings; `''` when no addrs were recorded. */
9
+ multiaddr: string | null;
10
+ }
11
+ /**
12
+ * Cohort-derived discovery seed for a strand's libp2p node. `bootstrapNodes`
13
+ * here are **strand-network** addresses resolved on demand from co-cadre
14
+ * siblings (see `collectStrandAddrs` / `STRAND_ADDR_PROTOCOL`), NOT the control
15
+ * addresses stored in `CadrePeer.Multiaddr`.
16
+ */
17
+ export interface CohortSeed {
18
+ /** Dialable strand-network multiaddr strings for cohort peers other than self (deduplicated). */
19
+ bootstrapNodes: string[];
20
+ /** True when at least one CadrePeer row other than self exists (even if it has no resolvable strand addr). */
21
+ hasOtherPeers: boolean;
22
+ }
23
+ /**
24
+ * Membership-only view of a strand's cohort, derived from the control network's
25
+ * CadrePeer rows. The bootstrap addresses themselves are resolved separately
26
+ * (over the strand-addr RPC) from these peerIds, never from the rows' addr field.
27
+ */
28
+ export interface CohortMembers {
29
+ /** PeerIds of cohort members other than self — the strand-addr RPC fan-out targets (deduplicated, in row order). */
30
+ otherPeerIds: string[];
31
+ /** True when at least one CadrePeer row other than self exists (even if it has no resolvable strand addr). */
32
+ hasOtherPeers: boolean;
33
+ }
34
+ /**
35
+ * Derive the membership view of a strand's cohort from the control network's
36
+ * CadrePeer rows: the peerIds of members other than `selfPeerId` (the strand-addr
37
+ * RPC fan-out targets) and whether any other member exists at all.
38
+ *
39
+ * Deliberately does NOT read `CadrePeer.Multiaddr` — that field carries each
40
+ * node's *control*-network address, which must not seed the *strand* mesh
41
+ * (dialing it reaches the remote's control instance, not its strand instance).
42
+ * The strand-network bootstrap addresses are resolved on demand over the control
43
+ * mesh from these peerIds. `hasOtherPeers` reflects membership presence, NOT
44
+ * dialability, so a cohort whose strand addrs are not yet resolvable still
45
+ * selects `networked` mode.
46
+ */
47
+ export declare function deriveCohortMembers(peers: CohortPeerRow[], selfPeerId?: string): CohortMembers;
48
+ /**
49
+ * Choose the strand mode. An explicit mode (from `addStrand`) always wins. When
50
+ * omitted (the `handleStrandAdded` discovery path, or an `addStrand` caller that
51
+ * leaves it unset), infer: `bootstrap` for a solo/first node (no other peers),
52
+ * `networked` once the cohort has other members.
53
+ */
54
+ export declare function selectStrandMode(explicitMode: StrandMode | undefined, hasOtherPeers: boolean): StrandMode;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Derive the membership view of a strand's cohort from the control network's
3
+ * CadrePeer rows: the peerIds of members other than `selfPeerId` (the strand-addr
4
+ * RPC fan-out targets) and whether any other member exists at all.
5
+ *
6
+ * Deliberately does NOT read `CadrePeer.Multiaddr` — that field carries each
7
+ * node's *control*-network address, which must not seed the *strand* mesh
8
+ * (dialing it reaches the remote's control instance, not its strand instance).
9
+ * The strand-network bootstrap addresses are resolved on demand over the control
10
+ * mesh from these peerIds. `hasOtherPeers` reflects membership presence, NOT
11
+ * dialability, so a cohort whose strand addrs are not yet resolvable still
12
+ * selects `networked` mode.
13
+ */
14
+ export function deriveCohortMembers(peers, selfPeerId) {
15
+ const otherPeerIds = [];
16
+ const seen = new Set();
17
+ for (const peer of peers) {
18
+ if (selfPeerId !== undefined && peer.peerId === selfPeerId) {
19
+ continue;
20
+ }
21
+ if (seen.has(peer.peerId)) {
22
+ continue;
23
+ }
24
+ seen.add(peer.peerId);
25
+ otherPeerIds.push(peer.peerId);
26
+ }
27
+ return { otherPeerIds, hasOtherPeers: otherPeerIds.length > 0 };
28
+ }
29
+ /**
30
+ * Choose the strand mode. An explicit mode (from `addStrand`) always wins. When
31
+ * omitted (the `handleStrandAdded` discovery path, or an `addStrand` caller that
32
+ * leaves it unset), infer: `bootstrap` for a solo/first node (no other peers),
33
+ * `networked` once the cohort has other members.
34
+ */
35
+ export function selectStrandMode(explicitMode, hasOtherPeers) {
36
+ return explicitMode ?? (hasOtherPeers ? 'networked' : 'bootstrap');
37
+ }
38
+ //# sourceMappingURL=strand-cohort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strand-cohort.js","sourceRoot":"","sources":["../src/strand-cohort.ts"],"names":[],"mappings":"AAqCA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAsB,EAAE,UAAmB;IAC7E,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,UAAU,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC3D,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;AAClE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAAoC,EAAE,aAAsB;IAC3F,OAAO,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AACrE,CAAC"}
@@ -26,28 +26,76 @@ export interface StrandDatabaseConfig {
26
26
  * across the two consumers.
27
27
  */
28
28
  rawStorage?: IRawStorage;
29
+ /**
30
+ * Strand type (`'o'` open / `'c'` closed) from the control-network strand row.
31
+ * Drives the founder bootstrap: open strands get a `Header` only; closed strands
32
+ * also get the founding `Member`+`Authority`.
33
+ */
34
+ strandType: 'o' | 'c';
35
+ /**
36
+ * The closed-strand `MemberPrivateKey` (base64 protobuf) from the strand row.
37
+ * Required when `founder` is true and `strandType` is `'c'` — it derives the
38
+ * founding `Member.Key`/`Authority.MemberKey`. Absent for open strands.
39
+ */
40
+ memberPrivateKey?: string;
41
+ /**
42
+ * Whether this node founds the strand. When true, {@link initialize} runs the
43
+ * one-time founder membership bootstrap after the schema is applied. Joiners
44
+ * leave this false and write nothing (rows arrive via sync). Defaults to false.
45
+ */
46
+ founder?: boolean;
29
47
  }
30
48
  /**
31
- * StrandDatabase manages the sApp schema for a strand using Quereus with Optimystic backend.
32
- * Each strand instance has its own isolated database with the sApp's schema applied.
49
+ * StrandDatabase manages the sApp schema for a strand using Quereus with the
50
+ * Optimystic backend. Each strand instance has its own isolated database with
51
+ * the sApp's schema applied.
52
+ *
53
+ * This class owns the `Database` lifecycle (creation, `getDatabase()`, `close()`)
54
+ * but delegates the actual SQL-surface composition — plugin registration, node
55
+ * wiring, catalog hydration, schema apply — to `connectToStrand` from
56
+ * `@serfab/quereus-plugin-sereus`, the single shared composition. The libp2p
57
+ * node is injected here, so `connectToStrand` never *creates* the node;
58
+ * `StrandInstanceManager` owns the node lifecycle. (The strand connection's
59
+ * `shutdown` still stops the injected node via the collection factory, so the
60
+ * manager's own `node.stop()` is an idempotent second stop — see `close()`.)
33
61
  */
34
62
  export declare class StrandDatabase {
35
63
  private db;
36
- private collectionFactory;
64
+ private shutdownStrand;
37
65
  private readonly config;
38
66
  private initialized;
39
67
  constructor(config: StrandDatabaseConfig);
40
68
  /**
41
- * Initialize the database - register plugins and execute sApp schema
69
+ * Initialize the database — create the `Database` and delegate the strand
70
+ * SQL-surface composition (plugins, node wiring, hydrate, schema apply) to
71
+ * `connectToStrand` with the injected libp2p node.
42
72
  */
43
73
  initialize(): Promise<void>;
44
- private executeSchema;
74
+ /**
75
+ * Run the founder membership bootstrap against the freshly-composed strand DB.
76
+ *
77
+ * Derives the founding keypair from the closed-strand `memberPrivateKey` (the
78
+ * `Member.Key`/`Authority.MemberKey` are its public key); a closed strand with no
79
+ * `memberPrivateKey` throws, because it could never seat a founding authority.
80
+ * Open strands derive no keypair (Header only). Idempotent — see
81
+ * {@link bootstrapFounderMembership}.
82
+ */
83
+ private bootstrapFounder;
84
+ /**
85
+ * Derive the founding keypair for a closed strand from its `memberPrivateKey`,
86
+ * failing loudly when the key is absent (a closed strand with no founding
87
+ * Authority can never admit anyone).
88
+ */
89
+ private deriveFounderKeyPair;
45
90
  /**
46
91
  * Get the underlying database for queries
47
92
  */
48
93
  getDatabase(): Database;
49
94
  /**
50
- * Close the database and cleanup resources
95
+ * Close the database and cleanup resources. Runs the strand-connection
96
+ * shutdown (collection-factory teardown, which also stops the injected node),
97
+ * then closes the `Database`. `StrandInstanceManager.releaseRuntime` issues a
98
+ * further idempotent `node.stop()` after this returns.
51
99
  */
52
100
  close(): Promise<void>;
53
101
  private ensureInitialized;
@@ -1,122 +1,107 @@
1
1
  import debug from 'debug';
2
- import { Database, registerPlugin } from '@quereus/quereus';
3
- import cryptoPlugin from '@optimystic/quereus-plugin-crypto/plugin';
4
- import optimysticPlugin from '@optimystic/quereus-plugin-optimystic/plugin';
2
+ import { Database } from '@quereus/quereus';
3
+ import { connectToStrand } from '@serfab/quereus-plugin-sereus';
4
+ import { bootstrapFounderMembership } from './strand-membership-writer.js';
5
+ import { strandMemberKeyPair } from './strand-member-key.js';
5
6
  const log = debug('sereus:cadre:strand-db');
6
7
  const timing = debug('sereus:cadre:timing');
7
8
  /**
8
- * StrandDatabase manages the sApp schema for a strand using Quereus with Optimystic backend.
9
- * Each strand instance has its own isolated database with the sApp's schema applied.
9
+ * StrandDatabase manages the sApp schema for a strand using Quereus with the
10
+ * Optimystic backend. Each strand instance has its own isolated database with
11
+ * the sApp's schema applied.
12
+ *
13
+ * This class owns the `Database` lifecycle (creation, `getDatabase()`, `close()`)
14
+ * but delegates the actual SQL-surface composition — plugin registration, node
15
+ * wiring, catalog hydration, schema apply — to `connectToStrand` from
16
+ * `@serfab/quereus-plugin-sereus`, the single shared composition. The libp2p
17
+ * node is injected here, so `connectToStrand` never *creates* the node;
18
+ * `StrandInstanceManager` owns the node lifecycle. (The strand connection's
19
+ * `shutdown` still stops the injected node via the collection factory, so the
20
+ * manager's own `node.stop()` is an idempotent second stop — see `close()`.)
10
21
  */
11
22
  export class StrandDatabase {
12
23
  constructor(config) {
13
24
  this.db = null;
14
- this.collectionFactory = null;
25
+ this.shutdownStrand = null;
15
26
  this.initialized = false;
16
27
  this.config = config;
17
28
  }
18
29
  /**
19
- * Initialize the database - register plugins and execute sApp schema
30
+ * Initialize the database — create the `Database` and delegate the strand
31
+ * SQL-surface composition (plugins, node wiring, hydrate, schema apply) to
32
+ * `connectToStrand` with the injected libp2p node.
20
33
  */
21
34
  async initialize() {
22
35
  if (this.initialized) {
23
36
  log('StrandDatabase for strand %s already initialized', this.config.strandId);
24
37
  return;
25
38
  }
26
- log('Initializing StrandDatabase for strand: %s (sApp: %s v%s)', this.config.strandId, this.config.sAppConfig.id, this.config.sAppConfig.version);
27
- // Create database instance
28
- this.db = new Database();
29
39
  const sid = this.config.strandId;
30
- // Register crypto plugin (provides digest, sign, verify functions)
31
- let t0 = performance.now();
32
- await registerPlugin(this.db, cryptoPlugin);
33
- timing('[strandDb:%s] cryptoPlugin: %dms', sid, Math.round(performance.now() - t0));
34
- log('Registered crypto plugin');
35
- // Register optimystic plugin. In `bootstrap` mode we route through the
36
- // local transactor so a solo node can initialize (schema apply etc.)
37
- // without network round trips. In `networked` mode the network transactor
38
- // is used. Mode is fixed for the lifetime of this Database instance; the
39
- // caller must restart the strand to transition modes.
40
- t0 = performance.now();
41
- const networkName = `strand-${sid}`;
42
40
  const mode = this.config.mode ?? 'networked';
43
- const defaultTransactor = mode === 'bootstrap' ? 'local' : 'network';
44
- // In bootstrap mode the local transactor IS the data path. Hand the plugin
45
- // the strand's raw storage (same instance the libp2p node uses) so writes
46
- // persist to the host backend instead of in-memory storage.
47
- const rawStorage = this.config.rawStorage;
48
- const pluginConfig = {
49
- default_transactor: defaultTransactor,
50
- default_key_network: 'libp2p',
51
- default_network_name: networkName,
52
- enable_cache: true,
53
- };
54
- if (mode === 'bootstrap' && rawStorage) {
55
- pluginConfig.rawStorageFactory = () => rawStorage;
56
- }
57
- // The plugin's published signature is `Record<string, SqlValue>` but it
58
- // also reads `rawStorageFactory` (a function reference) from the same map.
59
- // Cast through unknown rather than widen the public type.
60
- const pluginResult = optimysticPlugin(this.db, pluginConfig);
61
- log('Optimystic plugin registered for strand %s (mode=%s, transactor=%s, persistentStorage=%s)', sid, mode, defaultTransactor, mode === 'bootstrap' && !!rawStorage);
62
- // Register vtables and functions manually since we need access to collectionFactory
63
- for (const vtable of pluginResult.vtables) {
64
- this.db.registerModule(vtable.name, vtable.module, vtable.auxData);
65
- }
66
- for (const func of pluginResult.functions) {
67
- this.db.registerFunction(func.schema);
68
- }
69
- timing('[strandDb:%s] optimysticPlugin: %dms', sid, Math.round(performance.now() - t0));
70
- this.collectionFactory = pluginResult.collectionFactory;
71
- // Inject the libp2p node into the collection factory
72
- t0 = performance.now();
73
- this.collectionFactory.registerLibp2pNode(networkName, this.config.libp2pNode, this.config.coordinatedRepo);
74
- timing('[strandDb:%s] registerLibp2pNode: %dms', sid, Math.round(performance.now() - t0));
75
- log('Registered libp2p node with collection factory');
76
- // Set optimystic as the default virtual table module so that
77
- // `declare schema` tables (which omit USING) are backed by optimystic
78
- // instead of the built-in memory module.
79
- t0 = performance.now();
80
- this.db.setDefaultVtabName('optimystic');
81
- this.db.setDefaultVtabArgs({
82
- networkName,
83
- transactor: defaultTransactor,
84
- keyNetwork: 'libp2p',
41
+ log('Initializing StrandDatabase for strand: %s (sApp: %s v%s, mode=%s)', sid, this.config.sAppConfig.id, this.config.sAppConfig.version, mode);
42
+ this.db = new Database();
43
+ // Delegate to the shared composition. The node is injected, so:
44
+ // - `connectToStrand` never creates a node (its `createdNode` stays null);
45
+ // `StrandInstanceManager` owns the node lifecycle. Its `shutdown` does
46
+ // still stop the injected node via the collection factory, so the
47
+ // manager's later `node.stop()` is an idempotent second stop;
48
+ // - `storage` (the strand's raw storage, same instance the node uses) is
49
+ // handed to the plugin's local transactor in bootstrap mode so DML lands
50
+ // on the host backend rather than in-memory.
51
+ const t0 = performance.now();
52
+ const result = await connectToStrand(this.db, {
53
+ strandId: sid,
54
+ schema: this.config.sAppConfig.schema,
55
+ mode,
56
+ storage: this.config.rawStorage,
57
+ libp2pNode: this.config.libp2pNode,
58
+ coordinatedRepo: this.config.coordinatedRepo,
59
+ enableCache: true,
85
60
  });
86
- timing('[strandDb:%s] setDefaultVtab: %dms', sid, Math.round(performance.now() - t0));
87
- log('Set default vtab to optimystic (networkName=%s, transactor=%s)', networkName, defaultTransactor);
88
- // Hydrate Quereus's catalog from any persisted optimystic vtab schemas
89
- // before running `apply schema App;`. Without this, a warm restart diffs
90
- // the wrapped DDL against an empty catalog and re-emits CREATE TABLE /
91
- // CREATE INDEX for every persisted object — which round-trips through
92
- // optimystic storage and is the cause of the ~160s warm-start regression
93
- // tracked in strand-database-must-hydrate-catalog-before-apply-schema.
94
- // No-op on first launch (empty storage).
95
- t0 = performance.now();
96
- const hydrated = await pluginResult.hydrate(this.db);
97
- timing('[strandDb:%s] hydrate: %dms (tables=%d, indexes=%d)', sid, Math.round(performance.now() - t0), hydrated.tables, hydrated.indexes);
98
- log('Hydrated catalog for strand %s (tables=%d, indexes=%d)', sid, hydrated.tables, hydrated.indexes);
99
- // Execute the sApp schema DDL
100
- t0 = performance.now();
101
- await this.executeSchema();
102
- timing('[strandDb:%s] executeSchema: %dms', sid, Math.round(performance.now() - t0));
61
+ this.shutdownStrand = result.shutdown;
62
+ timing('[strandDb:%s] connectToStrand: %dms (hydrated tables=%d, indexes=%d)', sid, Math.round(performance.now() - t0), result.hydrated?.tables ?? 0, result.hydrated?.indexes ?? 0);
63
+ // Founder-only: write the one-time membership bootstrap now that the schema is
64
+ // applied (connectToStrand has returned). A throw here propagates out of
65
+ // initialize() so buildStrandRuntime's rollback tears the half-built strand
66
+ // down rather than leaking a node. Joiners skip this — their rows arrive via sync.
67
+ if (this.config.founder === true) {
68
+ await this.bootstrapFounder();
69
+ }
103
70
  this.initialized = true;
104
71
  log('StrandDatabase for strand %s initialized successfully', sid);
105
72
  }
106
- async executeSchema() {
107
- const rawSchema = this.config.sAppConfig.schema;
108
- log('Applying sApp schema for strand %s', this.config.strandId);
109
- // Wrap the raw schema DDL in a declarative schema block and apply it.
110
- // This ensures proper schema management with diff/apply semantics.
111
- // The schema is applied to a named schema 'App' to keep it isolated.
112
- const wrappedSchema = `
113
- declare schema App {
114
- ${rawSchema}
115
- }
116
- apply schema App;
117
- `;
118
- await this.db.exec(wrappedSchema);
119
- log('sApp schema applied to strand %s', this.config.strandId);
73
+ /**
74
+ * Run the founder membership bootstrap against the freshly-composed strand DB.
75
+ *
76
+ * Derives the founding keypair from the closed-strand `memberPrivateKey` (the
77
+ * `Member.Key`/`Authority.MemberKey` are its public key); a closed strand with no
78
+ * `memberPrivateKey` throws, because it could never seat a founding authority.
79
+ * Open strands derive no keypair (Header only). Idempotent — see
80
+ * {@link bootstrapFounderMembership}.
81
+ */
82
+ async bootstrapFounder() {
83
+ const { strandId, strandType, memberPrivateKey, sAppConfig } = this.config;
84
+ const founderKeyPair = strandType === 'c'
85
+ ? this.deriveFounderKeyPair(strandId, memberPrivateKey)
86
+ : undefined;
87
+ await bootstrapFounderMembership(this.db, {
88
+ strandId,
89
+ type: strandType,
90
+ sApp: sAppConfig,
91
+ founderKeyPair,
92
+ });
93
+ }
94
+ /**
95
+ * Derive the founding keypair for a closed strand from its `memberPrivateKey`,
96
+ * failing loudly when the key is absent (a closed strand with no founding
97
+ * Authority can never admit anyone).
98
+ */
99
+ deriveFounderKeyPair(strandId, memberPrivateKey) {
100
+ if (!memberPrivateKey) {
101
+ throw new Error(`Cannot found closed strand ${strandId}: the strand row has no MemberPrivateKey. ` +
102
+ 'A closed strand needs a founding Member/Authority derived from that key.');
103
+ }
104
+ return strandMemberKeyPair(memberPrivateKey);
120
105
  }
121
106
  /**
122
107
  * Get the underlying database for queries
@@ -126,15 +111,18 @@ export class StrandDatabase {
126
111
  return this.db;
127
112
  }
128
113
  /**
129
- * Close the database and cleanup resources
114
+ * Close the database and cleanup resources. Runs the strand-connection
115
+ * shutdown (collection-factory teardown, which also stops the injected node),
116
+ * then closes the `Database`. `StrandInstanceManager.releaseRuntime` issues a
117
+ * further idempotent `node.stop()` after this returns.
130
118
  */
131
119
  async close() {
132
- if (this.collectionFactory) {
133
- await this.collectionFactory.shutdown();
134
- this.collectionFactory = null;
120
+ if (this.shutdownStrand) {
121
+ await this.shutdownStrand();
122
+ this.shutdownStrand = null;
135
123
  }
136
124
  if (this.db) {
137
- this.db.close();
125
+ void this.db.close();
138
126
  this.db = null;
139
127
  }
140
128
  this.initialized = false;
@@ -1 +1 @@
1
- {"version":3,"file":"strand-database.js","sourceRoot":"","sources":["../src/strand-database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strand-database.js","sourceRoot":"","sources":["../src/strand-database.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { Libp2p } from '@libp2p/interface';
2
2
  import type { OpenInvitation, FormStrandResult, StrandFormationDisclosure } from './types.js';
3
- import type { DisclosureValidator, FormationUsageRecorder, StrandProvisioner } from './strand-solicitation.js';
3
+ import type { DisclosureValidator, FormationUsageRecorder, StrandProvisioner, FormationResponseValidator } from './strand-solicitation.js';
4
4
  /**
5
5
  * Configuration for StrandFormationManager
6
6
  */
@@ -20,12 +20,14 @@ export interface StrandFormationManagerConfig {
20
20
  * Options for creating a StrandFormationManager
21
21
  */
22
22
  export interface StrandFormationManagerOptions {
23
- /** Validates disclosures from initiators */
23
+ /** Validates disclosures from initiators (responder side) */
24
24
  disclosureValidator?: DisclosureValidator;
25
- /** Records and validates token usage */
25
+ /** Records and validates token usage (responder side) */
26
26
  formationUsageRecorder?: FormationUsageRecorder;
27
- /** Provisions strands after validation */
27
+ /** Provisions strands after validation (responder side) */
28
28
  strandProvisioner?: StrandProvisioner;
29
+ /** Validates the responder's result (initiator side); defaults to a structural check */
30
+ formationResponseValidator?: FormationResponseValidator;
29
31
  /** This party's ID for identification */
30
32
  partyId: string;
31
33
  /** This party's cadre peer addresses */
@@ -34,22 +36,29 @@ export interface StrandFormationManagerOptions {
34
36
  config?: StrandFormationManagerConfig;
35
37
  }
36
38
  /**
37
- * StrandFormationManager bridges cadre-core's strand solicitation interfaces
38
- * with strand-proto's SessionManager for actual protocol handling over libp2p.
39
+ * StrandFormationManager drives the native cadre-core formation transport
40
+ * (`strand-formation-protocol.ts`) from cadre-core's strand-solicitation interfaces.
39
41
  *
40
- * It implements SessionHooks by delegating to the existing interfaces:
41
- * - DisclosureValidator -> validateIdentity
42
- * - FormationUsageRecorder -> validateToken
43
- * - StrandProvisioner -> provisionStrand
42
+ * Responder side: a {@link FormationListener} wires the inbound protocol to
43
+ * {@link FormationUsageRecorder} (token), {@link DisclosureValidator} (identity),
44
+ * and {@link StrandProvisioner} (provisioning), disclosing this party's real
45
+ * identity + cadre only after validation.
46
+ *
47
+ * Initiator side: {@link formStrand} dials the responder carrying the real
48
+ * disclosure/token/cadre, then validates the responder's result via the
49
+ * {@link FormationResponseValidator} (or a built-in structural check).
44
50
  */
45
51
  export declare class StrandFormationManager {
46
- private readonly sessionManager;
47
52
  private readonly disclosureValidator?;
48
53
  private readonly formationUsageRecorder?;
49
54
  private readonly strandProvisioner?;
55
+ private readonly formationResponseValidator?;
50
56
  private readonly partyId;
51
57
  private readonly cadrePeerAddrs;
52
- private registeredNodes;
58
+ private readonly config;
59
+ private readonly listener;
60
+ private readonly registeredNodes;
61
+ private dialerSessions;
53
62
  constructor(options: StrandFormationManagerOptions);
54
63
  /**
55
64
  * Register this manager as a protocol handler on a libp2p node.
@@ -61,12 +70,11 @@ export declare class StrandFormationManager {
61
70
  */
62
71
  unregisterResponder(node: Libp2p, protocolId?: string): void;
63
72
  /**
64
- * Form a strand with a responder via an open invitation.
73
+ * Form a strand with a responder via an open invitation (initiator side).
65
74
  *
66
- * This is the initiator-side operation. It:
67
- * 1. Converts the OpenInvitation to a BootstrapLink
68
- * 2. Calls SessionManager.initiateBootstrap()
69
- * 3. Returns the result as a FormStrandResult
75
+ * Builds a contact message carrying the real token + disclosure + this party's
76
+ * real cadre addresses, dials the responder over the native protocol, and
77
+ * validates the responder's result before returning.
70
78
  */
71
79
  formStrand(invitation: OpenInvitation, disclosure: StrandFormationDisclosure, node: Libp2p): Promise<FormStrandResult>;
72
80
  /**
@@ -76,10 +84,62 @@ export declare class StrandFormationManager {
76
84
  listeners: number;
77
85
  dialers: number;
78
86
  };
87
+ private validateToken;
88
+ private validateDisclosure;
89
+ /**
90
+ * Responder-side provisioning. Routes on how the invite resolves
91
+ * ({@link ResolvedHostStrand}), and can REJECT post-validation by returning a
92
+ * {@link ResponderProvisionOutcome} with `approved: false` — `runSession` turns that
93
+ * into a clean, non-disclosing reply instead of a dropped result frame.
94
+ *
95
+ * - **bound** (host strand present): provision-then-record — write the single
96
+ * `FormationUsage` consent row against the pre-existing strand (record-only) and
97
+ * return it + its membership key (a read-gating secret disclosed only here, behind the
98
+ * token + disclosure validation `runSession` already enforced).
99
+ * - **missing** (invite names a host strand absent on this responder, e.g. unconverged):
100
+ * reject cleanly + retryably, writing NO usage row — recording usage here would fail the
101
+ * deferred `StrandExists` CHECK at commit and drop the frame.
102
+ * - **unbound** (no binding): the responder-provisions fallback — see {@link provisionUnbound}.
103
+ *
104
+ * Defense-in-depth: known provisioning/redeem failures (notably the concurrent
105
+ * `(Token, UseNumber)` PK collision when two redemptions of one unbound single-use invite
106
+ * race) are caught and mapped to a logged, retry-suggesting rejection rather than a thrown
107
+ * insert + a silently-closed stream. The LOG-before-reject keeps this a deliberate
108
+ * internal-error→protocol-rejection conversion (AGENTS.md: don't eat exceptions silently),
109
+ * not control-flow-by-exception.
110
+ */
111
+ private provisionAsResponder;
112
+ /**
113
+ * Responder-provisions fallback (invite binds no host strand). Precedence:
114
+ *
115
+ * 1. `recorder.provisionAndRecord` present (a real DB recorder) → atomic create-strand +
116
+ * record-consent, so the unbound redemption is single-use just like the bound path.
117
+ * Returns the new strand (+ key, null for an open responder-provisioned strand).
118
+ * 2. else `strandProvisioner` present → the legacy/mock contract: provision a bare strand,
119
+ * NO inline usage write (those callers record usage explicitly via
120
+ * `recordFormationComplete`, or assert transport invariants only). Threads the invite's
121
+ * REAL `sAppId`.
122
+ * 3. else → a structural placeholder (no recorder + no provisioner ⇒ no single-use semantics
123
+ * exist to enforce).
124
+ *
125
+ * Plan tradeoff — option (a) "record usage on the fallback" over (b) "remove the fallback":
126
+ * (a) closes the single-use hole with a targeted atomic create+record and leaves the
127
+ * `StrandProvisioner` mock-transport tests untouched; (b) would delete the provisioner
128
+ * surface and churn ~6 unit + ~6 integration sites for ZERO production benefit (production
129
+ * — `cadre-web.ts` / `cadre-phone.ts` — always publishes strand-BOUND invites and treats
130
+ * the responder-provisions placeholder as failure). The broader "should this fallback exist
131
+ * at all?" question lives in backlog `formation-initiatorcreates-cover-or-remove`.
132
+ */
133
+ private provisionUnbound;
134
+ /** Wrap a provision result as an approving {@link ResponderProvisionOutcome}. */
135
+ private approve;
79
136
  /**
80
- * Create SessionHooks that delegate to our interfaces
137
+ * The invite's authoritative `sAppId` for the responder-provisions fallback, read back
138
+ * from the recorder's `isTokenValid` invitation (the real `FormationInvite.sAppId`).
139
+ * Empty string when no recorder is wired or the invitation omits it.
81
140
  */
82
- private createSessionHooks;
141
+ private resolveInviteSAppId;
142
+ private validateResponse;
83
143
  }
84
144
  /**
85
145
  * Create a StrandFormationManager with the given options