threadforge 0.1.1 → 0.2.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 (358) hide show
  1. package/README.md +52 -20
  2. package/bin/forge.js +2 -1058
  3. package/bin/host-commands.d.ts +2 -0
  4. package/bin/host-commands.d.ts.map +1 -0
  5. package/bin/host-commands.js +7 -8
  6. package/bin/platform-commands.d.ts +2 -0
  7. package/bin/platform-commands.d.ts.map +1 -0
  8. package/bin/platform-commands.js +118 -36
  9. package/dist/cli/base-command.d.ts +12 -0
  10. package/dist/cli/base-command.d.ts.map +1 -0
  11. package/dist/cli/base-command.js +25 -0
  12. package/dist/cli/base-command.js.map +1 -0
  13. package/dist/cli/commands/build.d.ts +10 -0
  14. package/dist/cli/commands/build.d.ts.map +1 -0
  15. package/dist/cli/commands/build.js +110 -0
  16. package/dist/cli/commands/build.js.map +1 -0
  17. package/dist/cli/commands/deploy.d.ts +12 -0
  18. package/dist/cli/commands/deploy.d.ts.map +1 -0
  19. package/dist/cli/commands/deploy.js +143 -0
  20. package/dist/cli/commands/deploy.js.map +1 -0
  21. package/dist/cli/commands/dev.d.ts +10 -0
  22. package/dist/cli/commands/dev.d.ts.map +1 -0
  23. package/dist/cli/commands/dev.js +138 -0
  24. package/dist/cli/commands/dev.js.map +1 -0
  25. package/dist/cli/commands/generate.d.ts +10 -0
  26. package/dist/cli/commands/generate.d.ts.map +1 -0
  27. package/dist/cli/commands/generate.js +76 -0
  28. package/dist/cli/commands/generate.js.map +1 -0
  29. package/dist/cli/commands/host.d.ts +8 -0
  30. package/dist/cli/commands/host.d.ts.map +1 -0
  31. package/dist/cli/commands/host.js +20 -0
  32. package/dist/cli/commands/host.js.map +1 -0
  33. package/dist/cli/commands/init.d.ts +16 -0
  34. package/dist/cli/commands/init.d.ts.map +1 -0
  35. package/dist/cli/commands/init.js +246 -0
  36. package/dist/cli/commands/init.js.map +1 -0
  37. package/dist/cli/commands/platform.d.ts +8 -0
  38. package/dist/cli/commands/platform.d.ts.map +1 -0
  39. package/dist/cli/commands/platform.js +20 -0
  40. package/dist/cli/commands/platform.js.map +1 -0
  41. package/dist/cli/commands/restart.d.ts +8 -0
  42. package/dist/cli/commands/restart.d.ts.map +1 -0
  43. package/dist/cli/commands/restart.js +13 -0
  44. package/dist/cli/commands/restart.js.map +1 -0
  45. package/dist/cli/commands/scaffold/frontend.d.ts +10 -0
  46. package/dist/cli/commands/scaffold/frontend.d.ts.map +1 -0
  47. package/dist/cli/commands/scaffold/frontend.js +130 -0
  48. package/dist/cli/commands/scaffold/frontend.js.map +1 -0
  49. package/dist/cli/commands/scaffold/react.d.ts +7 -0
  50. package/dist/cli/commands/scaffold/react.d.ts.map +1 -0
  51. package/dist/cli/commands/scaffold/react.js +12 -0
  52. package/dist/cli/commands/scaffold/react.js.map +1 -0
  53. package/dist/cli/commands/scale.d.ts +8 -0
  54. package/dist/cli/commands/scale.d.ts.map +1 -0
  55. package/dist/cli/commands/scale.js +13 -0
  56. package/dist/cli/commands/scale.js.map +1 -0
  57. package/dist/cli/commands/start.d.ts +10 -0
  58. package/dist/cli/commands/start.d.ts.map +1 -0
  59. package/dist/cli/commands/start.js +71 -0
  60. package/dist/cli/commands/start.js.map +1 -0
  61. package/dist/cli/commands/status.d.ts +11 -0
  62. package/dist/cli/commands/status.d.ts.map +1 -0
  63. package/dist/cli/commands/status.js +60 -0
  64. package/dist/cli/commands/status.js.map +1 -0
  65. package/dist/cli/commands/stop.d.ts +10 -0
  66. package/dist/cli/commands/stop.d.ts.map +1 -0
  67. package/dist/cli/commands/stop.js +89 -0
  68. package/dist/cli/commands/stop.js.map +1 -0
  69. package/dist/cli/util/config-discovery.d.ts +8 -0
  70. package/dist/cli/util/config-discovery.d.ts.map +1 -0
  71. package/dist/cli/util/config-discovery.js +70 -0
  72. package/dist/cli/util/config-discovery.js.map +1 -0
  73. package/dist/cli/util/config-patcher.d.ts +17 -0
  74. package/dist/cli/util/config-patcher.d.ts.map +1 -0
  75. package/dist/cli/util/config-patcher.js +439 -0
  76. package/dist/cli/util/config-patcher.js.map +1 -0
  77. package/dist/cli/util/frontend-dev.d.ts +8 -0
  78. package/dist/cli/util/frontend-dev.d.ts.map +1 -0
  79. package/dist/cli/util/frontend-dev.js +117 -0
  80. package/dist/cli/util/frontend-dev.js.map +1 -0
  81. package/dist/cli/util/process.d.ts +5 -0
  82. package/dist/cli/util/process.d.ts.map +1 -0
  83. package/dist/cli/util/process.js +17 -0
  84. package/dist/cli/util/process.js.map +1 -0
  85. package/dist/cli/util/templates.d.ts +10 -0
  86. package/dist/cli/util/templates.d.ts.map +1 -0
  87. package/dist/cli/util/templates.js +157 -0
  88. package/dist/cli/util/templates.js.map +1 -0
  89. package/dist/core/AlertSink.d.ts +83 -0
  90. package/dist/core/AlertSink.d.ts.map +1 -0
  91. package/dist/core/AlertSink.js +126 -0
  92. package/dist/core/AlertSink.js.map +1 -0
  93. package/dist/core/DirectMessageBus.d.ts +88 -0
  94. package/dist/core/DirectMessageBus.d.ts.map +1 -0
  95. package/dist/core/DirectMessageBus.js +352 -0
  96. package/dist/core/DirectMessageBus.js.map +1 -0
  97. package/dist/core/EndpointResolver.d.ts +111 -0
  98. package/dist/core/EndpointResolver.d.ts.map +1 -0
  99. package/dist/core/EndpointResolver.js +336 -0
  100. package/dist/core/EndpointResolver.js.map +1 -0
  101. package/dist/core/ForgeContext.d.ts +221 -0
  102. package/dist/core/ForgeContext.d.ts.map +1 -0
  103. package/dist/core/ForgeContext.js +1169 -0
  104. package/dist/core/ForgeContext.js.map +1 -0
  105. package/dist/core/ForgeEndpoints.d.ts +71 -0
  106. package/dist/core/ForgeEndpoints.d.ts.map +1 -0
  107. package/dist/core/ForgeEndpoints.js +442 -0
  108. package/dist/core/ForgeEndpoints.js.map +1 -0
  109. package/dist/core/ForgeHost.d.ts +82 -0
  110. package/dist/core/ForgeHost.d.ts.map +1 -0
  111. package/dist/core/ForgeHost.js +107 -0
  112. package/dist/core/ForgeHost.js.map +1 -0
  113. package/dist/core/ForgePlatform.d.ts +96 -0
  114. package/dist/core/ForgePlatform.d.ts.map +1 -0
  115. package/dist/core/ForgePlatform.js +136 -0
  116. package/dist/core/ForgePlatform.js.map +1 -0
  117. package/dist/core/ForgeWebSocket.d.ts +56 -0
  118. package/dist/core/ForgeWebSocket.d.ts.map +1 -0
  119. package/dist/core/ForgeWebSocket.js +415 -0
  120. package/dist/core/ForgeWebSocket.js.map +1 -0
  121. package/dist/core/Ingress.d.ts +329 -0
  122. package/dist/core/Ingress.d.ts.map +1 -0
  123. package/dist/core/Ingress.js +694 -0
  124. package/dist/core/Ingress.js.map +1 -0
  125. package/dist/core/Interceptors.d.ts +134 -0
  126. package/dist/core/Interceptors.d.ts.map +1 -0
  127. package/dist/core/Interceptors.js +416 -0
  128. package/dist/core/Interceptors.js.map +1 -0
  129. package/dist/core/Logger.d.ts +20 -0
  130. package/dist/core/Logger.d.ts.map +1 -0
  131. package/dist/core/Logger.js +77 -0
  132. package/dist/core/Logger.js.map +1 -0
  133. package/dist/core/MessageBus.d.ts +15 -0
  134. package/dist/core/MessageBus.d.ts.map +1 -0
  135. package/dist/core/MessageBus.js +18 -0
  136. package/dist/core/MessageBus.js.map +1 -0
  137. package/dist/core/Prometheus.d.ts +80 -0
  138. package/dist/core/Prometheus.d.ts.map +1 -0
  139. package/dist/core/Prometheus.js +332 -0
  140. package/dist/core/Prometheus.js.map +1 -0
  141. package/dist/core/RequestContext.d.ts +214 -0
  142. package/dist/core/RequestContext.d.ts.map +1 -0
  143. package/dist/core/RequestContext.js +556 -0
  144. package/dist/core/RequestContext.js.map +1 -0
  145. package/dist/core/Router.d.ts +45 -0
  146. package/dist/core/Router.d.ts.map +1 -0
  147. package/dist/core/Router.js +285 -0
  148. package/dist/core/Router.js.map +1 -0
  149. package/dist/core/RoutingStrategy.d.ts +116 -0
  150. package/dist/core/RoutingStrategy.d.ts.map +1 -0
  151. package/dist/core/RoutingStrategy.js +306 -0
  152. package/dist/core/RoutingStrategy.js.map +1 -0
  153. package/dist/core/RpcConfig.d.ts +72 -0
  154. package/dist/core/RpcConfig.d.ts.map +1 -0
  155. package/dist/core/RpcConfig.js +127 -0
  156. package/dist/core/RpcConfig.js.map +1 -0
  157. package/dist/core/SignatureCache.d.ts +81 -0
  158. package/dist/core/SignatureCache.d.ts.map +1 -0
  159. package/dist/core/SignatureCache.js +172 -0
  160. package/dist/core/SignatureCache.js.map +1 -0
  161. package/dist/core/StaticFileServer.d.ts +34 -0
  162. package/dist/core/StaticFileServer.d.ts.map +1 -0
  163. package/dist/core/StaticFileServer.js +497 -0
  164. package/dist/core/StaticFileServer.js.map +1 -0
  165. package/dist/core/Supervisor.d.ts +198 -0
  166. package/dist/core/Supervisor.d.ts.map +1 -0
  167. package/dist/core/Supervisor.js +1418 -0
  168. package/dist/core/Supervisor.js.map +1 -0
  169. package/dist/core/ThreadAllocator.d.ts +52 -0
  170. package/dist/core/ThreadAllocator.d.ts.map +1 -0
  171. package/dist/core/ThreadAllocator.js +174 -0
  172. package/dist/core/ThreadAllocator.js.map +1 -0
  173. package/dist/core/WorkerChannelManager.d.ts +130 -0
  174. package/dist/core/WorkerChannelManager.d.ts.map +1 -0
  175. package/dist/core/WorkerChannelManager.js +956 -0
  176. package/dist/core/WorkerChannelManager.js.map +1 -0
  177. package/dist/core/config-enums.d.ts +41 -0
  178. package/dist/core/config-enums.d.ts.map +1 -0
  179. package/dist/core/config-enums.js +59 -0
  180. package/dist/core/config-enums.js.map +1 -0
  181. package/dist/core/config.d.ts +159 -0
  182. package/dist/core/config.d.ts.map +1 -0
  183. package/dist/core/config.js +694 -0
  184. package/dist/core/config.js.map +1 -0
  185. package/dist/core/host-config.d.ts +146 -0
  186. package/dist/core/host-config.d.ts.map +1 -0
  187. package/dist/core/host-config.js +312 -0
  188. package/dist/core/host-config.js.map +1 -0
  189. package/dist/core/ipc-errors.d.ts +27 -0
  190. package/dist/core/ipc-errors.d.ts.map +1 -0
  191. package/dist/core/ipc-errors.js +36 -0
  192. package/dist/core/ipc-errors.js.map +1 -0
  193. package/dist/core/network-utils.d.ts +35 -0
  194. package/dist/core/network-utils.d.ts.map +1 -0
  195. package/dist/core/network-utils.js +145 -0
  196. package/dist/core/network-utils.js.map +1 -0
  197. package/dist/core/platform-config.d.ts +142 -0
  198. package/dist/core/platform-config.d.ts.map +1 -0
  199. package/dist/core/platform-config.js +299 -0
  200. package/dist/core/platform-config.js.map +1 -0
  201. package/dist/decorators/ServiceProxy.d.ts +175 -0
  202. package/dist/decorators/ServiceProxy.d.ts.map +1 -0
  203. package/dist/decorators/ServiceProxy.js +969 -0
  204. package/dist/decorators/ServiceProxy.js.map +1 -0
  205. package/dist/decorators/index.d.ts +146 -0
  206. package/dist/decorators/index.d.ts.map +1 -0
  207. package/dist/decorators/index.js +545 -0
  208. package/dist/decorators/index.js.map +1 -0
  209. package/dist/deploy/NginxGenerator.d.ts +165 -0
  210. package/dist/deploy/NginxGenerator.d.ts.map +1 -0
  211. package/dist/deploy/NginxGenerator.js +781 -0
  212. package/dist/deploy/NginxGenerator.js.map +1 -0
  213. package/dist/deploy/PlatformManifestGenerator.d.ts +43 -0
  214. package/dist/deploy/PlatformManifestGenerator.d.ts.map +1 -0
  215. package/dist/deploy/PlatformManifestGenerator.js +80 -0
  216. package/dist/deploy/PlatformManifestGenerator.js.map +1 -0
  217. package/dist/deploy/RouteManifestGenerator.d.ts +42 -0
  218. package/dist/deploy/RouteManifestGenerator.d.ts.map +1 -0
  219. package/dist/deploy/RouteManifestGenerator.js +105 -0
  220. package/dist/deploy/RouteManifestGenerator.js.map +1 -0
  221. package/dist/deploy/index.d.ts +210 -0
  222. package/dist/deploy/index.d.ts.map +1 -0
  223. package/dist/deploy/index.js +918 -0
  224. package/dist/deploy/index.js.map +1 -0
  225. package/dist/frontend/FrontendDevLifecycle.d.ts +26 -0
  226. package/dist/frontend/FrontendDevLifecycle.d.ts.map +1 -0
  227. package/dist/frontend/FrontendDevLifecycle.js +60 -0
  228. package/dist/frontend/FrontendDevLifecycle.js.map +1 -0
  229. package/dist/frontend/FrontendPluginOrchestrator.d.ts +64 -0
  230. package/dist/frontend/FrontendPluginOrchestrator.d.ts.map +1 -0
  231. package/dist/frontend/FrontendPluginOrchestrator.js +167 -0
  232. package/dist/frontend/FrontendPluginOrchestrator.js.map +1 -0
  233. package/dist/frontend/SiteResolver.d.ts +33 -0
  234. package/dist/frontend/SiteResolver.d.ts.map +1 -0
  235. package/dist/frontend/SiteResolver.js +53 -0
  236. package/dist/frontend/SiteResolver.js.map +1 -0
  237. package/dist/frontend/StaticMountRegistry.d.ts +36 -0
  238. package/dist/frontend/StaticMountRegistry.d.ts.map +1 -0
  239. package/dist/frontend/StaticMountRegistry.js +94 -0
  240. package/dist/frontend/StaticMountRegistry.js.map +1 -0
  241. package/dist/frontend/index.d.ts +7 -0
  242. package/dist/frontend/index.d.ts.map +1 -0
  243. package/{src → dist}/frontend/index.js +4 -2
  244. package/dist/frontend/index.js.map +1 -0
  245. package/dist/frontend/pathUtils.d.ts +8 -0
  246. package/dist/frontend/pathUtils.d.ts.map +1 -0
  247. package/dist/frontend/pathUtils.js +17 -0
  248. package/dist/frontend/pathUtils.js.map +1 -0
  249. package/dist/frontend/plugins/index.d.ts +2 -0
  250. package/dist/frontend/plugins/index.d.ts.map +1 -0
  251. package/{src → dist}/frontend/plugins/index.js +1 -1
  252. package/dist/frontend/plugins/index.js.map +1 -0
  253. package/dist/frontend/plugins/viteFrontend.d.ts +51 -0
  254. package/dist/frontend/plugins/viteFrontend.d.ts.map +1 -0
  255. package/dist/frontend/plugins/viteFrontend.js +134 -0
  256. package/dist/frontend/plugins/viteFrontend.js.map +1 -0
  257. package/dist/frontend/types.d.ts +25 -0
  258. package/dist/frontend/types.d.ts.map +1 -0
  259. package/dist/frontend/types.js +2 -0
  260. package/dist/frontend/types.js.map +1 -0
  261. package/dist/index.d.ts +17 -0
  262. package/dist/index.d.ts.map +1 -0
  263. package/dist/index.js +32 -0
  264. package/dist/index.js.map +1 -0
  265. package/dist/internals.d.ts +21 -0
  266. package/dist/internals.d.ts.map +1 -0
  267. package/{src → dist}/internals.js +12 -14
  268. package/dist/internals.js.map +1 -0
  269. package/dist/plugins/PluginManager.d.ts +209 -0
  270. package/dist/plugins/PluginManager.d.ts.map +1 -0
  271. package/dist/plugins/PluginManager.js +365 -0
  272. package/dist/plugins/PluginManager.js.map +1 -0
  273. package/dist/plugins/ScopedPostgres.d.ts +78 -0
  274. package/dist/plugins/ScopedPostgres.d.ts.map +1 -0
  275. package/dist/plugins/ScopedPostgres.js +190 -0
  276. package/dist/plugins/ScopedPostgres.js.map +1 -0
  277. package/dist/plugins/ScopedRedis.d.ts +88 -0
  278. package/dist/plugins/ScopedRedis.d.ts.map +1 -0
  279. package/dist/plugins/ScopedRedis.js +169 -0
  280. package/dist/plugins/ScopedRedis.js.map +1 -0
  281. package/dist/plugins/index.d.ts +289 -0
  282. package/dist/plugins/index.d.ts.map +1 -0
  283. package/dist/plugins/index.js +1942 -0
  284. package/dist/plugins/index.js.map +1 -0
  285. package/dist/plugins/types.d.ts +59 -0
  286. package/dist/plugins/types.d.ts.map +1 -0
  287. package/dist/plugins/types.js +2 -0
  288. package/dist/plugins/types.js.map +1 -0
  289. package/dist/registry/ServiceRegistry.d.ts +305 -0
  290. package/dist/registry/ServiceRegistry.d.ts.map +1 -0
  291. package/dist/registry/ServiceRegistry.js +735 -0
  292. package/dist/registry/ServiceRegistry.js.map +1 -0
  293. package/dist/scaling/ScaleAdvisor.d.ts +214 -0
  294. package/dist/scaling/ScaleAdvisor.d.ts.map +1 -0
  295. package/dist/scaling/ScaleAdvisor.js +526 -0
  296. package/dist/scaling/ScaleAdvisor.js.map +1 -0
  297. package/dist/services/Service.d.ts +164 -0
  298. package/dist/services/Service.d.ts.map +1 -0
  299. package/dist/services/Service.js +106 -0
  300. package/dist/services/Service.js.map +1 -0
  301. package/dist/services/worker-bootstrap.d.ts +15 -0
  302. package/dist/services/worker-bootstrap.d.ts.map +1 -0
  303. package/dist/services/worker-bootstrap.js +744 -0
  304. package/dist/services/worker-bootstrap.js.map +1 -0
  305. package/dist/templates/auth-service.d.ts +42 -0
  306. package/dist/templates/auth-service.d.ts.map +1 -0
  307. package/dist/templates/auth-service.js +54 -0
  308. package/dist/templates/auth-service.js.map +1 -0
  309. package/dist/templates/identity-service.d.ts +50 -0
  310. package/dist/templates/identity-service.d.ts.map +1 -0
  311. package/dist/templates/identity-service.js +62 -0
  312. package/dist/templates/identity-service.js.map +1 -0
  313. package/dist/types/contract.d.ts +120 -0
  314. package/dist/types/contract.d.ts.map +1 -0
  315. package/dist/types/contract.js +69 -0
  316. package/dist/types/contract.js.map +1 -0
  317. package/package.json +78 -20
  318. package/src/core/DirectMessageBus.js +0 -364
  319. package/src/core/EndpointResolver.js +0 -259
  320. package/src/core/ForgeContext.js +0 -2236
  321. package/src/core/ForgeHost.js +0 -122
  322. package/src/core/ForgePlatform.js +0 -145
  323. package/src/core/Ingress.js +0 -768
  324. package/src/core/Interceptors.js +0 -420
  325. package/src/core/MessageBus.js +0 -321
  326. package/src/core/Prometheus.js +0 -305
  327. package/src/core/RequestContext.js +0 -413
  328. package/src/core/RoutingStrategy.js +0 -330
  329. package/src/core/Supervisor.js +0 -1349
  330. package/src/core/ThreadAllocator.js +0 -196
  331. package/src/core/WorkerChannelManager.js +0 -879
  332. package/src/core/config.js +0 -637
  333. package/src/core/host-config.js +0 -311
  334. package/src/core/network-utils.js +0 -166
  335. package/src/core/platform-config.js +0 -308
  336. package/src/decorators/ServiceProxy.js +0 -904
  337. package/src/decorators/index.js +0 -571
  338. package/src/deploy/NginxGenerator.js +0 -865
  339. package/src/deploy/PlatformManifestGenerator.js +0 -96
  340. package/src/deploy/RouteManifestGenerator.js +0 -112
  341. package/src/deploy/index.js +0 -984
  342. package/src/frontend/FrontendDevLifecycle.js +0 -65
  343. package/src/frontend/FrontendPluginOrchestrator.js +0 -187
  344. package/src/frontend/SiteResolver.js +0 -63
  345. package/src/frontend/StaticMountRegistry.js +0 -90
  346. package/src/frontend/plugins/viteFrontend.js +0 -79
  347. package/src/frontend/types.js +0 -35
  348. package/src/index.js +0 -58
  349. package/src/plugins/PluginManager.js +0 -537
  350. package/src/plugins/ScopedPostgres.js +0 -192
  351. package/src/plugins/ScopedRedis.js +0 -142
  352. package/src/plugins/index.js +0 -1756
  353. package/src/registry/ServiceRegistry.js +0 -797
  354. package/src/scaling/ScaleAdvisor.js +0 -442
  355. package/src/services/Service.js +0 -195
  356. package/src/services/worker-bootstrap.js +0 -679
  357. package/src/templates/auth-service.js +0 -65
  358. package/src/templates/identity-service.js +0 -75
