mcpmake 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/dist/commands/bundle.d.ts +1 -0
  2. package/dist/commands/bundle.d.ts.map +1 -0
  3. package/dist/commands/bundle.js +5 -4
  4. package/dist/commands/bundle.js.map +1 -0
  5. package/dist/commands/ci.d.ts +1 -0
  6. package/dist/commands/ci.d.ts.map +1 -0
  7. package/dist/commands/ci.js +3 -2
  8. package/dist/commands/ci.js.map +1 -0
  9. package/dist/commands/deploy.d.ts +1 -0
  10. package/dist/commands/deploy.d.ts.map +1 -0
  11. package/dist/commands/deploy.js +4 -3
  12. package/dist/commands/deploy.js.map +1 -0
  13. package/dist/commands/diff.d.ts +1 -0
  14. package/dist/commands/diff.d.ts.map +1 -0
  15. package/dist/commands/diff.js +5 -4
  16. package/dist/commands/diff.js.map +1 -0
  17. package/dist/commands/from/describe.d.ts +1 -0
  18. package/dist/commands/from/describe.d.ts.map +1 -0
  19. package/dist/commands/from/describe.js +11 -10
  20. package/dist/commands/from/describe.js.map +1 -0
  21. package/dist/commands/from/har.d.ts +1 -0
  22. package/dist/commands/from/har.d.ts.map +1 -0
  23. package/dist/commands/from/har.js +14 -13
  24. package/dist/commands/from/har.js.map +1 -0
  25. package/dist/commands/from/openapi.d.ts +1 -0
  26. package/dist/commands/from/openapi.d.ts.map +1 -0
  27. package/dist/commands/from/openapi.js +17 -16
  28. package/dist/commands/from/openapi.js.map +1 -0
  29. package/dist/commands/from/postman.d.ts +1 -0
  30. package/dist/commands/from/postman.d.ts.map +1 -0
  31. package/dist/commands/from/postman.js +13 -12
  32. package/dist/commands/from/postman.js.map +1 -0
  33. package/dist/commands/from/stainless.d.ts +110 -0
  34. package/dist/commands/from/stainless.d.ts.map +1 -0
  35. package/dist/commands/from/stainless.js +272 -0
  36. package/dist/commands/from/stainless.js.map +1 -0
  37. package/dist/commands/from/target-support.d.ts +1 -0
  38. package/dist/commands/from/target-support.d.ts.map +1 -0
  39. package/dist/commands/from/target-support.js +2 -1
  40. package/dist/commands/from/target-support.js.map +1 -0
  41. package/dist/commands/from/url.d.ts +1 -0
  42. package/dist/commands/from/url.d.ts.map +1 -0
  43. package/dist/commands/from/url.js +14 -13
  44. package/dist/commands/from/url.js.map +1 -0
  45. package/dist/commands/from/website.d.ts +1 -0
  46. package/dist/commands/from/website.d.ts.map +1 -0
  47. package/dist/commands/from/website.js +17 -16
  48. package/dist/commands/from/website.js.map +1 -0
  49. package/dist/commands/lint.d.ts +1 -0
  50. package/dist/commands/lint.d.ts.map +1 -0
  51. package/dist/commands/lint.js +6 -5
  52. package/dist/commands/lint.js.map +1 -0
  53. package/dist/commands/merge.d.ts +1 -0
  54. package/dist/commands/merge.d.ts.map +1 -0
  55. package/dist/commands/merge.js +3 -2
  56. package/dist/commands/merge.js.map +1 -0
  57. package/dist/commands/publish.d.ts +1 -0
  58. package/dist/commands/publish.d.ts.map +1 -0
  59. package/dist/commands/publish.js +4 -3
  60. package/dist/commands/publish.js.map +1 -0
  61. package/dist/commands/rescan.d.ts +1 -0
  62. package/dist/commands/rescan.d.ts.map +1 -0
  63. package/dist/commands/rescan.js +12 -11
  64. package/dist/commands/rescan.js.map +1 -0
  65. package/dist/commands/update.d.ts +1 -0
  66. package/dist/commands/update.d.ts.map +1 -0
  67. package/dist/commands/update.js +10 -9
  68. package/dist/commands/update.js.map +1 -0
  69. package/dist/commands/verify.d.ts +1 -0
  70. package/dist/commands/verify.d.ts.map +1 -0
  71. package/dist/commands/verify.js +7 -6
  72. package/dist/commands/verify.js.map +1 -0
  73. package/dist/index.d.ts +1 -0
  74. package/dist/index.d.ts.map +1 -0
  75. package/dist/index.js +23 -2
  76. package/dist/index.js.map +1 -0
  77. package/dist/registry/official-registry.d.ts +1 -0
  78. package/dist/registry/official-registry.d.ts.map +1 -0
  79. package/dist/registry/official-registry.js +1 -0
  80. package/dist/registry/official-registry.js.map +1 -0
  81. package/package.json +24 -42
  82. package/README.md +0 -691
  83. package/dist/analyzer/auth-detector.d.ts +0 -12
  84. package/dist/analyzer/auth-detector.js +0 -142
  85. package/dist/analyzer/dom-parser.d.ts +0 -10
  86. package/dist/analyzer/dom-parser.js +0 -259
  87. package/dist/analyzer/goal-crawler.d.ts +0 -25
  88. package/dist/analyzer/goal-crawler.js +0 -177
  89. package/dist/analyzer/hybrid-detector.d.ts +0 -28
  90. package/dist/analyzer/hybrid-detector.js +0 -96
  91. package/dist/analyzer/index.d.ts +0 -12
  92. package/dist/analyzer/index.js +0 -8
  93. package/dist/analyzer/screenshot-capture.d.ts +0 -29
  94. package/dist/analyzer/screenshot-capture.js +0 -42
  95. package/dist/analyzer/selector-builder.d.ts +0 -19
  96. package/dist/analyzer/selector-builder.js +0 -199
  97. package/dist/analyzer/semantic-analyzer.d.ts +0 -13
  98. package/dist/analyzer/semantic-analyzer.js +0 -145
  99. package/dist/analyzer/site-crawler.d.ts +0 -38
  100. package/dist/analyzer/site-crawler.js +0 -235
  101. package/dist/cloud/billing/billing-engine.d.ts +0 -44
  102. package/dist/cloud/billing/billing-engine.js +0 -81
  103. package/dist/cloud/billing/credit-store.d.ts +0 -64
  104. package/dist/cloud/billing/credit-store.js +0 -168
  105. package/dist/cloud/billing/index.d.ts +0 -4
  106. package/dist/cloud/billing/index.js +0 -2
  107. package/dist/cloud/billing/usage-store.d.ts +0 -42
  108. package/dist/cloud/billing/usage-store.js +0 -85
  109. package/dist/cloud/billing/usage-tracker.d.ts +0 -38
  110. package/dist/cloud/billing/usage-tracker.js +0 -95
  111. package/dist/cloud/build-pipeline.d.ts +0 -39
  112. package/dist/cloud/build-pipeline.js +0 -310
  113. package/dist/cloud/build-queue.d.ts +0 -30
  114. package/dist/cloud/build-queue.js +0 -70
  115. package/dist/cloud/caddy-manager.d.ts +0 -18
  116. package/dist/cloud/caddy-manager.js +0 -97
  117. package/dist/cloud/container-backend.d.ts +0 -62
  118. package/dist/cloud/container-backend.js +0 -59
  119. package/dist/cloud/container-manager.d.ts +0 -64
  120. package/dist/cloud/container-manager.js +0 -301
  121. package/dist/cloud/crypto.d.ts +0 -27
  122. package/dist/cloud/crypto.js +0 -63
  123. package/dist/cloud/db/index.d.ts +0 -27
  124. package/dist/cloud/db/index.js +0 -53
  125. package/dist/cloud/db/migrations.d.ts +0 -12
  126. package/dist/cloud/db/migrations.js +0 -329
  127. package/dist/cloud/db/pg-store.d.ts +0 -45
  128. package/dist/cloud/db/pg-store.js +0 -336
  129. package/dist/cloud/failure-tracker.d.ts +0 -51
  130. package/dist/cloud/failure-tracker.js +0 -102
  131. package/dist/cloud/idle-monitor.d.ts +0 -30
  132. package/dist/cloud/idle-monitor.js +0 -70
  133. package/dist/cloud/mailer.d.ts +0 -21
  134. package/dist/cloud/mailer.js +0 -193
  135. package/dist/cloud/mcp-proxy.d.ts +0 -58
  136. package/dist/cloud/mcp-proxy.js +0 -203
  137. package/dist/cloud/metric-samples.d.ts +0 -43
  138. package/dist/cloud/metric-samples.js +0 -85
  139. package/dist/cloud/metrics.d.ts +0 -26
  140. package/dist/cloud/metrics.js +0 -59
  141. package/dist/cloud/multipart.d.ts +0 -26
  142. package/dist/cloud/multipart.js +0 -132
  143. package/dist/cloud/observability.d.ts +0 -27
  144. package/dist/cloud/observability.js +0 -98
  145. package/dist/cloud/rate-limiter.d.ts +0 -31
  146. package/dist/cloud/rate-limiter.js +0 -58
  147. package/dist/cloud/request-security.d.ts +0 -5
  148. package/dist/cloud/request-security.js +0 -74
  149. package/dist/cloud/resource-monitor.d.ts +0 -69
  150. package/dist/cloud/resource-monitor.js +0 -130
  151. package/dist/cloud/secret-store.d.ts +0 -38
  152. package/dist/cloud/secret-store.js +0 -103
  153. package/dist/cloud/security.d.ts +0 -26
  154. package/dist/cloud/security.js +0 -142
  155. package/dist/cloud/server.d.ts +0 -21
  156. package/dist/cloud/server.js +0 -1079
  157. package/dist/cloud/shared-state.d.ts +0 -72
  158. package/dist/cloud/shared-state.js +0 -159
  159. package/dist/cloud/ssrf.d.ts +0 -43
  160. package/dist/cloud/ssrf.js +0 -150
  161. package/dist/cloud/store.d.ts +0 -41
  162. package/dist/cloud/store.js +0 -75
  163. package/dist/cloud/stripe.d.ts +0 -78
  164. package/dist/cloud/stripe.js +0 -317
  165. package/dist/cloud/telemetry-store.d.ts +0 -53
  166. package/dist/cloud/telemetry-store.js +0 -108
  167. package/dist/cloud/web/auth.d.ts +0 -225
  168. package/dist/cloud/web/auth.js +0 -555
  169. package/dist/cloud/web/charts.d.ts +0 -70
  170. package/dist/cloud/web/charts.js +0 -178
  171. package/dist/cloud/web/csrf.d.ts +0 -14
  172. package/dist/cloud/web/csrf.js +0 -22
  173. package/dist/cloud/web/docs.d.ts +0 -40
  174. package/dist/cloud/web/docs.js +0 -174
  175. package/dist/cloud/web/router.d.ts +0 -25
  176. package/dist/cloud/web/router.js +0 -1921
  177. package/dist/cloud/web/static/alpine.min.js +0 -5
  178. package/dist/cloud/web/static/favicon.svg +0 -4
  179. package/dist/cloud/web/static/htmx-sse.js +0 -290
  180. package/dist/cloud/web/static/htmx.min.js +0 -1
  181. package/dist/cloud/web/static/style.css +0 -2683
  182. package/dist/cloud/web/static-server.d.ts +0 -13
  183. package/dist/cloud/web/static-server.js +0 -73
  184. package/dist/cloud/web/template-engine.d.ts +0 -27
  185. package/dist/cloud/web/template-engine.js +0 -146
  186. package/dist/cloud/web/templates/layouts/admin.hbs +0 -57
  187. package/dist/cloud/web/templates/layouts/auth.hbs +0 -138
  188. package/dist/cloud/web/templates/layouts/base.hbs +0 -16
  189. package/dist/cloud/web/templates/layouts/dashboard.hbs +0 -39
  190. package/dist/cloud/web/templates/layouts/landing.hbs +0 -82
  191. package/dist/cloud/web/templates/pages/admin/overview.hbs +0 -123
  192. package/dist/cloud/web/templates/pages/admin/servers.hbs +0 -129
  193. package/dist/cloud/web/templates/pages/admin/telemetry.hbs +0 -39
  194. package/dist/cloud/web/templates/pages/admin/user-edit.hbs +0 -91
  195. package/dist/cloud/web/templates/pages/admin/users.hbs +0 -179
  196. package/dist/cloud/web/templates/pages/auth/forgot-password.hbs +0 -25
  197. package/dist/cloud/web/templates/pages/auth/login.hbs +0 -33
  198. package/dist/cloud/web/templates/pages/auth/register.hbs +0 -32
  199. package/dist/cloud/web/templates/pages/auth/reset-password.hbs +0 -34
  200. package/dist/cloud/web/templates/pages/dashboard/billing.hbs +0 -140
  201. package/dist/cloud/web/templates/pages/dashboard/create.hbs +0 -173
  202. package/dist/cloud/web/templates/pages/dashboard/index.hbs +0 -8
  203. package/dist/cloud/web/templates/pages/dashboard/server-detail.hbs +0 -280
  204. package/dist/cloud/web/templates/pages/dashboard/server-logs.hbs +0 -35
  205. package/dist/cloud/web/templates/pages/dashboard/server-metrics.hbs +0 -63
  206. package/dist/cloud/web/templates/pages/dashboard/servers-partial.hbs +0 -21
  207. package/dist/cloud/web/templates/pages/dashboard/servers.hbs +0 -44
  208. package/dist/cloud/web/templates/pages/docs/show.hbs +0 -16
  209. package/dist/cloud/web/templates/pages/errors/404.hbs +0 -9
  210. package/dist/cloud/web/templates/pages/errors/500.hbs +0 -8
  211. package/dist/cloud/web/templates/pages/landing/index.hbs +0 -223
  212. package/dist/cloud/web/templates/pages/legal/privacy.hbs +0 -71
  213. package/dist/cloud/web/templates/pages/legal/terms.hbs +0 -73
  214. package/dist/cloud/web/templates/partials/admin-stats.hbs +0 -52
  215. package/dist/cloud/web/templates/partials/flash-message.hbs +0 -6
  216. package/dist/cloud/web/templates/partials/pricing-table.hbs +0 -103
  217. package/dist/cloud/web/templates/partials/server-card.hbs +0 -19
  218. package/dist/cloud/web/templates/partials/status-badge.hbs +0 -1
  219. package/dist/config/configurable-command.d.ts +0 -13
  220. package/dist/config/configurable-command.js +0 -70
  221. package/dist/config/mcpmake-config.d.ts +0 -68
  222. package/dist/config/mcpmake-config.js +0 -207
  223. package/dist/docs/cli.md +0 -400
  224. package/dist/docs/mcp-2026-07-28-migration.md +0 -78
  225. package/dist/docs/migrate-from-stainless.md +0 -94
  226. package/dist/docs/quickstart.md +0 -166
  227. package/dist/docs/show-hn.md +0 -26
  228. package/dist/docs/website-servers.md +0 -169
  229. package/dist/emitter/code-writer.d.ts +0 -8
  230. package/dist/emitter/code-writer.js +0 -25
  231. package/dist/emitter/index.d.ts +0 -32
  232. package/dist/emitter/index.js +0 -280
  233. package/dist/emitter/mcpb-bundler.d.ts +0 -31
  234. package/dist/emitter/mcpb-bundler.js +0 -172
  235. package/dist/emitter/project-scaffolder.d.ts +0 -4
  236. package/dist/emitter/project-scaffolder.js +0 -89
  237. package/dist/emitter/python-template-loader.d.ts +0 -4
  238. package/dist/emitter/python-template-loader.js +0 -30
  239. package/dist/emitter/python-templates/dockerfile.hbs +0 -14
  240. package/dist/emitter/python-templates/env.example.hbs +0 -6
  241. package/dist/emitter/python-templates/requirements.txt.hbs +0 -4
  242. package/dist/emitter/python-templates/server.py.hbs +0 -77
  243. package/dist/emitter/site-scaffolder.d.ts +0 -13
  244. package/dist/emitter/site-scaffolder.js +0 -70
  245. package/dist/emitter/site-template-loader.d.ts +0 -5
  246. package/dist/emitter/site-template-loader.js +0 -47
  247. package/dist/emitter/site-templates/browser-manager.ts.hbs +0 -233
  248. package/dist/emitter/site-templates/config.ts.hbs +0 -28
  249. package/dist/emitter/site-templates/dockerfile.hbs +0 -31
  250. package/dist/emitter/site-templates/env.example.hbs +0 -19
  251. package/dist/emitter/site-templates/package.json.hbs +0 -26
  252. package/dist/emitter/site-templates/server-main-http.ts.hbs +0 -108
  253. package/dist/emitter/site-templates/server-main.ts.hbs +0 -23
  254. package/dist/emitter/site-templates/tool-handler-action.ts.hbs +0 -86
  255. package/dist/emitter/site-templates/tool-handler-form.ts.hbs +0 -116
  256. package/dist/emitter/site-templates/tool-handler-lifecycle.ts.hbs +0 -146
  257. package/dist/emitter/site-templates/tool-index.ts.hbs +0 -11
  258. package/dist/emitter/template-loader.d.ts +0 -1
  259. package/dist/emitter/template-loader.js +0 -27
  260. package/dist/emitter/templates/auth-provider.ts.hbs +0 -57
  261. package/dist/emitter/templates/config.ts.hbs +0 -63
  262. package/dist/emitter/templates/discovery.ts.hbs +0 -301
  263. package/dist/emitter/templates/dockerfile.hbs +0 -34
  264. package/dist/emitter/templates/env.example.hbs +0 -28
  265. package/dist/emitter/templates/gitignore.hbs +0 -5
  266. package/dist/emitter/templates/http-executor.ts.hbs +0 -117
  267. package/dist/emitter/templates/oauth.ts.hbs +0 -188
  268. package/dist/emitter/templates/package.json.hbs +0 -25
  269. package/dist/emitter/templates/prompts.ts.hbs +0 -22
  270. package/dist/emitter/templates/readme.md.hbs +0 -123
  271. package/dist/emitter/templates/resources.ts.hbs +0 -63
  272. package/dist/emitter/templates/server-main-http.ts.hbs +0 -407
  273. package/dist/emitter/templates/server-main.ts.hbs +0 -40
  274. package/dist/emitter/templates/task-handlers.ts.hbs +0 -189
  275. package/dist/emitter/templates/task-manager.ts.hbs +0 -139
  276. package/dist/emitter/templates/task-sse.ts.hbs +0 -105
  277. package/dist/emitter/templates/tool-handler.ts.hbs +0 -124
  278. package/dist/emitter/templates/tool-index.ts.hbs +0 -11
  279. package/dist/emitter/templates/tool-test.ts.hbs +0 -57
  280. package/dist/emitter/templates/trace.ts.hbs +0 -79
  281. package/dist/emitter/templates/tsconfig.json.hbs +0 -16
  282. package/dist/emitter/templates/types.ts.hbs +0 -5
  283. package/dist/emitter/worker-template-loader.d.ts +0 -5
  284. package/dist/emitter/worker-template-loader.js +0 -33
  285. package/dist/emitter/worker-templates/config.ts.hbs +0 -54
  286. package/dist/emitter/worker-templates/dev-vars.example.hbs +0 -10
  287. package/dist/emitter/worker-templates/gitignore.hbs +0 -6
  288. package/dist/emitter/worker-templates/package.json.hbs +0 -24
  289. package/dist/emitter/worker-templates/readme.md.hbs +0 -53
  290. package/dist/emitter/worker-templates/server.test.ts.hbs +0 -20
  291. package/dist/emitter/worker-templates/tool-handler.ts.hbs +0 -85
  292. package/dist/emitter/worker-templates/tool-index.ts.hbs +0 -28
  293. package/dist/emitter/worker-templates/tsconfig.json.hbs +0 -17
  294. package/dist/emitter/worker-templates/worker.ts.hbs +0 -242
  295. package/dist/emitter/worker-templates/wrangler.toml.hbs +0 -19
  296. package/dist/generator/spec-generator.d.ts +0 -6
  297. package/dist/generator/spec-generator.js +0 -50
  298. package/dist/parser/har-filter.d.ts +0 -8
  299. package/dist/parser/har-filter.js +0 -71
  300. package/dist/parser/har-loader.d.ts +0 -2
  301. package/dist/parser/har-loader.js +0 -14
  302. package/dist/parser/har-normalizer.d.ts +0 -20
  303. package/dist/parser/har-normalizer.js +0 -78
  304. package/dist/parser/index.d.ts +0 -10
  305. package/dist/parser/index.js +0 -6
  306. package/dist/parser/openapi-loader.d.ts +0 -6
  307. package/dist/parser/openapi-loader.js +0 -308
  308. package/dist/parser/operation-extractor.d.ts +0 -13
  309. package/dist/parser/operation-extractor.js +0 -155
  310. package/dist/parser/overlay-loader.d.ts +0 -10
  311. package/dist/parser/overlay-loader.js +0 -184
  312. package/dist/parser/postman-loader.d.ts +0 -9
  313. package/dist/parser/postman-loader.js +0 -106
  314. package/dist/parser/schema-converter.d.ts +0 -12
  315. package/dist/parser/schema-converter.js +0 -117
  316. package/dist/plugins/adapter.d.ts +0 -40
  317. package/dist/plugins/adapter.js +0 -15
  318. package/dist/plugins/loader.d.ts +0 -25
  319. package/dist/plugins/loader.js +0 -58
  320. package/dist/pricing.d.ts +0 -55
  321. package/dist/pricing.js +0 -133
  322. package/dist/providers/index.d.ts +0 -15
  323. package/dist/providers/index.js +0 -56
  324. package/dist/recorder/browser-recorder.d.ts +0 -22
  325. package/dist/recorder/browser-recorder.js +0 -205
  326. package/dist/rescan/diff-engine.d.ts +0 -5
  327. package/dist/rescan/diff-engine.js +0 -312
  328. package/dist/rescan/index.d.ts +0 -3
  329. package/dist/rescan/index.js +0 -2
  330. package/dist/rescan/rescan-runner.d.ts +0 -42
  331. package/dist/rescan/rescan-runner.js +0 -69
  332. package/dist/rescan/rescan-scheduler.d.ts +0 -41
  333. package/dist/rescan/rescan-scheduler.js +0 -179
  334. package/dist/site-transformer/browser-tools.d.ts +0 -10
  335. package/dist/site-transformer/browser-tools.js +0 -59
  336. package/dist/site-transformer/index.d.ts +0 -2
  337. package/dist/site-transformer/index.js +0 -2
  338. package/dist/site-transformer/selector-healer.d.ts +0 -8
  339. package/dist/site-transformer/selector-healer.js +0 -106
  340. package/dist/site-transformer/tool-generator.d.ts +0 -13
  341. package/dist/site-transformer/tool-generator.js +0 -245
  342. package/dist/transformer/auth-detector.d.ts +0 -13
  343. package/dist/transformer/auth-detector.js +0 -90
  344. package/dist/transformer/catalog-builder.d.ts +0 -18
  345. package/dist/transformer/catalog-builder.js +0 -56
  346. package/dist/transformer/client-compat.d.ts +0 -6
  347. package/dist/transformer/client-compat.js +0 -44
  348. package/dist/transformer/har-clusterer.d.ts +0 -9
  349. package/dist/transformer/har-clusterer.js +0 -27
  350. package/dist/transformer/har-dedup.d.ts +0 -10
  351. package/dist/transformer/har-dedup.js +0 -81
  352. package/dist/transformer/har-schema-inferrer.d.ts +0 -15
  353. package/dist/transformer/har-schema-inferrer.js +0 -90
  354. package/dist/transformer/har-to-operations.d.ts +0 -13
  355. package/dist/transformer/har-to-operations.js +0 -192
  356. package/dist/transformer/index.d.ts +0 -8
  357. package/dist/transformer/index.js +0 -6
  358. package/dist/transformer/llm-namer.d.ts +0 -6
  359. package/dist/transformer/llm-namer.js +0 -59
  360. package/dist/transformer/naming.d.ts +0 -4
  361. package/dist/transformer/naming.js +0 -30
  362. package/dist/transformer/operation-filter.d.ts +0 -13
  363. package/dist/transformer/operation-filter.js +0 -52
  364. package/dist/transformer/resource-builder.d.ts +0 -12
  365. package/dist/transformer/resource-builder.js +0 -80
  366. package/dist/transformer/schema-merger.d.ts +0 -14
  367. package/dist/transformer/schema-merger.js +0 -65
  368. package/dist/transformer/tool-builder.d.ts +0 -3
  369. package/dist/transformer/tool-builder.js +0 -114
  370. package/dist/types/index.d.ts +0 -131
  371. package/dist/types/index.js +0 -1
  372. package/dist/types/site.d.ts +0 -284
  373. package/dist/types/site.js +0 -8
  374. package/dist/utils/fail.d.ts +0 -48
  375. package/dist/utils/fail.js +0 -204
  376. package/dist/utils/fs.d.ts +0 -5
  377. package/dist/utils/fs.js +0 -28
  378. package/dist/utils/interactive.d.ts +0 -6
  379. package/dist/utils/interactive.js +0 -30
  380. package/dist/utils/logger.d.ts +0 -1
  381. package/dist/utils/logger.js +0 -2
  382. package/dist/utils/sanitize.d.ts +0 -28
  383. package/dist/utils/sanitize.js +0 -44
  384. package/dist/utils/watcher.d.ts +0 -11
  385. package/dist/utils/watcher.js +0 -36
