@serfab/cadre-host 0.9.0 → 0.11.0

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 (213) hide show
  1. package/dist/auth/index.d.ts +2 -0
  2. package/dist/auth/index.js +1 -0
  3. package/dist/auth/index.js.map +1 -1
  4. package/dist/auth/self-label.d.ts +36 -0
  5. package/dist/auth/self-label.js +57 -0
  6. package/dist/auth/self-label.js.map +1 -0
  7. package/dist/auth/trust-circle.d.ts +32 -5
  8. package/dist/auth/trust-circle.js +31 -11
  9. package/dist/auth/trust-circle.js.map +1 -1
  10. package/dist/bin/host.js +41 -5
  11. package/dist/bin/host.js.map +1 -1
  12. package/dist/donation/__tests__/fake-orchestrator.d.ts +103 -0
  13. package/dist/donation/__tests__/fake-orchestrator.js +180 -0
  14. package/dist/donation/__tests__/fake-orchestrator.js.map +1 -0
  15. package/dist/donation/donation-service.d.ts +237 -12
  16. package/dist/donation/donation-service.js +491 -34
  17. package/dist/donation/donation-service.js.map +1 -1
  18. package/dist/donation/donation-store.d.ts +7 -0
  19. package/dist/donation/donation-store.js +7 -0
  20. package/dist/donation/donation-store.js.map +1 -1
  21. package/dist/donation/donation-supervisor.d.ts +167 -0
  22. package/dist/donation/donation-supervisor.js +341 -0
  23. package/dist/donation/donation-supervisor.js.map +1 -0
  24. package/dist/donation/index.d.ts +4 -2
  25. package/dist/donation/index.js +2 -1
  26. package/dist/donation/index.js.map +1 -1
  27. package/dist/donation/types.d.ts +26 -0
  28. package/dist/donation/types.js.map +1 -1
  29. package/dist/index.d.ts +3 -1
  30. package/dist/index.js +3 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/orchestrator/host-process-orchestrator.d.ts +109 -5
  33. package/dist/orchestrator/host-process-orchestrator.js +341 -98
  34. package/dist/orchestrator/host-process-orchestrator.js.map +1 -1
  35. package/dist/orchestrator/node-identity.d.ts +26 -0
  36. package/dist/orchestrator/node-identity.js +36 -0
  37. package/dist/orchestrator/node-identity.js.map +1 -0
  38. package/dist/orchestrator/port-allocator.d.ts +14 -0
  39. package/dist/orchestrator/port-allocator.js +45 -0
  40. package/dist/orchestrator/port-allocator.js.map +1 -1
  41. package/dist/owner/owner-node-client.d.ts +20 -5
  42. package/dist/owner/owner-node-client.js +21 -4
  43. package/dist/owner/owner-node-client.js.map +1 -1
  44. package/dist/server/error-handler.d.ts +7 -1
  45. package/dist/server/error-handler.js +23 -1
  46. package/dist/server/error-handler.js.map +1 -1
  47. package/dist/server/events/types.d.ts +3 -0
  48. package/dist/server/index.d.ts +7 -0
  49. package/dist/server/index.js +9 -3
  50. package/dist/server/index.js.map +1 -1
  51. package/dist/server/routes/grants.js +22 -3
  52. package/dist/server/routes/grants.js.map +1 -1
  53. package/dist/server/routes/strands.d.ts +20 -0
  54. package/dist/server/routes/strands.js +38 -0
  55. package/dist/server/routes/strands.js.map +1 -0
  56. package/dist/server/static.js +38 -38
  57. package/dist/strands/index.d.ts +7 -0
  58. package/dist/strands/index.js +6 -0
  59. package/dist/strands/index.js.map +1 -0
  60. package/dist/strands/strand-service.d.ts +50 -0
  61. package/dist/strands/strand-service.js +103 -0
  62. package/dist/strands/strand-service.js.map +1 -0
  63. package/dist/strands/types.d.ts +93 -0
  64. package/dist/strands/types.js +23 -0
  65. package/dist/strands/types.js.map +1 -0
  66. package/dist/ui/assets/index-BVoqLjyX.css +1 -0
  67. package/dist/ui/assets/index-C-iks41M.js +17 -0
  68. package/dist/ui/assets/index-C-iks41M.js.map +1 -0
  69. package/dist/ui/index.html +14 -14
  70. package/dist/update/release-key.d.ts +1 -1
  71. package/dist/update/release-key.js +1 -1
  72. package/package.json +5 -5
  73. package/service/cadre-host.service.tmpl +16 -16
  74. package/service/com.serfab.cadre-host.plist.tmpl +35 -35
  75. package/service/install-service.ps1 +98 -98
  76. package/service/uninstall-service.ps1 +19 -19
  77. package/src/__tests__/build-targets.test.ts +26 -0
  78. package/src/__tests__/cli-invite.smoke.test.ts +192 -192
  79. package/src/__tests__/cli-nat.smoke.test.ts +212 -212
  80. package/src/__tests__/cli.smoke.test.ts +46 -46
  81. package/src/__tests__/global-setup.ts +51 -0
  82. package/src/__tests__/host-owner.smoke.test.ts +123 -123
  83. package/src/__tests__/orchestrator-env-scrub.test.ts +140 -0
  84. package/src/__tests__/orchestrator-node-identity.test.ts +204 -0
  85. package/src/__tests__/orchestrator-owner.test.ts +198 -198
  86. package/src/__tests__/orchestrator-pin-keys.test.ts +153 -153
  87. package/src/__tests__/orchestrator-push.test.ts +145 -145
  88. package/src/__tests__/orchestrator.test.ts +951 -570
  89. package/src/auth/__tests__/duration.test.ts +28 -28
  90. package/src/auth/__tests__/self-label.test.ts +85 -0
  91. package/src/auth/__tests__/trust-circle-integration.test.ts +152 -147
  92. package/src/auth/__tests__/trust-circle-store.test.ts +115 -115
  93. package/src/auth/__tests__/trust-circle.test.ts +445 -401
  94. package/src/auth/duration.ts +33 -33
  95. package/src/auth/index.ts +21 -19
  96. package/src/auth/self-label.ts +74 -0
  97. package/src/auth/trust-circle-store.ts +155 -155
  98. package/src/auth/trust-circle.ts +45 -13
  99. package/src/auth/types.ts +99 -99
  100. package/src/bin/host.ts +1299 -1258
  101. package/src/donation/__tests__/donation-service.test.ts +1068 -290
  102. package/src/donation/__tests__/donation-supervisor.test.ts +510 -0
  103. package/src/donation/__tests__/fake-orchestrator.test.ts +168 -0
  104. package/src/donation/__tests__/fake-orchestrator.ts +225 -0
  105. package/src/donation/__tests__/grant-service.test.ts +213 -213
  106. package/src/donation/__tests__/grant-store.test.ts +113 -113
  107. package/src/donation/donation-service.ts +962 -392
  108. package/src/donation/donation-store.ts +171 -164
  109. package/src/donation/donation-supervisor.ts +388 -0
  110. package/src/donation/grant-service.ts +200 -200
  111. package/src/donation/grant-store.ts +152 -152
  112. package/src/donation/index.ts +64 -49
  113. package/src/donation/types.ts +243 -220
  114. package/src/index.ts +14 -0
  115. package/src/installer/__tests__/identity.test.ts +34 -34
  116. package/src/installer/__tests__/paths.test.ts +47 -47
  117. package/src/installer/__tests__/service-host.test.ts +62 -62
  118. package/src/installer/__tests__/wizard.test.ts +64 -64
  119. package/src/installer/identity.ts +49 -49
  120. package/src/installer/paths.ts +109 -109
  121. package/src/installer/platform.ts +27 -27
  122. package/src/installer/service-host/index.ts +21 -21
  123. package/src/installer/service-host/template.ts +21 -21
  124. package/src/installer/wizard.ts +103 -103
  125. package/src/nat/__tests__/address-resolver.test.ts +82 -82
  126. package/src/nat/__tests__/ddns-duckdns.test.ts +83 -83
  127. package/src/nat/__tests__/ddns-updater.test.ts +253 -253
  128. package/src/nat/__tests__/external-ip.test.ts +124 -124
  129. package/src/nat/__tests__/nat-service.test.ts +497 -497
  130. package/src/nat/__tests__/nat-store.test.ts +93 -93
  131. package/src/nat/__tests__/port-mapper.test.ts +191 -191
  132. package/src/nat/__tests__/reachability.test.ts +24 -24
  133. package/src/nat/__tests__/secrets.test.ts +178 -178
  134. package/src/nat/address-resolver.ts +51 -51
  135. package/src/nat/ddns/duckdns.ts +76 -76
  136. package/src/nat/ddns/index.ts +55 -55
  137. package/src/nat/ddns/updater.ts +243 -243
  138. package/src/nat/external-ip.ts +154 -154
  139. package/src/nat/index.ts +71 -71
  140. package/src/nat/nat-service.ts +501 -501
  141. package/src/nat/nat-store.ts +154 -154
  142. package/src/nat/port-mapper.ts +329 -329
  143. package/src/nat/reachability.ts +34 -34
  144. package/src/nat/secrets/file-store.ts +130 -130
  145. package/src/nat/secrets/index.ts +112 -112
  146. package/src/nat/secrets/keytar-store.ts +67 -67
  147. package/src/nat/types.ts +159 -159
  148. package/src/orchestrator/__tests__/node-identity.test.ts +62 -0
  149. package/src/orchestrator/host-process-orchestrator.ts +1133 -894
  150. package/src/orchestrator/index.ts +10 -10
  151. package/src/orchestrator/log-rotator.ts +53 -53
  152. package/src/orchestrator/node-identity.ts +40 -0
  153. package/src/orchestrator/pid-liveness.ts +24 -24
  154. package/src/orchestrator/port-allocator.ts +91 -43
  155. package/src/orchestrator/state-store.ts +90 -90
  156. package/src/orchestrator/types.ts +141 -141
  157. package/src/owner/__tests__/owner-node-client.test.ts +194 -194
  158. package/src/owner/index.ts +12 -12
  159. package/src/owner/owner-node-client.ts +259 -233
  160. package/src/push/__tests__/push.test.ts +90 -90
  161. package/src/push/index.ts +146 -146
  162. package/src/server/__tests__/bus.test.ts +38 -38
  163. package/src/server/__tests__/error-handler.test.ts +118 -118
  164. package/src/server/__tests__/grants-admin-route.test.ts +73 -73
  165. package/src/server/__tests__/grants-route.test.ts +263 -189
  166. package/src/server/__tests__/nodes-route.test.ts +259 -259
  167. package/src/server/__tests__/origin-guard.test.ts +72 -72
  168. package/src/server/__tests__/publishers.test.ts +216 -216
  169. package/src/server/__tests__/server.smoke.test.ts +253 -253
  170. package/src/server/__tests__/settings-route.test.ts +194 -194
  171. package/src/server/__tests__/sse-route.test.ts +119 -119
  172. package/src/server/__tests__/static.test.ts +145 -145
  173. package/src/server/__tests__/status-route.test.ts +134 -134
  174. package/src/server/__tests__/strands-route.test.ts +233 -0
  175. package/src/server/error-handler.ts +178 -155
  176. package/src/server/events/bus.ts +42 -42
  177. package/src/server/events/sse-route.ts +81 -81
  178. package/src/server/events/types.ts +23 -22
  179. package/src/server/index.ts +267 -254
  180. package/src/server/origin-guard.ts +84 -84
  181. package/src/server/routes/grants-admin.ts +41 -41
  182. package/src/server/routes/grants.ts +210 -186
  183. package/src/server/routes/nat.ts +63 -63
  184. package/src/server/routes/nodes.ts +170 -170
  185. package/src/server/routes/settings.ts +123 -123
  186. package/src/server/routes/status.ts +118 -118
  187. package/src/server/routes/strands.ts +54 -0
  188. package/src/server/routes/trust-circle.ts +49 -49
  189. package/src/server/routes/update.ts +43 -43
  190. package/src/server/server.ts +122 -122
  191. package/src/server/settings-store.ts +37 -37
  192. package/src/server/static.ts +207 -207
  193. package/src/strands/__tests__/strand-service.test.ts +165 -0
  194. package/src/strands/index.ts +14 -0
  195. package/src/strands/strand-service.ts +135 -0
  196. package/src/strands/types.ts +102 -0
  197. package/src/update/__tests__/apply.test.ts +158 -158
  198. package/src/update/__tests__/manifest.test.ts +128 -128
  199. package/src/update/__tests__/release-key.test.ts +42 -42
  200. package/src/update/__tests__/sign.test.ts +78 -78
  201. package/src/update/__tests__/store.test.ts +81 -81
  202. package/src/update/__tests__/update-service.integration.test.ts +256 -256
  203. package/src/update/__tests__/version.test.ts +31 -31
  204. package/src/update/apply.ts +190 -190
  205. package/src/update/index.ts +341 -341
  206. package/src/update/release-key.ts +71 -71
  207. package/src/update/sign.ts +74 -74
  208. package/src/update/store.ts +101 -101
  209. package/src/update/types.ts +109 -109
  210. package/src/update/version.ts +80 -80
  211. package/dist/ui/assets/index-BlMXQPSw.js +0 -14
  212. package/dist/ui/assets/index-BlMXQPSw.js.map +0 -1
  213. package/dist/ui/assets/index-BwU5mJGF.css +0 -1
