@supatype/cli 0.1.0-alpha.10

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 (416) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test.log +221 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/assets/supatype-logo-wordmark.ascii.txt +6 -0
  5. package/bin/dev-entry.ts +2 -0
  6. package/bin/supatype.js +5 -0
  7. package/dist/app/framework.d.ts +44 -0
  8. package/dist/app/framework.d.ts.map +1 -0
  9. package/dist/app/framework.js +200 -0
  10. package/dist/app/framework.js.map +1 -0
  11. package/dist/app/proxy-dev-app.d.ts +13 -0
  12. package/dist/app/proxy-dev-app.d.ts.map +1 -0
  13. package/dist/app/proxy-dev-app.js +54 -0
  14. package/dist/app/proxy-dev-app.js.map +1 -0
  15. package/dist/app-config.d.ts +7 -0
  16. package/dist/app-config.d.ts.map +1 -0
  17. package/dist/app-config.js +113 -0
  18. package/dist/app-config.js.map +1 -0
  19. package/dist/assets/supatype-logo-wordmark.ascii.txt +6 -0
  20. package/dist/augmentation-generator.d.ts +2 -0
  21. package/dist/augmentation-generator.d.ts.map +1 -0
  22. package/dist/augmentation-generator.js +111 -0
  23. package/dist/augmentation-generator.js.map +1 -0
  24. package/dist/binary-cache.d.ts +98 -0
  25. package/dist/binary-cache.d.ts.map +1 -0
  26. package/dist/binary-cache.js +687 -0
  27. package/dist/binary-cache.js.map +1 -0
  28. package/dist/cli.d.ts +2 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +61 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/commands/admin.d.ts +4 -0
  33. package/dist/commands/admin.d.ts.map +1 -0
  34. package/dist/commands/admin.js +271 -0
  35. package/dist/commands/admin.js.map +1 -0
  36. package/dist/commands/app.d.ts +3 -0
  37. package/dist/commands/app.d.ts.map +1 -0
  38. package/dist/commands/app.js +82 -0
  39. package/dist/commands/app.js.map +1 -0
  40. package/dist/commands/cache.d.ts +6 -0
  41. package/dist/commands/cache.d.ts.map +1 -0
  42. package/dist/commands/cache.js +105 -0
  43. package/dist/commands/cache.js.map +1 -0
  44. package/dist/commands/cloud.d.ts +23 -0
  45. package/dist/commands/cloud.d.ts.map +1 -0
  46. package/dist/commands/cloud.js +254 -0
  47. package/dist/commands/cloud.js.map +1 -0
  48. package/dist/commands/db.d.ts +8 -0
  49. package/dist/commands/db.d.ts.map +1 -0
  50. package/dist/commands/db.js +116 -0
  51. package/dist/commands/db.js.map +1 -0
  52. package/dist/commands/deploy-types.d.ts +14 -0
  53. package/dist/commands/deploy-types.d.ts.map +1 -0
  54. package/dist/commands/deploy-types.js +38 -0
  55. package/dist/commands/deploy-types.js.map +1 -0
  56. package/dist/commands/deploy.d.ts +15 -0
  57. package/dist/commands/deploy.d.ts.map +1 -0
  58. package/dist/commands/deploy.js +322 -0
  59. package/dist/commands/deploy.js.map +1 -0
  60. package/dist/commands/dev.d.ts +14 -0
  61. package/dist/commands/dev.d.ts.map +1 -0
  62. package/dist/commands/dev.js +806 -0
  63. package/dist/commands/dev.js.map +1 -0
  64. package/dist/commands/diff.d.ts +3 -0
  65. package/dist/commands/diff.d.ts.map +1 -0
  66. package/dist/commands/diff.js +54 -0
  67. package/dist/commands/diff.js.map +1 -0
  68. package/dist/commands/engine.d.ts +7 -0
  69. package/dist/commands/engine.d.ts.map +1 -0
  70. package/dist/commands/engine.js +27 -0
  71. package/dist/commands/engine.js.map +1 -0
  72. package/dist/commands/functions.d.ts +3 -0
  73. package/dist/commands/functions.d.ts.map +1 -0
  74. package/dist/commands/functions.js +749 -0
  75. package/dist/commands/functions.js.map +1 -0
  76. package/dist/commands/generate.d.ts +3 -0
  77. package/dist/commands/generate.d.ts.map +1 -0
  78. package/dist/commands/generate.js +38 -0
  79. package/dist/commands/generate.js.map +1 -0
  80. package/dist/commands/init.d.ts +7 -0
  81. package/dist/commands/init.d.ts.map +1 -0
  82. package/dist/commands/init.js +228 -0
  83. package/dist/commands/init.js.map +1 -0
  84. package/dist/commands/keys.d.ts +4 -0
  85. package/dist/commands/keys.d.ts.map +1 -0
  86. package/dist/commands/keys.js +57 -0
  87. package/dist/commands/keys.js.map +1 -0
  88. package/dist/commands/logs.d.ts +6 -0
  89. package/dist/commands/logs.d.ts.map +1 -0
  90. package/dist/commands/logs.js +52 -0
  91. package/dist/commands/logs.js.map +1 -0
  92. package/dist/commands/migrate-from-v1.d.ts +5 -0
  93. package/dist/commands/migrate-from-v1.d.ts.map +1 -0
  94. package/dist/commands/migrate-from-v1.js +125 -0
  95. package/dist/commands/migrate-from-v1.js.map +1 -0
  96. package/dist/commands/migrate.d.ts +3 -0
  97. package/dist/commands/migrate.d.ts.map +1 -0
  98. package/dist/commands/migrate.js +75 -0
  99. package/dist/commands/migrate.js.map +1 -0
  100. package/dist/commands/pg.d.ts +8 -0
  101. package/dist/commands/pg.d.ts.map +1 -0
  102. package/dist/commands/pg.js +102 -0
  103. package/dist/commands/pg.js.map +1 -0
  104. package/dist/commands/plugins.d.ts +3 -0
  105. package/dist/commands/plugins.d.ts.map +1 -0
  106. package/dist/commands/plugins.js +431 -0
  107. package/dist/commands/plugins.js.map +1 -0
  108. package/dist/commands/pull.d.ts +3 -0
  109. package/dist/commands/pull.d.ts.map +1 -0
  110. package/dist/commands/pull.js +12 -0
  111. package/dist/commands/pull.js.map +1 -0
  112. package/dist/commands/push.d.ts +3 -0
  113. package/dist/commands/push.d.ts.map +1 -0
  114. package/dist/commands/push.js +179 -0
  115. package/dist/commands/push.js.map +1 -0
  116. package/dist/commands/seed.d.ts +5 -0
  117. package/dist/commands/seed.d.ts.map +1 -0
  118. package/dist/commands/seed.js +55 -0
  119. package/dist/commands/seed.js.map +1 -0
  120. package/dist/commands/self-host.d.ts +9 -0
  121. package/dist/commands/self-host.d.ts.map +1 -0
  122. package/dist/commands/self-host.js +310 -0
  123. package/dist/commands/self-host.js.map +1 -0
  124. package/dist/commands/self-update.d.ts +9 -0
  125. package/dist/commands/self-update.d.ts.map +1 -0
  126. package/dist/commands/self-update.js +33 -0
  127. package/dist/commands/self-update.js.map +1 -0
  128. package/dist/commands/status.d.ts +6 -0
  129. package/dist/commands/status.d.ts.map +1 -0
  130. package/dist/commands/status.js +70 -0
  131. package/dist/commands/status.js.map +1 -0
  132. package/dist/commands/types.d.ts +3 -0
  133. package/dist/commands/types.d.ts.map +1 -0
  134. package/dist/commands/types.js +62 -0
  135. package/dist/commands/types.js.map +1 -0
  136. package/dist/commands/update.d.ts +7 -0
  137. package/dist/commands/update.d.ts.map +1 -0
  138. package/dist/commands/update.js +118 -0
  139. package/dist/commands/update.js.map +1 -0
  140. package/dist/components.d.ts +5 -0
  141. package/dist/components.d.ts.map +1 -0
  142. package/dist/components.js +3 -0
  143. package/dist/components.js.map +1 -0
  144. package/dist/config.d.ts +65 -0
  145. package/dist/config.d.ts.map +1 -0
  146. package/dist/config.js +134 -0
  147. package/dist/config.js.map +1 -0
  148. package/dist/dev-compose.d.ts +19 -0
  149. package/dist/dev-compose.d.ts.map +1 -0
  150. package/dist/dev-compose.js +468 -0
  151. package/dist/dev-compose.js.map +1 -0
  152. package/dist/dev-log-bus.d.ts +30 -0
  153. package/dist/dev-log-bus.d.ts.map +1 -0
  154. package/dist/dev-log-bus.js +87 -0
  155. package/dist/dev-log-bus.js.map +1 -0
  156. package/dist/dev-log-filter.d.ts +10 -0
  157. package/dist/dev-log-filter.d.ts.map +1 -0
  158. package/dist/dev-log-filter.js +36 -0
  159. package/dist/dev-log-filter.js.map +1 -0
  160. package/dist/dev-logo.d.ts +12 -0
  161. package/dist/dev-logo.d.ts.map +1 -0
  162. package/dist/dev-logo.js +57 -0
  163. package/dist/dev-logo.js.map +1 -0
  164. package/dist/dev-session.d.ts +26 -0
  165. package/dist/dev-session.d.ts.map +1 -0
  166. package/dist/dev-session.js +106 -0
  167. package/dist/dev-session.js.map +1 -0
  168. package/dist/dev-shutdown.d.ts +9 -0
  169. package/dist/dev-shutdown.d.ts.map +1 -0
  170. package/dist/dev-shutdown.js +50 -0
  171. package/dist/dev-shutdown.js.map +1 -0
  172. package/dist/dev-task-colors.d.ts +14 -0
  173. package/dist/dev-task-colors.d.ts.map +1 -0
  174. package/dist/dev-task-colors.js +44 -0
  175. package/dist/dev-task-colors.js.map +1 -0
  176. package/dist/dev-tui.d.ts +24 -0
  177. package/dist/dev-tui.d.ts.map +1 -0
  178. package/dist/dev-tui.js +188 -0
  179. package/dist/dev-tui.js.map +1 -0
  180. package/dist/diff-output.d.ts +4 -0
  181. package/dist/diff-output.d.ts.map +1 -0
  182. package/dist/diff-output.js +12 -0
  183. package/dist/diff-output.js.map +1 -0
  184. package/dist/docker-postgres.d.ts +57 -0
  185. package/dist/docker-postgres.d.ts.map +1 -0
  186. package/dist/docker-postgres.js +208 -0
  187. package/dist/docker-postgres.js.map +1 -0
  188. package/dist/engine-client.d.ts +69 -0
  189. package/dist/engine-client.d.ts.map +1 -0
  190. package/dist/engine-client.js +157 -0
  191. package/dist/engine-client.js.map +1 -0
  192. package/dist/engine-push-output.d.ts +16 -0
  193. package/dist/engine-push-output.d.ts.map +1 -0
  194. package/dist/engine-push-output.js +61 -0
  195. package/dist/engine-push-output.js.map +1 -0
  196. package/dist/ensure-binary.d.ts +7 -0
  197. package/dist/ensure-binary.d.ts.map +1 -0
  198. package/dist/ensure-binary.js +17 -0
  199. package/dist/ensure-binary.js.map +1 -0
  200. package/dist/functions-router-gen.d.ts +14 -0
  201. package/dist/functions-router-gen.d.ts.map +1 -0
  202. package/dist/functions-router-gen.js +199 -0
  203. package/dist/functions-router-gen.js.map +1 -0
  204. package/dist/index.d.ts +11 -0
  205. package/dist/index.d.ts.map +1 -0
  206. package/dist/index.js +9 -0
  207. package/dist/index.js.map +1 -0
  208. package/dist/jwt.d.ts +3 -0
  209. package/dist/jwt.d.ts.map +1 -0
  210. package/dist/jwt.js +13 -0
  211. package/dist/jwt.js.map +1 -0
  212. package/dist/kong-config.d.ts +25 -0
  213. package/dist/kong-config.d.ts.map +1 -0
  214. package/dist/kong-config.js +71 -0
  215. package/dist/kong-config.js.map +1 -0
  216. package/dist/local-gateway.d.ts +7 -0
  217. package/dist/local-gateway.d.ts.map +1 -0
  218. package/dist/local-gateway.js +9 -0
  219. package/dist/local-gateway.js.map +1 -0
  220. package/dist/local-storage.d.ts +8 -0
  221. package/dist/local-storage.d.ts.map +1 -0
  222. package/dist/local-storage.js +14 -0
  223. package/dist/local-storage.js.map +1 -0
  224. package/dist/pgbouncer-userlist.d.ts +5 -0
  225. package/dist/pgbouncer-userlist.d.ts.map +1 -0
  226. package/dist/pgbouncer-userlist.js +14 -0
  227. package/dist/pgbouncer-userlist.js.map +1 -0
  228. package/dist/postgres-ctl.d.ts +44 -0
  229. package/dist/postgres-ctl.d.ts.map +1 -0
  230. package/dist/postgres-ctl.js +137 -0
  231. package/dist/postgres-ctl.js.map +1 -0
  232. package/dist/process-manager.d.ts +49 -0
  233. package/dist/process-manager.d.ts.map +1 -0
  234. package/dist/process-manager.js +177 -0
  235. package/dist/process-manager.js.map +1 -0
  236. package/dist/project-config.d.ts +238 -0
  237. package/dist/project-config.d.ts.map +1 -0
  238. package/dist/project-config.js +159 -0
  239. package/dist/project-config.js.map +1 -0
  240. package/dist/pull-utils.d.ts +31 -0
  241. package/dist/pull-utils.d.ts.map +1 -0
  242. package/dist/pull-utils.js +77 -0
  243. package/dist/pull-utils.js.map +1 -0
  244. package/dist/release-pins.d.ts +7 -0
  245. package/dist/release-pins.d.ts.map +1 -0
  246. package/dist/release-pins.js +27 -0
  247. package/dist/release-pins.js.map +1 -0
  248. package/dist/release-public-key.d.ts +8 -0
  249. package/dist/release-public-key.d.ts.map +1 -0
  250. package/dist/release-public-key.js +13 -0
  251. package/dist/release-public-key.js.map +1 -0
  252. package/dist/restore-system-relation-targets.d.ts +3 -0
  253. package/dist/restore-system-relation-targets.d.ts.map +1 -0
  254. package/dist/restore-system-relation-targets.js +45 -0
  255. package/dist/restore-system-relation-targets.js.map +1 -0
  256. package/dist/runtime-routes.d.ts +34 -0
  257. package/dist/runtime-routes.d.ts.map +1 -0
  258. package/dist/runtime-routes.js +252 -0
  259. package/dist/runtime-routes.js.map +1 -0
  260. package/dist/schema-ast-v2.d.ts +127 -0
  261. package/dist/schema-ast-v2.d.ts.map +1 -0
  262. package/dist/schema-ast-v2.js +226 -0
  263. package/dist/schema-ast-v2.js.map +1 -0
  264. package/dist/scripts/postinstall.d.ts +11 -0
  265. package/dist/scripts/postinstall.d.ts.map +1 -0
  266. package/dist/scripts/postinstall.js +47 -0
  267. package/dist/scripts/postinstall.js.map +1 -0
  268. package/dist/seed.d.ts +8 -0
  269. package/dist/seed.d.ts.map +1 -0
  270. package/dist/seed.js +32 -0
  271. package/dist/seed.js.map +1 -0
  272. package/dist/self-host-compose.d.ts +43 -0
  273. package/dist/self-host-compose.d.ts.map +1 -0
  274. package/dist/self-host-compose.js +400 -0
  275. package/dist/self-host-compose.js.map +1 -0
  276. package/dist/storage-provision.d.ts +24 -0
  277. package/dist/storage-provision.d.ts.map +1 -0
  278. package/dist/storage-provision.js +44 -0
  279. package/dist/storage-provision.js.map +1 -0
  280. package/dist/studio-admin-roles.d.ts +7 -0
  281. package/dist/studio-admin-roles.d.ts.map +1 -0
  282. package/dist/studio-admin-roles.js +14 -0
  283. package/dist/studio-admin-roles.js.map +1 -0
  284. package/dist/studio-dev-server.d.ts +22 -0
  285. package/dist/studio-dev-server.d.ts.map +1 -0
  286. package/dist/studio-dev-server.js +28 -0
  287. package/dist/studio-dev-server.js.map +1 -0
  288. package/dist/supatype-eval-1781522769253.d.mts +2 -0
  289. package/dist/supatype-eval-1781522769253.d.mts.map +1 -0
  290. package/dist/supatype-eval-1781522769253.mjs +3 -0
  291. package/dist/supatype-eval-1781522769253.mjs.map +1 -0
  292. package/dist/systemd.d.ts +26 -0
  293. package/dist/systemd.d.ts.map +1 -0
  294. package/dist/systemd.js +102 -0
  295. package/dist/systemd.js.map +1 -0
  296. package/dist/tsx-runner.d.ts +18 -0
  297. package/dist/tsx-runner.d.ts.map +1 -0
  298. package/dist/tsx-runner.js +69 -0
  299. package/dist/tsx-runner.js.map +1 -0
  300. package/dist/type-extractor.d.ts +4 -0
  301. package/dist/type-extractor.d.ts.map +1 -0
  302. package/dist/type-extractor.js +1213 -0
  303. package/dist/type-extractor.js.map +1 -0
  304. package/dist/type-resolver.d.ts +33 -0
  305. package/dist/type-resolver.d.ts.map +1 -0
  306. package/dist/type-resolver.js +338 -0
  307. package/dist/type-resolver.js.map +1 -0
  308. package/package.json +41 -0
  309. package/releases/deno/VERSION +1 -0
  310. package/scripts/mirror-deno-release.sh +76 -0
  311. package/src/TYPE-RESOLUTION.md +294 -0
  312. package/src/app/framework.ts +249 -0
  313. package/src/app/proxy-dev-app.ts +68 -0
  314. package/src/app-config.ts +128 -0
  315. package/src/augmentation-generator.ts +126 -0
  316. package/src/binary-cache.ts +845 -0
  317. package/src/cli.ts +63 -0
  318. package/src/commands/admin.ts +372 -0
  319. package/src/commands/app.ts +97 -0
  320. package/src/commands/cache.ts +117 -0
  321. package/src/commands/cloud.ts +325 -0
  322. package/src/commands/db.ts +136 -0
  323. package/src/commands/deploy-types.ts +49 -0
  324. package/src/commands/deploy.ts +400 -0
  325. package/src/commands/dev.ts +1009 -0
  326. package/src/commands/diff.ts +63 -0
  327. package/src/commands/engine.ts +30 -0
  328. package/src/commands/functions.ts +901 -0
  329. package/src/commands/generate.ts +44 -0
  330. package/src/commands/init.ts +253 -0
  331. package/src/commands/keys.ts +66 -0
  332. package/src/commands/logs.ts +58 -0
  333. package/src/commands/migrate-from-v1.ts +131 -0
  334. package/src/commands/migrate.ts +87 -0
  335. package/src/commands/pg.ts +133 -0
  336. package/src/commands/plugins.ts +508 -0
  337. package/src/commands/pull.ts +17 -0
  338. package/src/commands/push.ts +226 -0
  339. package/src/commands/seed.ts +68 -0
  340. package/src/commands/self-host.ts +364 -0
  341. package/src/commands/self-update.ts +45 -0
  342. package/src/commands/status.ts +84 -0
  343. package/src/commands/types.ts +76 -0
  344. package/src/commands/update.ts +136 -0
  345. package/src/components.ts +6 -0
  346. package/src/config.ts +223 -0
  347. package/src/dev-compose.ts +583 -0
  348. package/src/dev-log-bus.ts +101 -0
  349. package/src/dev-log-filter.ts +32 -0
  350. package/src/dev-logo.ts +62 -0
  351. package/src/dev-session.ts +130 -0
  352. package/src/dev-shutdown.ts +54 -0
  353. package/src/dev-task-colors.ts +47 -0
  354. package/src/dev-tui.ts +232 -0
  355. package/src/diff-output.ts +12 -0
  356. package/src/docker-postgres.ts +295 -0
  357. package/src/engine-client.ts +236 -0
  358. package/src/engine-push-output.ts +71 -0
  359. package/src/ensure-binary.ts +28 -0
  360. package/src/functions-router-gen.ts +224 -0
  361. package/src/index.ts +11 -0
  362. package/src/jwt.ts +14 -0
  363. package/src/kong-config.ts +93 -0
  364. package/src/local-gateway.ts +9 -0
  365. package/src/local-storage.ts +14 -0
  366. package/src/pgbouncer-userlist.ts +15 -0
  367. package/src/postgres-ctl.ts +171 -0
  368. package/src/process-manager.ts +220 -0
  369. package/src/project-config.ts +388 -0
  370. package/src/pull-utils.ts +81 -0
  371. package/src/release-pins.ts +31 -0
  372. package/src/release-public-key.ts +12 -0
  373. package/src/restore-system-relation-targets.ts +45 -0
  374. package/src/runtime-routes.ts +291 -0
  375. package/src/schema-ast-v2.ts +324 -0
  376. package/src/scripts/postinstall.ts +51 -0
  377. package/src/seed.ts +43 -0
  378. package/src/self-host-compose.ts +452 -0
  379. package/src/storage-provision.ts +58 -0
  380. package/src/studio-admin-roles.ts +16 -0
  381. package/src/studio-dev-server.ts +53 -0
  382. package/src/supatype-eval-1781522769253.mts +1 -0
  383. package/src/systemd.ts +137 -0
  384. package/src/tsx-runner.ts +89 -0
  385. package/src/type-extractor.ts +1479 -0
  386. package/src/type-resolver.ts +457 -0
  387. package/tests/app-command.test.ts +54 -0
  388. package/tests/augmentation-generator.test.ts +59 -0
  389. package/tests/binary-cache-cloud-overrides.test.ts +123 -0
  390. package/tests/cached-artifact-format.test.ts +84 -0
  391. package/tests/cli-help.test.ts +133 -0
  392. package/tests/config.test.ts +252 -0
  393. package/tests/dev-ui.test.ts +139 -0
  394. package/tests/docker-postgres.test.ts +39 -0
  395. package/tests/engine-distribution.test.ts +418 -0
  396. package/tests/engine-push-output.test.ts +67 -0
  397. package/tests/ensure-binary.test.ts +59 -0
  398. package/tests/init.test.ts +127 -0
  399. package/tests/keys.test.ts +160 -0
  400. package/tests/migrate-from-v1.test.ts +29 -0
  401. package/tests/normalize-admin-config.test.ts +48 -0
  402. package/tests/pg-spawn-env.test.ts +18 -0
  403. package/tests/postgres-archive-tag.test.ts +9 -0
  404. package/tests/proxy-dev-app.test.ts +33 -0
  405. package/tests/pull-utils.test.ts +150 -0
  406. package/tests/release-pins.test.ts +28 -0
  407. package/tests/runtime-contract.test.ts +370 -0
  408. package/tests/seed-discover.test.ts +31 -0
  409. package/tests/studio-admin-roles.test.ts +27 -0
  410. package/tests/tsconfig.json +9 -0
  411. package/tests/tsx-runner.test.ts +66 -0
  412. package/tests/type-extractor.test.ts +985 -0
  413. package/tests/type-resolver.test.ts +59 -0
  414. package/tsconfig.json +10 -0
  415. package/tsconfig.tsbuildinfo +1 -0
  416. package/vitest.config.ts +12 -0
