threadforge 0.1.0 → 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 (359) hide show
  1. package/README.md +52 -20
  2. package/bin/forge.js +2 -1049
  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 +160 -49
  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 +84 -22
  318. package/shared/identity.js +26 -0
  319. package/src/core/DirectMessageBus.js +0 -364
  320. package/src/core/EndpointResolver.js +0 -247
  321. package/src/core/ForgeContext.js +0 -2227
  322. package/src/core/ForgeHost.js +0 -122
  323. package/src/core/ForgePlatform.js +0 -145
  324. package/src/core/Ingress.js +0 -768
  325. package/src/core/Interceptors.js +0 -420
  326. package/src/core/MessageBus.js +0 -310
  327. package/src/core/Prometheus.js +0 -305
  328. package/src/core/RequestContext.js +0 -413
  329. package/src/core/RoutingStrategy.js +0 -316
  330. package/src/core/Supervisor.js +0 -1306
  331. package/src/core/ThreadAllocator.js +0 -196
  332. package/src/core/WorkerChannelManager.js +0 -879
  333. package/src/core/config.js +0 -624
  334. package/src/core/host-config.js +0 -311
  335. package/src/core/network-utils.js +0 -166
  336. package/src/core/platform-config.js +0 -308
  337. package/src/decorators/ServiceProxy.js +0 -899
  338. package/src/decorators/index.js +0 -571
  339. package/src/deploy/NginxGenerator.js +0 -865
  340. package/src/deploy/PlatformManifestGenerator.js +0 -96
  341. package/src/deploy/RouteManifestGenerator.js +0 -112
  342. package/src/deploy/index.js +0 -984
  343. package/src/frontend/FrontendDevLifecycle.js +0 -65
  344. package/src/frontend/FrontendPluginOrchestrator.js +0 -187
  345. package/src/frontend/SiteResolver.js +0 -63
  346. package/src/frontend/StaticMountRegistry.js +0 -90
  347. package/src/frontend/plugins/viteFrontend.js +0 -79
  348. package/src/frontend/types.js +0 -35
  349. package/src/index.js +0 -56
  350. package/src/plugins/PluginManager.js +0 -537
  351. package/src/plugins/ScopedPostgres.js +0 -192
  352. package/src/plugins/ScopedRedis.js +0 -142
  353. package/src/plugins/index.js +0 -1729
  354. package/src/registry/ServiceRegistry.js +0 -796
  355. package/src/scaling/ScaleAdvisor.js +0 -442
  356. package/src/services/Service.js +0 -195
  357. package/src/services/worker-bootstrap.js +0 -676
  358. package/src/templates/auth-service.js +0 -65
  359. package/src/templates/identity-service.js +0 -75