@@ -0,0 +1,285 @@
1
+ const ROUTE_CACHE_MAX = 10_000;
2
+ /**
3
+ * Simple pattern-matching HTTP router.
4
+ * P11: Includes a route matching cache.
5
+ */
6
+ export class Router {
7
+ routes;
8
+ middleware;
9
+ _cache;
10
+ constructor() {
11
+ this.routes = new Map();
12
+ this.middleware = [];
13
+ // P11: Route cache — URL→handler lookups
14
+ this._cache = new Map();
15
+ }
16
+ use(fn) {
17
+ this.middleware.push(fn);
18
+ }
19
+ get(pattern, handler) {
20
+ this._add("GET", pattern, handler);
21
+ }
22
+ post(pattern, handler) {
23
+ this._add("POST", pattern, handler);
24
+ }
25
+ put(pattern, handler) {
26
+ this._add("PUT", pattern, handler);
27
+ }
28
+ patch(pattern, handler) {
29
+ this._add("PATCH", pattern, handler);
30
+ }
31
+ delete(pattern, handler) {
32
+ this._add("DELETE", pattern, handler);
33
+ }
34
+ _add(method, pattern, handler) {
35
+ const paramNames = [];
36
+ const isWildcard = pattern.endsWith("/*");
37
+ // Count literal (non-param, non-wildcard) segments for specificity ranking
38
+ const segments = pattern.replace(/\/\*$/, "").split("/").filter(Boolean);
39
+ const literalCount = segments.filter((s) => !s.startsWith(":")).length;
40
+ const totalSegments = segments.length;
41
+ const base = isWildcard ? pattern.slice(0, -2) : pattern;
42
+ // Escape regex-special characters before replacing :param placeholders
43
+ const escaped = base.replace(/([.*+?^${}()|[\]\\])/g, "\\$1");
44
+ const regexStr = escaped.replace(/:(\w+)/g, (_, name) => {
45
+ paramNames.push(name);
46
+ return "([^/]+)";
47
+ });
48
+ if (paramNames.length > 10) {
49
+ throw new Error(`Route "${pattern}" has ${paramNames.length} params (max 10)`);
50
+ }
51
+ let regex;
52
+ if (isWildcard) {
53
+ regex = new RegExp(`^${regexStr}(?:/(.*))?$`);
54
+ }
55
+ else {
56
+ regex = new RegExp(`^${regexStr}$`);
57
+ }
58
+ const route = {
59
+ method,
60
+ pattern,
61
+ regex,
62
+ paramNames,
63
+ handler,
64
+ isWildcard,
65
+ literalCount,
66
+ totalSegments,
67
+ };
68
+ if (!this.routes.has(method))
69
+ this.routes.set(method, []);
70
+ this.routes.get(method).push(route);
71
+ // Invalidate route cache when routes change
72
+ this._cache.clear();
73
+ }
74
+ _parseQuery(searchParams) {
75
+ const result = {};
76
+ for (const key of searchParams.keys()) {
77
+ if (key in result)
78
+ continue; // already processed via getAll
79
+ const values = searchParams.getAll(key);
80
+ result[key] = values.length > 1 ? values : values[0];
81
+ }
82
+ return result;
83
+ }
84
+ _autoOptions(normalized, query) {
85
+ const methods = new Set();
86
+ for (const [method, bucket] of this.routes) {
87
+ for (const route of bucket) {
88
+ if (normalized.match(route.regex)) {
89
+ methods.add(method);
90
+ break;
91
+ }
92
+ }
93
+ }
94
+ if (methods.size === 0)
95
+ return null;
96
+ methods.add("OPTIONS");
97
+ if (methods.has("GET"))
98
+ methods.add("HEAD");
99
+ const allow = [...methods].sort().join(", ");
100
+ return {
101
+ handler: (_req, res) => {
102
+ res.writeHead(204, { Allow: allow });
103
+ res.end();
104
+ },
105
+ params: {},
106
+ query,
107
+ pattern: "OPTIONS(auto)",
108
+ };
109
+ }
110
+ match(method, url) {
111
+ // H-SEC-1: Cache by method:pathname only (not full URL with query string).
112
+ // This prevents cache poisoning via unique query parameters while still
113
+ // providing the performance benefit of caching route matching.
114
+ // The query string is still passed to _matchUncached for parsing.
115
+ const qIdx = url.indexOf("?");
116
+ const pathname = qIdx === -1 ? url : url.slice(0, qIdx);
117
+ const cacheKey = `${method}:${pathname}`;
118
+ const cached = this._cache.get(cacheKey);
119
+ if (cached !== undefined) {
120
+ // LRU: Move to end of Map so eviction removes least-recently-used entries
121
+ this._cache.delete(cacheKey);
122
+ this._cache.set(cacheKey, cached);
123
+ // Re-parse query from original url for the cached result
124
+ if (cached) {
125
+ let query = {};
126
+ if (qIdx !== -1) {
127
+ try {
128
+ query = this._parseQuery(new URL(url, "http://localhost").searchParams);
129
+ }
130
+ catch {
131
+ return null; // Malformed URL — caller should return 400
132
+ }
133
+ }
134
+ return { ...cached, query };
135
+ }
136
+ return cached;
137
+ }
138
+ const result = this._matchUncached(method, url);
139
+ // P11: Store in cache (evict 20% when full). Don't cache null (unmatched)
140
+ // to prevent attackers filling the cache with misses.
141
+ if (result !== null) {
142
+ if (this._cache.size >= ROUTE_CACHE_MAX) {
143
+ const deleteCount = Math.ceil(ROUTE_CACHE_MAX * 0.2);
144
+ const iter = this._cache.keys();
145
+ for (let i = 0; i < deleteCount; i++) {
146
+ const key = iter.next().value;
147
+ if (key !== undefined)
148
+ this._cache.delete(key);
149
+ }
150
+ }
151
+ this._cache.set(cacheKey, result);
152
+ }
153
+ return result;
154
+ }
155
+ _matchUncached(method, url) {
156
+ // Reject null bytes — path traversal / request smuggling vector
157
+ if (url.includes("\0"))
158
+ return null;
159
+ let parsed;
160
+ try {
161
+ parsed = new URL(url, "http://localhost");
162
+ }
163
+ catch {
164
+ return null; // Malformed URL — caller should return 400
165
+ }
166
+ // P-3: Reuse the already-parsed pathname instead of constructing a second URL.
167
+ // URL constructor already normalizes encoded traversals (e.g. ..%2F).
168
+ let normalized = parsed.pathname;
169
+ // Strip trailing slashes (except root "/")
170
+ if (normalized.length > 1 && normalized.endsWith("/")) {
171
+ normalized = normalized.slice(0, -1);
172
+ }
173
+ const query = this._parseQuery(parsed.searchParams);
174
+ // HEAD requests match GET routes (RFC 7231 § 4.3.2)
175
+ const isHead = method === "HEAD";
176
+ const effectiveMethod = isHead ? "GET" : method;
177
+ // Collect route buckets to search — only the relevant method(s)
178
+ const buckets = [];
179
+ if (this.routes.has(effectiveMethod))
180
+ buckets.push(this.routes.get(effectiveMethod));
181
+ if (isHead && this.routes.has("HEAD"))
182
+ buckets.push(this.routes.get("HEAD"));
183
+ // Priority tiers: exact > parameterized > wildcard
184
+ let bestParam = null;
185
+ let bestParamScore = -1;
186
+ let bestWildcard = null;
187
+ let bestWildcardScore = -1;
188
+ for (const bucket of buckets) {
189
+ for (const route of bucket) {
190
+ const match = normalized.match(route.regex);
191
+ if (!match)
192
+ continue;
193
+ const params = {};
194
+ let paramTraversal = false;
195
+ let decodeError = false;
196
+ route.paramNames.forEach((name, i) => {
197
+ let val;
198
+ try {
199
+ val = decodeURIComponent(match[i + 1]);
200
+ }
201
+ catch {
202
+ decodeError = true;
203
+ return;
204
+ }
205
+ // Detect double-encoding by attempting further decodes (up to 2 iterations)
206
+ for (let d = 0; d < 2; d++) {
207
+ try {
208
+ const decoded = decodeURIComponent(val);
209
+ if (decoded === val)
210
+ break;
211
+ val = decoded;
212
+ }
213
+ catch {
214
+ break;
215
+ }
216
+ }
217
+ if (val.includes("..") || val.includes("\0") || val.includes("%00"))
218
+ paramTraversal = true;
219
+ params[name] = val;
220
+ });
221
+ if (decodeError)
222
+ return null;
223
+ if (paramTraversal)
224
+ continue;
225
+ // Wildcard routes — lowest priority tier
226
+ if (route.isWildcard) {
227
+ const wildcardIndex = route.paramNames.length + 1;
228
+ params["*"] = match[wildcardIndex] ?? "";
229
+ params.wildcard = params["*"];
230
+ const score = route.literalCount * 1000 + route.totalSegments;
231
+ if (score > bestWildcardScore) {
232
+ bestWildcardScore = score;
233
+ bestWildcard = { handler: route.handler, params, query, pattern: route.pattern };
234
+ }
235
+ continue;
236
+ }
237
+ // Exact match (no params) — highest priority, return immediately
238
+ if (route.paramNames.length === 0) {
239
+ return { handler: route.handler, params, query, pattern: route.pattern };
240
+ }
241
+ // Parameterized route — pick the most specific
242
+ const score = route.literalCount * 1000 + route.totalSegments;
243
+ if (score > bestParamScore) {
244
+ bestParamScore = score;
245
+ bestParam = { handler: route.handler, params, query, pattern: route.pattern };
246
+ }
247
+ }
248
+ }
249
+ if (bestParam)
250
+ return bestParam;
251
+ if (bestWildcard)
252
+ return bestWildcard;
253
+ // Auto OPTIONS if no explicit handler matched
254
+ if (method === "OPTIONS") {
255
+ return this._autoOptions(normalized, query);
256
+ }
257
+ // 405 Method Not Allowed — path matches but method doesn't
258
+ const allowedMethods = new Set();
259
+ for (const [routeMethod, bucket] of this.routes) {
260
+ for (const route of bucket) {
261
+ if (normalized.match(route.regex)) {
262
+ allowedMethods.add(routeMethod);
263
+ break;
264
+ }
265
+ }
266
+ }
267
+ if (allowedMethods.size > 0) {
268
+ allowedMethods.add("OPTIONS");
269
+ if (allowedMethods.has("GET"))
270
+ allowedMethods.add("HEAD");
271
+ const allow = [...allowedMethods].sort().join(", ");
272
+ return {
273
+ handler: (_req, res) => {
274
+ res.writeHead(405, { "Content-Type": "application/json", Allow: allow });
275
+ res.end(JSON.stringify({ error: "Method Not Allowed" }));
276
+ },
277
+ params: {},
278
+ query,
279
+ pattern: "405(auto)",
280
+ };
281
+ }
282
+ return null;
283
+ }
284
+ }
285
+ //# sourceMappingURL=Router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Router.js","sourceRoot":"","sources":["../../src/core/Router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Routing Strategies
3
+ *
4
+ * When a service has multiple workers, the proxy needs to decide
5
+ * which worker handles each request. Different strategies suit
6
+ * different service patterns.
7
+ *
8
+ * Strategies:
9
+ *
10
+ * round-robin Default. Cycles through workers sequentially.
11
+ * Best for: stateless services, uniform workloads.
12
+ *
13
+ * hash Routes by a key (e.g., userId). Same key always
14
+ * goes to the same worker. Uses consistent hashing
15
+ * so adding/removing workers only remaps ~1/N keys.
16
+ * Best for: stateful services, in-memory caches,
17
+ * services that benefit from data locality.
18
+ *
19
+ * least-pending Routes to the worker with fewest in-flight requests.
20
+ * Best for: variable-latency services (DB queries,
21
+ * external API calls).
22
+ *
23
+ * broadcast Sends to ALL workers. Returns the first response.
24
+ * Best for: search/aggregation across sharded data.
25
+ *
26
+ * primary Always routes to worker 0. Others are standbys.
27
+ * Best for: singleton services (cron scheduler,
28
+ * leader election).
29
+ */
30
+ interface WorkerEntry {
31
+ key: string;
32
+ socket: unknown;
33
+ pending: number;
34
+ }
35
+ interface CallContext {
36
+ __forge_args?: unknown[];
37
+ __forge_hash?: string | number;
38
+ [key: string]: unknown;
39
+ }
40
+ interface HashStrategyOptions {
41
+ key?: string;
42
+ vnodes?: number;
43
+ salt?: string;
44
+ }
45
+ interface RoutingStrategy {
46
+ pick(workers: WorkerEntry[], callContext?: CallContext | null): WorkerEntry | WorkerEntry[] | null;
47
+ readonly name: string;
48
+ }
49
+ export declare class RoundRobinStrategy implements RoutingStrategy {
50
+ index: number;
51
+ constructor();
52
+ pick(workers: WorkerEntry[], _callContext?: CallContext | null): WorkerEntry | null;
53
+ get name(): string;
54
+ }
55
+ export declare class HashStrategy implements RoutingStrategy {
56
+ keyField: string | null;
57
+ vnodes: number;
58
+ private _ring;
59
+ private _workerCacheKey;
60
+ private _ringHashes;
61
+ private _ringKeys;
62
+ private _fallbackCounter;
63
+ private _salt;
64
+ constructor(options?: HashStrategyOptions);
65
+ pick(workers: WorkerEntry[], callContext?: CallContext | null): WorkerEntry | null;
66
+ private _extractKey;
67
+ private _buildRing;
68
+ private _findOnRing;
69
+ /**
70
+ * Pre-compute a keyed SHA-256 hash for ring building (called at build time).
71
+ */
72
+ private _computeHash;
73
+ /**
74
+ * P-1: Fast FNV-1a hash for runtime routing decisions.
75
+ * Salted to prevent predictable distribution from external input.
76
+ */
77
+ private _simpleHash;
78
+ get name(): string;
79
+ }
80
+ export declare class LeastPendingStrategy implements RoutingStrategy {
81
+ private _pending;
82
+ private _lastWorkerKeys;
83
+ constructor();
84
+ /**
85
+ * Pick the worker with the fewest in-flight requests.
86
+ */
87
+ pick(workers: WorkerEntry[], _callContext?: CallContext | null): WorkerEntry | null;
88
+ /** Call when dispatching a request to a worker */
89
+ acquire(workerKey: string): void;
90
+ /** Call when a request to a worker completes */
91
+ release(workerKey: string): void;
92
+ get name(): string;
93
+ }
94
+ export declare class BroadcastStrategy implements RoutingStrategy {
95
+ /**
96
+ * Returns ALL workers. The caller is responsible for sending
97
+ * to all of them and handling multiple responses.
98
+ */
99
+ pick(workers: WorkerEntry[], _callContext?: CallContext | null): WorkerEntry[];
100
+ get name(): string;
101
+ get isBroadcast(): boolean;
102
+ }
103
+ export declare class PrimaryStrategy implements RoutingStrategy {
104
+ /**
105
+ * Always routes to worker index 0. If worker 0 is down,
106
+ * routes to the next available.
107
+ */
108
+ pick(workers: WorkerEntry[], _callContext?: CallContext | null): WorkerEntry | null;
109
+ get name(): string;
110
+ }
111
+ /**
112
+ * Create a routing strategy by name.
113
+ */
114
+ export declare function createStrategy(name: string, options?: HashStrategyOptions): RoutingStrategy;
115
+ export {};
116
+ //# sourceMappingURL=RoutingStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoutingStrategy.d.ts","sourceRoot":"","sources":["../../src/core/RoutingStrategy.ts"],"names":[],"mappings":"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"}