iec-cli 0.6.6

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 (443) hide show
  1. package/README.md +159 -0
  2. package/dist/commands/backup.d.ts +11 -0
  3. package/dist/commands/backup.d.ts.map +1 -0
  4. package/dist/commands/backup.js +112 -0
  5. package/dist/commands/backup.js.map +1 -0
  6. package/dist/commands/config.d.ts +28 -0
  7. package/dist/commands/config.d.ts.map +1 -0
  8. package/dist/commands/config.js +190 -0
  9. package/dist/commands/config.js.map +1 -0
  10. package/dist/commands/deploy.d.ts +16 -0
  11. package/dist/commands/deploy.d.ts.map +1 -0
  12. package/dist/commands/deploy.js +235 -0
  13. package/dist/commands/deploy.js.map +1 -0
  14. package/dist/commands/destroy.d.ts +12 -0
  15. package/dist/commands/destroy.d.ts.map +1 -0
  16. package/dist/commands/destroy.js +62 -0
  17. package/dist/commands/destroy.js.map +1 -0
  18. package/dist/commands/domains.d.ts +36 -0
  19. package/dist/commands/domains.d.ts.map +1 -0
  20. package/dist/commands/domains.js +323 -0
  21. package/dist/commands/domains.js.map +1 -0
  22. package/dist/commands/env.d.ts +7 -0
  23. package/dist/commands/env.d.ts.map +1 -0
  24. package/dist/commands/env.js +42 -0
  25. package/dist/commands/env.js.map +1 -0
  26. package/dist/commands/git.d.ts +32 -0
  27. package/dist/commands/git.d.ts.map +1 -0
  28. package/dist/commands/git.js +340 -0
  29. package/dist/commands/git.js.map +1 -0
  30. package/dist/commands/init-ai.d.ts +7 -0
  31. package/dist/commands/init-ai.d.ts.map +1 -0
  32. package/dist/commands/init-ai.js +257 -0
  33. package/dist/commands/init-ai.js.map +1 -0
  34. package/dist/commands/init.d.ts +8 -0
  35. package/dist/commands/init.d.ts.map +1 -0
  36. package/dist/commands/init.js +228 -0
  37. package/dist/commands/init.js.map +1 -0
  38. package/dist/commands/link.d.ts +10 -0
  39. package/dist/commands/link.d.ts.map +1 -0
  40. package/dist/commands/link.js +193 -0
  41. package/dist/commands/link.js.map +1 -0
  42. package/dist/commands/login.d.ts +16 -0
  43. package/dist/commands/login.d.ts.map +1 -0
  44. package/dist/commands/login.js +468 -0
  45. package/dist/commands/login.js.map +1 -0
  46. package/dist/commands/logs.d.ts +16 -0
  47. package/dist/commands/logs.d.ts.map +1 -0
  48. package/dist/commands/logs.js +362 -0
  49. package/dist/commands/logs.js.map +1 -0
  50. package/dist/commands/oauth.d.ts +33 -0
  51. package/dist/commands/oauth.d.ts.map +1 -0
  52. package/dist/commands/oauth.js +181 -0
  53. package/dist/commands/oauth.js.map +1 -0
  54. package/dist/commands/preflight.d.ts +8 -0
  55. package/dist/commands/preflight.d.ts.map +1 -0
  56. package/dist/commands/preflight.js +190 -0
  57. package/dist/commands/preflight.js.map +1 -0
  58. package/dist/commands/program.d.ts +7 -0
  59. package/dist/commands/program.d.ts.map +1 -0
  60. package/dist/commands/program.js +59 -0
  61. package/dist/commands/program.js.map +1 -0
  62. package/dist/commands/programs.d.ts +7 -0
  63. package/dist/commands/programs.d.ts.map +1 -0
  64. package/dist/commands/programs.js +42 -0
  65. package/dist/commands/programs.js.map +1 -0
  66. package/dist/commands/push.d.ts +12 -0
  67. package/dist/commands/push.d.ts.map +1 -0
  68. package/dist/commands/push.js +166 -0
  69. package/dist/commands/push.js.map +1 -0
  70. package/dist/commands/register-scaffold.test.d.ts +2 -0
  71. package/dist/commands/register-scaffold.test.d.ts.map +1 -0
  72. package/dist/commands/register-scaffold.test.js +291 -0
  73. package/dist/commands/register-scaffold.test.js.map +1 -0
  74. package/dist/commands/register.d.ts +7 -0
  75. package/dist/commands/register.d.ts.map +1 -0
  76. package/dist/commands/register.js +304 -0
  77. package/dist/commands/register.js.map +1 -0
  78. package/dist/commands/rollback.d.ts +11 -0
  79. package/dist/commands/rollback.d.ts.map +1 -0
  80. package/dist/commands/rollback.js +147 -0
  81. package/dist/commands/rollback.js.map +1 -0
  82. package/dist/commands/sample.d.ts +15 -0
  83. package/dist/commands/sample.d.ts.map +1 -0
  84. package/dist/commands/sample.js +312 -0
  85. package/dist/commands/sample.js.map +1 -0
  86. package/dist/commands/scopes.d.ts +29 -0
  87. package/dist/commands/scopes.d.ts.map +1 -0
  88. package/dist/commands/scopes.js +203 -0
  89. package/dist/commands/scopes.js.map +1 -0
  90. package/dist/commands/services.d.ts +13 -0
  91. package/dist/commands/services.d.ts.map +1 -0
  92. package/dist/commands/services.js +95 -0
  93. package/dist/commands/services.js.map +1 -0
  94. package/dist/commands/settings.d.ts +10 -0
  95. package/dist/commands/settings.d.ts.map +1 -0
  96. package/dist/commands/settings.js +41 -0
  97. package/dist/commands/settings.js.map +1 -0
  98. package/dist/commands/signup.d.ts +9 -0
  99. package/dist/commands/signup.d.ts.map +1 -0
  100. package/dist/commands/signup.js +192 -0
  101. package/dist/commands/signup.js.map +1 -0
  102. package/dist/commands/status.d.ts +9 -0
  103. package/dist/commands/status.d.ts.map +1 -0
  104. package/dist/commands/status.js +170 -0
  105. package/dist/commands/status.js.map +1 -0
  106. package/dist/commands/troubleshoot.d.ts +19 -0
  107. package/dist/commands/troubleshoot.d.ts.map +1 -0
  108. package/dist/commands/troubleshoot.js +465 -0
  109. package/dist/commands/troubleshoot.js.map +1 -0
  110. package/dist/commands/update.d.ts +6 -0
  111. package/dist/commands/update.d.ts.map +1 -0
  112. package/dist/commands/update.js +64 -0
  113. package/dist/commands/update.js.map +1 -0
  114. package/dist/commands/user.d.ts +17 -0
  115. package/dist/commands/user.d.ts.map +1 -0
  116. package/dist/commands/user.js +126 -0
  117. package/dist/commands/user.js.map +1 -0
  118. package/dist/commands/versions.d.ts +16 -0
  119. package/dist/commands/versions.d.ts.map +1 -0
  120. package/dist/commands/versions.js +116 -0
  121. package/dist/commands/versions.js.map +1 -0
  122. package/dist/index.d.ts +3 -0
  123. package/dist/index.d.ts.map +1 -0
  124. package/dist/index.js +556 -0
  125. package/dist/index.js.map +1 -0
  126. package/dist/lib/__tests__/scaffold-integration.test.d.ts +2 -0
  127. package/dist/lib/__tests__/scaffold-integration.test.d.ts.map +1 -0
  128. package/dist/lib/__tests__/scaffold-integration.test.js +321 -0
  129. package/dist/lib/__tests__/scaffold-integration.test.js.map +1 -0
  130. package/dist/lib/ai/client.d.ts +39 -0
  131. package/dist/lib/ai/client.d.ts.map +1 -0
  132. package/dist/lib/ai/client.js +236 -0
  133. package/dist/lib/ai/client.js.map +1 -0
  134. package/dist/lib/ai/generator.d.ts +17 -0
  135. package/dist/lib/ai/generator.d.ts.map +1 -0
  136. package/dist/lib/ai/generator.js +338 -0
  137. package/dist/lib/ai/generator.js.map +1 -0
  138. package/dist/lib/ai/prompts.d.ts +47 -0
  139. package/dist/lib/ai/prompts.d.ts.map +1 -0
  140. package/dist/lib/ai/prompts.js +247 -0
  141. package/dist/lib/ai/prompts.js.map +1 -0
  142. package/dist/lib/ai/scanner.d.ts +50 -0
  143. package/dist/lib/ai/scanner.d.ts.map +1 -0
  144. package/dist/lib/ai/scanner.js +237 -0
  145. package/dist/lib/ai/scanner.js.map +1 -0
  146. package/dist/lib/api.d.ts +18 -0
  147. package/dist/lib/api.d.ts.map +1 -0
  148. package/dist/lib/api.js +67 -0
  149. package/dist/lib/api.js.map +1 -0
  150. package/dist/lib/auto-register.d.ts +12 -0
  151. package/dist/lib/auto-register.d.ts.map +1 -0
  152. package/dist/lib/auto-register.js +42 -0
  153. package/dist/lib/auto-register.js.map +1 -0
  154. package/dist/lib/bio.d.ts +90 -0
  155. package/dist/lib/bio.d.ts.map +1 -0
  156. package/dist/lib/bio.js +247 -0
  157. package/dist/lib/bio.js.map +1 -0
  158. package/dist/lib/builder.d.ts +65 -0
  159. package/dist/lib/builder.d.ts.map +1 -0
  160. package/dist/lib/builder.js +192 -0
  161. package/dist/lib/builder.js.map +1 -0
  162. package/dist/lib/catalog.d.ts +3 -0
  163. package/dist/lib/catalog.d.ts.map +1 -0
  164. package/dist/lib/catalog.js +17 -0
  165. package/dist/lib/catalog.js.map +1 -0
  166. package/dist/lib/config.d.ts +20 -0
  167. package/dist/lib/config.d.ts.map +1 -0
  168. package/dist/lib/config.js +124 -0
  169. package/dist/lib/config.js.map +1 -0
  170. package/dist/lib/forgejo.d.ts +188 -0
  171. package/dist/lib/forgejo.d.ts.map +1 -0
  172. package/dist/lib/forgejo.js +305 -0
  173. package/dist/lib/forgejo.js.map +1 -0
  174. package/dist/lib/output.d.ts +12 -0
  175. package/dist/lib/output.d.ts.map +1 -0
  176. package/dist/lib/output.js +39 -0
  177. package/dist/lib/output.js.map +1 -0
  178. package/dist/lib/scaffold.d.ts +30 -0
  179. package/dist/lib/scaffold.d.ts.map +1 -0
  180. package/dist/lib/scaffold.js +180 -0
  181. package/dist/lib/scaffold.js.map +1 -0
  182. package/dist/lib/scope-requests.d.ts +17 -0
  183. package/dist/lib/scope-requests.d.ts.map +1 -0
  184. package/dist/lib/scope-requests.js +78 -0
  185. package/dist/lib/scope-requests.js.map +1 -0
  186. package/dist/lib/scope-requests.test.d.ts +2 -0
  187. package/dist/lib/scope-requests.test.d.ts.map +1 -0
  188. package/dist/lib/scope-requests.test.js +239 -0
  189. package/dist/lib/scope-requests.test.js.map +1 -0
  190. package/dist/lib/troubleshoot/analyzer.d.ts +14 -0
  191. package/dist/lib/troubleshoot/analyzer.d.ts.map +1 -0
  192. package/dist/lib/troubleshoot/analyzer.js +541 -0
  193. package/dist/lib/troubleshoot/analyzer.js.map +1 -0
  194. package/dist/lib/troubleshoot/auto-fix.d.ts +29 -0
  195. package/dist/lib/troubleshoot/auto-fix.d.ts.map +1 -0
  196. package/dist/lib/troubleshoot/auto-fix.js +373 -0
  197. package/dist/lib/troubleshoot/auto-fix.js.map +1 -0
  198. package/dist/lib/troubleshoot/index.d.ts +5 -0
  199. package/dist/lib/troubleshoot/index.d.ts.map +1 -0
  200. package/dist/lib/troubleshoot/index.js +6 -0
  201. package/dist/lib/troubleshoot/index.js.map +1 -0
  202. package/dist/lib/troubleshoot/log-fetcher.d.ts +43 -0
  203. package/dist/lib/troubleshoot/log-fetcher.d.ts.map +1 -0
  204. package/dist/lib/troubleshoot/log-fetcher.js +431 -0
  205. package/dist/lib/troubleshoot/log-fetcher.js.map +1 -0
  206. package/dist/lib/troubleshoot/redactor.d.ts +35 -0
  207. package/dist/lib/troubleshoot/redactor.d.ts.map +1 -0
  208. package/dist/lib/troubleshoot/redactor.js +208 -0
  209. package/dist/lib/troubleshoot/redactor.js.map +1 -0
  210. package/dist/lib/validators/catalog-schemas.d.ts +59 -0
  211. package/dist/lib/validators/catalog-schemas.d.ts.map +1 -0
  212. package/dist/lib/validators/catalog-schemas.js +32 -0
  213. package/dist/lib/validators/catalog-schemas.js.map +1 -0
  214. package/dist/lib/validators/catalog-validator.d.ts +3 -0
  215. package/dist/lib/validators/catalog-validator.d.ts.map +1 -0
  216. package/dist/lib/validators/catalog-validator.js +247 -0
  217. package/dist/lib/validators/catalog-validator.js.map +1 -0
  218. package/dist/lib/validators/catalog-validator.test.d.ts +2 -0
  219. package/dist/lib/validators/catalog-validator.test.d.ts.map +1 -0
  220. package/dist/lib/validators/catalog-validator.test.js +420 -0
  221. package/dist/lib/validators/catalog-validator.test.js.map +1 -0
  222. package/dist/lib/validators/dockerfile-validator.d.ts +5 -0
  223. package/dist/lib/validators/dockerfile-validator.d.ts.map +1 -0
  224. package/dist/lib/validators/dockerfile-validator.js +295 -0
  225. package/dist/lib/validators/dockerfile-validator.js.map +1 -0
  226. package/dist/lib/validators/dockerfile-validator.test.d.ts +2 -0
  227. package/dist/lib/validators/dockerfile-validator.test.d.ts.map +1 -0
  228. package/dist/lib/validators/dockerfile-validator.test.js +161 -0
  229. package/dist/lib/validators/dockerfile-validator.test.js.map +1 -0
  230. package/dist/lib/validators/env-validator.d.ts +3 -0
  231. package/dist/lib/validators/env-validator.d.ts.map +1 -0
  232. package/dist/lib/validators/env-validator.js +268 -0
  233. package/dist/lib/validators/env-validator.js.map +1 -0
  234. package/dist/lib/validators/git-validator.d.ts +3 -0
  235. package/dist/lib/validators/git-validator.d.ts.map +1 -0
  236. package/dist/lib/validators/git-validator.js +236 -0
  237. package/dist/lib/validators/git-validator.js.map +1 -0
  238. package/dist/lib/validators/health-detector.d.ts +4 -0
  239. package/dist/lib/validators/health-detector.d.ts.map +1 -0
  240. package/dist/lib/validators/health-detector.js +172 -0
  241. package/dist/lib/validators/health-detector.js.map +1 -0
  242. package/dist/lib/validators/health-detector.test.d.ts +2 -0
  243. package/dist/lib/validators/health-detector.test.d.ts.map +1 -0
  244. package/dist/lib/validators/health-detector.test.js +118 -0
  245. package/dist/lib/validators/health-detector.test.js.map +1 -0
  246. package/dist/lib/validators/index.d.ts +8 -0
  247. package/dist/lib/validators/index.d.ts.map +1 -0
  248. package/dist/lib/validators/index.js +8 -0
  249. package/dist/lib/validators/index.js.map +1 -0
  250. package/dist/lib/validators/route-validator.d.ts +3 -0
  251. package/dist/lib/validators/route-validator.d.ts.map +1 -0
  252. package/dist/lib/validators/route-validator.js +238 -0
  253. package/dist/lib/validators/route-validator.js.map +1 -0
  254. package/dist/lib/validators/scope-validator.d.ts +3 -0
  255. package/dist/lib/validators/scope-validator.d.ts.map +1 -0
  256. package/dist/lib/validators/scope-validator.js +141 -0
  257. package/dist/lib/validators/scope-validator.js.map +1 -0
  258. package/dist/lib/watch.d.ts +35 -0
  259. package/dist/lib/watch.d.ts.map +1 -0
  260. package/dist/lib/watch.js +171 -0
  261. package/dist/lib/watch.js.map +1 -0
  262. package/dist/templates/api/.env.example +15 -0
  263. package/dist/templates/api/Dockerfile +45 -0
  264. package/dist/templates/api/README.md +85 -0
  265. package/dist/templates/api/catalog-info.yaml +22 -0
  266. package/dist/templates/api/gitignore +31 -0
  267. package/dist/templates/api/helm/{{name}}/Chart.yaml +9 -0
  268. package/dist/templates/api/helm/{{name}}/templates/deployment.yaml +72 -0
  269. package/dist/templates/api/helm/{{name}}/templates/ingress.yaml +43 -0
  270. package/dist/templates/api/helm/{{name}}/templates/service.yaml +17 -0
  271. package/dist/templates/api/helm/{{name}}/values.yaml +64 -0
  272. package/dist/templates/api/package.json +33 -0
  273. package/dist/templates/api/src/index.ts +61 -0
  274. package/dist/templates/api/src/routes/example.ts +165 -0
  275. package/dist/templates/api/tsconfig.json +18 -0
  276. package/dist/templates/crosspod/README.md +87 -0
  277. package/dist/templates/crosspod/service-a/Dockerfile +27 -0
  278. package/dist/templates/crosspod/service-a/catalog-info.yaml +54 -0
  279. package/dist/templates/crosspod/service-a/gitignore +5 -0
  280. package/dist/templates/crosspod/service-a/helm/{{name}}-service-a/Chart.yaml +6 -0
  281. package/dist/templates/crosspod/service-a/helm/{{name}}-service-a/templates/deployment.yaml +72 -0
  282. package/dist/templates/crosspod/service-a/helm/{{name}}-service-a/templates/ingress.yaml +43 -0
  283. package/dist/templates/crosspod/service-a/helm/{{name}}-service-a/templates/service.yaml +17 -0
  284. package/dist/templates/crosspod/service-a/helm/{{name}}-service-a/values.yaml +44 -0
  285. package/dist/templates/crosspod/service-a/package.json +29 -0
  286. package/dist/templates/crosspod/service-a/src/index.ts +89 -0
  287. package/dist/templates/crosspod/service-a/tsconfig.json +14 -0
  288. package/dist/templates/crosspod/service-b/Dockerfile +27 -0
  289. package/dist/templates/crosspod/service-b/catalog-info.yaml +27 -0
  290. package/dist/templates/crosspod/service-b/gitignore +5 -0
  291. package/dist/templates/crosspod/service-b/helm/{{name}}-service-b/Chart.yaml +6 -0
  292. package/dist/templates/crosspod/service-b/helm/{{name}}-service-b/templates/deployment.yaml +72 -0
  293. package/dist/templates/crosspod/service-b/helm/{{name}}-service-b/templates/ingress.yaml +43 -0
  294. package/dist/templates/crosspod/service-b/helm/{{name}}-service-b/templates/service.yaml +17 -0
  295. package/dist/templates/crosspod/service-b/helm/{{name}}-service-b/values.yaml +47 -0
  296. package/dist/templates/crosspod/service-b/package.json +26 -0
  297. package/dist/templates/crosspod/service-b/src/index.ts +143 -0
  298. package/dist/templates/crosspod/service-b/tsconfig.json +14 -0
  299. package/dist/templates/mga/{{name}}-api/.env.example +5 -0
  300. package/dist/templates/mga/{{name}}-api/Dockerfile +45 -0
  301. package/dist/templates/mga/{{name}}-api/catalog-info.yaml +44 -0
  302. package/dist/templates/mga/{{name}}-api/gitignore +31 -0
  303. package/dist/templates/mga/{{name}}-api/helm/{{name}}-api/Chart.yaml +9 -0
  304. package/dist/templates/mga/{{name}}-api/helm/{{name}}-api/templates/deployment.yaml +72 -0
  305. package/dist/templates/mga/{{name}}-api/helm/{{name}}-api/templates/ingress.yaml +43 -0
  306. package/dist/templates/mga/{{name}}-api/helm/{{name}}-api/templates/service.yaml +17 -0
  307. package/dist/templates/mga/{{name}}-api/helm/{{name}}-api/values.yaml +65 -0
  308. package/dist/templates/mga/{{name}}-api/package.json +37 -0
  309. package/dist/templates/mga/{{name}}-api/src/index.ts +82 -0
  310. package/dist/templates/mga/{{name}}-api/src/lib/mongo.ts +19 -0
  311. package/dist/templates/mga/{{name}}-api/src/middleware/auth.ts +133 -0
  312. package/dist/templates/mga/{{name}}-api/src/models/agent.ts +45 -0
  313. package/dist/templates/mga/{{name}}-api/src/models/application.ts +58 -0
  314. package/dist/templates/mga/{{name}}-api/src/models/invite.ts +39 -0
  315. package/dist/templates/mga/{{name}}-api/src/models/policy.ts +59 -0
  316. package/dist/templates/mga/{{name}}-api/src/models/product.ts +51 -0
  317. package/dist/templates/mga/{{name}}-api/src/models/quote.ts +68 -0
  318. package/dist/templates/mga/{{name}}-api/src/routes/agents.ts +98 -0
  319. package/dist/templates/mga/{{name}}-api/src/routes/applications.ts +170 -0
  320. package/dist/templates/mga/{{name}}-api/src/routes/invites.ts +146 -0
  321. package/dist/templates/mga/{{name}}-api/src/routes/policies.ts +70 -0
  322. package/dist/templates/mga/{{name}}-api/src/routes/products.ts +154 -0
  323. package/dist/templates/mga/{{name}}-api/src/routes/quotes.ts +263 -0
  324. package/dist/templates/mga/{{name}}-api/src/routes/reports.ts +199 -0
  325. package/dist/templates/mga/{{name}}-api/tsconfig.json +18 -0
  326. package/dist/templates/mga/{{name}}-web/.dockerignore +6 -0
  327. package/dist/templates/mga/{{name}}-web/.env.example +6 -0
  328. package/dist/templates/mga/{{name}}-web/Dockerfile +51 -0
  329. package/dist/templates/mga/{{name}}-web/catalog-info.yaml +24 -0
  330. package/dist/templates/mga/{{name}}-web/dockerignore +6 -0
  331. package/dist/templates/mga/{{name}}-web/gitignore +36 -0
  332. package/dist/templates/mga/{{name}}-web/helm/{{name}}-web/Chart.yaml +9 -0
  333. package/dist/templates/mga/{{name}}-web/helm/{{name}}-web/templates/_helpers.tpl +49 -0
  334. package/dist/templates/mga/{{name}}-web/helm/{{name}}-web/templates/configmap.yaml +10 -0
  335. package/dist/templates/mga/{{name}}-web/helm/{{name}}-web/templates/deployment.yaml +56 -0
  336. package/dist/templates/mga/{{name}}-web/helm/{{name}}-web/templates/ingress.yaml +41 -0
  337. package/dist/templates/mga/{{name}}-web/helm/{{name}}-web/templates/service.yaml +15 -0
  338. package/dist/templates/mga/{{name}}-web/helm/{{name}}-web/values.yaml +70 -0
  339. package/dist/templates/mga/{{name}}-web/next.config.js +8 -0
  340. package/dist/templates/mga/{{name}}-web/package.json +30 -0
  341. package/dist/templates/mga/{{name}}-web/public/.gitkeep +0 -0
  342. package/dist/templates/mga/{{name}}-web/public/gitkeep +0 -0
  343. package/dist/templates/mga/{{name}}-web/src/app/api/auth/callback/route.ts +77 -0
  344. package/dist/templates/mga/{{name}}-web/src/app/api/auth/login/route.ts +16 -0
  345. package/dist/templates/mga/{{name}}-web/src/app/api/auth/logout/route.ts +7 -0
  346. package/dist/templates/mga/{{name}}-web/src/app/api/auth/session/route.ts +42 -0
  347. package/dist/templates/mga/{{name}}-web/src/app/api/health/route.ts +10 -0
  348. package/dist/templates/mga/{{name}}-web/src/app/api/proxy/applications/route.ts +47 -0
  349. package/dist/templates/mga/{{name}}-web/src/app/applications/layout.tsx +17 -0
  350. package/dist/templates/mga/{{name}}-web/src/app/applications/new/page.tsx +374 -0
  351. package/dist/templates/mga/{{name}}-web/src/app/applications/page.tsx +109 -0
  352. package/dist/templates/mga/{{name}}-web/src/app/dashboard/admin/page.tsx +179 -0
  353. package/dist/templates/mga/{{name}}-web/src/app/dashboard/agent/page.tsx +125 -0
  354. package/dist/templates/mga/{{name}}-web/src/app/dashboard/insured/page.tsx +145 -0
  355. package/dist/templates/mga/{{name}}-web/src/app/dashboard/layout.tsx +17 -0
  356. package/dist/templates/mga/{{name}}-web/src/app/dashboard/page.tsx +27 -0
  357. package/dist/templates/mga/{{name}}-web/src/app/dashboard/shell.tsx +89 -0
  358. package/dist/templates/mga/{{name}}-web/src/app/globals.css +477 -0
  359. package/dist/templates/mga/{{name}}-web/src/app/layout.tsx +19 -0
  360. package/dist/templates/mga/{{name}}-web/src/app/page.tsx +74 -0
  361. package/dist/templates/mga/{{name}}-web/src/app/reports/layout.tsx +21 -0
  362. package/dist/templates/mga/{{name}}-web/src/app/reports/page.tsx +231 -0
  363. package/dist/templates/mga/{{name}}-web/src/lib/api.ts +79 -0
  364. package/dist/templates/mga/{{name}}-web/src/lib/auth.ts +285 -0
  365. package/dist/templates/mga/{{name}}-web/src/middleware.ts +71 -0
  366. package/dist/templates/mga/{{name}}-web/tsconfig.json +26 -0
  367. package/dist/templates/nextjs/.env.example +11 -0
  368. package/dist/templates/nextjs/Dockerfile +51 -0
  369. package/dist/templates/nextjs/README.md +87 -0
  370. package/dist/templates/nextjs/catalog-info.yaml +16 -0
  371. package/dist/templates/nextjs/gitignore +36 -0
  372. package/dist/templates/nextjs/helm/{{name}}/Chart.yaml +9 -0
  373. package/dist/templates/nextjs/helm/{{name}}/templates/deployment.yaml +72 -0
  374. package/dist/templates/nextjs/helm/{{name}}/templates/ingress.yaml +43 -0
  375. package/dist/templates/nextjs/helm/{{name}}/templates/service.yaml +17 -0
  376. package/dist/templates/nextjs/helm/{{name}}/values.yaml +60 -0
  377. package/dist/templates/nextjs/next.config.js +23 -0
  378. package/dist/templates/nextjs/package.json +29 -0
  379. package/dist/templates/nextjs/public/.gitkeep +0 -0
  380. package/dist/templates/nextjs/public/gitkeep +0 -0
  381. package/dist/templates/nextjs/src/app/api/example/route.ts +63 -0
  382. package/dist/templates/nextjs/src/app/api/health/route.ts +10 -0
  383. package/dist/templates/nextjs/src/app/layout.tsx +18 -0
  384. package/dist/templates/nextjs/src/app/page.tsx +49 -0
  385. package/dist/templates/nextjs/tsconfig.json +26 -0
  386. package/dist/templates/nextjs-oauth/.dockerignore +6 -0
  387. package/dist/templates/nextjs-oauth/.env.example +12 -0
  388. package/dist/templates/nextjs-oauth/Dockerfile +51 -0
  389. package/dist/templates/nextjs-oauth/README.md +115 -0
  390. package/dist/templates/nextjs-oauth/catalog-info.yaml +17 -0
  391. package/dist/templates/nextjs-oauth/dockerignore +6 -0
  392. package/dist/templates/nextjs-oauth/gitignore +36 -0
  393. package/dist/templates/nextjs-oauth/helm/Chart.yaml +6 -0
  394. package/dist/templates/nextjs-oauth/helm/templates/_helpers.tpl +49 -0
  395. package/dist/templates/nextjs-oauth/helm/templates/configmap.yaml +10 -0
  396. package/dist/templates/nextjs-oauth/helm/templates/deployment.yaml +56 -0
  397. package/dist/templates/nextjs-oauth/helm/templates/ingress.yaml +41 -0
  398. package/dist/templates/nextjs-oauth/helm/templates/service.yaml +15 -0
  399. package/dist/templates/nextjs-oauth/helm/values.yaml +69 -0
  400. package/dist/templates/nextjs-oauth/helm/{{name}}/Chart.yaml +9 -0
  401. package/dist/templates/nextjs-oauth/helm/{{name}}/templates/deployment.yaml +68 -0
  402. package/dist/templates/nextjs-oauth/helm/{{name}}/templates/service.yaml +17 -0
  403. package/dist/templates/nextjs-oauth/helm/{{name}}/values.yaml +51 -0
  404. package/dist/templates/nextjs-oauth/next.config.js +23 -0
  405. package/dist/templates/nextjs-oauth/package.json +30 -0
  406. package/dist/templates/nextjs-oauth/public/.gitkeep +0 -0
  407. package/dist/templates/nextjs-oauth/public/gitkeep +0 -0
  408. package/dist/templates/nextjs-oauth/src/app/api/auth/callback/route.ts +77 -0
  409. package/dist/templates/nextjs-oauth/src/app/api/auth/login/route.ts +16 -0
  410. package/dist/templates/nextjs-oauth/src/app/api/auth/logout/route.ts +7 -0
  411. package/dist/templates/nextjs-oauth/src/app/api/auth/session/route.ts +42 -0
  412. package/dist/templates/nextjs-oauth/src/app/api/example/route.ts +63 -0
  413. package/dist/templates/nextjs-oauth/src/app/api/health/route.ts +10 -0
  414. package/dist/templates/nextjs-oauth/src/app/dashboard/page.tsx +92 -0
  415. package/dist/templates/nextjs-oauth/src/app/layout.tsx +18 -0
  416. package/dist/templates/nextjs-oauth/src/app/page.tsx +110 -0
  417. package/dist/templates/nextjs-oauth/src/lib/auth.ts +285 -0
  418. package/dist/templates/nextjs-oauth/src/middleware.ts +71 -0
  419. package/dist/templates/nextjs-oauth/tsconfig.json +26 -0
  420. package/dist/templates/static/catalog-info.yaml +14 -0
  421. package/dist/templates/static/index.html +16 -0
  422. package/dist/templates/static/styles.css +39 -0
  423. package/dist/templates/worker/.env.example +13 -0
  424. package/dist/templates/worker/Dockerfile +26 -0
  425. package/dist/templates/worker/README.md +106 -0
  426. package/dist/templates/worker/catalog-info.yaml +19 -0
  427. package/dist/templates/worker/gitignore +5 -0
  428. package/dist/templates/worker/helm/{{name}}/Chart.yaml +9 -0
  429. package/dist/templates/worker/helm/{{name}}/templates/deployment.yaml +68 -0
  430. package/dist/templates/worker/helm/{{name}}/templates/ingress.yaml +43 -0
  431. package/dist/templates/worker/helm/{{name}}/values.yaml +64 -0
  432. package/dist/templates/worker/package.json +26 -0
  433. package/dist/templates/worker/src/index.ts +185 -0
  434. package/dist/templates/worker/tsconfig.json +14 -0
  435. package/dist/types/index.d.ts +596 -0
  436. package/dist/types/index.d.ts.map +1 -0
  437. package/dist/types/index.js +41 -0
  438. package/dist/types/index.js.map +1 -0
  439. package/dist/types/platform.d.ts +191 -0
  440. package/dist/types/platform.d.ts.map +1 -0
  441. package/dist/types/platform.js +17 -0
  442. package/dist/types/platform.js.map +1 -0
  443. package/package.json +62 -0