@@ -1,308 +0,0 @@
1
- /**
2
- * Platform Mode Configuration
3
- *
4
- * Transforms a user-facing `platform.apps` config into ForgeHost's
5
- * internal `projects` format. Platform Mode is a config transformation
6
- * layer on top of ForgeHost — it reuses resolveHostConfig() as the engine.
7
- *
8
- * Usage:
9
- *
10
- * import { definePlatform } from 'threadforge';
11
- *
12
- * export default definePlatform({
13
- * platform: {
14
- * globalAuth: true,
15
- * apps: {
16
- * coolapp: {
17
- * domains: ['coolapp.io'],
18
- * services: ['coolapp-api'],
19
- * schema: 'coolapp',
20
- * },
21
- * },
22
- * },
23
- * plugins: [redis(), postgres()],
24
- * identity: { entry: './services/identity.js', type: 'edge', port: 3001 },
25
- * auth: { entry: './services/auth.js', type: 'edge', port: 3002 },
26
- * 'coolapp-api': { entry: './apps/coolapp/api.js', type: 'edge', port: 4001 },
27
- * });
28
- */
29
-
30
- import { defineServices } from "./config.js";
31
- import { resolveHostConfig } from "./host-config.js";
32
-
33
- const APP_ID_RE = /^[a-z][a-z0-9_-]*$/;
34
- const BASE_PATH_RE = /^\/[^\s?#]*$/;
35
-
36
- function isPlainObject(value) {
37
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
38
- }
39
-
40
- function normalizeFrontendConfig(appId, frontend) {
41
- if (!isPlainObject(frontend)) {
42
- throw new Error(`App "${appId}" frontend must be an object`);
43
- }
44
-
45
- if (typeof frontend.plugin !== "string" || frontend.plugin.trim() === "") {
46
- throw new Error(`App "${appId}" frontend.plugin must be a non-empty string`);
47
- }
48
-
49
- if (typeof frontend.root !== "string" || frontend.root.trim() === "") {
50
- throw new Error(`App "${appId}" frontend.root must be a non-empty string`);
51
- }
52
-
53
- if (frontend.outDir !== undefined && (typeof frontend.outDir !== "string" || frontend.outDir.trim() === "")) {
54
- throw new Error(`App "${appId}" frontend.outDir must be a non-empty string when provided`);
55
- }
56
-
57
- if (frontend.basePath !== undefined) {
58
- if (typeof frontend.basePath !== "string" || !BASE_PATH_RE.test(frontend.basePath)) {
59
- throw new Error(
60
- `App "${appId}" frontend.basePath must start with "/" and cannot include query strings or fragments`,
61
- );
62
- }
63
- }
64
-
65
- if (frontend.spaFallback !== undefined && typeof frontend.spaFallback !== "boolean") {
66
- throw new Error(`App "${appId}" frontend.spaFallback must be a boolean when provided`);
67
- }
68
-
69
- if (frontend.env !== undefined && !isPlainObject(frontend.env)) {
70
- throw new Error(`App "${appId}" frontend.env must be an object when provided`);
71
- }
72
- if (frontend.options !== undefined && !isPlainObject(frontend.options)) {
73
- throw new Error(`App "${appId}" frontend.options must be an object when provided`);
74
- }
75
-
76
- return {
77
- plugin: frontend.plugin,
78
- root: frontend.root,
79
- outDir: frontend.outDir ?? `.threadforge/build/${appId}`,
80
- basePath: frontend.basePath ?? "/",
81
- spaFallback: frontend.spaFallback ?? true,
82
- env: frontend.env ?? {},
83
- options: frontend.options ?? {},
84
- };
85
- }
86
-
87
- /**
88
- * Normalize an app's domain(s) to an array.
89
- * Accepts either `domains: [...]` or `domain: '...'`.
90
- *
91
- * @param {{ domains?: string[], domain?: string }} app
92
- * @returns {string[]}
93
- */
94
- export function resolveAppDomains(app) {
95
- if (app.domains) return app.domains;
96
- if (app.domain) return [app.domain];
97
- return [];
98
- }
99
-
100
- /**
101
- * Validate the platform config shape.
102
- *
103
- * @param {Object} config - Raw platform config
104
- * @throws {Error} On invalid config
105
- */
106
- export function validatePlatformConfig(config) {
107
- if (!config || typeof config !== "object") {
108
- throw new Error("definePlatform() requires a config object");
109
- }
110
-
111
- if (!config.platform || typeof config.platform !== "object") {
112
- throw new Error("definePlatform() requires a platform block");
113
- }
114
-
115
- const { apps } = config.platform;
116
- if (!apps || typeof apps !== "object") {
117
- throw new Error("platform.apps must be a non-empty object");
118
- }
119
-
120
- const appIds = Object.keys(apps);
121
- if (appIds.length === 0) {
122
- throw new Error("platform.apps must contain at least one app");
123
- }
124
-
125
- const schemas = new Set();
126
-
127
- for (const appId of appIds) {
128
- if (!APP_ID_RE.test(appId)) {
129
- throw new Error(
130
- `Invalid app ID "${appId}": must start with a lowercase letter and contain only lowercase letters, digits, hyphens, and underscores`,
131
- );
132
- }
133
-
134
- const app = apps[appId];
135
- if (!app || typeof app !== "object") {
136
- throw new Error(`App "${appId}" must be an object`);
137
- }
138
-
139
- if (!app.domains && !app.domain) {
140
- throw new Error(`App "${appId}" must have a domains array`);
141
- }
142
-
143
- const domains = resolveAppDomains(app);
144
- if (domains.length === 0) {
145
- throw new Error(`App "${appId}" must have at least one domain`);
146
- }
147
-
148
- if (!app.services && !app.config) {
149
- throw new Error(`App "${appId}" must have either services or config`);
150
- }
151
-
152
- if (app.frontend) {
153
- normalizeFrontendConfig(appId, app.frontend);
154
- }
155
-
156
- const schema = app.schema ?? appId;
157
- if (schemas.has(schema)) {
158
- throw new Error(`Duplicate schema "${schema}" — each app must have a unique schema`);
159
- }
160
- schemas.add(schema);
161
- }
162
- }
163
-
164
- /**
165
- * Transform platform config into ForgeHost's internal projects format.
166
- *
167
- * Maps platform.apps → hostConfig.projects, preserving custom schemas
168
- * and auto-injecting identity+auth when globalAuth is enabled.
169
- *
170
- * @param {Object} config - Validated platform config
171
- * @returns {Object} ForgeHost-compatible config
172
- */
173
- export function transformToHostConfig(config) {
174
- const { platform } = config;
175
- const apps = platform.apps;
176
- const globalAuth = platform.globalAuth ?? false;
177
-
178
- // Collect all service names claimed by apps
179
- const claimedServices = new Set();
180
- for (const app of Object.values(apps)) {
181
- for (const svcName of app.services ?? []) {
182
- claimedServices.add(svcName);
183
- }
184
- }
185
-
186
- // Build shared services: any service definition in config that is not
187
- // claimed by an app and not a reserved top-level key
188
- const shared = {};
189
- for (const [key, value] of Object.entries(config)) {
190
- if (key === "platform" || key === "plugins") continue;
191
- if (claimedServices.has(key)) continue;
192
- if (typeof value !== "object" || value === null) continue;
193
- if (!value.entry && !value.type) continue;
194
- shared[key] = value;
195
- }
196
-
197
- // Auto-inject identity + auth as shared services when globalAuth is enabled
198
- if (globalAuth) {
199
- if (!shared.identity) {
200
- shared.identity = {
201
- entry: "./shared/identity.js",
202
- type: "edge",
203
- port: 3001,
204
- };
205
- }
206
- if (!shared.auth) {
207
- shared.auth = {
208
- entry: "./shared/auth.js",
209
- type: "edge",
210
- port: 3002,
211
- };
212
- }
213
- }
214
-
215
- // Build projects map from apps
216
- const projects = {};
217
- for (const [appId, app] of Object.entries(apps)) {
218
- const domains = resolveAppDomains(app);
219
-
220
- // Build inline service map from claimed service names
221
- const inlineServices = {};
222
- for (const svcName of app.services ?? []) {
223
- const svcConfig = config[svcName];
224
- if (svcConfig) {
225
- inlineServices[svcName] = svcConfig;
226
- }
227
- }
228
-
229
- const hasInlineServices = Object.keys(inlineServices).length > 0;
230
- const frontend = app.frontend ? normalizeFrontendConfig(appId, app.frontend) : null;
231
- if (frontend && app.static) {
232
- console.warn(
233
- `[ThreadForge] App "${appId}" defines both "frontend" and legacy "static". ` +
234
- `Using frontend plugin config and ignoring "static".`,
235
- );
236
- }
237
-
238
- projects[appId] = {
239
- domain: domains[0],
240
- domains,
241
- schema: app.schema ?? appId,
242
- static: frontend ? null : (app.static ?? null),
243
- frontend,
244
- services: hasInlineServices ? inlineServices : undefined,
245
- config: app.config,
246
- };
247
- }
248
-
249
- return {
250
- domain: platform.domain ?? null,
251
- basePort: platform.basePort ?? 3200,
252
- metricsPort: platform.metricsPort ?? 9090,
253
- projects,
254
- shared,
255
- plugins: config.plugins ?? [],
256
- frontendPlugins: config.frontendPlugins ?? [],
257
- };
258
- }
259
-
260
- /**
261
- * Define a Platform Mode config.
262
- *
263
- * Validates the config and returns a marked config object.
264
- *
265
- * @param {Object} config - Platform config
266
- * @returns {Object} Validated config marked with _isPlatformConfig
267
- */
268
- export function definePlatform(config) {
269
- validatePlatformConfig(config);
270
-
271
- return {
272
- _isPlatformConfig: true,
273
- _raw: config,
274
- platform: config.platform,
275
- plugins: config.plugins ?? [],
276
- frontendPlugins: config.frontendPlugins ?? [],
277
- };
278
- }
279
-
280
- /**
281
- * Resolve a platform config fully: transform → resolveHostConfig → defineServices.
282
- *
283
- * @param {Object} config - Output from definePlatform() or raw platform config
284
- * @returns {Object} Fully resolved config ready for Supervisor
285
- */
286
- export async function resolveAndDefinePlatform(config) {
287
- const raw = config._isPlatformConfig ? config._raw : config;
288
- validatePlatformConfig(raw);
289
-
290
- const hostConfig = transformToHostConfig(raw);
291
- const resolved = await resolveHostConfig(hostConfig);
292
-
293
- const result = defineServices(resolved.services, {
294
- plugins: resolved.plugins,
295
- frontendPlugins: resolved.frontendPlugins,
296
- sites: resolved.sites,
297
- metricsPort: resolved.metricsPort,
298
- });
299
-
300
- result._isPlatformMode = true;
301
- result._isHostMode = true;
302
- result._hostMeta = resolved.hostMeta;
303
- result._hostDomain = resolved.domain;
304
- result._sites = resolved.sites;
305
- result._platformConfig = raw.platform;
306
-
307
- return result;
308
- }