@spine-event-engine/server 2.0.0-snapshot.11

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 (378) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +209 -0
  3. package/REFERENCE.md +760 -0
  4. package/dist/browser/browser-server.d.ts +95 -0
  5. package/dist/browser/browser-server.d.ts.map +1 -0
  6. package/dist/browser/browser-server.js +719 -0
  7. package/dist/browser/browser-server.js.map +1 -0
  8. package/dist/browser/durable-subscription-bindings.d.ts +122 -0
  9. package/dist/browser/durable-subscription-bindings.d.ts.map +1 -0
  10. package/dist/browser/durable-subscription-bindings.js +524 -0
  11. package/dist/browser/durable-subscription-bindings.js.map +1 -0
  12. package/dist/browser/index.d.ts +12 -0
  13. package/dist/browser/index.d.ts.map +1 -0
  14. package/dist/browser/index.js +24 -0
  15. package/dist/browser/index.js.map +1 -0
  16. package/dist/browser/options.d.ts +183 -0
  17. package/dist/browser/options.d.ts.map +1 -0
  18. package/dist/browser/options.js +15 -0
  19. package/dist/browser/options.js.map +1 -0
  20. package/dist/bus/command-bus.d.ts +63 -0
  21. package/dist/bus/command-bus.d.ts.map +1 -0
  22. package/dist/bus/command-bus.js +236 -0
  23. package/dist/bus/command-bus.js.map +1 -0
  24. package/dist/bus/command-dispatcher-registry.d.ts +33 -0
  25. package/dist/bus/command-dispatcher-registry.d.ts.map +1 -0
  26. package/dist/bus/command-dispatcher-registry.js +75 -0
  27. package/dist/bus/command-dispatcher-registry.js.map +1 -0
  28. package/dist/bus/command-dispatcher.d.ts +25 -0
  29. package/dist/bus/command-dispatcher.d.ts.map +1 -0
  30. package/dist/bus/command-dispatcher.js +15 -0
  31. package/dist/bus/command-dispatcher.js.map +1 -0
  32. package/dist/bus/command-errors.d.ts +23 -0
  33. package/dist/bus/command-errors.d.ts.map +1 -0
  34. package/dist/bus/command-errors.js +52 -0
  35. package/dist/bus/command-errors.js.map +1 -0
  36. package/dist/bus/event-bus.d.ts +113 -0
  37. package/dist/bus/event-bus.d.ts.map +1 -0
  38. package/dist/bus/event-bus.js +518 -0
  39. package/dist/bus/event-bus.js.map +1 -0
  40. package/dist/bus/event-dispatcher-origin-schemas.d.ts +17 -0
  41. package/dist/bus/event-dispatcher-origin-schemas.d.ts.map +1 -0
  42. package/dist/bus/event-dispatcher-origin-schemas.js +32 -0
  43. package/dist/bus/event-dispatcher-origin-schemas.js.map +1 -0
  44. package/dist/bus/event-dispatcher-registry.d.ts +48 -0
  45. package/dist/bus/event-dispatcher-registry.d.ts.map +1 -0
  46. package/dist/bus/event-dispatcher-registry.js +176 -0
  47. package/dist/bus/event-dispatcher-registry.js.map +1 -0
  48. package/dist/bus/event-dispatcher.d.ts +48 -0
  49. package/dist/bus/event-dispatcher.d.ts.map +1 -0
  50. package/dist/bus/event-dispatcher.js +15 -0
  51. package/dist/bus/event-dispatcher.js.map +1 -0
  52. package/dist/context/bounded-context.d.ts +592 -0
  53. package/dist/context/bounded-context.d.ts.map +1 -0
  54. package/dist/context/bounded-context.js +1897 -0
  55. package/dist/context/bounded-context.js.map +1 -0
  56. package/dist/context/entity-inbox.d.ts +63 -0
  57. package/dist/context/entity-inbox.d.ts.map +1 -0
  58. package/dist/context/entity-inbox.js +387 -0
  59. package/dist/context/entity-inbox.js.map +1 -0
  60. package/dist/context/local-inbox-handoff.d.ts +248 -0
  61. package/dist/context/local-inbox-handoff.d.ts.map +1 -0
  62. package/dist/context/local-inbox-handoff.js +340 -0
  63. package/dist/context/local-inbox-handoff.js.map +1 -0
  64. package/dist/context/projection-handoff.d.ts +46 -0
  65. package/dist/context/projection-handoff.d.ts.map +1 -0
  66. package/dist/context/projection-handoff.js +177 -0
  67. package/dist/context/projection-handoff.js.map +1 -0
  68. package/dist/context/tenant-index.d.ts +41 -0
  69. package/dist/context/tenant-index.d.ts.map +1 -0
  70. package/dist/context/tenant-index.js +93 -0
  71. package/dist/context/tenant-index.js.map +1 -0
  72. package/dist/delivery/conditional-pickup.d.ts +25 -0
  73. package/dist/delivery/conditional-pickup.d.ts.map +1 -0
  74. package/dist/delivery/conditional-pickup.js +26 -0
  75. package/dist/delivery/conditional-pickup.js.map +1 -0
  76. package/dist/delivery/delivery-builder.d.ts +216 -0
  77. package/dist/delivery/delivery-builder.d.ts.map +1 -0
  78. package/dist/delivery/delivery-builder.js +323 -0
  79. package/dist/delivery/delivery-builder.js.map +1 -0
  80. package/dist/delivery/delivery-lease.d.ts +15 -0
  81. package/dist/delivery/delivery-lease.d.ts.map +1 -0
  82. package/dist/delivery/delivery-lease.js +44 -0
  83. package/dist/delivery/delivery-lease.js.map +1 -0
  84. package/dist/delivery/delivery-loop.d.ts +113 -0
  85. package/dist/delivery/delivery-loop.d.ts.map +1 -0
  86. package/dist/delivery/delivery-loop.js +119 -0
  87. package/dist/delivery/delivery-loop.js.map +1 -0
  88. package/dist/delivery/delivery-monitor.d.ts +165 -0
  89. package/dist/delivery/delivery-monitor.d.ts.map +1 -0
  90. package/dist/delivery/delivery-monitor.js +168 -0
  91. package/dist/delivery/delivery-monitor.js.map +1 -0
  92. package/dist/delivery/delivery-ports.d.ts +151 -0
  93. package/dist/delivery/delivery-ports.d.ts.map +1 -0
  94. package/dist/delivery/delivery-ports.js +15 -0
  95. package/dist/delivery/delivery-ports.js.map +1 -0
  96. package/dist/delivery/delivery-run-control.d.ts +50 -0
  97. package/dist/delivery/delivery-run-control.d.ts.map +1 -0
  98. package/dist/delivery/delivery-run-control.js +66 -0
  99. package/dist/delivery/delivery-run-control.js.map +1 -0
  100. package/dist/delivery/delivery-run-coordinator.d.ts +218 -0
  101. package/dist/delivery/delivery-run-coordinator.d.ts.map +1 -0
  102. package/dist/delivery/delivery-run-coordinator.js +609 -0
  103. package/dist/delivery/delivery-run-coordinator.js.map +1 -0
  104. package/dist/delivery/delivery-storage-error.d.ts +13 -0
  105. package/dist/delivery/delivery-storage-error.d.ts.map +1 -0
  106. package/dist/delivery/delivery-storage-error.js +30 -0
  107. package/dist/delivery/delivery-storage-error.js.map +1 -0
  108. package/dist/delivery/delivery-supervisor.d.ts +175 -0
  109. package/dist/delivery/delivery-supervisor.d.ts.map +1 -0
  110. package/dist/delivery/delivery-supervisor.js +469 -0
  111. package/dist/delivery/delivery-supervisor.js.map +1 -0
  112. package/dist/delivery/delivery-worker.d.ts +180 -0
  113. package/dist/delivery/delivery-worker.d.ts.map +1 -0
  114. package/dist/delivery/delivery-worker.js +232 -0
  115. package/dist/delivery/delivery-worker.js.map +1 -0
  116. package/dist/delivery/delivery.d.ts +236 -0
  117. package/dist/delivery/delivery.d.ts.map +1 -0
  118. package/dist/delivery/delivery.js +539 -0
  119. package/dist/delivery/delivery.js.map +1 -0
  120. package/dist/delivery/inbox-records.d.ts +19 -0
  121. package/dist/delivery/inbox-records.d.ts.map +1 -0
  122. package/dist/delivery/inbox-records.js +291 -0
  123. package/dist/delivery/inbox-records.js.map +1 -0
  124. package/dist/delivery/inbox-storage.d.ts +83 -0
  125. package/dist/delivery/inbox-storage.d.ts.map +1 -0
  126. package/dist/delivery/inbox-storage.js +336 -0
  127. package/dist/delivery/inbox-storage.js.map +1 -0
  128. package/dist/delivery/inbox.d.ts +272 -0
  129. package/dist/delivery/inbox.d.ts.map +1 -0
  130. package/dist/delivery/inbox.js +183 -0
  131. package/dist/delivery/inbox.js.map +1 -0
  132. package/dist/delivery/parked-delivery-obligations.d.ts +182 -0
  133. package/dist/delivery/parked-delivery-obligations.d.ts.map +1 -0
  134. package/dist/delivery/parked-delivery-obligations.js +390 -0
  135. package/dist/delivery/parked-delivery-obligations.js.map +1 -0
  136. package/dist/delivery/shard-index.d.ts +41 -0
  137. package/dist/delivery/shard-index.d.ts.map +1 -0
  138. package/dist/delivery/shard-index.js +67 -0
  139. package/dist/delivery/shard-index.js.map +1 -0
  140. package/dist/delivery/sharded-work-registry.d.ts +114 -0
  141. package/dist/delivery/sharded-work-registry.d.ts.map +1 -0
  142. package/dist/delivery/sharded-work-registry.js +361 -0
  143. package/dist/delivery/sharded-work-registry.js.map +1 -0
  144. package/dist/entity/entity-metadata.d.ts +173 -0
  145. package/dist/entity/entity-metadata.d.ts.map +1 -0
  146. package/dist/entity/entity-metadata.js +187 -0
  147. package/dist/entity/entity-metadata.js.map +1 -0
  148. package/dist/entity/entity-storage-descriptor.d.ts +64 -0
  149. package/dist/entity/entity-storage-descriptor.d.ts.map +1 -0
  150. package/dist/entity/entity-storage-descriptor.js +227 -0
  151. package/dist/entity/entity-storage-descriptor.js.map +1 -0
  152. package/dist/entity/entity-transaction.d.ts +372 -0
  153. package/dist/entity/entity-transaction.d.ts.map +1 -0
  154. package/dist/entity/entity-transaction.js +413 -0
  155. package/dist/entity/entity-transaction.js.map +1 -0
  156. package/dist/entity/entity-transition-validation.d.ts +47 -0
  157. package/dist/entity/entity-transition-validation.d.ts.map +1 -0
  158. package/dist/entity/entity-transition-validation.js +327 -0
  159. package/dist/entity/entity-transition-validation.js.map +1 -0
  160. package/dist/entity/entity.d.ts +605 -0
  161. package/dist/entity/entity.d.ts.map +1 -0
  162. package/dist/entity/entity.js +981 -0
  163. package/dist/entity/entity.js.map +1 -0
  164. package/dist/entity/implicit-required-id.d.ts +15 -0
  165. package/dist/entity/implicit-required-id.d.ts.map +1 -0
  166. package/dist/entity/implicit-required-id.js +123 -0
  167. package/dist/entity/implicit-required-id.js.map +1 -0
  168. package/dist/entity/spec-scanner.d.ts +14 -0
  169. package/dist/entity/spec-scanner.d.ts.map +1 -0
  170. package/dist/entity/spec-scanner.js +37 -0
  171. package/dist/entity/spec-scanner.js.map +1 -0
  172. package/dist/handler/command-registration-readiness.d.ts +99 -0
  173. package/dist/handler/command-registration-readiness.d.ts.map +1 -0
  174. package/dist/handler/command-registration-readiness.js +120 -0
  175. package/dist/handler/command-registration-readiness.js.map +1 -0
  176. package/dist/handler/declared-rejections.d.ts +11 -0
  177. package/dist/handler/declared-rejections.d.ts.map +1 -0
  178. package/dist/handler/declared-rejections.js +34 -0
  179. package/dist/handler/declared-rejections.js.map +1 -0
  180. package/dist/handler/event-handler-filter.d.ts +43 -0
  181. package/dist/handler/event-handler-filter.d.ts.map +1 -0
  182. package/dist/handler/event-handler-filter.js +128 -0
  183. package/dist/handler/event-handler-filter.js.map +1 -0
  184. package/dist/handler/event-registration-readiness.d.ts +196 -0
  185. package/dist/handler/event-registration-readiness.d.ts.map +1 -0
  186. package/dist/handler/event-registration-readiness.js +187 -0
  187. package/dist/handler/event-registration-readiness.js.map +1 -0
  188. package/dist/handler/external.d.ts +10 -0
  189. package/dist/handler/external.d.ts.map +1 -0
  190. package/dist/handler/external.js +15 -0
  191. package/dist/handler/external.js.map +1 -0
  192. package/dist/handler/generated-handler-registry.d.ts +185 -0
  193. package/dist/handler/generated-handler-registry.d.ts.map +1 -0
  194. package/dist/handler/generated-handler-registry.js +439 -0
  195. package/dist/handler/generated-handler-registry.js.map +1 -0
  196. package/dist/handler/generated-registry-discovery.d.ts +94 -0
  197. package/dist/handler/generated-registry-discovery.d.ts.map +1 -0
  198. package/dist/handler/generated-registry-discovery.js +226 -0
  199. package/dist/handler/generated-registry-discovery.js.map +1 -0
  200. package/dist/handler/handler-decorators.d.ts +151 -0
  201. package/dist/handler/handler-decorators.d.ts.map +1 -0
  202. package/dist/handler/handler-decorators.js +275 -0
  203. package/dist/handler/handler-decorators.js.map +1 -0
  204. package/dist/handler/handler-metadata.d.ts +553 -0
  205. package/dist/handler/handler-metadata.d.ts.map +1 -0
  206. package/dist/handler/handler-metadata.js +437 -0
  207. package/dist/handler/handler-metadata.js.map +1 -0
  208. package/dist/handler/registration-readiness-metadata.d.ts +68 -0
  209. package/dist/handler/registration-readiness-metadata.d.ts.map +1 -0
  210. package/dist/handler/registration-readiness-metadata.js +171 -0
  211. package/dist/handler/registration-readiness-metadata.js.map +1 -0
  212. package/dist/handler/rejection-source.d.ts +11 -0
  213. package/dist/handler/rejection-source.d.ts.map +1 -0
  214. package/dist/handler/rejection-source.js +25 -0
  215. package/dist/handler/rejection-source.js.map +1 -0
  216. package/dist/handler/standalone.d.ts +25 -0
  217. package/dist/handler/standalone.d.ts.map +1 -0
  218. package/dist/handler/standalone.js +38 -0
  219. package/dist/handler/standalone.js.map +1 -0
  220. package/dist/index.d.ts +46 -0
  221. package/dist/index.d.ts.map +1 -0
  222. package/dist/index.js +54 -0
  223. package/dist/index.js.map +1 -0
  224. package/dist/integration/external-messages.d.ts +49 -0
  225. package/dist/integration/external-messages.d.ts.map +1 -0
  226. package/dist/integration/external-messages.js +112 -0
  227. package/dist/integration/external-messages.js.map +1 -0
  228. package/dist/integration/integration-broker.d.ts +74 -0
  229. package/dist/integration/integration-broker.d.ts.map +1 -0
  230. package/dist/integration/integration-broker.js +444 -0
  231. package/dist/integration/integration-broker.js.map +1 -0
  232. package/dist/integration/third-party-context.d.ts +56 -0
  233. package/dist/integration/third-party-context.d.ts.map +1 -0
  234. package/dist/integration/third-party-context.js +130 -0
  235. package/dist/integration/third-party-context.js.map +1 -0
  236. package/dist/repository/command-errors.d.ts +25 -0
  237. package/dist/repository/command-errors.d.ts.map +1 -0
  238. package/dist/repository/command-errors.js +43 -0
  239. package/dist/repository/command-errors.js.map +1 -0
  240. package/dist/repository/command-routing.d.ts +72 -0
  241. package/dist/repository/command-routing.d.ts.map +1 -0
  242. package/dist/repository/command-routing.js +98 -0
  243. package/dist/repository/command-routing.js.map +1 -0
  244. package/dist/repository/commit-fence.d.ts +22 -0
  245. package/dist/repository/commit-fence.d.ts.map +1 -0
  246. package/dist/repository/commit-fence.js +37 -0
  247. package/dist/repository/commit-fence.js.map +1 -0
  248. package/dist/repository/event-routing.d.ts +71 -0
  249. package/dist/repository/event-routing.d.ts.map +1 -0
  250. package/dist/repository/event-routing.js +96 -0
  251. package/dist/repository/event-routing.js.map +1 -0
  252. package/dist/repository/primitive-id.d.ts +75 -0
  253. package/dist/repository/primitive-id.d.ts.map +1 -0
  254. package/dist/repository/primitive-id.js +85 -0
  255. package/dist/repository/primitive-id.js.map +1 -0
  256. package/dist/repository/repository.d.ts +667 -0
  257. package/dist/repository/repository.d.ts.map +1 -0
  258. package/dist/repository/repository.js +3510 -0
  259. package/dist/repository/repository.js.map +1 -0
  260. package/dist/repository/routing-declarations.d.ts +75 -0
  261. package/dist/repository/routing-declarations.d.ts.map +1 -0
  262. package/dist/repository/routing-declarations.js +101 -0
  263. package/dist/repository/routing-declarations.js.map +1 -0
  264. package/dist/repository/state-update-routing.d.ts +66 -0
  265. package/dist/repository/state-update-routing.d.ts.map +1 -0
  266. package/dist/repository/state-update-routing.js +91 -0
  267. package/dist/repository/state-update-routing.js.map +1 -0
  268. package/dist/runtime/runtime.d.ts +156 -0
  269. package/dist/runtime/runtime.d.ts.map +1 -0
  270. package/dist/runtime/runtime.js +215 -0
  271. package/dist/runtime/runtime.js.map +1 -0
  272. package/dist/runtime/signal-intake.d.ts +84 -0
  273. package/dist/runtime/signal-intake.d.ts.map +1 -0
  274. package/dist/runtime/signal-intake.js +94 -0
  275. package/dist/runtime/signal-intake.js.map +1 -0
  276. package/dist/runtime/signal-metadata.d.ts +217 -0
  277. package/dist/runtime/signal-metadata.d.ts.map +1 -0
  278. package/dist/runtime/signal-metadata.js +333 -0
  279. package/dist/runtime/signal-metadata.js.map +1 -0
  280. package/dist/runtime/signal-publisher.d.ts +144 -0
  281. package/dist/runtime/signal-publisher.d.ts.map +1 -0
  282. package/dist/runtime/signal-publisher.js +248 -0
  283. package/dist/runtime/signal-publisher.js.map +1 -0
  284. package/dist/runtime/standalone-handler-runtime.d.ts +114 -0
  285. package/dist/runtime/standalone-handler-runtime.d.ts.map +1 -0
  286. package/dist/runtime/standalone-handler-runtime.js +307 -0
  287. package/dist/runtime/standalone-handler-runtime.js.map +1 -0
  288. package/dist/server/environment-attachment.d.ts +356 -0
  289. package/dist/server/environment-attachment.d.ts.map +1 -0
  290. package/dist/server/environment-attachment.js +2062 -0
  291. package/dist/server/environment-attachment.js.map +1 -0
  292. package/dist/server/environment-delivery-records.d.ts +77 -0
  293. package/dist/server/environment-delivery-records.d.ts.map +1 -0
  294. package/dist/server/environment-delivery-records.js +282 -0
  295. package/dist/server/environment-delivery-records.js.map +1 -0
  296. package/dist/server/environment-delivery-worker.d.ts +161 -0
  297. package/dist/server/environment-delivery-worker.d.ts.map +1 -0
  298. package/dist/server/environment-delivery-worker.js +673 -0
  299. package/dist/server/environment-delivery-worker.js.map +1 -0
  300. package/dist/server/environment.d.ts +43 -0
  301. package/dist/server/environment.d.ts.map +1 -0
  302. package/dist/server/environment.js +90 -0
  303. package/dist/server/environment.js.map +1 -0
  304. package/dist/server/managed-child-subscription.d.ts +11 -0
  305. package/dist/server/managed-child-subscription.d.ts.map +1 -0
  306. package/dist/server/managed-child-subscription.js +44 -0
  307. package/dist/server/managed-child-subscription.js.map +1 -0
  308. package/dist/server/managed-server-application.d.ts +327 -0
  309. package/dist/server/managed-server-application.d.ts.map +1 -0
  310. package/dist/server/managed-server-application.js +937 -0
  311. package/dist/server/managed-server-application.js.map +1 -0
  312. package/dist/server/node-coordinator.d.ts +191 -0
  313. package/dist/server/node-coordinator.d.ts.map +1 -0
  314. package/dist/server/node-coordinator.js +552 -0
  315. package/dist/server/node-coordinator.js.map +1 -0
  316. package/dist/server/process-server-coordinator.d.ts +15 -0
  317. package/dist/server/process-server-coordinator.d.ts.map +1 -0
  318. package/dist/server/process-server-coordinator.js +112 -0
  319. package/dist/server/process-server-coordinator.js.map +1 -0
  320. package/dist/server/reserved-spine-rpc-paths.json +8 -0
  321. package/dist/server/retryable-close.d.ts +28 -0
  322. package/dist/server/retryable-close.d.ts.map +1 -0
  323. package/dist/server/retryable-close.js +129 -0
  324. package/dist/server/retryable-close.js.map +1 -0
  325. package/dist/server/server-environment.d.ts +180 -0
  326. package/dist/server/server-environment.d.ts.map +1 -0
  327. package/dist/server/server-environment.js +418 -0
  328. package/dist/server/server-environment.js.map +1 -0
  329. package/dist/server/server-log.d.ts +18 -0
  330. package/dist/server/server-log.d.ts.map +1 -0
  331. package/dist/server/server-log.js +100 -0
  332. package/dist/server/server-log.js.map +1 -0
  333. package/dist/server/server.d.ts +221 -0
  334. package/dist/server/server.d.ts.map +1 -0
  335. package/dist/server/server.js +704 -0
  336. package/dist/server/server.js.map +1 -0
  337. package/dist/services/query-reader.d.ts +19 -0
  338. package/dist/services/query-reader.d.ts.map +1 -0
  339. package/dist/services/query-reader.js +43 -0
  340. package/dist/services/query-reader.js.map +1 -0
  341. package/dist/services/spine-services.d.ts +88 -0
  342. package/dist/services/spine-services.d.ts.map +1 -0
  343. package/dist/services/spine-services.js +1582 -0
  344. package/dist/services/spine-services.js.map +1 -0
  345. package/dist/spi/delivery.d.ts +5 -0
  346. package/dist/spi/delivery.d.ts.map +1 -0
  347. package/dist/spi/delivery.js +18 -0
  348. package/dist/spi/delivery.js.map +1 -0
  349. package/dist/spi/handler-registry.d.ts +8 -0
  350. package/dist/spi/handler-registry.d.ts.map +1 -0
  351. package/dist/spi/handler-registry.js +15 -0
  352. package/dist/spi/handler-registry.js.map +1 -0
  353. package/dist/stand/stand.d.ts +294 -0
  354. package/dist/stand/stand.d.ts.map +1 -0
  355. package/dist/stand/stand.js +681 -0
  356. package/dist/stand/stand.js.map +1 -0
  357. package/dist/stand/subscription-observer.d.ts +53 -0
  358. package/dist/stand/subscription-observer.d.ts.map +1 -0
  359. package/dist/stand/subscription-observer.js +444 -0
  360. package/dist/stand/subscription-observer.js.map +1 -0
  361. package/dist/stand/subscription-records.d.ts +12 -0
  362. package/dist/stand/subscription-records.d.ts.map +1 -0
  363. package/dist/stand/subscription-records.js +99 -0
  364. package/dist/stand/subscription-records.js.map +1 -0
  365. package/dist/stand/subscription-registry.d.ts +285 -0
  366. package/dist/stand/subscription-registry.d.ts.map +1 -0
  367. package/dist/stand/subscription-registry.js +403 -0
  368. package/dist/stand/subscription-registry.js.map +1 -0
  369. package/dist/stand/subscription-runtime.d.ts +102 -0
  370. package/dist/stand/subscription-runtime.d.ts.map +1 -0
  371. package/dist/stand/subscription-runtime.js +380 -0
  372. package/dist/stand/subscription-runtime.js.map +1 -0
  373. package/dist/testing/index.d.ts +36 -0
  374. package/dist/testing/index.d.ts.map +1 -0
  375. package/dist/testing/index.js +54 -0
  376. package/dist/testing/index.js.map +1 -0
  377. package/dist/tsconfig.tsbuildinfo +1 -0
  378. package/package.json +76 -0