@@ -12,5 +12,6 @@ export { GrantService, createGrantAdminHandlers, DEFAULT_MAX_NODES, } from './gr
12
12
  export { GrantError, DonationError } from './types.js';
13
13
  /* ──────────────── donation lifecycle (2-donation-service) ──────────────── */
14
14
  export { DonationStore } from './donation-store.js';
15
- export { DonationService, DONATION_AWAITING_SEED_TTL_MS, DONATION_REAP_SWEEP_MS, } from './donation-service.js';
15
+ export { DonationService, DONATION_AWAITING_SEED_TTL_MS, DONATION_PROVISIONING_TTL_MS, DONATION_REAP_SWEEP_MS, } from './donation-service.js';
16
+ export { DonationSupervisor, DONATION_RESPAWN_BACKOFF_BASE_MS, DONATION_RESPAWN_BACKOFF_MAX_MS, DONATION_RESPAWN_MAX_ATTEMPTS, DONATION_RESPAWN_HEALTHY_MS, DONATION_RESPAWN_SWEEP_MS, } from './donation-supervisor.js';
16
17
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/donation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAWvD,+EAA+E;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,eAAe,EACf,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/donation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAWvD,+EAA+E;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,eAAe,EACf,6BAA6B,EAC7B,4BAA4B,EAC5B,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAS/B,OAAO,EACL,kBAAkB,EAClB,gCAAgC,EAChC,+BAA+B,EAC/B,6BAA6B,EAC7B,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC"}
@@ -120,6 +120,12 @@ export type DonationStatus = 'provisioning' | 'awaiting_seed' | 'seeded' | 'erro
120
120
  * foreign party), and `seedToken` gates the node's own `POST /seed` — it is