@@ -1,336 +0,0 @@
1
- /**
2
- * PostgreSQL-backed store implementations.
3
- *
4
- * Drop-in replacements for the in-memory ServerStore, UserStore, and
5
- * SessionStore. Every query is parameterized.
6
- */
7
- import { randomBytes } from 'node:crypto';
8
- // ---------------------------------------------------------------------------
9
- // Helpers
10
- // ---------------------------------------------------------------------------
11
- const SESSION_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
12
- // ---------------------------------------------------------------------------
13
- // PgServerStore
14
- // ---------------------------------------------------------------------------
15
- export class PgServerStore {
16
- db;
17
- constructor(db) {
18
- this.db = db;
19
- }
20
- async create(record) {
21
- const existing = await this.get(record.slug);
22
- if (existing) {
23
- throw new Error(`Server with slug "${record.slug}" already exists`);
24
- }
25
- await this.db.query(`INSERT INTO servers (slug, user_id, spec_hash, container_id, port, bearer_token, status, tool_count, created_at, last_active_at)
26
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, [
27
- record.slug,
28
- record.userId ?? null,
29
- record.specHash,
30
- record.containerId,
31
- record.port,
32
- record.bearerToken,
33
- record.status,
34
- record.toolCount,
35
- record.createdAt,
36
- record.lastActiveAt,
37
- ]);
38
- }
39
- async get(slug) {
40
- const { rows } = await this.db.query('SELECT * FROM servers WHERE slug = $1', [slug]);
41
- return rows.length > 0 ? rowToServerRecord(rows[0]) : undefined;
42
- }
43
- async list() {
44
- const { rows } = await this.db.query('SELECT * FROM servers ORDER BY created_at DESC');
45
- return rows.map(rowToServerRecord);
46
- }
47
- async update(slug, updates) {
48
- const existing = await this.get(slug);
49
- if (!existing) {
50
- throw new Error(`Server with slug "${slug}" not found`);
51
- }
52
- // Build SET clause from non-slug fields
53
- const { slug: _ignored, ...safeUpdates } = updates;
54
- const fieldMap = {
55
- userId: 'user_id',
56
- specHash: 'spec_hash',
57
- containerId: 'container_id',
58
- port: 'port',
59
- bearerToken: 'bearer_token',
60
- status: 'status',
61
- toolCount: 'tool_count',
62
- createdAt: 'created_at',
63
- lastActiveAt: 'last_active_at',
64
- };
65
- const setClauses = [];
66
- const values = [];
67
- let paramIndex = 1;
68
- for (const [key, value] of Object.entries(safeUpdates)) {
69
- const column = fieldMap[key];
70
- if (column && value !== undefined) {
71
- setClauses.push(`${column} = $${paramIndex}`);
72
- values.push(value);
73
- paramIndex++;
74
- }
75
- }
76
- if (setClauses.length === 0)
77
- return;
78
- values.push(slug);
79
- await this.db.query(`UPDATE servers SET ${setClauses.join(', ')} WHERE slug = $${paramIndex}`, values);
80
- }
81
- async delete(slug) {
82
- await this.db.query('DELETE FROM servers WHERE slug = $1', [slug]);
83
- }
84
- async findByPort(port) {
85
- const { rows } = await this.db.query('SELECT * FROM servers WHERE port = $1 LIMIT 1', [
86
- port,
87
- ]);
88
- return rows.length > 0 ? rowToServerRecord(rows[0]) : undefined;
89
- }
90
- }
91
- function rowToServerRecord(row) {
92
- return {
93
- slug: row.slug,
94
- userId: row.user_id ?? undefined,
95
- specHash: row.spec_hash,
96
- containerId: row.container_id,
97
- port: row.port,
98
- bearerToken: row.bearer_token,
99
- status: row.status,
100
- toolCount: row.tool_count,
101
- createdAt: typeof row.created_at === 'string' ? row.created_at : new Date(row.created_at).toISOString(),
102
- lastActiveAt: typeof row.last_active_at === 'string'
103
- ? row.last_active_at
104
- : new Date(row.last_active_at).toISOString(),
105
- };
106
- }
107
- // ---------------------------------------------------------------------------
108
- // PgUserStore
109
- // ---------------------------------------------------------------------------
110
- export class PgUserStore {
111
- db;
112
- constructor(db) {
113
- this.db = db;
114
- }
115
- async create(record) {
116
- const normalizedEmail = record.email.toLowerCase().trim();
117
- const existing = await this.getByEmail(normalizedEmail);
118
- if (existing) {
119
- throw new Error(`User with email "${normalizedEmail}" already exists`);
120
- }
121
- await this.db.query(`INSERT INTO users (id, email, password_hash, plan, is_admin, created_at, last_login_at, stripe_customer_id)
122
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, [
123
- record.id,
124
- normalizedEmail,
125
- record.passwordHash,
126
- record.plan,
127
- record.isAdmin,
128
- record.createdAt,
129
- record.lastLoginAt,
130
- record.stripeCustomerId ?? null,
131
- ]);
132
- }
133
- async getById(id) {
134
- const { rows } = await this.db.query('SELECT * FROM users WHERE id = $1', [id]);
135
- return rows.length > 0 ? rowToUserRecord(rows[0]) : undefined;
136
- }
137
- async getByEmail(email) {
138
- const normalized = email.toLowerCase().trim();
139
- const { rows } = await this.db.query('SELECT * FROM users WHERE email = $1', [normalized]);
140
- return rows.length > 0 ? rowToUserRecord(rows[0]) : undefined;
141
- }
142
- async list() {
143
- const { rows } = await this.db.query('SELECT * FROM users ORDER BY created_at DESC');
144
- return rows.map(rowToUserRecord);
145
- }
146
- async update(id, updates) {
147
- const existing = await this.getById(id);
148
- if (!existing) {
149
- throw new Error(`User with id "${id}" not found`);
150
- }
151
- const { id: _ignored, ...safeUpdates } = updates;
152
- const fieldMap = {
153
- email: 'email',
154
- passwordHash: 'password_hash',
155
- plan: 'plan',
156
- isAdmin: 'is_admin',
157
- createdAt: 'created_at',
158
- lastLoginAt: 'last_login_at',
159
- stripeCustomerId: 'stripe_customer_id',
160
- passwordResetTokenHash: 'password_reset_token_hash',
161
- passwordResetExpiresAt: 'password_reset_expires_at',
162
- emailVerified: 'email_verified',
163
- emailVerificationTokenHash: 'email_verification_token_hash',
164
- subscriptionPeriodEnd: 'subscription_period_end',
165
- creditsCalls: 'credits_calls',
166
- };
167
- const setClauses = [];
168
- const values = [];
169
- let paramIndex = 1;
170
- for (const [key, value] of Object.entries(safeUpdates)) {
171
- const column = fieldMap[key];
172
- if (column && value !== undefined) {
173
- setClauses.push(`${column} = $${paramIndex}`);
174
- values.push(value);
175
- paramIndex++;
176
- }
177
- }
178
- if (setClauses.length === 0)
179
- return;
180
- values.push(id);
181
- await this.db.query(`UPDATE users SET ${setClauses.join(', ')} WHERE id = $${paramIndex}`, values);
182
- }
183
- async getByResetToken(tokenHash) {
184
- const { rows } = await this.db.query('SELECT * FROM users WHERE password_reset_token_hash = $1 AND password_reset_expires_at > $2', [tokenHash, Date.now()]);
185
- return rows.length > 0 ? rowToUserRecord(rows[0]) : undefined;
186
- }
187
- async getByVerificationToken(tokenHash) {
188
- const { rows } = await this.db.query('SELECT * FROM users WHERE email_verification_token_hash = $1', [tokenHash]);
189
- return rows.length > 0 ? rowToUserRecord(rows[0]) : undefined;
190
- }
191
- async getByStripeCustomerId(customerId) {
192
- const { rows } = await this.db.query('SELECT * FROM users WHERE stripe_customer_id = $1 LIMIT 1', [customerId]);
193
- return rows.length > 0 ? rowToUserRecord(rows[0]) : undefined;
194
- }
195
- async clearResetToken(id) {
196
- await this.db.query('UPDATE users SET password_reset_token_hash = NULL, password_reset_expires_at = NULL WHERE id = $1', [id]);
197
- }
198
- async clearVerificationToken(id) {
199
- await this.db.query('UPDATE users SET email_verification_token_hash = NULL WHERE id = $1', [
200
- id,
201
- ]);
202
- }
203
- async delete(id) {
204
- await this.db.query('DELETE FROM users WHERE id = $1', [id]);
205
- }
206
- async count() {
207
- const { rows } = await this.db.query('SELECT count(*) AS count FROM users');
208
- return parseInt(rows[0].count, 10);
209
- }
210
- }
211
- function rowToUserRecord(row) {
212
- const record = {
213
- id: row.id,
214
- email: row.email,
215
- passwordHash: row.password_hash,
216
- plan: row.plan,
217
- isAdmin: row.is_admin,
218
- createdAt: typeof row.created_at === 'string' ? row.created_at : new Date(row.created_at).toISOString(),
219
- lastLoginAt: typeof row.last_login_at === 'string'
220
- ? row.last_login_at
221
- : new Date(row.last_login_at).toISOString(),
222
- };
223
- if (row.stripe_customer_id) {
224
- record.stripeCustomerId = row.stripe_customer_id;
225
- }
226
- if (row.password_reset_token_hash) {
227
- record.passwordResetTokenHash = row.password_reset_token_hash;
228
- }
229
- if (row.password_reset_expires_at != null) {
230
- record.passwordResetExpiresAt =
231
- typeof row.password_reset_expires_at === 'number'
232
- ? row.password_reset_expires_at
233
- : Number(row.password_reset_expires_at);
234
- }
235
- if (row.email_verified != null) {
236
- record.emailVerified = row.email_verified === true || row.email_verified === 't';
237
- }
238
- if (row.email_verification_token_hash) {
239
- record.emailVerificationTokenHash = row.email_verification_token_hash;
240
- }
241
- if (row.subscription_period_end != null) {
242
- record.subscriptionPeriodEnd =
243
- typeof row.subscription_period_end === 'number'
244
- ? row.subscription_period_end
245
- : Number(row.subscription_period_end);
246
- }
247
- if (row.credits_calls != null) {
248
- record.creditsCalls =
249
- typeof row.credits_calls === 'number' ? row.credits_calls : Number(row.credits_calls);
250
- }
251
- return record;
252
- }
253
- // ---------------------------------------------------------------------------
254
- // PgSessionStore
255
- // ---------------------------------------------------------------------------
256
- export class PgSessionStore {
257
- db;
258
- constructor(db) {
259
- this.db = db;
260
- }
261
- async create(userId) {
262
- const token = randomBytes(32).toString('hex');
263
- const csrfToken = randomBytes(16).toString('hex');
264
- const now = Date.now();
265
- const session = {
266
- token,
267
- userId,
268
- csrfToken,
269
- createdAt: now,
270
- expiresAt: now + SESSION_MAX_AGE_MS,
271
- };
272
- await this.db.query(`INSERT INTO sessions (token, user_id, csrf_token, created_at, expires_at, pending_server_tokens)
273
- VALUES ($1, $2, $3, $4, $5, $6)`, [token, userId, csrfToken, now, session.expiresAt, null]);
274
- return session;
275
- }
276
- async get(token) {
277
- const { rows } = await this.db.query('SELECT * FROM sessions WHERE token = $1', [token]);
278
- if (rows.length === 0)
279
- return undefined;
280
- const session = rowToSessionRecord(rows[0]);
281
- // Check expiry
282
- if (Date.now() > session.expiresAt) {
283
- await this.destroy(token);
284
- return undefined;
285
- }
286
- return session;
287
- }
288
- async destroy(token) {
289
- await this.db.query('DELETE FROM sessions WHERE token = $1', [token]);
290
- }
291
- async setPendingServerToken(sessionToken, slug, serverBearerToken) {
292
- const session = await this.get(sessionToken);
293
- if (!session)
294
- return;
295
- const pending = session.pendingServerTokens ?? {};
296
- pending[slug] = serverBearerToken;
297
- await this.db.query('UPDATE sessions SET pending_server_tokens = $1 WHERE token = $2', [
298
- JSON.stringify(pending),
299
- sessionToken,
300
- ]);
301
- }
302
- async consumePendingServerToken(sessionToken, slug) {
303
- const session = await this.get(sessionToken);
304
- if (!session?.pendingServerTokens)
305
- return undefined;
306
- const value = session.pendingServerTokens[slug];
307
- if (value === undefined)
308
- return undefined;
309
- delete session.pendingServerTokens[slug];
310
- const remaining = Object.keys(session.pendingServerTokens).length > 0
311
- ? JSON.stringify(session.pendingServerTokens)
312
- : null;
313
- await this.db.query('UPDATE sessions SET pending_server_tokens = $1 WHERE token = $2', [
314
- remaining,
315
- sessionToken,
316
- ]);
317
- return value;
318
- }
319
- async cleanup() {
320
- await this.db.query('DELETE FROM sessions WHERE expires_at < $1', [Date.now()]);
321
- }
322
- }
323
- function rowToSessionRecord(row) {
324
- const pending = row.pending_server_tokens;
325
- const record = {
326
- token: row.token,
327
- userId: row.user_id,
328
- csrfToken: row.csrf_token,
329
- createdAt: typeof row.created_at === 'number' ? row.created_at : Number(row.created_at),
330
- expiresAt: typeof row.expires_at === 'number' ? row.expires_at : Number(row.expires_at),
331
- };
332
- if (pending && typeof pending === 'object' && Object.keys(pending).length > 0) {
333
- record.pendingServerTokens = pending;
334
- }
335
- return record;
336
- }
@@ -1,51 +0,0 @@
1
- /**
2
- * In-memory API failure-rate tracker.
3
- *
4
- * Counts completed HTTP responses by status class in a rolling ring of
5
- * per-minute buckets. There is no single response choke point in the server
6
- * (responses complete via sendJson, sendHtml, redirects, SSE, and the proxy
7
- * stream), so this is fed once per response from the `res` `'finish'`/`'close'`
8
- * events in the server callback — never from the individual writers.
9
- *
10
- * Purely in-memory and bounded (one bucket per minute, capped window). Longer
11
- * history is derived by the periodic sampler into `metric_samples`.
12
- */
13
- /** Aggregate counts over a window. */
14
- export interface FailureWindow {
15
- total: number;
16
- c2xx: number;
17
- c3xx: number;
18
- c4xx: number;
19
- c5xx: number;
20
- /** Responses that never finished (client abort / destroyed socket). */
21
- aborted: number;
22
- /** (5xx + aborted) / total, as a percentage. The "is the API healthy" number. */
23
- serverErrorRatePct: number;
24
- /** 4xx / total, as a percentage. Client errors (often expected). */
25
- clientErrorRatePct: number;
26
- }
27
- /** One per-minute point, for sparklines. */
28
- export interface FailurePoint {
29
- /** Minute index (epoch ms / 60000). */
30
- minute: number;
31
- total: number;
32
- errors: number;
33
- }
34
- export declare class FailureTracker {
35
- private buckets;
36
- private static minute;
37
- private bucket;
38
- /** Record a completed response by its final status code. */
39
- record(statusCode: number, now?: number): void;
40
- /** Record a response that never finished (aborted / destroyed). */
41
- recordAborted(now?: number): void;
42
- /** Drop buckets older than the retained window. */
43
- prune(now?: number): void;
44
- /** Aggregate counts over the last `minutes` minutes (default 60). */
45
- window(minutes?: number, now?: number): FailureWindow;
46
- /**
47
- * Per-minute series over the last `minutes` minutes (oldest first), with empty
48
- * minutes filled as zero so a sparkline has a stable x-axis.
49
- */
50
- series(minutes?: number, now?: number): FailurePoint[];
51
- }
@@ -1,102 +0,0 @@
1
- /**
2
- * In-memory API failure-rate tracker.
3
- *
4
- * Counts completed HTTP responses by status class in a rolling ring of
5
- * per-minute buckets. There is no single response choke point in the server
6
- * (responses complete via sendJson, sendHtml, redirects, SSE, and the proxy
7
- * stream), so this is fed once per response from the `res` `'finish'`/`'close'`
8
- * events in the server callback — never from the individual writers.
9
- *
10
- * Purely in-memory and bounded (one bucket per minute, capped window). Longer
11
- * history is derived by the periodic sampler into `metric_samples`.
12
- */
13
- const WINDOW_MINUTES = 60;
14
- /** Keep a little slack beyond the window so reads never race a prune. */
15
- const MAX_BUCKETS = WINDOW_MINUTES + 5;
16
- function emptyBucket() {
17
- return { c2xx: 0, c3xx: 0, c4xx: 0, c5xx: 0, aborted: 0 };
18
- }
19
- export class FailureTracker {
20
- buckets = new Map();
21
- static minute(now) {
22
- return Math.floor(now / 60_000);
23
- }
24
- bucket(now) {
25
- const m = FailureTracker.minute(now);
26
- let b = this.buckets.get(m);
27
- if (!b) {
28
- b = emptyBucket();
29
- this.buckets.set(m, b);
30
- // Bound memory: drop buckets older than the retained window.
31
- if (this.buckets.size > MAX_BUCKETS)
32
- this.prune(now);
33
- }
34
- return b;
35
- }
36
- /** Record a completed response by its final status code. */
37
- record(statusCode, now = Date.now()) {
38
- const b = this.bucket(now);
39
- if (statusCode >= 500)
40
- b.c5xx++;
41
- else if (statusCode >= 400)
42
- b.c4xx++;
43
- else if (statusCode >= 300)
44
- b.c3xx++;
45
- else
46
- b.c2xx++;
47
- }
48
- /** Record a response that never finished (aborted / destroyed). */
49
- recordAborted(now = Date.now()) {
50
- this.bucket(now).aborted++;
51
- }
52
- /** Drop buckets older than the retained window. */
53
- prune(now = Date.now()) {
54
- const cutoff = FailureTracker.minute(now) - MAX_BUCKETS;
55
- for (const m of this.buckets.keys()) {
56
- if (m < cutoff)
57
- this.buckets.delete(m);
58
- }
59
- }
60
- /** Aggregate counts over the last `minutes` minutes (default 60). */
61
- window(minutes = WINDOW_MINUTES, now = Date.now()) {
62
- const cutoff = FailureTracker.minute(now) - (minutes - 1);
63
- const agg = emptyBucket();
64
- for (const [m, b] of this.buckets) {
65
- if (m < cutoff)
66
- continue;
67
- agg.c2xx += b.c2xx;
68
- agg.c3xx += b.c3xx;
69
- agg.c4xx += b.c4xx;
70
- agg.c5xx += b.c5xx;
71
- agg.aborted += b.aborted;
72
- }
73
- const total = agg.c2xx + agg.c3xx + agg.c4xx + agg.c5xx + agg.aborted;
74
- const pct = (n) => (total > 0 ? (n / total) * 100 : 0);
75
- return {
76
- total,
77
- c2xx: agg.c2xx,
78
- c3xx: agg.c3xx,
79
- c4xx: agg.c4xx,
80
- c5xx: agg.c5xx,
81
- aborted: agg.aborted,
82
- serverErrorRatePct: pct(agg.c5xx + agg.aborted),
83
- clientErrorRatePct: pct(agg.c4xx),
84
- };
85
- }
86
- /**
87
- * Per-minute series over the last `minutes` minutes (oldest first), with empty
88
- * minutes filled as zero so a sparkline has a stable x-axis.
89
- */
90
- series(minutes = WINDOW_MINUTES, now = Date.now()) {
91
- const end = FailureTracker.minute(now);
92
- const start = end - (minutes - 1);
93
- const out = [];
94
- for (let m = start; m <= end; m++) {
95
- const b = this.buckets.get(m);
96
- const total = b ? b.c2xx + b.c3xx + b.c4xx + b.c5xx + b.aborted : 0;
97
- const errors = b ? b.c5xx + b.aborted : 0;
98
- out.push({ minute: m, total, errors });
99
- }
100
- return out;
101
- }
102
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * Monitors container activity and stops idle containers.
3
- *
4
- * Runs a periodic check (default: every 60s) and stops containers
5
- * that haven't had activity for longer than the configured threshold.
6
- */
7
- import type { ServerStore } from './store.js';
8
- export interface IdleMonitorOptions {
9
- /** Check interval in ms (default: 60_000 = 1 minute) */
10
- checkIntervalMs?: number;
11
- /** Idle threshold in ms for http servers (default: 3_600_000 = 1 hour) */
12
- idleThresholdMs?: number;
13
- /** Idle threshold in ms for Playwright servers (default: 1_800_000 = 30 minutes) */
14
- playwrightIdleThresholdMs?: number;
15
- /** Domain for Caddy route removal */
16
- domain?: string;
17
- }
18
- export declare class IdleMonitor {
19
- private readonly store;
20
- private readonly portRelease;
21
- private timer;
22
- private readonly checkIntervalMs;
23
- private readonly idleThresholdMs;
24
- private readonly playwrightIdleThresholdMs;
25
- private readonly domain;
26
- constructor(store: ServerStore, portRelease: (port: number) => void, options?: IdleMonitorOptions);
27
- start(): void;
28
- stop(): void;
29
- check(): Promise<number>;
30
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * Monitors container activity and stops idle containers.
3
- *
4
- * Runs a periodic check (default: every 60s) and stops containers
5
- * that haven't had activity for longer than the configured threshold.
6
- */
7
- import { logger } from '../utils/logger.js';
8
- import { getContainerBackend } from './container-backend.js';
9
- export class IdleMonitor {
10
- store;
11
- portRelease;
12
- timer;
13
- checkIntervalMs;
14
- idleThresholdMs;
15
- playwrightIdleThresholdMs;
16
- domain;
17
- constructor(store, portRelease, options = {}) {
18
- this.store = store;
19
- this.portRelease = portRelease;
20
- this.checkIntervalMs = options.checkIntervalMs ?? 60_000;
21
- this.idleThresholdMs = options.idleThresholdMs ?? 3_600_000;
22
- // Playwright containers use more resources, so default to a shorter idle timeout
23
- this.playwrightIdleThresholdMs = options.playwrightIdleThresholdMs ?? 1_800_000;
24
- this.domain = options.domain ?? 'mcpmake.dev';
25
- }
26
- start() {
27
- if (this.timer)
28
- return;
29
- logger.info(`Idle monitor started (check every ${this.checkIntervalMs / 1000}s, threshold ${this.idleThresholdMs / 1000}s)`);
30
- this.timer = setInterval(() => this.check(), this.checkIntervalMs);
31
- this.timer.unref(); // Don't prevent process exit
32
- }
33
- stop() {
34
- if (this.timer) {
35
- clearInterval(this.timer);
36
- this.timer = undefined;
37
- logger.info('Idle monitor stopped');
38
- }
39
- }
40
- async check() {
41
- const now = Date.now();
42
- const servers = this.store.list();
43
- let stoppedCount = 0;
44
- for (const server of servers) {
45
- if (server.status !== 'running')
46
- continue;
47
- const lastActive = new Date(server.lastActiveAt).getTime();
48
- const idleMs = now - lastActive;
49
- const threshold = server.serverType === 'playwright' ? this.playwrightIdleThresholdMs : this.idleThresholdMs;
50
- if (idleMs > threshold) {
51
- logger.info(`Stopping idle server: ${server.slug} (idle for ${Math.round(idleMs / 60_000)}min)`);
52
- try {
53
- await getContainerBackend().stopContainer(server.containerId);
54
- }
55
- catch (err) {
56
- logger.warn(`Failed to stop container for ${server.slug}: ${err}`);
57
- }
58
- // No Caddy route to remove — routing is backend-authoritative; the
59
- // backend returns 503 for requests to a stopped server.
60
- this.portRelease(server.port);
61
- this.store.update(server.slug, { status: 'stopped' });
62
- stoppedCount++;
63
- }
64
- }
65
- if (stoppedCount > 0) {
66
- logger.info(`Idle monitor: stopped ${stoppedCount} idle server(s)`);
67
- }
68
- return stoppedCount;
69
- }
70
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Minimal email sender for transactional emails (password reset, etc.).
3
- *
4
- * Supports two modes:
5
- * 1. Console (default) — logs the email to stdout. Useful for development
6
- * and self-hosted instances without email infrastructure.
7
- * 2. SMTP — sends via an external SMTP relay. Requires env vars:
8
- * SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, MAIL_FROM
9
- *
10
- * Uses Node.js built-in `net`/`tls` modules — zero external dependencies.
11
- */
12
- export interface MailOptions {
13
- to: string;
14
- subject: string;
15
- text: string;
16
- html?: string;
17
- }
18
- /**
19
- * Send an email. Falls back to console logging when SMTP is not configured.
20
- */
21
- export declare function sendMail(options: MailOptions): Promise<void>;