@@ -0,0 +1,39 @@
1
+ import mongoose, { type Document, Schema } from 'mongoose'
2
+
3
+ export type InviteStatus = 'pending' | 'accepted' | 'expired'
4
+
5
+ export interface IInvite extends Document {
6
+ email: string
7
+ firstName: string
8
+ lastName: string
9
+ invitedBy: string
10
+ token: string
11
+ status: InviteStatus
12
+ expiresAt: Date
13
+ acceptedAt: Date | null
14
+ createdAt: Date
15
+ }
16
+
17
+ const inviteSchema = new Schema<IInvite>(
18
+ {
19
+ email: { type: String, required: true, lowercase: true, trim: true },
20
+ firstName: { type: String, required: true, trim: true },
21
+ lastName: { type: String, required: true, trim: true },
22
+ invitedBy: { type: String, required: true },
23
+ token: { type: String, required: true, unique: true },
24
+ status: {
25
+ type: String,
26
+ enum: ['pending', 'accepted', 'expired'],
27
+ default: 'pending',
28
+ },
29
+ expiresAt: { type: Date, required: true },
30
+ acceptedAt: { type: Date, default: null },
31
+ },
32
+ { timestamps: true },
33
+ )
34
+
35
+ inviteSchema.index({ token: 1 }, { unique: true })
36
+ inviteSchema.index({ email: 1 })
37
+ inviteSchema.index({ status: 1 })
38
+
39
+ export const Invite = mongoose.model<IInvite>('Invite', inviteSchema)
@@ -0,0 +1,59 @@
1
+ import mongoose, { type Document, Schema } from 'mongoose'
2
+
3
+ export type PolicyStatus = 'active' | 'cancelled' | 'expired' | 'lapsed'
4
+
5
+ export interface IPolicyCoverageLimits {
6
+ dataBreachLimit: number
7
+ ransomwareLimit: number
8
+ liabilityLimit: number
9
+ }
10
+
11
+ export interface IPolicy extends Document {
12
+ quoteId: string
13
+ applicationId: string
14
+ productId: string
15
+ agentId: string
16
+ insuredName: string
17
+ insuredEmail: string
18
+ policyNumber: string
19
+ premiumAmount: number
20
+ coverageLimits: IPolicyCoverageLimits
21
+ effectiveDate: Date
22
+ expirationDate: Date
23
+ status: PolicyStatus
24
+ createdAt: Date
25
+ updatedAt: Date
26
+ }
27
+
28
+ const policySchema = new Schema<IPolicy>(
29
+ {
30
+ quoteId: { type: String, required: true },
31
+ applicationId: { type: String, required: true },
32
+ productId: { type: String, required: true },
33
+ agentId: { type: String, required: true },
34
+ insuredName: { type: String, required: true, trim: true },
35
+ insuredEmail: { type: String, required: true, lowercase: true, trim: true },
36
+ policyNumber: { type: String, required: true, unique: true },
37
+ premiumAmount: { type: Number, required: true },
38
+ coverageLimits: {
39
+ dataBreachLimit: { type: Number, required: true },
40
+ ransomwareLimit: { type: Number, required: true },
41
+ liabilityLimit: { type: Number, required: true },
42
+ },
43
+ effectiveDate: { type: Date, required: true },
44
+ expirationDate: { type: Date, required: true },
45
+ status: {
46
+ type: String,
47
+ enum: ['active', 'cancelled', 'expired', 'lapsed'],
48
+ default: 'active',
49
+ },
50
+ },
51
+ { timestamps: true },
52
+ )
53
+
54
+ policySchema.index({ policyNumber: 1 }, { unique: true })
55
+ policySchema.index({ agentId: 1, status: 1 })
56
+ policySchema.index({ status: 1 })
57
+ policySchema.index({ insuredEmail: 1 })
58
+
59
+ export const Policy = mongoose.model<IPolicy>('Policy', policySchema)
@@ -0,0 +1,51 @@
1
+ import mongoose, { type Document, Schema } from 'mongoose'
2
+
3
+ export interface ICoverageLimits {
4
+ dataBreachLimit: number
5
+ ransomwareLimit: number
6
+ liabilityLimit: number
7
+ }
8
+
9
+ export interface IRiskFactors {
10
+ industryMultipliers: Record<string, number>
11
+ }
12
+
13
+ export interface IProduct extends Document {
14
+ name: string
15
+ description: string
16
+ basePremiumPerEmployee: number
17
+ minEmployees: number
18
+ maxEmployees: number
19
+ coverageLimits: ICoverageLimits
20
+ riskFactors: IRiskFactors
21
+ active: boolean
22
+ createdBy: string
23
+ createdAt: Date
24
+ updatedAt: Date
25
+ }
26
+
27
+ const productSchema = new Schema<IProduct>(
28
+ {
29
+ name: { type: String, required: true, trim: true },
30
+ description: { type: String, required: true },
31
+ basePremiumPerEmployee: { type: Number, required: true },
32
+ minEmployees: { type: Number, required: true, default: 1 },
33
+ maxEmployees: { type: Number, required: true, default: 10000 },
34
+ coverageLimits: {
35
+ dataBreachLimit: { type: Number, required: true },
36
+ ransomwareLimit: { type: Number, required: true },
37
+ liabilityLimit: { type: Number, required: true },
38
+ },
39
+ riskFactors: {
40
+ industryMultipliers: { type: Map, of: Number, default: {} },
41
+ },
42
+ active: { type: Boolean, default: true },
43
+ createdBy: { type: String, required: true },
44
+ },
45
+ { timestamps: true },
46
+ )
47
+
48
+ productSchema.index({ active: 1 })
49
+ productSchema.index({ name: 1 }, { unique: true })
50
+
51
+ export const Product = mongoose.model<IProduct>('Product', productSchema)
@@ -0,0 +1,68 @@
1
+ import mongoose, { type Document, Schema } from 'mongoose'
2
+
3
+ export type QuoteStatus = 'pending' | 'accepted' | 'declined' | 'expired'
4
+
5
+ export interface ICalculationDetails {
6
+ basePremiumPerEmployee: number
7
+ employeeCount: number
8
+ limitFactor: number
9
+ riskFactor: number
10
+ breakdown: string
11
+ }
12
+
13
+ export interface IQuoteCoverageLimits {
14
+ dataBreachLimit: number
15
+ ransomwareLimit: number
16
+ liabilityLimit: number
17
+ }
18
+
19
+ export interface IQuote extends Document {
20
+ applicationId: string
21
+ productId: string
22
+ agentId: string
23
+ premiumAmount: number
24
+ coverageLimits: IQuoteCoverageLimits
25
+ deductible: number
26
+ termMonths: number
27
+ status: QuoteStatus
28
+ validUntil: Date
29
+ calculationDetails: ICalculationDetails
30
+ createdAt: Date
31
+ updatedAt: Date
32
+ }
33
+
34
+ const quoteSchema = new Schema<IQuote>(
35
+ {
36
+ applicationId: { type: String, required: true },
37
+ productId: { type: String, required: true },
38
+ agentId: { type: String, required: true },
39
+ premiumAmount: { type: Number, required: true },
40
+ coverageLimits: {
41
+ dataBreachLimit: { type: Number, required: true },
42
+ ransomwareLimit: { type: Number, required: true },
43
+ liabilityLimit: { type: Number, required: true },
44
+ },
45
+ deductible: { type: Number, required: true },
46
+ termMonths: { type: Number, default: 12 },
47
+ status: {
48
+ type: String,
49
+ enum: ['pending', 'accepted', 'declined', 'expired'],
50
+ default: 'pending',
51
+ },
52
+ validUntil: { type: Date, required: true },
53
+ calculationDetails: {
54
+ basePremiumPerEmployee: { type: Number, required: true },
55
+ employeeCount: { type: Number, required: true },
56
+ limitFactor: { type: Number, required: true },
57
+ riskFactor: { type: Number, required: true },
58
+ breakdown: { type: String, required: true },
59
+ },
60
+ },
61
+ { timestamps: true },
62
+ )
63
+
64
+ quoteSchema.index({ applicationId: 1 })
65
+ quoteSchema.index({ agentId: 1, status: 1 })
66
+ quoteSchema.index({ status: 1, validUntil: 1 })
67
+
68
+ export const Quote = mongoose.model<IQuote>('Quote', quoteSchema)
@@ -0,0 +1,98 @@
1
+ import { Router, type Request, type Response } from 'express'
2
+ import { z } from 'zod'
3
+ import { authMiddleware, requireRole } from '../middleware/auth.js'
4
+ import { Agent } from '../models/agent.js'
5
+
6
+ const router = Router()
7
+
8
+ const UpdateAgentStatusSchema = z.object({
9
+ status: z.enum(['active', 'suspended', 'inactive']),
10
+ })
11
+
12
+ // List all agents (admin only)
13
+ router.get('/', authMiddleware, requireRole('mga_admin'), async (_req: Request, res: Response) => {
14
+ try {
15
+ const agents = await Agent.find().sort({ lastName: 1, firstName: 1 }).lean()
16
+ res.json({
17
+ success: true,
18
+ data: agents,
19
+ meta: { total: agents.length },
20
+ })
21
+ } catch (err) {
22
+ process.stderr.write(`Failed to list agents: ${err instanceof Error ? err.message : String(err)}\n`)
23
+ res.status(500).json({
24
+ success: false,
25
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to list agents' },
26
+ })
27
+ }
28
+ })
29
+
30
+ // Get agent profile (agent sees own, admin sees any)
31
+ router.get('/:id', authMiddleware, requireRole('mga_admin', 'agent'), async (req: Request, res: Response) => {
32
+ try {
33
+ const agent = await Agent.findById(req.params.id).lean()
34
+ if (!agent) {
35
+ res.status(404).json({
36
+ success: false,
37
+ error: { code: 'NOT_FOUND', message: 'Agent not found' },
38
+ })
39
+ return
40
+ }
41
+
42
+ // Agents can only view their own profile
43
+ const isAdmin = req.user!.roles.includes('mga_admin')
44
+ if (!isAdmin && agent.userId !== req.user!.id) {
45
+ res.status(403).json({
46
+ success: false,
47
+ error: { code: 'FORBIDDEN', message: 'Insufficient permissions' },
48
+ })
49
+ return
50
+ }
51
+
52
+ res.json({ success: true, data: agent })
53
+ } catch (err) {
54
+ process.stderr.write(`Failed to get agent: ${err instanceof Error ? err.message : String(err)}\n`)
55
+ res.status(500).json({
56
+ success: false,
57
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to get agent' },
58
+ })
59
+ }
60
+ })
61
+
62
+ // Update agent status (admin only)
63
+ router.put('/:id/status', authMiddleware, requireRole('mga_admin'), async (req: Request, res: Response) => {
64
+ const result = UpdateAgentStatusSchema.safeParse(req.body)
65
+ if (!result.success) {
66
+ res.status(400).json({
67
+ success: false,
68
+ error: { code: 'VALIDATION_ERROR', message: 'Invalid request body', details: result.error.flatten() },
69
+ })
70
+ return
71
+ }
72
+
73
+ try {
74
+ const agent = await Agent.findByIdAndUpdate(
75
+ req.params.id,
76
+ { $set: { status: result.data.status } },
77
+ { new: true, runValidators: true },
78
+ ).lean()
79
+
80
+ if (!agent) {
81
+ res.status(404).json({
82
+ success: false,
83
+ error: { code: 'NOT_FOUND', message: 'Agent not found' },
84
+ })
85
+ return
86
+ }
87
+
88
+ res.json({ success: true, data: agent })
89
+ } catch (err) {
90
+ process.stderr.write(`Failed to update agent status: ${err instanceof Error ? err.message : String(err)}\n`)
91
+ res.status(500).json({
92
+ success: false,
93
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to update agent status' },
94
+ })
95
+ }
96
+ })
97
+
98
+ export { router as agentsRouter }
@@ -0,0 +1,170 @@
1
+ import { Router, type Request, type Response } from 'express'
2
+ import { z } from 'zod'
3
+ import { authMiddleware, requireRole } from '../middleware/auth.js'
4
+ import { Application } from '../models/application.js'
5
+
6
+ const router = Router()
7
+
8
+ const US_STATE_CODES = [
9
+ 'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA',
10
+ 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD',
11
+ 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ',
12
+ 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC',
13
+ 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY', 'DC',
14
+ ] as const
15
+
16
+ const CreateApplicationSchema = z.object({
17
+ applicantName: z.string().min(1).max(200),
18
+ applicantEmail: z.string().email(),
19
+ companyName: z.string().min(1).max(300),
20
+ industry: z.string().min(1).max(100),
21
+ employeeCount: z.number().int().positive(),
22
+ annualRevenue: z.number().int().nonnegative(),
23
+ currentCoverage: z.boolean().default(false),
24
+ previousClaims: z.number().int().nonnegative().default(0),
25
+ requestedCoverageLimit: z.number().int().positive(),
26
+ productId: z.string().min(1),
27
+ notes: z.string().max(5000).default(''),
28
+ state: z.enum(US_STATE_CODES),
29
+ })
30
+
31
+ const UpdateApplicationSchema = CreateApplicationSchema.partial().extend({
32
+ status: z.enum(['draft', 'submitted', 'quoted', 'bound', 'declined', 'expired']).optional(),
33
+ })
34
+
35
+ // List applications (role-filtered)
36
+ router.get('/', authMiddleware, requireRole('mga_admin', 'agent', 'insured'), async (req: Request, res: Response) => {
37
+ try {
38
+ const user = req.user!
39
+ const isAdmin = user.roles.includes('mga_admin')
40
+
41
+ const filter: Record<string, unknown> = {}
42
+ if (!isAdmin && user.roles.includes('agent')) {
43
+ filter.agentId = user.id
44
+ } else if (!isAdmin && user.roles.includes('insured')) {
45
+ filter.applicantEmail = user.email
46
+ }
47
+
48
+ const applications = await Application.find(filter).sort({ createdAt: -1 }).lean()
49
+ res.json({
50
+ success: true,
51
+ data: applications,
52
+ meta: { total: applications.length },
53
+ })
54
+ } catch (err) {
55
+ process.stderr.write(`Failed to list applications: ${err instanceof Error ? err.message : String(err)}\n`)
56
+ res.status(500).json({
57
+ success: false,
58
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to list applications' },
59
+ })
60
+ }
61
+ })
62
+
63
+ // Get single application
64
+ router.get('/:id', authMiddleware, requireRole('mga_admin', 'agent', 'insured'), async (req: Request, res: Response) => {
65
+ try {
66
+ const application = await Application.findById(req.params.id).lean()
67
+ if (!application) {
68
+ res.status(404).json({
69
+ success: false,
70
+ error: { code: 'NOT_FOUND', message: 'Application not found' },
71
+ })
72
+ return
73
+ }
74
+
75
+ const user = req.user!
76
+ const isAdmin = user.roles.includes('mga_admin')
77
+ const isOwnAgent = user.roles.includes('agent') && application.agentId === user.id
78
+ const isOwnInsured = user.roles.includes('insured') && application.applicantEmail === user.email
79
+
80
+ if (!isAdmin && !isOwnAgent && !isOwnInsured) {
81
+ res.status(403).json({
82
+ success: false,
83
+ error: { code: 'FORBIDDEN', message: 'Insufficient permissions' },
84
+ })
85
+ return
86
+ }
87
+
88
+ res.json({ success: true, data: application })
89
+ } catch (err) {
90
+ process.stderr.write(`Failed to get application: ${err instanceof Error ? err.message : String(err)}\n`)
91
+ res.status(500).json({
92
+ success: false,
93
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to get application' },
94
+ })
95
+ }
96
+ })
97
+
98
+ // Create application
99
+ router.post('/', authMiddleware, requireRole('agent', 'insured'), async (req: Request, res: Response) => {
100
+ const result = CreateApplicationSchema.safeParse(req.body)
101
+ if (!result.success) {
102
+ res.status(400).json({
103
+ success: false,
104
+ error: { code: 'VALIDATION_ERROR', message: 'Invalid request body', details: result.error.flatten() },
105
+ })
106
+ return
107
+ }
108
+
109
+ try {
110
+ const application = await Application.create({
111
+ ...result.data,
112
+ agentId: req.user!.id,
113
+ })
114
+ res.status(201).json({ success: true, data: application.toObject() })
115
+ } catch (err) {
116
+ process.stderr.write(`Failed to create application: ${err instanceof Error ? err.message : String(err)}\n`)
117
+ res.status(500).json({
118
+ success: false,
119
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to create application' },
120
+ })
121
+ }
122
+ })
123
+
124
+ // Update application
125
+ router.put('/:id', authMiddleware, requireRole('mga_admin', 'agent'), async (req: Request, res: Response) => {
126
+ const result = UpdateApplicationSchema.safeParse(req.body)
127
+ if (!result.success) {
128
+ res.status(400).json({
129
+ success: false,
130
+ error: { code: 'VALIDATION_ERROR', message: 'Invalid request body', details: result.error.flatten() },
131
+ })
132
+ return
133
+ }
134
+
135
+ try {
136
+ const existing = await Application.findById(req.params.id).lean()
137
+ if (!existing) {
138
+ res.status(404).json({
139
+ success: false,
140
+ error: { code: 'NOT_FOUND', message: 'Application not found' },
141
+ })
142
+ return
143
+ }
144
+
145
+ const isAdmin = req.user!.roles.includes('mga_admin')
146
+ if (!isAdmin && existing.agentId !== req.user!.id) {
147
+ res.status(403).json({
148
+ success: false,
149
+ error: { code: 'FORBIDDEN', message: 'Insufficient permissions' },
150
+ })
151
+ return
152
+ }
153
+
154
+ const application = await Application.findByIdAndUpdate(
155
+ req.params.id,
156
+ { $set: result.data },
157
+ { new: true, runValidators: true },
158
+ ).lean()
159
+
160
+ res.json({ success: true, data: application })
161
+ } catch (err) {
162
+ process.stderr.write(`Failed to update application: ${err instanceof Error ? err.message : String(err)}\n`)
163
+ res.status(500).json({
164
+ success: false,
165
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to update application' },
166
+ })
167
+ }
168
+ })
169
+
170
+ export { router as applicationsRouter }
@@ -0,0 +1,146 @@
1
+ import { Router, type Request, type Response } from 'express'
2
+ import { z } from 'zod'
3
+ import crypto from 'node:crypto'
4
+ import { authMiddleware, requireRole } from '../middleware/auth.js'
5
+ import { Invite } from '../models/invite.js'
6
+ import { Agent } from '../models/agent.js'
7
+
8
+ const router = Router()
9
+
10
+ const INVITE_EXPIRY_DAYS = 7
11
+
12
+ const CreateInviteSchema = z.object({
13
+ email: z.string().email(),
14
+ firstName: z.string().min(1).max(100),
15
+ lastName: z.string().min(1).max(100),
16
+ })
17
+
18
+ // List all invites (admin only)
19
+ router.get('/', authMiddleware, requireRole('mga_admin'), async (_req: Request, res: Response) => {
20
+ try {
21
+ const invites = await Invite.find().sort({ createdAt: -1 }).lean()
22
+ res.json({
23
+ success: true,
24
+ data: invites,
25
+ meta: { total: invites.length },
26
+ })
27
+ } catch (err) {
28
+ process.stderr.write(`Failed to list invites: ${err instanceof Error ? err.message : String(err)}\n`)
29
+ res.status(500).json({
30
+ success: false,
31
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to list invites' },
32
+ })
33
+ }
34
+ })
35
+
36
+ // Create invite (admin only)
37
+ router.post('/', authMiddleware, requireRole('mga_admin'), async (req: Request, res: Response) => {
38
+ const result = CreateInviteSchema.safeParse(req.body)
39
+ if (!result.success) {
40
+ res.status(400).json({
41
+ success: false,
42
+ error: { code: 'VALIDATION_ERROR', message: 'Invalid request body', details: result.error.flatten() },
43
+ })
44
+ return
45
+ }
46
+
47
+ try {
48
+ const existingInvite = await Invite.findOne({
49
+ email: result.data.email,
50
+ status: 'pending',
51
+ }).lean()
52
+
53
+ if (existingInvite) {
54
+ res.status(409).json({
55
+ success: false,
56
+ error: { code: 'CONFLICT', message: 'A pending invite already exists for this email' },
57
+ })
58
+ return
59
+ }
60
+
61
+ const expiresAt = new Date()
62
+ expiresAt.setDate(expiresAt.getDate() + INVITE_EXPIRY_DAYS)
63
+
64
+ const invite = await Invite.create({
65
+ ...result.data,
66
+ invitedBy: req.user!.id,
67
+ token: crypto.randomBytes(32).toString('hex'),
68
+ expiresAt,
69
+ })
70
+
71
+ res.status(201).json({ success: true, data: invite.toObject() })
72
+ } catch (err) {
73
+ process.stderr.write(`Failed to create invite: ${err instanceof Error ? err.message : String(err)}\n`)
74
+ res.status(500).json({
75
+ success: false,
76
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to create invite' },
77
+ })
78
+ }
79
+ })
80
+
81
+ // Accept invite (public with token)
82
+ router.post('/accept', async (req: Request, res: Response) => {
83
+ const tokenSchema = z.object({
84
+ token: z.string().min(1),
85
+ userId: z.string().min(1),
86
+ licenseNumber: z.string().min(1),
87
+ licenseState: z.string().length(2),
88
+ })
89
+
90
+ const result = tokenSchema.safeParse(req.body)
91
+ if (!result.success) {
92
+ res.status(400).json({
93
+ success: false,
94
+ error: { code: 'VALIDATION_ERROR', message: 'Invalid request body', details: result.error.flatten() },
95
+ })
96
+ return
97
+ }
98
+
99
+ try {
100
+ const invite = await Invite.findOne({
101
+ token: result.data.token,
102
+ status: 'pending',
103
+ })
104
+
105
+ if (!invite) {
106
+ res.status(404).json({
107
+ success: false,
108
+ error: { code: 'NOT_FOUND', message: 'Invite not found or already used' },
109
+ })
110
+ return
111
+ }
112
+
113
+ if (invite.expiresAt < new Date()) {
114
+ await Invite.findByIdAndUpdate(invite._id, { $set: { status: 'expired' } })
115
+ res.status(410).json({
116
+ success: false,
117
+ error: { code: 'EXPIRED', message: 'This invite has expired' },
118
+ })
119
+ return
120
+ }
121
+
122
+ const agent = await Agent.create({
123
+ userId: result.data.userId,
124
+ email: invite.email,
125
+ firstName: invite.firstName,
126
+ lastName: invite.lastName,
127
+ licenseNumber: result.data.licenseNumber,
128
+ licenseState: result.data.licenseState,
129
+ invitedBy: invite.invitedBy,
130
+ })
131
+
132
+ await Invite.findByIdAndUpdate(invite._id, {
133
+ $set: { status: 'accepted', acceptedAt: new Date() },
134
+ })
135
+
136
+ res.status(201).json({ success: true, data: agent.toObject() })
137
+ } catch (err) {
138
+ process.stderr.write(`Failed to accept invite: ${err instanceof Error ? err.message : String(err)}\n`)
139
+ res.status(500).json({
140
+ success: false,
141
+ error: { code: 'INTERNAL_ERROR', message: 'Failed to accept invite' },
142
+ })
143
+ }
144
+ })
145
+
146
+ export { router as invitesRouter }