@@ -0,0 +1,719 @@
1
+ /*
2
+ * Copyright 2026, CodeMatters. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
+ * in compliance with the License. You may obtain a copy of the License at
6
+ *
7
+ * https://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
10
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
+ * or implied. See the License for the specific language governing permissions and limitations under
12
+ * the License.
13
+ */
14
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
15
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
16
+ /* eslint-disable @typescript-eslint/require-await */
17
+ import * as http from "node:http";
18
+ import { createNativeGatewayServices, DynamicSubscriptionCreator, DynamicUnaryForwarder, InMemorySubscriptionBindings, NativeSubscriptionCreator, SubscriptionGateway, TransportFacts, UnaryGateway, } from "@spine-event-engine/auth";
19
+ import { connectNodeAdapter, createGrpcTransport, Http2SessionManager, } from "@connectrpc/connect-node";
20
+ import { AuthenticationService } from "@spine-event-engine/proto/auth";
21
+ import { ApplicationNode } from "@spine-event-engine/deployment";
22
+ import { CommandService, QueryService, SubscriptionService, } from "@spine-event-engine/proto/client";
23
+ import { Server, serverBuilderAccess } from "../server/server.js";
24
+ import { attachDurableSubscriptionCleanup, isDurableSubscriptionBindings, } from "./durable-subscription-bindings.js";
25
+ import reservedSpineRpcPaths from "../server/reserved-spine-rpc-paths.json" with { type: "json" };
26
+ import { Environment, EnvironmentType } from "../server/environment.js";
27
+ import { ProcessServerCoordinator } from "../server/process-server-coordinator.js";
28
+ import { ServerEnvironment } from "../server/server-environment.js";
29
+ const gracefulBrowserDrainMs = 100;
30
+ const reservedPathSet = new Set(reservedSpineRpcPaths);
31
+ /**
32
+ * Runs the private native endpoint behind one admitted browser listener.
33
+ *
34
+ * Hosts browser-facing Spine gateway routes independently from native server assembly.
35
+ */
36
+ export const browserServerImplementation = Object.freeze({
37
+ async open(native, input) {
38
+ const running = BrowserServerValues.running(native);
39
+ if (running !== undefined && !BrowserServerValues.isLoopback(running.host))
40
+ throw new Error("Combined browser server requires a loopback native listener.");
41
+ let options;
42
+ try {
43
+ options = BrowserServer.preflight(native === undefined ? "standalone" : "combined", input);
44
+ }
45
+ catch (error) {
46
+ await BrowserServerValues.rollback(error, running === undefined ? [] : [() => running.close()]);
47
+ throw error;
48
+ }
49
+ const origins = BrowserServer.origins(options.origins);
50
+ const authRoutes = BrowserServer.authRoutes(options.authRoutes);
51
+ const activeAuth = new Set();
52
+ const maxActiveAuthRequests = options.maxActiveAuthRequests ?? 64;
53
+ if (!Number.isSafeInteger(maxActiveAuthRequests) || maxActiveAuthRequests < 1)
54
+ throw new Error("Browser maxActiveAuthRequests must be a positive safe integer.");
55
+ let draining = false;
56
+ const backendBaseUrls = native === undefined
57
+ ? options.backend === undefined
58
+ ? []
59
+ : BrowserServer.backendUrls(BrowserServerValues.backendUrlsFor(options.backend))
60
+ : Array.isArray(native)
61
+ ? BrowserServer.backendUrls(native)
62
+ : [
63
+ typeof native === "string"
64
+ ? native
65
+ : BrowserServerValues.requiredRunning(running).baseUrl,
66
+ ];
67
+ const fixedNodes = backendBaseUrls.map((endpoint, index) => new ApplicationNode({ id: `fixed/${index.toString()}`, endpoint }));
68
+ let dynamic;
69
+ let stopDiscovery;
70
+ const forwarder = (dynamic = new DynamicUnaryForwarder({
71
+ create: async (node) => {
72
+ const manager = options.dynamicManagerFactory?.(node) ??
73
+ new Http2SessionManager(node.endpoint, undefined, node.tlsServerName === undefined ? undefined : { servername: node.tlsServerName });
74
+ const client = new NativeSubscriptionCreator(createGrpcTransport({
75
+ ...BrowserServer.dynamicTransportOptions(node),
76
+ sessionManager: manager,
77
+ }));
78
+ return {
79
+ forward: client.forward.bind(client),
80
+ subscribe: client.subscribe.bind(client),
81
+ activate: client.activate.bind(client),
82
+ cancel: client.cancel.bind(client),
83
+ dispose: client.dispose.bind(client),
84
+ close: async () => {
85
+ manager.abort();
86
+ },
87
+ };
88
+ },
89
+ }));
90
+ const creator = new DynamicSubscriptionCreator(dynamic);
91
+ const bindings = options.bindings ??
92
+ new InMemorySubscriptionBindings({
93
+ nextId: () => globalThis.crypto.randomUUID(),
94
+ dispose: (definition, signal) => creator.cancel({ wire: definition }, signal),
95
+ });
96
+ const requests = BrowserServer.requests(options);
97
+ const admission = options.publicAccess === true
98
+ ? { publicAccess: true }
99
+ : { sessions: options.sessions };
100
+ const unary = new UnaryGateway({
101
+ ...(options.registry === undefined ? {} : { registry: options.registry }),
102
+ maxRequestBytes: 1_048_576,
103
+ ...admission,
104
+ authorize: options.authorize,
105
+ contexts: options.contexts,
106
+ clock: options.clock,
107
+ forward: forwarder.forward.bind(forwarder),
108
+ });
109
+ const subscriptions = new SubscriptionGateway({
110
+ bindings,
111
+ ...admission,
112
+ authorize: options.authorize,
113
+ contexts: options.contexts,
114
+ clock: options.clock,
115
+ creator,
116
+ });
117
+ try {
118
+ if (options.discovery !== undefined)
119
+ stopDiscovery = await BrowserServerValues.watch(options.discovery, dynamic);
120
+ else
121
+ await dynamic.reconcile(fixedNodes);
122
+ if (isDurableSubscriptionBindings(bindings))
123
+ attachDurableSubscriptionCleanup(bindings, (definition, signal) => creator.cancel({ wire: definition }, signal));
124
+ const durableBindings = bindings;
125
+ if (durableBindings.recoverActive !== undefined) {
126
+ const now = options.clock.now();
127
+ const nowMs = Number(now.seconds.toString()) * 1_000 +
128
+ Math.floor(Number(now.nanos.toString()) / 1_000_000);
129
+ if (Number.isSafeInteger(nowMs))
130
+ await durableBindings.recoverActive({
131
+ nowMs,
132
+ onDefinition: async (definition, whenExpires) => {
133
+ await creator.rehydrate(definition);
134
+ subscriptions.scheduleExpiry(whenExpires);
135
+ },
136
+ });
137
+ }
138
+ }
139
+ catch (error) {
140
+ const failures = [error];
141
+ for (const cleanup of [
142
+ () => subscriptions.close(),
143
+ () => stopDiscovery?.(),
144
+ () => dynamic.close(),
145
+ () => running?.close(),
146
+ ])
147
+ try {
148
+ await cleanup();
149
+ }
150
+ catch (cleanupError) {
151
+ failures.push(cleanupError);
152
+ }
153
+ if (failures.length === 1)
154
+ throw error;
155
+ throw new AggregateError(failures, "Browser subscription recovery startup rollback failed.");
156
+ }
157
+ const services = createNativeGatewayServices({ unary, subscriptions, requests });
158
+ const handler = connectNodeAdapter({
159
+ routes: (router) => {
160
+ router.service(AuthenticationService, services.authentication);
161
+ router.service(CommandService, services.command);
162
+ router.service(QueryService, services.query);
163
+ router.service(SubscriptionService, services.subscription);
164
+ },
165
+ readMaxBytes: options.readMaxBytes,
166
+ writeMaxBytes: options.writeMaxBytes,
167
+ });
168
+ const server = http.createServer((request, response) => {
169
+ if (draining) {
170
+ response.statusCode = 503;
171
+ response.end();
172
+ return;
173
+ }
174
+ const path = request.url ?? "";
175
+ const auth = authRoutes.get(path);
176
+ if (auth !== undefined && request.method === auth.method) {
177
+ if (activeAuth.size >= maxActiveAuthRequests) {
178
+ response.statusCode = 503;
179
+ response.end();
180
+ return;
181
+ }
182
+ void BrowserServer.dispatchAuth(request, response, auth, activeAuth, options.writeMaxBytes);
183
+ return;
184
+ }
185
+ if (auth !== undefined) {
186
+ const origin = request.headers.origin;
187
+ if (request.method === "OPTIONS" && origin !== undefined && auth.origins.includes(origin)) {
188
+ response.setHeader("access-control-allow-origin", origin);
189
+ response.setHeader("access-control-allow-methods", `${auth.method},OPTIONS`);
190
+ response.statusCode = 204;
191
+ }
192
+ else
193
+ response.statusCode = request.method === "OPTIONS" ? 403 : 405;
194
+ response.end();
195
+ return;
196
+ }
197
+ const origin = request.headers.origin;
198
+ if (origin === undefined || !origins.has(origin)) {
199
+ response.statusCode = 403;
200
+ response.end();
201
+ return;
202
+ }
203
+ response.setHeader("access-control-allow-origin", origin);
204
+ response.setHeader("access-control-allow-credentials", "true");
205
+ response.setHeader("access-control-expose-headers", "grpc-status,grpc-message");
206
+ response.setHeader("vary", "Origin");
207
+ if (request.method === "OPTIONS") {
208
+ response.setHeader("access-control-allow-methods", "POST,OPTIONS");
209
+ response.setHeader("access-control-allow-headers", "authorization,content-type,connect-protocol-version,x-csrf-token");
210
+ response.setHeader("access-control-max-age", "600");
211
+ response.statusCode = 204;
212
+ response.end();
213
+ return;
214
+ }
215
+ handler(request, response);
216
+ });
217
+ let address;
218
+ try {
219
+ address = await BrowserServer.listen(server, options.host, options.port);
220
+ }
221
+ catch (error) {
222
+ const cleanup = await Promise.allSettled([
223
+ subscriptions.close(),
224
+ stopDiscovery?.(),
225
+ dynamic.close(),
226
+ BrowserServer.closeListener(server),
227
+ running?.close(),
228
+ ]);
229
+ const failures = cleanup.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
230
+ if (failures.length > 0)
231
+ throw new AggregateError([error, ...failures], "Server browser startup rollback failed.");
232
+ throw error;
233
+ }
234
+ return new RunningBrowserServer(server, running, subscriptions, address, activeAuth, () => {
235
+ draining = true;
236
+ }, stopDiscovery, dynamic);
237
+ },
238
+ async run(nativeOrOptions, suppliedOptions) {
239
+ const options = suppliedOptions ?? nativeOrOptions;
240
+ if (nativeOrOptions instanceof Server) {
241
+ if (!serverBuilderAccess.isLoopback(nativeOrOptions))
242
+ throw new Error("Combined browser server requires a loopback native listener.");
243
+ BrowserServer.preflight("combined", options);
244
+ }
245
+ else
246
+ BrowserServer.preflight("standalone", options);
247
+ const native = nativeOrOptions instanceof Server ? await nativeOrOptions.start() : undefined;
248
+ const running = native === undefined
249
+ ? await BrowserServer.open(undefined, options)
250
+ : await BrowserServer.open(native, options);
251
+ return ProcessServerCoordinator.add(running, native === undefined ? undefined : ServerEnvironment.instance(), undefined, () => undefined);
252
+ },
253
+ preflight(mode, input) {
254
+ const options = {
255
+ ...input,
256
+ host: input.host ?? "127.0.0.1",
257
+ port: input.port ?? 0,
258
+ readMaxBytes: input.readMaxBytes ?? 4_194_304,
259
+ writeMaxBytes: input.writeMaxBytes ?? 4_194_304,
260
+ production: Environment.instance().type === EnvironmentType.Production,
261
+ };
262
+ if (!options.host.trim())
263
+ throw new Error("Browser server host must not be blank.");
264
+ if (!Number.isInteger(options.port) || options.port < 0 || options.port > 65_535)
265
+ throw new Error("Browser server port must be an integer from 0 through 65535.");
266
+ if (!Number.isInteger(options.readMaxBytes) || options.readMaxBytes < 1)
267
+ throw new Error("Browser server readMaxBytes must be a positive integer.");
268
+ if (!Number.isInteger(options.writeMaxBytes) || options.writeMaxBytes < 1)
269
+ throw new Error("Browser server writeMaxBytes must be a positive integer.");
270
+ if (mode === "standalone" && options.backend === undefined && options.discovery === undefined)
271
+ throw new Error("Standalone browser server requires a backend or discovery.");
272
+ BrowserServer.requireDurableBindings(options, options.production);
273
+ BrowserServer.origins(options.origins);
274
+ BrowserServer.authRoutes(options.authRoutes);
275
+ const capacity = options.maxActiveAuthRequests ?? 64;
276
+ if (!Number.isSafeInteger(capacity) || capacity < 1)
277
+ throw new Error("Browser maxActiveAuthRequests must be a positive safe integer.");
278
+ return options;
279
+ },
280
+ requests(options) {
281
+ return {
282
+ credential: (context) => {
283
+ const headers = Object.fromEntries(context.requestHeader.entries());
284
+ const extracted = options.cookies?.extract(headers);
285
+ if (extracted !== undefined) {
286
+ return extracted.kind === "rejected" ? { kind: "bearer", value: "" } : extracted;
287
+ }
288
+ const authorization = context.requestHeader.get("authorization") ?? "";
289
+ return /^Bearer [^\s]+$/.test(authorization)
290
+ ? { kind: "bearer", value: authorization.slice("Bearer ".length) }
291
+ : undefined;
292
+ },
293
+ transport: (context) => {
294
+ const origin = context.requestHeader.get("origin");
295
+ return TransportFacts.from({
296
+ service: "browser",
297
+ method: "gateway",
298
+ ...(origin === null ? {} : { origin }),
299
+ headers: Object.fromEntries(context.requestHeader.entries()),
300
+ });
301
+ },
302
+ };
303
+ },
304
+ origins(values) {
305
+ const origins = new Set(values.map((value) => {
306
+ let origin;
307
+ try {
308
+ origin = new URL(value);
309
+ }
310
+ catch {
311
+ throw new Error("Server browser origins must be canonical HTTP(S) origins.");
312
+ }
313
+ if ((origin.protocol !== "http:" && origin.protocol !== "https:") ||
314
+ origin.origin !== value ||
315
+ origin.pathname !== "/" ||
316
+ origin.search ||
317
+ origin.hash) {
318
+ throw new Error("Server browser origins must be canonical HTTP(S) origins.");
319
+ }
320
+ return value;
321
+ }));
322
+ if (origins.size === 0 || origins.size !== values.length)
323
+ throw new Error("Server browser origins must be unique and non-empty.");
324
+ return origins;
325
+ },
326
+ backendUrl(value) {
327
+ let backend;
328
+ try {
329
+ backend = new URL(value);
330
+ }
331
+ catch {
332
+ throw new Error("Server browser backend must be a canonical HTTP(S) origin.");
333
+ }
334
+ if ((backend.protocol !== "http:" && backend.protocol !== "https:") ||
335
+ backend.origin !== value ||
336
+ backend.pathname !== "/" ||
337
+ backend.search ||
338
+ backend.hash ||
339
+ backend.username ||
340
+ backend.password) {
341
+ throw new Error("Server browser backend must be a canonical HTTP(S) origin.");
342
+ }
343
+ return value;
344
+ },
345
+ backendUrls(values) {
346
+ if (values.length < 1)
347
+ throw new Error("Server browser backends must contain at least one origin.");
348
+ const urls = values.map((value) => BrowserServer.backendUrl(value));
349
+ if (new Set(urls).size !== urls.length)
350
+ throw new Error("Server browser backends must be unique canonical HTTP(S) origins.");
351
+ return urls;
352
+ },
353
+ dynamicTransportOptions(node) {
354
+ return {
355
+ baseUrl: node.endpoint,
356
+ ...(node.tlsServerName === undefined
357
+ ? {}
358
+ : { nodeOptions: { servername: node.tlsServerName } }),
359
+ };
360
+ },
361
+ requireDurableBindings(options, production) {
362
+ const supplied = options;
363
+ const standalone = options.backend !== undefined || options.discovery !== undefined;
364
+ if (options.backend !== undefined) {
365
+ BrowserServer.backendUrls(BrowserServerValues.backendUrlsFor(options.backend));
366
+ }
367
+ if (standalone) {
368
+ if ((supplied.sessions === undefined) === (options.publicAccess !== true))
369
+ throw new Error("Standalone browser server requires exactly one of sessions or publicAccess.");
370
+ if (supplied.sessions !== undefined && typeof supplied.sessions.resolve !== "function")
371
+ throw new Error("Standalone browser server requires sessions with a resolver.");
372
+ if (typeof options.authorize !== "function")
373
+ throw new Error("Standalone browser server requires authorization.");
374
+ if (supplied.contexts === undefined ||
375
+ typeof supplied.contexts.resolve !== "function" ||
376
+ typeof supplied.contexts.resolveContext !== "function")
377
+ throw new Error("Standalone browser server requires context resolution.");
378
+ if (supplied.clock === undefined || typeof supplied.clock.now !== "function")
379
+ throw new Error("Standalone browser server requires a clock.");
380
+ if (options.bindings === undefined && options.publicAccess !== true)
381
+ throw new Error("Standalone browser server requires explicit subscription bindings.");
382
+ }
383
+ if (supplied.publicAccess === true && supplied.bindings !== undefined)
384
+ throw new Error("Public browser access owns process-local subscription bindings.");
385
+ if (standalone && production && options.registry === undefined)
386
+ throw new Error("Production standalone browser server requires a type registry.");
387
+ const bindings = options.bindings;
388
+ if (production && options.publicAccess !== true && !isDurableSubscriptionBindings(bindings))
389
+ throw new Error("Production browser server requires durable subscription bindings.");
390
+ if (standalone &&
391
+ options.publicAccess !== true &&
392
+ production &&
393
+ (bindings === undefined ||
394
+ !("namespace" in bindings) ||
395
+ typeof bindings.namespace !== "string" ||
396
+ !bindings.namespace.trim()))
397
+ throw new Error("Production standalone browser server requires named durable subscription bindings.");
398
+ },
399
+ authRoutes(routes) {
400
+ const result = new Map();
401
+ for (const route of routes ?? []) {
402
+ const method = route.method;
403
+ if (method !== "GET" && method !== "POST")
404
+ throw new Error("Browser auth routes must use GET or POST.");
405
+ if (reservedPathSet.has(route.path))
406
+ throw new Error("Browser auth routes must not use reserved Spine RPC paths.");
407
+ if (!/^\/(?!\/)(?:[A-Za-z0-9_-]+\/)*[A-Za-z0-9_-]+$/.test(route.path))
408
+ throw new Error("Browser auth routes must use exact canonical non-root paths.");
409
+ if (!Number.isSafeInteger(route.maxRequestBytes) ||
410
+ route.maxRequestBytes <= 0 ||
411
+ route.maxRequestBytes > 4_194_304)
412
+ throw new Error("Browser auth route maxRequestBytes must be a positive safe transport bound.");
413
+ if (!Number.isSafeInteger(route.timeoutMs) ||
414
+ route.timeoutMs < 1 ||
415
+ route.timeoutMs > 2_147_483_647)
416
+ throw new Error("Browser auth route timeoutMs must be a safe positive millisecond duration.");
417
+ BrowserServer.origins(route.origins);
418
+ if (result.has(route.path))
419
+ throw new Error("Browser auth routes must use one method per canonical path.");
420
+ result.set(route.path, route);
421
+ }
422
+ return result;
423
+ },
424
+ async dispatchAuth(request, response, route, active, writeMaxBytes) {
425
+ const origin = request.headers.origin;
426
+ if ((origin === undefined && route.allowMissingOrigin !== true) ||
427
+ (origin !== undefined && !route.origins.includes(origin))) {
428
+ response.statusCode = 403;
429
+ response.end();
430
+ return;
431
+ }
432
+ const length = request.headers["content-length"];
433
+ if (length !== undefined && (!/^\d+$/.test(length) || Number(length) > route.maxRequestBytes)) {
434
+ response.statusCode = 413;
435
+ response.end();
436
+ return;
437
+ }
438
+ const controller = new AbortController();
439
+ active.add(controller);
440
+ const timer = setTimeout(() => {
441
+ controller.abort();
442
+ request.resume();
443
+ }, route.timeoutMs);
444
+ const abort = () => {
445
+ controller.abort();
446
+ };
447
+ request.once("aborted", abort);
448
+ response.once("close", abort);
449
+ let rejectAbort;
450
+ const aborted = new Promise((_resolve, reject) => {
451
+ rejectAbort = reject;
452
+ });
453
+ let responseReader;
454
+ const onAbort = () => {
455
+ rejectAbort(new Error("browser auth request aborted"));
456
+ void responseReader?.cancel().catch(() => undefined);
457
+ };
458
+ controller.signal.addEventListener("abort", onAbort, { once: true });
459
+ try {
460
+ const requestChunks = [];
461
+ let size = 0;
462
+ const requestBody = request[Symbol.asyncIterator]();
463
+ for (;;) {
464
+ const next = await Promise.race([requestBody.next(), aborted]);
465
+ if (next.done)
466
+ break;
467
+ const bytes = Buffer.from(next.value);
468
+ size += bytes.byteLength;
469
+ if (size > route.maxRequestBytes) {
470
+ response.statusCode = 413;
471
+ response.end();
472
+ return;
473
+ }
474
+ requestChunks.push(bytes);
475
+ }
476
+ const url = new URL(request.url ?? route.path, `http://${request.headers.host ?? "localhost"}`);
477
+ const input = new Request(url, {
478
+ method: route.method,
479
+ headers: request.headers,
480
+ ...(size === 0 ? {} : { body: Buffer.concat(requestChunks) }),
481
+ signal: controller.signal,
482
+ });
483
+ const result = await Promise.race([route.onRequest(input, controller.signal), aborted]);
484
+ if (controller.signal.aborted) {
485
+ if (!response.writableEnded) {
486
+ response.statusCode = 504;
487
+ response.end();
488
+ }
489
+ return;
490
+ }
491
+ responseReader = result.body?.getReader();
492
+ const responseChunks = [];
493
+ let responseBytes = 0;
494
+ if (responseReader !== undefined) {
495
+ for (;;) {
496
+ const next = await Promise.race([responseReader.read(), aborted]);
497
+ if (next.done)
498
+ break;
499
+ responseBytes += next.value.byteLength;
500
+ if (responseBytes > writeMaxBytes) {
501
+ await responseReader.cancel().catch(() => undefined);
502
+ response.statusCode = 413;
503
+ response.end();
504
+ return;
505
+ }
506
+ responseChunks.push(next.value);
507
+ }
508
+ }
509
+ response.statusCode = result.status;
510
+ result.headers.forEach((value, key) => response.setHeader(key, value));
511
+ response.end(Buffer.concat(responseChunks));
512
+ }
513
+ catch {
514
+ if (!response.writableEnded) {
515
+ if (controller.signal.aborted) {
516
+ response.shouldKeepAlive = false;
517
+ response.setHeader("connection", "close");
518
+ }
519
+ response.statusCode = controller.signal.aborted ? 504 : 500;
520
+ response.end();
521
+ }
522
+ }
523
+ finally {
524
+ clearTimeout(timer);
525
+ request.off("aborted", abort);
526
+ response.off("close", abort);
527
+ controller.signal.removeEventListener("abort", onAbort);
528
+ active.delete(controller);
529
+ }
530
+ },
531
+ listen(server, host, port) {
532
+ return new Promise((resolve, reject) => {
533
+ const onError = (error) => {
534
+ reject(error);
535
+ };
536
+ server.once("error", onError);
537
+ server.listen(port, host, () => {
538
+ server.off("error", onError);
539
+ resolve(server.address());
540
+ });
541
+ });
542
+ },
543
+ closeListener(server) {
544
+ return new Promise((resolve, reject) => {
545
+ if (!server.listening) {
546
+ resolve();
547
+ return;
548
+ }
549
+ const timer = setTimeout(() => {
550
+ server.closeAllConnections();
551
+ }, gracefulBrowserDrainMs);
552
+ timer.unref();
553
+ server.close((error) => {
554
+ clearTimeout(timer);
555
+ if (error === undefined)
556
+ resolve();
557
+ else
558
+ reject(error);
559
+ });
560
+ });
561
+ },
562
+ });
563
+ /**
564
+ * Provides the internal white-box browser-host seam for source-level behavior tests.
565
+ *
566
+ * @internal
567
+ */
568
+ export const browserServerTestAccess = Object.freeze({
569
+ ...browserServerImplementation,
570
+ });
571
+ const BrowserServer = browserServerImplementation;
572
+ const BrowserServerValues = Object.freeze({
573
+ async watch(source, forwarder) {
574
+ return await source.watch((nodes) => {
575
+ void forwarder.reconcile(nodes);
576
+ });
577
+ },
578
+ requiredRunning(value) {
579
+ if (value === undefined)
580
+ throw new Error("Browser server local backend is absent.");
581
+ return value;
582
+ },
583
+ isLoopback(host) {
584
+ if (host === "::1" || host === "::ffff:127.0.0.1")
585
+ return true;
586
+ const match = /^127\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/u.exec(host);
587
+ return match?.slice(1).every((part) => Number(part) <= 255) === true;
588
+ },
589
+ async rollback(error, cleanups) {
590
+ const failures = [error];
591
+ for (const cleanup of cleanups)
592
+ try {
593
+ await cleanup();
594
+ }
595
+ catch (cleanupError) {
596
+ failures.push(cleanupError);
597
+ }
598
+ if (failures.length === 1)
599
+ throw error;
600
+ throw new AggregateError(failures, "Browser server startup rollback failed.");
601
+ },
602
+ firstCreator(values) {
603
+ const creator = values[0];
604
+ if (creator === undefined)
605
+ throw new Error("Browser server backend is absent.");
606
+ return creator;
607
+ },
608
+ running(native) {
609
+ return native === undefined || typeof native === "string" || Array.isArray(native)
610
+ ? undefined
611
+ : native;
612
+ },
613
+ backendUrlsFor(backend) {
614
+ const source = backend;
615
+ if (typeof source.baseUrl === "string" && source.baseUrls === undefined)
616
+ return [source.baseUrl];
617
+ if (source.baseUrl === undefined && Array.isArray(source.baseUrls)) {
618
+ const values = source.baseUrls;
619
+ if (values.some((value) => typeof value !== "string"))
620
+ throw new Error("Server browser backend URLs must be strings.");
621
+ return values;
622
+ }
623
+ throw new Error("Server browser backend must configure exactly one of baseUrl or baseUrls.");
624
+ },
625
+ });
626
+ class RunningBrowserServer {
627
+ #server;
628
+ #subscriptions;
629
+ #native;
630
+ #activeAuth;
631
+ #onDrain;
632
+ #stopDiscovery;
633
+ #dynamic;
634
+ host;
635
+ port;
636
+ baseUrl;
637
+ #closed;
638
+ #listenerClose;
639
+ #listenerClosed = false;
640
+ #subscriptionsClosed = false;
641
+ #discoveryStopped = false;
642
+ #dynamicClosed = false;
643
+ #nativeClosed = false;
644
+ constructor(server, native, subscriptions, address, activeAuth, onDrain, stopDiscovery, dynamic) {
645
+ this.#server = server;
646
+ this.#native = native;
647
+ this.#subscriptions = subscriptions;
648
+ this.#activeAuth = activeAuth;
649
+ this.#onDrain = onDrain;
650
+ this.#stopDiscovery = stopDiscovery;
651
+ this.#dynamic = dynamic;
652
+ this.host = typeof address.address === "string" ? address.address : "127.0.0.1";
653
+ this.port = address.port;
654
+ const host = this.host.includes(":") && !this.host.startsWith("[") ? `[${this.host}]` : this.host;
655
+ this.baseUrl = `http://${host}:${this.port.toString()}`;
656
+ }
657
+ close() {
658
+ this.#closed ??= this.#closeOnce().catch((error) => {
659
+ this.#closed = undefined;
660
+ throw error;
661
+ });
662
+ return this.#closed;
663
+ }
664
+ async #closeOnce() {
665
+ this.#onDrain();
666
+ for (const controller of this.#activeAuth)
667
+ controller.abort();
668
+ const listener = this.#listenerClosed ? undefined : this.#closeListenerPhase();
669
+ const failures = [];
670
+ await this.#phase(this.#subscriptionsClosed ? undefined : this.#subscriptions.close(), () => {
671
+ this.#subscriptionsClosed = true;
672
+ }, failures);
673
+ await this.#phase(this.#discoveryStopped ? undefined : this.#stopDiscovery?.(), () => {
674
+ this.#discoveryStopped = true;
675
+ }, failures);
676
+ await this.#phase(this.#dynamicClosed ? undefined : this.#dynamic?.close(), () => {
677
+ this.#dynamicClosed = true;
678
+ }, failures);
679
+ await this.#phase(listener, () => {
680
+ this.#listenerClosed = true;
681
+ }, failures);
682
+ await this.#phase(this.#native === undefined || this.#nativeClosed ? undefined : this.#native.close(), () => {
683
+ this.#nativeClosed = true;
684
+ }, failures);
685
+ if (failures.length > 0) {
686
+ const reason = failures[0];
687
+ const primary = reason instanceof Error ? reason : new Error(String(reason));
688
+ if (failures.length > 1)
689
+ Object.defineProperty(primary, "cleanupErrors", { value: failures.slice(1) });
690
+ throw primary;
691
+ }
692
+ }
693
+ async #phase(operation, onSuccess, failures) {
694
+ if (operation === undefined)
695
+ return;
696
+ try {
697
+ await operation;
698
+ onSuccess();
699
+ }
700
+ catch (error) {
701
+ failures.push(error);
702
+ }
703
+ }
704
+ #closeListenerPhase() {
705
+ const current = this.#listenerClose;
706
+ if (current !== undefined)
707
+ return current;
708
+ const closing = BrowserServer.closeListener(this.#server);
709
+ this.#listenerClose = closing;
710
+ void closing.then(() => {
711
+ this.#listenerClosed = true;
712
+ this.#listenerClose = undefined;
713
+ }, () => {
714
+ this.#listenerClose = undefined;
715
+ });
716
+ return closing;
717
+ }
718
+ }
719
+ //# sourceMappingURL=browser-server.js.map