@@ -0,0 +1,749 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, unlinkSync, } from "node:fs";
2
+ import { resolve, join, basename, relative, isAbsolute } from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+ import { localKongBaseUrl } from "../local-gateway.js";
5
+ import { loadConfig } from "../config.js";
6
+ import { ensureBinary } from "../ensure-binary.js";
7
+ import { functionsPathCandidatesFromProject, preferredFunctionsPathFromProject, } from "../project-config.js";
8
+ import { discoverTsFunctionsInDir, generateFunctionsRouterSource, } from "../functions-router-gen.js";
9
+ import { selfHostComposePaths } from "../self-host-compose.js";
10
+ // ─── Constants ───────────────────────────────────────────────────────────────
11
+ const SHARED_DIR = "_shared";
12
+ const ENV_LOCAL = ".env.local";
13
+ const ENV_PRODUCTION = ".env.production";
14
+ // ─── Registration ────────────────────────────────────────────────────────────
15
+ export function registerFunctions(program) {
16
+ const fnCmd = program
17
+ .command("functions")
18
+ .description("Manage Supatype Edge Functions (Deno-based serverless TypeScript)");
19
+ fnCmd
20
+ .command("new <name>")
21
+ .description("Scaffold a new edge function")
22
+ .action((name) => {
23
+ scaffoldFunction(process.cwd(), name);
24
+ });
25
+ fnCmd
26
+ .command("serve")
27
+ .description("Start a local Deno server that serves all functions with hot reload")
28
+ .option("--port <port>", "Port to serve on", "54321")
29
+ .option("--env-file <path>", "Path to env file", ENV_LOCAL)
30
+ .action(async (opts) => {
31
+ await serve(process.cwd(), opts);
32
+ });
33
+ fnCmd
34
+ .command("deploy")
35
+ .description("Deploy all functions (or --only <name> for one) to the linked project")
36
+ .option("--only <name>", "Deploy a single function")
37
+ .option("--dry-run", "Show what would be deployed without deploying")
38
+ .action(async (opts) => {
39
+ await deploy(process.cwd(), opts);
40
+ });
41
+ fnCmd
42
+ .command("list")
43
+ .description("List all deployed functions for the linked project")
44
+ .action(async () => {
45
+ await listFunctions(process.cwd());
46
+ });
47
+ fnCmd
48
+ .command("delete <name>")
49
+ .description("Remove a deployed function")
50
+ .action(async (name) => {
51
+ await deleteFunction(process.cwd(), name);
52
+ });
53
+ fnCmd
54
+ .command("logs <name>")
55
+ .description("Tail logs for a deployed function")
56
+ .option("--since <duration>", "Show logs since duration (e.g. 1h, 30m)", "1h")
57
+ .action(async (name, opts) => {
58
+ await functionLogs(process.cwd(), name, opts);
59
+ });
60
+ fnCmd
61
+ .command("invoke <name>")
62
+ .description("Invoke a local or deployed function")
63
+ .option("--data <json>", "JSON body to send", "{}")
64
+ .option("--auth", "Include a test JWT in the request")
65
+ .option("--local", "Invoke the local dev server (default if serve is running)")
66
+ .action(async (name, opts) => {
67
+ await invoke(process.cwd(), name, opts);
68
+ });
69
+ const envCmd = fnCmd
70
+ .command("env")
71
+ .description("Manage function environment variables");
72
+ envCmd
73
+ .command("list")
74
+ .description("List environment variables (values masked)")
75
+ .action(async () => {
76
+ await envList(process.cwd());
77
+ });
78
+ envCmd
79
+ .command("set <keyvalue>")
80
+ .description("Set an environment variable (KEY=value)")
81
+ .action(async (keyvalue) => {
82
+ await envSet(process.cwd(), keyvalue);
83
+ });
84
+ envCmd
85
+ .command("unset <key>")
86
+ .description("Remove an environment variable")
87
+ .action(async (key) => {
88
+ await envUnset(process.cwd(), key);
89
+ });
90
+ }
91
+ // ─── Scaffold ────────────────────────────────────────────────────────────────
92
+ function scaffoldFunction(cwd, name) {
93
+ const functionsDir = resolveFunctionsDir(cwd, "write");
94
+ const fnDir = resolve(functionsDir, name);
95
+ if (existsSync(fnDir)) {
96
+ console.error(`Function "${name}" already exists at ${relative(cwd, fnDir)}`);
97
+ process.exit(1);
98
+ }
99
+ mkdirSync(fnDir, { recursive: true });
100
+ const indexContent = `// ${name} — Supatype Edge Function
101
+ // Docs: https://supatype.com/docs/edge-functions
102
+
103
+ export default async function handler(req: Request): Promise<Response> {
104
+ const { method, url } = req
105
+
106
+ // Example: read request body for POST requests
107
+ if (method === "POST") {
108
+ const body = await req.json()
109
+ return new Response(JSON.stringify({ message: "Hello from ${name}!", received: body }), {
110
+ status: 200,
111
+ headers: { "Content-Type": "application/json" },
112
+ })
113
+ }
114
+
115
+ return new Response(JSON.stringify({ message: "Hello from ${name}!" }), {
116
+ status: 200,
117
+ headers: { "Content-Type": "application/json" },
118
+ })
119
+ }
120
+ `;
121
+ writeFileSync(join(fnDir, "index.ts"), indexContent, "utf8");
122
+ // Ensure _shared directory exists
123
+ const sharedDir = resolve(functionsDir, SHARED_DIR);
124
+ if (!existsSync(sharedDir)) {
125
+ mkdirSync(sharedDir, { recursive: true });
126
+ writeFileSync(join(sharedDir, "README.md"), "# Shared Code\n\nFiles in `_shared/` are available to all functions via relative imports.\nThis directory is not deployed as a function.\n\nExample: `import { sendEmail } from '../_shared/email.ts'`\n", "utf8");
127
+ }
128
+ // Ensure .env.local exists
129
+ const envLocalPath = resolve(functionsDir, ENV_LOCAL);
130
+ if (!existsSync(envLocalPath)) {
131
+ writeFileSync(envLocalPath, "# Local environment variables for edge functions\n# These are NOT committed to git\n# Set production env vars via: npx supatype functions env set KEY=value\n", "utf8");
132
+ }
133
+ const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir);
134
+ console.log(`Created function: ${functionsDirLabel}/${name}/index.ts`);
135
+ console.log();
136
+ console.log(" Local dev: npx supatype functions serve");
137
+ console.log(` Invoke: npx supatype functions invoke ${name}`);
138
+ console.log(" Deploy: npx supatype functions deploy");
139
+ }
140
+ function resolveFunctionsDir(cwd, mode) {
141
+ try {
142
+ const cfg = loadConfig(cwd);
143
+ if (mode === "write") {
144
+ return preferredFunctionsPathFromProject(cfg, cwd);
145
+ }
146
+ const candidates = functionsPathCandidatesFromProject(cfg, cwd);
147
+ return candidates.find(dir => existsSync(dir)) ?? candidates[0] ?? resolve(cwd, "functions");
148
+ }
149
+ catch {
150
+ // Keep commands usable even if config cannot be loaded yet.
151
+ const modern = resolve(cwd, "functions");
152
+ const legacy = resolve(cwd, "supatype/functions");
153
+ if (mode === "write")
154
+ return existsSync(legacy) ? legacy : modern;
155
+ return existsSync(modern) ? modern : legacy;
156
+ }
157
+ }
158
+ function relativeFunctionsDir(cwd, functionsDir) {
159
+ const rel = relative(cwd, functionsDir);
160
+ return rel.length > 0 ? rel : ".";
161
+ }
162
+ function resolveEnvFilePath(cwd, functionsDir, envFile) {
163
+ if (isAbsolute(envFile))
164
+ return envFile;
165
+ if (envFile.includes("/") || envFile.includes("\\"))
166
+ return resolve(cwd, envFile);
167
+ return resolve(functionsDir, envFile);
168
+ }
169
+ function discoverFunctions(cwd) {
170
+ const functionsDir = resolveFunctionsDir(cwd, "read");
171
+ if (!existsSync(functionsDir))
172
+ return [];
173
+ const entries = readdirSync(functionsDir);
174
+ const fns = [];
175
+ for (const entry of entries) {
176
+ if (entry.startsWith("_") || entry.startsWith("."))
177
+ continue;
178
+ const fullPath = join(functionsDir, entry);
179
+ const stat = statSync(fullPath);
180
+ if (stat.isDirectory()) {
181
+ // Directory function — look for index.ts
182
+ const indexPath = join(fullPath, "index.ts");
183
+ if (existsSync(indexPath)) {
184
+ fns.push({ name: entry, entrypoint: indexPath, absPath: fullPath });
185
+ }
186
+ }
187
+ else if (entry.endsWith(".ts") && !entry.endsWith(".d.ts")) {
188
+ // Single-file function
189
+ const name = basename(entry, ".ts");
190
+ fns.push({ name, entrypoint: fullPath, absPath: fullPath });
191
+ }
192
+ }
193
+ return fns.sort((a, b) => a.name.localeCompare(b.name));
194
+ }
195
+ // ─── Serve (local dev) ──────────────────────────────────────────────────────
196
+ async function serve(cwd, opts) {
197
+ const config = loadConfig(cwd);
198
+ const functionsDir = resolveFunctionsDir(cwd, "read");
199
+ const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir);
200
+ const routes = discoverTsFunctionsInDir(functionsDir);
201
+ if (routes.length === 0) {
202
+ console.error(`No functions found in ${functionsDirLabel}/`);
203
+ console.error("Create one with: npx supatype functions new <name>");
204
+ process.exit(1);
205
+ }
206
+ console.log(`Discovered ${routes.length} function(s):`);
207
+ for (const fn of routes) {
208
+ console.log(` /${fn.name} → ${relative(cwd, fn.entrypoint)}`);
209
+ }
210
+ console.log();
211
+ // Generate a Deno entry script that routes requests to the correct function
212
+ const routerPath = resolve(functionsDir, ".serve-router.ts");
213
+ const routerScript = generateFunctionsRouterSource(routerPath, routes);
214
+ writeFileSync(routerPath, routerScript, "utf8");
215
+ const envFilePath = resolveEnvFilePath(cwd, functionsDir, opts.envFile);
216
+ const envArgs = [];
217
+ if (existsSync(envFilePath)) {
218
+ envArgs.push("--env-file", envFilePath);
219
+ }
220
+ console.log(`Serving functions at http://localhost:${opts.port}/functions/v1/`);
221
+ console.log("Watching for changes...\n");
222
+ let denoBin;
223
+ try {
224
+ denoBin = await ensureBinary("deno", config);
225
+ }
226
+ catch (err) {
227
+ console.error(`[supatype] Could not provision Deno: ${err.message}`);
228
+ process.exit(1);
229
+ }
230
+ const result = spawnSync(denoBin, [
231
+ "run",
232
+ "--allow-net",
233
+ "--allow-env",
234
+ "--allow-read",
235
+ "--watch",
236
+ ...envArgs,
237
+ routerPath,
238
+ ], {
239
+ stdio: "inherit",
240
+ cwd,
241
+ env: {
242
+ ...process.env,
243
+ PORT: opts.port,
244
+ SUPATYPE_DENO_FUNCTIONS_DIR: functionsDir,
245
+ SUPATYPE_SHARED_ENV_FILE: resolve(functionsDir, ENV_LOCAL),
246
+ SUPATYPE_URL: process.env["SUPATYPE_URL"] ?? localKongBaseUrl(),
247
+ SUPATYPE_ANON_KEY: process.env["SUPATYPE_ANON_KEY"] ?? "",
248
+ SUPATYPE_SERVICE_ROLE_KEY: process.env["SUPATYPE_SERVICE_ROLE_KEY"] ?? "",
249
+ },
250
+ });
251
+ // Clean up router script
252
+ try {
253
+ unlinkSync(routerPath);
254
+ }
255
+ catch { /* ignore */ }
256
+ if (result.status !== 0) {
257
+ console.error("Function server exited with errors.");
258
+ process.exit(result.status ?? 1);
259
+ }
260
+ }
261
+ // ─── Deploy ──────────────────────────────────────────────────────────────────
262
+ async function deploy(cwd, opts) {
263
+ const allFns = discoverFunctions(cwd);
264
+ const fns = opts.only
265
+ ? allFns.filter(f => f.name === opts.only)
266
+ : allFns;
267
+ if (fns.length === 0) {
268
+ const functionsDir = resolveFunctionsDir(cwd, "read");
269
+ const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir);
270
+ if (opts.only) {
271
+ console.error(`Function "${opts.only}" not found in ${functionsDirLabel}/`);
272
+ }
273
+ else {
274
+ console.error(`No functions found in ${functionsDirLabel}/`);
275
+ }
276
+ process.exit(1);
277
+ }
278
+ if (opts.dryRun) {
279
+ console.log("Dry run — the following functions would be deployed:\n");
280
+ for (const fn of fns) {
281
+ console.log(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`);
282
+ }
283
+ console.log(`\nTotal: ${fns.length} function(s)`);
284
+ return;
285
+ }
286
+ const composePath = selfHostComposePaths(cwd).composePath;
287
+ if (existsSync(composePath)) {
288
+ await deploySelfHosted(cwd, fns);
289
+ return;
290
+ }
291
+ await deployCloud(cwd, fns);
292
+ }
293
+ async function deploySelfHosted(cwd, fns) {
294
+ console.log("Self-host Compose deployment.\n");
295
+ console.log("Functions are served from your project functions/ directory (no bundle step).\n");
296
+ for (const fn of fns) {
297
+ console.log(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`);
298
+ }
299
+ console.log(`\n${fns.length} function(s) ready on disk.`);
300
+ console.log("Restart the functions-worker container to load changes:");
301
+ console.log(" supatype self-host compose restart functions-worker");
302
+ console.log("\nKong → supatype-server → functions-worker (per-project worker).");
303
+ }
304
+ async function deployCloud(cwd, fns) {
305
+ const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
306
+ const linked = getLinkedProject(cwd);
307
+ if (!linked) {
308
+ console.error("No linked project. Run: npx supatype cloud link");
309
+ process.exit(1);
310
+ }
311
+ const token = getCloudToken();
312
+ if (!token) {
313
+ console.error("Not logged in. Run: npx supatype cloud login");
314
+ process.exit(1);
315
+ }
316
+ const apiUrl = getCloudApiUrl();
317
+ console.log(`Deploying to project: ${linked.ref}\n`);
318
+ for (const fn of fns) {
319
+ const start = Date.now();
320
+ // Read source code
321
+ const source = readFunctionSource(fn);
322
+ try {
323
+ const res = await fetch(`${apiUrl}/api/v1/projects/${linked.ref}/functions/deploy`, {
324
+ method: "POST",
325
+ headers: {
326
+ Authorization: `Bearer ${token}`,
327
+ "Content-Type": "application/json",
328
+ "X-Org-Id": linked.orgId ?? "",
329
+ },
330
+ body: JSON.stringify({
331
+ functions: [{
332
+ name: fn.name,
333
+ source,
334
+ entrypoint: `${fn.name}/index.ts`,
335
+ }],
336
+ }),
337
+ signal: AbortSignal.timeout(60_000),
338
+ });
339
+ if (!res.ok) {
340
+ const body = await res.json().catch(() => ({}));
341
+ console.error(` ${fn.name} ✗ ${body["message"] ?? res.statusText}`);
342
+ continue;
343
+ }
344
+ const duration = Date.now() - start;
345
+ console.log(` ${fn.name} ✓ deployed (${duration}ms)`);
346
+ }
347
+ catch (err) {
348
+ console.error(` ${fn.name} ✗ ${err instanceof Error ? err.message : "unknown error"}`);
349
+ }
350
+ }
351
+ console.log(`\nDeployed ${fns.length} function(s)`);
352
+ console.log(`Invoke: https://${linked.ref}.supatype.dev/functions/v1/<name>`);
353
+ }
354
+ function readFunctionSource(fn) {
355
+ const stat = statSync(fn.absPath);
356
+ if (stat.isFile()) {
357
+ return readFileSync(fn.absPath, "utf8");
358
+ }
359
+ // Directory function — read all .ts files
360
+ const files = {};
361
+ const entries = readdirSync(fn.absPath, { recursive: true });
362
+ for (const entry of entries) {
363
+ const fullPath = join(fn.absPath, entry);
364
+ if (statSync(fullPath).isFile() && (entry.endsWith(".ts") || entry.endsWith(".js"))) {
365
+ files[entry] = readFileSync(fullPath, "utf8");
366
+ }
367
+ }
368
+ return JSON.stringify(files);
369
+ }
370
+ // ─── List ────────────────────────────────────────────────────────────────────
371
+ async function listFunctions(cwd) {
372
+ const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
373
+ const linked = getLinkedProject(cwd);
374
+ if (!linked) {
375
+ // Show local functions instead
376
+ const fns = discoverFunctions(cwd);
377
+ if (fns.length === 0) {
378
+ console.log("No functions found locally or remotely.");
379
+ return;
380
+ }
381
+ console.log("Local functions (not linked to a cloud project):\n");
382
+ for (const fn of fns) {
383
+ console.log(` ${fn.name.padEnd(30)} ${relative(cwd, fn.entrypoint)}`);
384
+ }
385
+ return;
386
+ }
387
+ const token = getCloudToken();
388
+ if (!token) {
389
+ console.error("Not logged in. Run: npx supatype cloud login");
390
+ process.exit(1);
391
+ }
392
+ try {
393
+ const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions`, {
394
+ headers: {
395
+ Authorization: `Bearer ${token}`,
396
+ "X-Org-Id": linked.orgId ?? "",
397
+ },
398
+ signal: AbortSignal.timeout(10_000),
399
+ });
400
+ if (!res.ok) {
401
+ console.error(`Failed to list functions: ${res.statusText}`);
402
+ process.exit(1);
403
+ }
404
+ const { data } = await res.json();
405
+ if (data.length === 0) {
406
+ console.log("No deployed functions.");
407
+ return;
408
+ }
409
+ console.log("Deployed functions:\n");
410
+ console.log(` ${"Name".padEnd(28)} ${"Last Deployed".padEnd(24)} ${"Invocations (24h)".padEnd(20)} Avg Duration`);
411
+ console.log(` ${"─".repeat(28)} ${"─".repeat(24)} ${"─".repeat(20)} ${"─".repeat(12)}`);
412
+ for (const fn of data) {
413
+ const deployed = fn.deployedAt ? new Date(fn.deployedAt).toLocaleString() : "—";
414
+ console.log(` ${fn.name.padEnd(28)} ${deployed.padEnd(24)} ${String(fn.invocations24h ?? 0).padEnd(20)} ${fn.avgDurationMs ?? 0}ms`);
415
+ }
416
+ }
417
+ catch (err) {
418
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
419
+ process.exit(1);
420
+ }
421
+ }
422
+ // ─── Delete ──────────────────────────────────────────────────────────────────
423
+ async function deleteFunction(cwd, name) {
424
+ const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
425
+ const linked = getLinkedProject(cwd);
426
+ if (!linked) {
427
+ console.error("No linked project. Run: npx supatype cloud link");
428
+ process.exit(1);
429
+ }
430
+ const token = getCloudToken();
431
+ if (!token) {
432
+ console.error("Not logged in. Run: npx supatype cloud login");
433
+ process.exit(1);
434
+ }
435
+ try {
436
+ const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/${name}`, {
437
+ method: "DELETE",
438
+ headers: {
439
+ Authorization: `Bearer ${token}`,
440
+ "X-Org-Id": linked.orgId ?? "",
441
+ },
442
+ signal: AbortSignal.timeout(10_000),
443
+ });
444
+ if (!res.ok) {
445
+ const body = await res.json().catch(() => ({}));
446
+ console.error(`Failed to delete "${name}": ${body["message"] ?? res.statusText}`);
447
+ process.exit(1);
448
+ }
449
+ console.log(`Function "${name}" deleted. It will return 404 immediately.`);
450
+ }
451
+ catch (err) {
452
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
453
+ process.exit(1);
454
+ }
455
+ }
456
+ // ─── Logs ────────────────────────────────────────────────────────────────────
457
+ async function functionLogs(cwd, name, opts) {
458
+ const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
459
+ const linked = getLinkedProject(cwd);
460
+ if (!linked) {
461
+ console.error("No linked project. Run: npx supatype cloud link");
462
+ process.exit(1);
463
+ }
464
+ const token = getCloudToken();
465
+ if (!token) {
466
+ console.error("Not logged in. Run: npx supatype cloud login");
467
+ process.exit(1);
468
+ }
469
+ try {
470
+ const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/${name}/logs?since=${opts.since}`, {
471
+ headers: {
472
+ Authorization: `Bearer ${token}`,
473
+ "X-Org-Id": linked.orgId ?? "",
474
+ },
475
+ signal: AbortSignal.timeout(10_000),
476
+ });
477
+ if (!res.ok) {
478
+ console.error(`Failed to fetch logs: ${res.statusText}`);
479
+ process.exit(1);
480
+ }
481
+ const { data } = await res.json();
482
+ if (data.length === 0) {
483
+ console.log(`No logs for "${name}" in the last ${opts.since}.`);
484
+ return;
485
+ }
486
+ for (const entry of data) {
487
+ const ts = new Date(entry.timestamp).toISOString().slice(11, 23);
488
+ const level = entry.level.toUpperCase().padEnd(5);
489
+ console.log(`${ts} [${level}] ${entry.message}`);
490
+ }
491
+ }
492
+ catch (err) {
493
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
494
+ process.exit(1);
495
+ }
496
+ }
497
+ // ─── Invoke ──────────────────────────────────────────────────────────────────
498
+ async function invoke(cwd, name, opts) {
499
+ let url;
500
+ const headers = { "Content-Type": "application/json" };
501
+ if (opts.local) {
502
+ url = `http://localhost:54321/functions/v1/${name}`;
503
+ }
504
+ else {
505
+ const { getLinkedProject, getCloudToken } = await loadCloudHelpers();
506
+ const linked = getLinkedProject(cwd);
507
+ if (linked) {
508
+ url = `https://${linked.ref}.supatype.dev/functions/v1/${name}`;
509
+ const token = getCloudToken();
510
+ if (token && opts.auth) {
511
+ headers["Authorization"] = `Bearer ${token}`;
512
+ }
513
+ }
514
+ else {
515
+ // Default to local
516
+ url = `http://localhost:54321/functions/v1/${name}`;
517
+ }
518
+ }
519
+ if (opts.auth && !headers["Authorization"]) {
520
+ // Generate a test JWT for local invocation
521
+ headers["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIiLCJyb2xlIjoiYXV0aGVudGljYXRlZCIsImlhdCI6MTcwMDAwMDAwMH0.test";
522
+ }
523
+ try {
524
+ let body;
525
+ try {
526
+ JSON.parse(opts.data);
527
+ body = opts.data;
528
+ }
529
+ catch {
530
+ console.error("Invalid JSON data. Use --data '{\"key\": \"value\"}'");
531
+ process.exit(1);
532
+ }
533
+ const start = Date.now();
534
+ const res = await fetch(url, {
535
+ method: "POST",
536
+ headers,
537
+ body,
538
+ signal: AbortSignal.timeout(30_000),
539
+ });
540
+ const duration = Date.now() - start;
541
+ const responseBody = await res.text();
542
+ console.log(`Status: ${res.status} (${duration}ms)`);
543
+ console.log();
544
+ // Try to pretty-print JSON
545
+ try {
546
+ const json = JSON.parse(responseBody);
547
+ console.log(JSON.stringify(json, null, 2));
548
+ }
549
+ catch {
550
+ console.log(responseBody);
551
+ }
552
+ }
553
+ catch (err) {
554
+ if (err instanceof TypeError && err.message.includes("fetch")) {
555
+ console.error(`Cannot reach ${url}`);
556
+ console.error("Is the function server running? Start it with: npx supatype functions serve");
557
+ }
558
+ else {
559
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
560
+ }
561
+ process.exit(1);
562
+ }
563
+ }
564
+ // ─── Env management ──────────────────────────────────────────────────────────
565
+ async function envList(cwd) {
566
+ const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
567
+ const linked = getLinkedProject(cwd);
568
+ if (!linked) {
569
+ // Show local env vars
570
+ const envPath = resolve(resolveFunctionsDir(cwd, "read"), ENV_LOCAL);
571
+ if (!existsSync(envPath)) {
572
+ console.log("No environment variables configured.");
573
+ return;
574
+ }
575
+ const lines = readFileSync(envPath, "utf8").split("\n");
576
+ console.log("Local environment variables:\n");
577
+ for (const line of lines) {
578
+ const trimmed = line.trim();
579
+ if (!trimmed || trimmed.startsWith("#"))
580
+ continue;
581
+ const eqIdx = trimmed.indexOf("=");
582
+ if (eqIdx > 0) {
583
+ const key = trimmed.slice(0, eqIdx);
584
+ console.log(` ${key} = ••••••••`);
585
+ }
586
+ }
587
+ return;
588
+ }
589
+ const token = getCloudToken();
590
+ if (!token) {
591
+ console.error("Not logged in. Run: npx supatype cloud login");
592
+ process.exit(1);
593
+ }
594
+ try {
595
+ const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env`, {
596
+ headers: {
597
+ Authorization: `Bearer ${token}`,
598
+ "X-Org-Id": linked.orgId ?? "",
599
+ },
600
+ signal: AbortSignal.timeout(10_000),
601
+ });
602
+ if (!res.ok) {
603
+ console.error(`Failed to list env vars: ${res.statusText}`);
604
+ process.exit(1);
605
+ }
606
+ const { data } = await res.json();
607
+ if (data.length === 0) {
608
+ console.log("No environment variables set.");
609
+ return;
610
+ }
611
+ console.log("Environment variables (values masked):\n");
612
+ for (const key of data) {
613
+ console.log(` ${key} = ••••••••`);
614
+ }
615
+ }
616
+ catch (err) {
617
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
618
+ process.exit(1);
619
+ }
620
+ }
621
+ async function envSet(cwd, keyvalue) {
622
+ const eqIdx = keyvalue.indexOf("=");
623
+ if (eqIdx <= 0) {
624
+ console.error("Invalid format. Use: npx supatype functions env set KEY=value");
625
+ process.exit(1);
626
+ }
627
+ const key = keyvalue.slice(0, eqIdx);
628
+ const value = keyvalue.slice(eqIdx + 1);
629
+ const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
630
+ const linked = getLinkedProject(cwd);
631
+ if (!linked) {
632
+ // Set in local env file
633
+ const envPath = resolve(resolveFunctionsDir(cwd, "write"), ENV_LOCAL);
634
+ let content = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
635
+ // Replace existing or append
636
+ const regex = new RegExp(`^${key}=.*$`, "m");
637
+ if (regex.test(content)) {
638
+ content = content.replace(regex, `${key}=${value}`);
639
+ }
640
+ else {
641
+ content = content.trimEnd() + `\n${key}=${value}\n`;
642
+ }
643
+ writeFileSync(envPath, content, "utf8");
644
+ console.log(`Set ${key} in local env file.`);
645
+ return;
646
+ }
647
+ const token = getCloudToken();
648
+ if (!token) {
649
+ console.error("Not logged in. Run: npx supatype cloud login");
650
+ process.exit(1);
651
+ }
652
+ try {
653
+ const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env`, {
654
+ method: "POST",
655
+ headers: {
656
+ Authorization: `Bearer ${token}`,
657
+ "Content-Type": "application/json",
658
+ "X-Org-Id": linked.orgId ?? "",
659
+ },
660
+ body: JSON.stringify({ key, value }),
661
+ signal: AbortSignal.timeout(10_000),
662
+ });
663
+ if (!res.ok) {
664
+ const body = await res.json().catch(() => ({}));
665
+ console.error(`Failed to set env var: ${body["message"] ?? res.statusText}`);
666
+ process.exit(1);
667
+ }
668
+ console.log(`Set ${key} for project ${linked.ref}.`);
669
+ }
670
+ catch (err) {
671
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
672
+ process.exit(1);
673
+ }
674
+ }
675
+ async function envUnset(cwd, key) {
676
+ const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
677
+ const linked = getLinkedProject(cwd);
678
+ if (!linked) {
679
+ const envPath = resolve(resolveFunctionsDir(cwd, "read"), ENV_LOCAL);
680
+ if (!existsSync(envPath)) {
681
+ console.error("No local env file found.");
682
+ process.exit(1);
683
+ }
684
+ let content = readFileSync(envPath, "utf8");
685
+ const regex = new RegExp(`^${key}=.*\n?`, "m");
686
+ content = content.replace(regex, "");
687
+ writeFileSync(envPath, content, "utf8");
688
+ console.log(`Removed ${key} from local env file.`);
689
+ return;
690
+ }
691
+ const token = getCloudToken();
692
+ if (!token) {
693
+ console.error("Not logged in. Run: npx supatype cloud login");
694
+ process.exit(1);
695
+ }
696
+ try {
697
+ const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env/${key}`, {
698
+ method: "DELETE",
699
+ headers: {
700
+ Authorization: `Bearer ${token}`,
701
+ "X-Org-Id": linked.orgId ?? "",
702
+ },
703
+ signal: AbortSignal.timeout(10_000),
704
+ });
705
+ if (!res.ok) {
706
+ const body = await res.json().catch(() => ({}));
707
+ console.error(`Failed to unset env var: ${body["message"] ?? res.statusText}`);
708
+ process.exit(1);
709
+ }
710
+ console.log(`Removed ${key} for project ${linked.ref}.`);
711
+ }
712
+ catch (err) {
713
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
714
+ process.exit(1);
715
+ }
716
+ }
717
+ async function loadCloudHelpers() {
718
+ // These helpers read the local .supatype/linked.json and auth token
719
+ return {
720
+ getLinkedProject(cwd) {
721
+ const linkedPath = resolve(cwd, ".supatype/linked.json");
722
+ if (!existsSync(linkedPath))
723
+ return null;
724
+ try {
725
+ const data = JSON.parse(readFileSync(linkedPath, "utf8"));
726
+ const ref = data["ref"];
727
+ const orgId = data["orgId"];
728
+ return ref ? { ref, ...(orgId !== undefined ? { orgId } : {}) } : null;
729
+ }
730
+ catch {
731
+ return null;
732
+ }
733
+ },
734
+ getCloudToken() {
735
+ // Check env first, then config file
736
+ if (process.env["SUPATYPE_ACCESS_TOKEN"]) {
737
+ return process.env["SUPATYPE_ACCESS_TOKEN"];
738
+ }
739
+ const tokenPath = resolve(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "~", ".supatype/token");
740
+ if (!existsSync(tokenPath))
741
+ return null;
742
+ return readFileSync(tokenPath, "utf8").trim() || null;
743
+ },
744
+ getCloudApiUrl() {
745
+ return process.env["SUPATYPE_API_URL"] ?? "https://api.supatype.com";
746
+ },
747
+ };
748
+ }
749
+ //# sourceMappingURL=functions.js.map