121
121
  * minted host-side, persisted here (so a host restart in the request→seed gap
122
122
  * can still present the seed), and NEVER returned to the grantee.
123
+ *
124
+ * The record also carries every input the original spawn consumed
125
+ * (`partyId` + `profile` + `bootstrapNodes` + `ownerKeys`), so a crashed node can
126
+ * be re-spawned from the record alone — see `DonationService.respawn`. Records
127
+ * written before those two fields existed have neither; such a record is NOT
128
+ * respawnable and is skipped (never crashes a sweep).
123
129
  */
124
130
  export interface Donation {
125
131
  /** "grn_<nanoid>" — also the donated node's orchestrator containerId. */
@@ -128,6 +134,26 @@ export interface Donation {
128
134
  grantToken: string;
129
135
  /** The REQUESTER's cadre (a foreign party this host merely hosts a node for). */
130
136
  partyId: string;
137
+ /**
138
+ * Requester control-network bootstrap multiaddrs — replayed on respawn.
139
+ * Absent on records written before respawn support; those are not respawnable.
140
+ */
141
+ bootstrapNodes?: string[];
142
+ /**
143
+ * Requester owner public key(s), base64url — replayed as the node's pinned
144
+ * seed-trust anchors (`CADRE_OWNER_KEYS`) on respawn. Absent on records written
145
+ * before respawn support; those are not respawnable.
146
+ */
147
+ ownerKeys?: string[];
148
+ /**
149
+ * Respawn bookkeeping, owned by the supervisor's backoff. Absent until the
150
+ * first respawn attempt. Not secret — it rides along in `DonationView` so the
151
+ * borrower's `GET /grants/:id` shows the counters for free.
152
+ */
153
+ respawn?: {
154
+ attempts: number;
155
+ lastAttemptAt: string;
156
+ };
131
157
  /** Node profile. Defaults to `storage` so the node participates and is dialable. */
132
158
  profile: 'storage' | 'transaction';
133
159
  status: DonationStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/donation/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAyKH,sEAAsE;AACtE,MAAM,OAAO,aAAc,SAAQ,KAAK;IAGtC,YAAY,IAAuB,EAAE,OAAe;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAUD,6DAA6D;AAC7D,MAAM,OAAO,UAAW,SAAQ,KAAK;IAGnC,YAAY,IAAoB,EAAE,OAAe;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/donation/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAgMH,sEAAsE;AACtE,MAAM,OAAO,aAAc,SAAQ,KAAK;IAGtC,YAAY,IAAuB,EAAE,OAAe;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAUD,6DAA6D;AAC7D,MAAM,OAAO,UAAW,SAAQ,KAAK;IAGnC,YAAY,IAAoB,EAAE,OAAe;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -22,8 +22,10 @@ export { HostProcessOrchestrator, OWNER_CONTAINER_ID } from './orchestrator/inde
22
22
  export type { HostProcessConfig, PersistedHandle, ManagedNodeInfo, NodeStateListener, NodePorts, OwnerAdminEndpoint, OwnerSpawnConfig, } from './orchestrator/index.js';
23
23
  export { OwnerNodeClient, OwnerNodeUnavailableError } from './owner/index.js';
24
24
  export type { OwnerNodeClientOptions } from './owner/index.js';
25
- export { TrustCircleService, TrustCircleStore, TrustCircleError, createTrustCircleHandlers, parseDuration, DEFAULT_INVITE_TTL_MS, } from './auth/index.js';
25
+ export { TrustCircleService, TrustCircleStore, TrustCircleError, createTrustCircleHandlers, parseDuration, ensureSelfLabel, DEFAULT_INVITE_TTL_MS, } from './auth/index.js';
26
26
  export type { TrustCircleServiceOptions, CadreNodeLike, TrustCircleMember, PendingInvite, TrustCircleFile, TrustCircleSnapshot, TrustCircleHandlers, TrustCircleErrorCode, } from './auth/index.js';
27
+ export { StrandService, StrandError, createStrandHandlers } from './strands/index.js';
28
+ export type { StrandServiceOptions, CadreNodeLike as StrandCadreNodeLike, StrandSummary, StrandListSnapshot, StrandRemovalResult, StrandHandlers, StrandErrorCode, } from './strands/index.js';
27
29
  export { GrantStore, GrantService, createGrantAdminHandlers, GrantError, DEFAULT_MAX_NODES, DonationStore, DonationService, DonationError, } from './donation/index.js';
28
30
  export type { Grant, GrantDenyReason, GrantValidation, GrantValidator, GrantFile, GrantAdminHandlers, GrantErrorCode, GrantServiceOptions, Donation, DonationView, DonationStatus, DonationFile, DonationErrorCode, DonationProvisionRequest, DonationSeedResult, DonationPeerInfo, DonationServiceOptions, } from './donation/index.js';
29
31
  export { Installer, readHostConfig, updateHostConfig, writeHostConfig } from './installer/index.js';
package/dist/index.js CHANGED
@@ -19,7 +19,9 @@
19
19
  */
20
20
  export { HostProcessOrchestrator, OWNER_CONTAINER_ID } from './orchestrator/index.js';
21
21
  export { OwnerNodeClient, OwnerNodeUnavailableError } from './owner/index.js';
22
- export { TrustCircleService, TrustCircleStore, TrustCircleError, createTrustCircleHandlers, parseDuration, DEFAULT_INVITE_TTL_MS, } from './auth/index.js';
22
+ export { TrustCircleService, TrustCircleStore, TrustCircleError, createTrustCircleHandlers, parseDuration, ensureSelfLabel, DEFAULT_INVITE_TTL_MS, } from './auth/index.js';
23
+ /* ──────────────── strand management ──────────────── */
24
+ export { StrandService, StrandError, createStrandHandlers } from './strands/index.js';
23
25
  /* ──────────────── donation grant tokens ──────────────── */
24
26
  export { GrantStore, GrantService, createGrantAdminHandlers, GrantError, DEFAULT_MAX_NODES, DonationStore, DonationService, DonationError, } from './donation/index.js';
25
27
  export { Installer, readHostConfig, updateHostConfig, writeHostConfig } from './installer/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAWH,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAWtF,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAG9E,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,aAAa,EACb,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAYzB,6DAA6D;AAE7D,OAAO,EACL,UAAU,EACV,YAAY,EACZ,wBAAwB,EACxB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,qBAAqB,CAAC;AAqB7B,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAepG,mEAAmE;AAEnE,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,UAAU,GACX,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAe3B,OAAO,EACL,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AA+BxB,+DAA+D;AAE/D,OAAO,EACL,mBAAmB,EACnB,QAAQ,EACR,iBAAiB,GAClB,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAWH,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAWtF,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAG9E,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,aAAa,EACb,eAAe,EACf,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAYzB,yDAAyD;AAEzD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAWtF,6DAA6D;AAE7D,OAAO,EACL,UAAU,EACV,YAAY,EACZ,wBAAwB,EACxB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,qBAAqB,CAAC;AAqB7B,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAepG,mEAAmE;AAEnE,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,UAAU,GACX,MAAM,iBAAiB,CAAC;AAQzB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,yBAAyB,EACzB,cAAc,EACd,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAe3B,OAAO,EACL,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AA+BxB,+DAA+D;AAE/D,OAAO,EACL,mBAAmB,EACnB,QAAQ,EACR,iBAAiB,GAClB,MAAM,mBAAmB,CAAC"}
@@ -1,5 +1,4 @@
1
1
  import type { Orchestrator, OrchestratorCreateRequest, OrchestratorCreateResult, OrchestratorStats } from '@serfab/cadre-provider';
2
- import { type PersistedHandle } from './state-store.js';
3
2
  import { type OwnerSpawnConfig, type HostProcessConfig, type ManagedNodeInfo, type NodeStateListener } from './types.js';
4
3
  /** Fixed friendly id for the admin's owner node. */
5
4
  export declare const OWNER_CONTAINER_ID = "owner";
@@ -84,9 +83,44 @@ export declare class HostProcessOrchestrator implements Orchestrator {
84
83
  * transitions (child exit, manual stop). Returns an unsubscribe fn.
85
84
  */
86
85
  onStateChange(listener: NodeStateListener): () => void;
87
- /** Handles that init() found dead (PID gone or token mismatch). */
88
- listDeadHandles(): PersistedHandle[];
86
+ /**
87
+ * Spawn a generic managed node — the donated-node path (the requester's cadre,
88
+ * pinned to the *requester's* owner key). The node is given its own protobuf
89
+ * identity key inside its workdir (`ensureNodeIdentity`, reused across
90
+ * re-spawns of the same containerId), which is what makes its peer id stable
91
+ * across restarts AND what makes its node-local stores durable: `cadre-cli
92
+ * start` opens the file-backed bootstrap-peer and trusted-owner stores only
93
+ * when a protobuf identity key file is configured, and puts them beside it.
94
+ * Terminating the loan (`removeContainer`) deletes the workdir, so the key and
95
+ * both stores go with it.
96
+ */
89
97
  createContainer(request: OrchestratorCreateRequest): Promise<OrchestratorCreateResult>;
98
+ /**
99
+ * Remove the working directory a spawn created for `containerId` when no
100
+ * handle owns it — the cleanup of last resort for a donation record that
101
+ * never got a `dockerId` (the host died between `ensureNodeIdentity` and the
102
+ * handle write, so `createContainer`'s own unwind never ran). Returns whether
103
+ * anything was removed.
104
+ *
105
+ * Synchronous, mirroring {@link resolveDockerId}: nothing on this path needs
106
+ * to await.
107
+ */
108
+ reclaimWorkdir(containerId: string): boolean;
109
+ /**
110
+ * Best-effort removal of a workdir no handle owns. Logs, never throws: every
111
+ * caller is either unwinding a failure it must report instead of this one, or
112
+ * tearing a container down along a path where a surviving directory is a
113
+ * nuisance rather than a fault.
114
+ *
115
+ * `retries` sizes the wait for the OS to release a cwd handle — Windows drops
116
+ * it asynchronously after a child exits. `createContainer`'s unwind needs none
117
+ * of that (its throw surface ends before any child is spawned), but
118
+ * `reclaimWorkdir` can still meet an orphan process the previous host left
119
+ * running with this directory as its cwd, so it is not a *guaranteed*
120
+ * no-process path either — it simply logs and leaves the directory when the
121
+ * removal fails.
122
+ */
123
+ private discardWorkdir;
90
124
  /**
91
125
  * Resolve the push credentials to inject into the node about to spawn. Called
92
126
  * on every spawn so a re-spawn re-reads the secret store — raw private keys are
@@ -120,12 +154,82 @@ export declare class HostProcessOrchestrator implements Orchestrator {
120
154
  restartOwnerNode(): Promise<ManagedNodeInfo>;
121
155
  /**
122
156
  * Core spawn mechanics shared by `createContainer` and `ensureOwnerNode`.
123
- * The caller has already allocated `ports`. Releases the ports on a
124
- * synchronous spawn failure.
157
+ *
158
+ * The caller has already allocated `ports` and **owns their lifetime**: this
159
+ * method never releases them, so every caller must release on any throw out
160
+ * of here (it has to unwind its handle drop on the same path anyway — see
161
+ * `restoreDroppedHandles`).
162
+ *
163
+ * That contract holds because this method throws only *before* the child is
164
+ * spawned and its handle stored — everything after that point is
165
+ * best-effort. Anything new added at the tail must keep it that way.
166
+ *
167
+ * Entirely synchronous, which is what makes that unwind sound. Do not add an
168
+ * `await` here.
125
169
  */
126
170
  private launchChild;
171
+ /**
172
+ * Drop any handle left over from a previous spawn of the same `containerId`
173
+ * and release its ports. Handles are keyed by the per-spawn `dockerId`, so
174
+ * without this a re-spawn (donated-node respawn) would strand the prior
175
+ * handle in the map forever, leaking four ports from a bounded range each
176
+ * time. Mirrors the same cleanup in `ensureOwnerNode`.
177
+ *
178
+ * DO NOT delete the workdir: the identity key and node-local stores
179
+ * (trusted-owner anchor, retained cold-start dial targets) live there and are
180
+ * the whole reason a respawn comes back as the same node. `launchChild`
181
+ * reuses the same workdir.
182
+ *
183
+ * NOTE: releasing the ports hands them straight back to the allocator, so a
184
+ * re-spawn while the *previous* child is still listening can bind-clash. Every
185
+ * caller today re-spawns only a container it has established is not running
186
+ * (`DonationService.respawn`, `ensureOwnerNode`). If a caller ever needs to
187
+ * replace a live child, stop it first — or hold the ports until its exit.
188
+ *
189
+ * **The drop is reversible.** It happens before the launch can fail, so the
190
+ * dropped handles are returned and every caller restores them via
191
+ * {@link restoreDroppedHandles} when the launch throws — otherwise the caller
192
+ * would be left holding a dockerId this orchestrator no longer knows, and the
193
+ * node's workdir could never be reclaimed. On a *successful* spawn the drop
194
+ * stands: `DonationService.abandonRespawn` depends on the old handle being
195
+ * gone by then.
196
+ */
197
+ private dropStaleHandle;
198
+ /**
199
+ * Inverse of {@link dropStaleHandle}, for a spawn that then failed: put each
200
+ * handle back in the map and re-reserve its four ports, leaving host state
201
+ * exactly as the failed attempt found it.
202
+ *
203
+ * **Precondition: the drop → launch window is synchronous.** Restoring is
204
+ * sound only because nothing can have taken those ports or run cleanup
205
+ * against the handle in between — `launchChild` contains no `await` and both
206
+ * callers resolve push credentials *before* their drop. `launchChild`'s half
207
+ * is enforced: its declared return type is not a Promise, so adding an
208
+ * `await` there is a compile error. The callers' half is not — an `await`
209
+ * slipped between a drop and its launch silently breaks this.
210
+ *
211
+ * No `persist()` here: `state.json` is rewritten only by `launchChild` and
212
+ * only *after* the new handle is stored, so throughout the failure window the
213
+ * on-disk state still lists the dropped handle — this restore realigns memory
214
+ * to disk rather than diverging from it.
215
+ *
216
+ * NOTE: a restored handle keeps `alive: true` even if its child exited while
217
+ * it was out of the map (`launchChild`'s exit listener looks the handle up by
218
+ * dockerId and finds nothing). Only reachable by re-spawning a container
219
+ * whose child is still live, which `dropStaleHandle`'s note above already
220
+ * forbids.
221
+ */
222
+ private restoreDroppedHandles;
223
+ /** A managed node's own directory under `rootDir` — config, log, storage, identity. */
224
+ private workdirFor;
127
225
  /** Locate the owner node's handle, if one has been spawned. */
128
226
  private findOwnerHandle;
227
+ /**
228
+ * Inverse of {@link releasePorts} — hold a handle's whole port set against
229
+ * the allocator. Used both to rehydrate on `init` and to undo a drop whose
230
+ * launch then failed.
231
+ */
232
+ private reservePorts;
129
233
  private releasePorts;
130
234
  stopContainer(dockerId: string): Promise<void>;
131
235
  removeContainer(dockerId: string): Promise<void>;