@supatype/cli 0.1.0-alpha.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (407) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/.turbo/turbo-test.log +285 -69
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/assets/supatype-logo-wordmark.ascii.txt +6 -0
  5. package/bin/dev-entry.ts +2 -1
  6. package/dist/app/framework.js +1 -3
  7. package/dist/app/framework.js.map +1 -1
  8. package/dist/app/proxy-dev-app.d.ts +14 -0
  9. package/dist/app/proxy-dev-app.d.ts.map +1 -1
  10. package/dist/app/proxy-dev-app.js +110 -6
  11. package/dist/app/proxy-dev-app.js.map +1 -1
  12. package/dist/app-config.d.ts +10 -0
  13. package/dist/app-config.d.ts.map +1 -1
  14. package/dist/app-config.js +72 -0
  15. package/dist/app-config.js.map +1 -1
  16. package/dist/assets/supatype-logo-wordmark.ascii.txt +6 -0
  17. package/dist/binary-cache.d.ts +19 -7
  18. package/dist/binary-cache.d.ts.map +1 -1
  19. package/dist/binary-cache.js +92 -46
  20. package/dist/binary-cache.js.map +1 -1
  21. package/dist/cli.d.ts +1 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +17 -2
  24. package/dist/cli.js.map +1 -1
  25. package/dist/commands/add.d.ts +3 -0
  26. package/dist/commands/add.d.ts.map +1 -0
  27. package/dist/commands/add.js +86 -0
  28. package/dist/commands/add.js.map +1 -0
  29. package/dist/commands/admin.d.ts +28 -1
  30. package/dist/commands/admin.d.ts.map +1 -1
  31. package/dist/commands/admin.js +297 -149
  32. package/dist/commands/admin.js.map +1 -1
  33. package/dist/commands/adopt.d.ts +3 -0
  34. package/dist/commands/adopt.d.ts.map +1 -0
  35. package/dist/commands/adopt.js +55 -0
  36. package/dist/commands/adopt.js.map +1 -0
  37. package/dist/commands/app.d.ts.map +1 -1
  38. package/dist/commands/app.js +20 -17
  39. package/dist/commands/app.js.map +1 -1
  40. package/dist/commands/cache.d.ts.map +1 -1
  41. package/dist/commands/cache.js +11 -10
  42. package/dist/commands/cache.js.map +1 -1
  43. package/dist/commands/cloud.d.ts +4 -9
  44. package/dist/commands/cloud.d.ts.map +1 -1
  45. package/dist/commands/cloud.js +75 -125
  46. package/dist/commands/cloud.js.map +1 -1
  47. package/dist/commands/db.d.ts.map +1 -1
  48. package/dist/commands/db.js +37 -58
  49. package/dist/commands/db.js.map +1 -1
  50. package/dist/commands/deploy.d.ts.map +1 -1
  51. package/dist/commands/deploy.js +140 -96
  52. package/dist/commands/deploy.js.map +1 -1
  53. package/dist/commands/dev.d.ts.map +1 -1
  54. package/dist/commands/dev.js +74 -39
  55. package/dist/commands/dev.js.map +1 -1
  56. package/dist/commands/diff.d.ts.map +1 -1
  57. package/dist/commands/diff.js +39 -39
  58. package/dist/commands/diff.js.map +1 -1
  59. package/dist/commands/doctor.d.ts +3 -0
  60. package/dist/commands/doctor.d.ts.map +1 -0
  61. package/dist/commands/doctor.js +78 -0
  62. package/dist/commands/doctor.js.map +1 -0
  63. package/dist/commands/engine.d.ts.map +1 -1
  64. package/dist/commands/engine.js +5 -4
  65. package/dist/commands/engine.js.map +1 -1
  66. package/dist/commands/functions.d.ts.map +1 -1
  67. package/dist/commands/functions.js +172 -119
  68. package/dist/commands/functions.js.map +1 -1
  69. package/dist/commands/generate.d.ts.map +1 -1
  70. package/dist/commands/generate.js +5 -4
  71. package/dist/commands/generate.js.map +1 -1
  72. package/dist/commands/init.d.ts +35 -1
  73. package/dist/commands/init.d.ts.map +1 -1
  74. package/dist/commands/init.js +883 -107
  75. package/dist/commands/init.js.map +1 -1
  76. package/dist/commands/introspect.d.ts +3 -0
  77. package/dist/commands/introspect.d.ts.map +1 -0
  78. package/dist/commands/introspect.js +35 -0
  79. package/dist/commands/introspect.js.map +1 -0
  80. package/dist/commands/keys.d.ts +15 -1
  81. package/dist/commands/keys.d.ts.map +1 -1
  82. package/dist/commands/keys.js +46 -10
  83. package/dist/commands/keys.js.map +1 -1
  84. package/dist/commands/link-helpers.d.ts +15 -0
  85. package/dist/commands/link-helpers.d.ts.map +1 -0
  86. package/dist/commands/link-helpers.js +225 -0
  87. package/dist/commands/link-helpers.js.map +1 -0
  88. package/dist/commands/logs.d.ts.map +1 -1
  89. package/dist/commands/logs.js +5 -4
  90. package/dist/commands/logs.js.map +1 -1
  91. package/dist/commands/migrate-from-v1.d.ts.map +1 -1
  92. package/dist/commands/migrate-from-v1.js +3 -2
  93. package/dist/commands/migrate-from-v1.js.map +1 -1
  94. package/dist/commands/migrate.d.ts.map +1 -1
  95. package/dist/commands/migrate.js +119 -26
  96. package/dist/commands/migrate.js.map +1 -1
  97. package/dist/commands/pg.d.ts.map +1 -1
  98. package/dist/commands/pg.js +11 -12
  99. package/dist/commands/pg.js.map +1 -1
  100. package/dist/commands/plugins.d.ts.map +1 -1
  101. package/dist/commands/plugins.js +55 -46
  102. package/dist/commands/plugins.js.map +1 -1
  103. package/dist/commands/pull.d.ts.map +1 -1
  104. package/dist/commands/pull.js +33 -5
  105. package/dist/commands/pull.js.map +1 -1
  106. package/dist/commands/push.d.ts.map +1 -1
  107. package/dist/commands/push.js +111 -138
  108. package/dist/commands/push.js.map +1 -1
  109. package/dist/commands/seed.d.ts.map +1 -1
  110. package/dist/commands/seed.js +4 -3
  111. package/dist/commands/seed.js.map +1 -1
  112. package/dist/commands/self-host.d.ts +2 -2
  113. package/dist/commands/self-host.d.ts.map +1 -1
  114. package/dist/commands/self-host.js +65 -50
  115. package/dist/commands/self-host.js.map +1 -1
  116. package/dist/commands/self-update.d.ts.map +1 -1
  117. package/dist/commands/self-update.js +3 -2
  118. package/dist/commands/self-update.js.map +1 -1
  119. package/dist/commands/status.d.ts +1 -1
  120. package/dist/commands/status.d.ts.map +1 -1
  121. package/dist/commands/status.js +95 -29
  122. package/dist/commands/status.js.map +1 -1
  123. package/dist/commands/types.d.ts.map +1 -1
  124. package/dist/commands/types.js +3 -2
  125. package/dist/commands/types.js.map +1 -1
  126. package/dist/commands/update.d.ts.map +1 -1
  127. package/dist/commands/update.js +54 -21
  128. package/dist/commands/update.js.map +1 -1
  129. package/dist/compose-rename.d.ts +10 -0
  130. package/dist/compose-rename.d.ts.map +1 -0
  131. package/dist/compose-rename.js +67 -0
  132. package/dist/compose-rename.js.map +1 -0
  133. package/dist/config.d.ts +2 -1
  134. package/dist/config.d.ts.map +1 -1
  135. package/dist/config.js.map +1 -1
  136. package/dist/dev-compose.d.ts +26 -0
  137. package/dist/dev-compose.d.ts.map +1 -1
  138. package/dist/dev-compose.js +357 -79
  139. package/dist/dev-compose.js.map +1 -1
  140. package/dist/dev-log-bus.d.ts +30 -0
  141. package/dist/dev-log-bus.d.ts.map +1 -0
  142. package/dist/dev-log-bus.js +87 -0
  143. package/dist/dev-log-bus.js.map +1 -0
  144. package/dist/dev-log-filter.d.ts +10 -0
  145. package/dist/dev-log-filter.d.ts.map +1 -0
  146. package/dist/dev-log-filter.js +36 -0
  147. package/dist/dev-log-filter.js.map +1 -0
  148. package/dist/dev-logo.d.ts +12 -0
  149. package/dist/dev-logo.d.ts.map +1 -0
  150. package/dist/dev-logo.js +56 -0
  151. package/dist/dev-logo.js.map +1 -0
  152. package/dist/dev-ports.d.ts +27 -0
  153. package/dist/dev-ports.d.ts.map +1 -0
  154. package/dist/dev-ports.js +171 -0
  155. package/dist/dev-ports.js.map +1 -0
  156. package/dist/dev-session-lock.d.ts +25 -0
  157. package/dist/dev-session-lock.d.ts.map +1 -0
  158. package/dist/dev-session-lock.js +81 -0
  159. package/dist/dev-session-lock.js.map +1 -0
  160. package/dist/dev-session.d.ts +26 -0
  161. package/dist/dev-session.d.ts.map +1 -0
  162. package/dist/dev-session.js +106 -0
  163. package/dist/dev-session.js.map +1 -0
  164. package/dist/dev-shutdown.d.ts +25 -0
  165. package/dist/dev-shutdown.d.ts.map +1 -0
  166. package/dist/dev-shutdown.js +114 -0
  167. package/dist/dev-shutdown.js.map +1 -0
  168. package/dist/dev-task-colors.d.ts +13 -0
  169. package/dist/dev-task-colors.d.ts.map +1 -0
  170. package/dist/dev-task-colors.js +43 -0
  171. package/dist/dev-task-colors.js.map +1 -0
  172. package/dist/dev-tui.d.ts +24 -0
  173. package/dist/dev-tui.d.ts.map +1 -0
  174. package/dist/dev-tui.js +188 -0
  175. package/dist/dev-tui.js.map +1 -0
  176. package/dist/diff-output.d.ts +5 -1
  177. package/dist/diff-output.d.ts.map +1 -1
  178. package/dist/diff-output.js +69 -0
  179. package/dist/diff-output.js.map +1 -1
  180. package/dist/docker-runtime.d.ts +30 -0
  181. package/dist/docker-runtime.d.ts.map +1 -0
  182. package/dist/docker-runtime.js +118 -0
  183. package/dist/docker-runtime.js.map +1 -0
  184. package/dist/engine-client.d.ts +10 -1
  185. package/dist/engine-client.d.ts.map +1 -1
  186. package/dist/engine-client.js +76 -17
  187. package/dist/engine-client.js.map +1 -1
  188. package/dist/engine-push-output.d.ts +17 -0
  189. package/dist/engine-push-output.d.ts.map +1 -0
  190. package/dist/engine-push-output.js +64 -0
  191. package/dist/engine-push-output.js.map +1 -0
  192. package/dist/ensure-binary.js +2 -2
  193. package/dist/ensure-binary.js.map +1 -1
  194. package/dist/env-file.d.ts +5 -0
  195. package/dist/env-file.d.ts.map +1 -0
  196. package/dist/env-file.js +33 -0
  197. package/dist/env-file.js.map +1 -0
  198. package/dist/gitignore.d.ts +8 -0
  199. package/dist/gitignore.d.ts.map +1 -0
  200. package/dist/gitignore.js +41 -0
  201. package/dist/gitignore.js.map +1 -0
  202. package/dist/kong-config.d.ts +9 -0
  203. package/dist/kong-config.d.ts.map +1 -1
  204. package/dist/kong-config.js +18 -1
  205. package/dist/kong-config.js.map +1 -1
  206. package/dist/link.d.ts +66 -0
  207. package/dist/link.d.ts.map +1 -0
  208. package/dist/link.js +160 -0
  209. package/dist/link.js.map +1 -0
  210. package/dist/process-manager.d.ts +8 -0
  211. package/dist/process-manager.d.ts.map +1 -1
  212. package/dist/process-manager.js +53 -9
  213. package/dist/process-manager.js.map +1 -1
  214. package/dist/project-config.d.ts +30 -3
  215. package/dist/project-config.d.ts.map +1 -1
  216. package/dist/project-config.js +37 -4
  217. package/dist/project-config.js.map +1 -1
  218. package/dist/prompts.d.ts +3 -0
  219. package/dist/prompts.d.ts.map +1 -0
  220. package/dist/prompts.js +3 -0
  221. package/dist/prompts.js.map +1 -0
  222. package/dist/pull-utils.d.ts +50 -14
  223. package/dist/pull-utils.d.ts.map +1 -1
  224. package/dist/pull-utils.js +152 -12
  225. package/dist/pull-utils.js.map +1 -1
  226. package/dist/resolve-target.d.ts +86 -0
  227. package/dist/resolve-target.d.ts.map +1 -0
  228. package/dist/resolve-target.js +291 -0
  229. package/dist/resolve-target.js.map +1 -0
  230. package/dist/restore-system-relation-targets.d.ts +3 -0
  231. package/dist/restore-system-relation-targets.d.ts.map +1 -0
  232. package/dist/restore-system-relation-targets.js +45 -0
  233. package/dist/restore-system-relation-targets.js.map +1 -0
  234. package/dist/runtime-routes.d.ts.map +1 -1
  235. package/dist/runtime-routes.js +7 -0
  236. package/dist/runtime-routes.js.map +1 -1
  237. package/dist/schema-ast-v2.d.ts +1 -1
  238. package/dist/schema-ast-v2.d.ts.map +1 -1
  239. package/dist/schema-ast-v2.js +2 -2
  240. package/dist/schema-ast-v2.js.map +1 -1
  241. package/dist/schema-sources.d.ts +40 -0
  242. package/dist/schema-sources.d.ts.map +1 -0
  243. package/dist/schema-sources.js +183 -0
  244. package/dist/schema-sources.js.map +1 -0
  245. package/dist/scripts/postinstall.js +5 -1
  246. package/dist/scripts/postinstall.js.map +1 -1
  247. package/dist/self-host-compose.d.ts +37 -1
  248. package/dist/self-host-compose.d.ts.map +1 -1
  249. package/dist/self-host-compose.js +234 -43
  250. package/dist/self-host-compose.js.map +1 -1
  251. package/dist/storage-provision.d.ts +4 -0
  252. package/dist/storage-provision.d.ts.map +1 -1
  253. package/dist/storage-provision.js +24 -2
  254. package/dist/storage-provision.js.map +1 -1
  255. package/dist/supatype-eval-1781522769253.d.mts +2 -0
  256. package/dist/supatype-eval-1781522769253.d.mts.map +1 -0
  257. package/dist/supatype-eval-1781522769253.mjs +3 -0
  258. package/dist/supatype-eval-1781522769253.mjs.map +1 -0
  259. package/dist/systemd.js +2 -2
  260. package/dist/systemd.js.map +1 -1
  261. package/dist/target-client.d.ts +10 -0
  262. package/dist/target-client.d.ts.map +1 -0
  263. package/dist/target-client.js +22 -0
  264. package/dist/target-client.js.map +1 -0
  265. package/dist/type-extractor.d.ts +11 -0
  266. package/dist/type-extractor.d.ts.map +1 -1
  267. package/dist/type-extractor.js +95 -8
  268. package/dist/type-extractor.js.map +1 -1
  269. package/dist/ui/brand.d.ts +9 -0
  270. package/dist/ui/brand.d.ts.map +1 -0
  271. package/dist/ui/brand.js +11 -0
  272. package/dist/ui/brand.js.map +1 -0
  273. package/dist/ui/confirm.d.ts +12 -0
  274. package/dist/ui/confirm.d.ts.map +1 -0
  275. package/dist/ui/confirm.js +28 -0
  276. package/dist/ui/confirm.js.map +1 -0
  277. package/dist/ui/fatal.d.ts +10 -0
  278. package/dist/ui/fatal.d.ts.map +1 -0
  279. package/dist/ui/fatal.js +34 -0
  280. package/dist/ui/fatal.js.map +1 -0
  281. package/dist/ui/index.d.ts +9 -0
  282. package/dist/ui/index.d.ts.map +1 -0
  283. package/dist/ui/index.js +9 -0
  284. package/dist/ui/index.js.map +1 -0
  285. package/dist/ui/interactive.d.ts +3 -0
  286. package/dist/ui/interactive.d.ts.map +1 -0
  287. package/dist/ui/interactive.js +5 -0
  288. package/dist/ui/interactive.js.map +1 -0
  289. package/dist/ui/messages.d.ts +10 -0
  290. package/dist/ui/messages.d.ts.map +1 -0
  291. package/dist/ui/messages.js +35 -0
  292. package/dist/ui/messages.js.map +1 -0
  293. package/dist/ui/next-steps.d.ts +3 -0
  294. package/dist/ui/next-steps.d.ts.map +1 -0
  295. package/dist/ui/next-steps.js +10 -0
  296. package/dist/ui/next-steps.js.map +1 -0
  297. package/dist/ui/progress.d.ts +5 -0
  298. package/dist/ui/progress.d.ts.map +1 -0
  299. package/dist/ui/progress.js +24 -0
  300. package/dist/ui/progress.js.map +1 -0
  301. package/dist/ui/prompts.d.ts +14 -0
  302. package/dist/ui/prompts.d.ts.map +1 -0
  303. package/dist/ui/prompts.js +34 -0
  304. package/dist/ui/prompts.js.map +1 -0
  305. package/package.json +5 -2
  306. package/src/app/framework.ts +1 -3
  307. package/src/app/proxy-dev-app.ts +114 -6
  308. package/src/app-config.ts +80 -0
  309. package/src/binary-cache.ts +102 -52
  310. package/src/cli.ts +16 -2
  311. package/src/commands/add.ts +97 -0
  312. package/src/commands/admin.ts +381 -190
  313. package/src/commands/adopt.ts +82 -0
  314. package/src/commands/app.ts +20 -17
  315. package/src/commands/cache.ts +11 -10
  316. package/src/commands/cloud.ts +91 -142
  317. package/src/commands/db.ts +40 -63
  318. package/src/commands/deploy.ts +186 -126
  319. package/src/commands/dev.ts +98 -55
  320. package/src/commands/diff.ts +52 -43
  321. package/src/commands/doctor.ts +103 -0
  322. package/src/commands/engine.ts +5 -4
  323. package/src/commands/functions.ts +187 -123
  324. package/src/commands/generate.ts +5 -4
  325. package/src/commands/init.ts +1087 -104
  326. package/src/commands/introspect.ts +48 -0
  327. package/src/commands/keys.ts +56 -14
  328. package/src/commands/link-helpers.ts +273 -0
  329. package/src/commands/logs.ts +5 -4
  330. package/src/commands/migrate-from-v1.ts +3 -2
  331. package/src/commands/migrate.ts +167 -27
  332. package/src/commands/pg.ts +13 -18
  333. package/src/commands/plugins.ts +55 -46
  334. package/src/commands/pull.ts +38 -9
  335. package/src/commands/push.ts +148 -175
  336. package/src/commands/seed.ts +5 -4
  337. package/src/commands/self-host.ts +85 -54
  338. package/src/commands/self-update.ts +3 -2
  339. package/src/commands/status.ts +102 -33
  340. package/src/commands/types.ts +3 -2
  341. package/src/commands/update.ts +59 -23
  342. package/src/compose-rename.ts +76 -0
  343. package/src/config.ts +2 -1
  344. package/src/dev-compose.ts +462 -76
  345. package/src/dev-log-bus.ts +101 -0
  346. package/src/dev-log-filter.ts +32 -0
  347. package/src/dev-logo.ts +61 -0
  348. package/src/dev-ports.ts +212 -0
  349. package/src/dev-session-lock.ts +101 -0
  350. package/src/dev-session.ts +130 -0
  351. package/src/dev-shutdown.ts +147 -0
  352. package/src/dev-task-colors.ts +47 -0
  353. package/src/dev-tui.ts +232 -0
  354. package/src/diff-output.ts +79 -1
  355. package/src/docker-runtime.ts +151 -0
  356. package/src/engine-client.ts +81 -17
  357. package/src/engine-push-output.ts +75 -0
  358. package/src/ensure-binary.ts +2 -2
  359. package/src/env-file.ts +37 -0
  360. package/src/gitignore.ts +48 -0
  361. package/src/kong-config.ts +24 -1
  362. package/src/link.ts +243 -0
  363. package/src/process-manager.ts +66 -10
  364. package/src/project-config.ts +62 -7
  365. package/src/prompts.ts +2 -0
  366. package/src/pull-utils.ts +217 -23
  367. package/src/resolve-target.ts +419 -0
  368. package/src/restore-system-relation-targets.ts +45 -0
  369. package/src/runtime-routes.ts +7 -0
  370. package/src/schema-ast-v2.ts +2 -1
  371. package/src/schema-sources.ts +248 -0
  372. package/src/scripts/postinstall.ts +7 -1
  373. package/src/self-host-compose.ts +262 -46
  374. package/src/storage-provision.ts +33 -1
  375. package/src/supatype-eval-1781522769253.mts +1 -0
  376. package/src/systemd.ts +2 -2
  377. package/src/target-client.ts +40 -0
  378. package/src/type-extractor.ts +124 -11
  379. package/src/ui/README.md +17 -0
  380. package/src/ui/brand.ts +12 -0
  381. package/src/ui/confirm.ts +38 -0
  382. package/src/ui/fatal.ts +43 -0
  383. package/src/ui/index.ts +8 -0
  384. package/src/ui/interactive.ts +4 -0
  385. package/src/ui/messages.ts +43 -0
  386. package/src/ui/next-steps.ts +10 -0
  387. package/src/ui/progress.ts +28 -0
  388. package/src/ui/prompts.ts +40 -0
  389. package/tests/admin-ensure.test.ts +59 -0
  390. package/tests/cli-help.test.ts +27 -2
  391. package/tests/config.test.ts +29 -2
  392. package/tests/dev-ports.test.ts +41 -0
  393. package/tests/dev-session-lock.test.ts +54 -0
  394. package/tests/dev-ui.test.ts +162 -0
  395. package/tests/docker-runtime.test.ts +236 -0
  396. package/tests/engine-push-output.test.ts +67 -0
  397. package/tests/init.test.ts +197 -18
  398. package/tests/link.test.ts +148 -0
  399. package/tests/minisign.test.ts +102 -0
  400. package/tests/proxy-dev-app.test.ts +45 -1
  401. package/tests/pull-utils.test.ts +5 -4
  402. package/tests/runtime-contract.test.ts +186 -2
  403. package/tests/schema-sources.test.ts +119 -0
  404. package/tests/storage-provision.test.ts +100 -0
  405. package/tests/ui-confirm.test.ts +41 -0
  406. package/tests/ui-messages.test.ts +66 -0
  407. package/tsconfig.tsbuildinfo +1 -1
@@ -21,7 +21,11 @@ import {
21
21
  discoverTsFunctionsInDir,
22
22
  generateFunctionsRouterSource,
23
23
  } from "../functions-router-gen.js"
24
- import { selfHostComposePaths } from "../self-host-compose.js"
24
+ import { loadProjectLink } from "../link.js"
25
+ import { resolveTarget } from "../resolve-target.js"
26
+ import { targetFetch } from "../target-client.js"
27
+ import { error, info, plain } from "../ui/messages.js"
28
+ import { nextSteps } from "../ui/next-steps.js"
25
29
 
26
30
  // ─── Constants ───────────────────────────────────────────────────────────────
27
31
 
@@ -56,8 +60,9 @@ export function registerFunctions(program: Command): void {
56
60
  .command("deploy")
57
61
  .description("Deploy all functions (or --only <name> for one) to the linked project")
58
62
  .option("--only <name>", "Deploy a single function")
63
+ .option("--env <name>", "Target environment when linked")
59
64
  .option("--dry-run", "Show what would be deployed without deploying")
60
- .action(async (opts: { only?: string; dryRun?: boolean }) => {
65
+ .action(async (opts: { only?: string; env?: string; dryRun?: boolean }) => {
61
66
  await deploy(process.cwd(), opts)
62
67
  })
63
68
 
@@ -125,7 +130,7 @@ function scaffoldFunction(cwd: string, name: string): void {
125
130
  const functionsDir = resolveFunctionsDir(cwd, "write")
126
131
  const fnDir = resolve(functionsDir, name)
127
132
  if (existsSync(fnDir)) {
128
- console.error(`Function "${name}" already exists at ${relative(cwd, fnDir)}`)
133
+ error(`Function "${name}" already exists at ${relative(cwd, fnDir)}`)
129
134
  process.exit(1)
130
135
  }
131
136
 
@@ -177,11 +182,12 @@ export default async function handler(req: Request): Promise<Response> {
177
182
  }
178
183
 
179
184
  const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir)
180
- console.log(`Created function: ${functionsDirLabel}/${name}/index.ts`)
181
- console.log()
182
- console.log(" Local dev: npx supatype functions serve")
183
- console.log(` Invoke: npx supatype functions invoke ${name}`)
184
- console.log(" Deploy: npx supatype functions deploy")
185
+ info(`Created function: ${functionsDirLabel}/${name}/index.ts`)
186
+ nextSteps("Next steps:", [
187
+ "Local dev: npx supatype functions serve",
188
+ `Invoke: npx supatype functions invoke ${name}`,
189
+ "Deploy: npx supatype functions deploy",
190
+ ])
185
191
  }
186
192
 
187
193
  // ─── Discover functions ──────────────────────────────────────────────────────
@@ -257,16 +263,16 @@ async function serve(cwd: string, opts: { port: string; envFile: string }): Prom
257
263
  const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir)
258
264
  const routes = discoverTsFunctionsInDir(functionsDir)
259
265
  if (routes.length === 0) {
260
- console.error(`No functions found in ${functionsDirLabel}/`)
261
- console.error("Create one with: npx supatype functions new <name>")
266
+ error(`No functions found in ${functionsDirLabel}/`)
267
+ error("Create one with: npx supatype functions new <name>")
262
268
  process.exit(1)
263
269
  }
264
270
 
265
- console.log(`Discovered ${routes.length} function(s):`)
271
+ plain(`Discovered ${routes.length} function(s):`)
266
272
  for (const fn of routes) {
267
- console.log(` /${fn.name} → ${relative(cwd, fn.entrypoint)}`)
273
+ plain(` /${fn.name} → ${relative(cwd, fn.entrypoint)}`)
268
274
  }
269
- console.log()
275
+ plain()
270
276
 
271
277
  // Generate a Deno entry script that routes requests to the correct function
272
278
  const routerPath = resolve(functionsDir, ".serve-router.ts")
@@ -279,14 +285,15 @@ async function serve(cwd: string, opts: { port: string; envFile: string }): Prom
279
285
  envArgs.push("--env-file", envFilePath)
280
286
  }
281
287
 
282
- console.log(`Serving functions at http://localhost:${opts.port}/functions/v1/`)
283
- console.log("Watching for changes...\n")
288
+ info(`Serving functions at http://localhost:${opts.port}/functions/v1/`)
289
+ info("Watching for changes...")
290
+ plain()
284
291
 
285
292
  let denoBin: string
286
293
  try {
287
294
  denoBin = await ensureBinary("deno", config)
288
295
  } catch (err) {
289
- console.error(`[supatype] Could not provision Deno v${config.versions.deno}: ${(err as Error).message}`)
296
+ error(`Could not provision Deno: ${(err as Error).message}`)
290
297
  process.exit(1)
291
298
  }
292
299
 
@@ -320,14 +327,14 @@ async function serve(cwd: string, opts: { port: string; envFile: string }): Prom
320
327
  try { unlinkSync(routerPath) } catch { /* ignore */ }
321
328
 
322
329
  if (result.status !== 0) {
323
- console.error("Function server exited with errors.")
330
+ error("Function server exited with errors.")
324
331
  process.exit(result.status ?? 1)
325
332
  }
326
333
  }
327
334
 
328
335
  // ─── Deploy ──────────────────────────────────────────────────────────────────
329
336
 
330
- async function deploy(cwd: string, opts: { only?: string; dryRun?: boolean }): Promise<void> {
337
+ async function deploy(cwd: string, opts: { only?: string; env?: string; dryRun?: boolean }): Promise<void> {
331
338
  const allFns = discoverFunctions(cwd)
332
339
  const fns = opts.only
333
340
  ? allFns.filter(f => f.name === opts.only)
@@ -337,62 +344,120 @@ async function deploy(cwd: string, opts: { only?: string; dryRun?: boolean }): P
337
344
  const functionsDir = resolveFunctionsDir(cwd, "read")
338
345
  const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir)
339
346
  if (opts.only) {
340
- console.error(`Function "${opts.only}" not found in ${functionsDirLabel}/`)
347
+ error(`Function "${opts.only}" not found in ${functionsDirLabel}/`)
341
348
  } else {
342
- console.error(`No functions found in ${functionsDirLabel}/`)
349
+ error(`No functions found in ${functionsDirLabel}/`)
343
350
  }
344
351
  process.exit(1)
345
352
  }
346
353
 
347
354
  if (opts.dryRun) {
348
- console.log("Dry run — the following functions would be deployed:\n")
355
+ plain("Dry run — the following functions would be deployed:\n")
349
356
  for (const fn of fns) {
350
- console.log(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`)
357
+ plain(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`)
351
358
  }
352
- console.log(`\nTotal: ${fns.length} function(s)`)
359
+ plain(`\nTotal: ${fns.length} function(s)`)
353
360
  return
354
361
  }
355
362
 
363
+ const link = loadProjectLink(cwd)
364
+ if (link) {
365
+ try {
366
+ const target = resolveTarget(cwd, { env: opts.env })
367
+ if (target.mode !== "direct" && target.token) {
368
+ await deployViaTarget(cwd, target, fns)
369
+ return
370
+ }
371
+ } catch {
372
+ /* fall through to compose/local */
373
+ }
374
+ }
375
+
376
+ const { selfHostComposePaths } = await import("../self-host-compose.js")
356
377
  const composePath = selfHostComposePaths(cwd).composePath
357
378
  if (existsSync(composePath)) {
358
379
  await deploySelfHosted(cwd, fns)
359
380
  return
360
381
  }
361
382
 
362
- await deployCloud(cwd, fns)
383
+ await deployCloud(cwd, fns, opts.env)
363
384
  }
364
385
 
365
386
  async function deploySelfHosted(cwd: string, fns: DiscoveredFunction[]): Promise<void> {
366
- console.log("Self-host Compose deployment.\n")
367
- console.log("Functions are served from your project functions/ directory (no bundle step).\n")
387
+ info("Self-host Compose deployment.")
388
+ plain("Functions are served from your project functions/ directory (no bundle step).\n")
389
+
390
+ for (const fn of fns) {
391
+ plain(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`)
392
+ }
393
+
394
+ plain(`\n${fns.length} function(s) ready on disk.`)
395
+ info("Restart the functions-worker container to load changes:")
396
+ plain(" supatype self-host compose restart functions-worker")
397
+ plain("\nKong → supatype-server → functions-worker (per-project worker).")
398
+ }
399
+
400
+ async function deployViaTarget(
401
+ cwd: string,
402
+ target: ReturnType<typeof resolveTarget>,
403
+ fns: DiscoveredFunction[],
404
+ ): Promise<void> {
405
+ info(`Deploying to ${target.mode} project: ${target.projectRef} (${target.environment})`)
406
+ plain()
368
407
 
369
408
  for (const fn of fns) {
370
- console.log(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`)
409
+ const start = Date.now()
410
+ const source = readFunctionSource(fn)
411
+
412
+ try {
413
+ await targetFetch(
414
+ target.apiBaseUrl,
415
+ target.apiPrefix,
416
+ {
417
+ method: "POST",
418
+ path: `/projects/${target.projectRef}/functions/deploy`,
419
+ body: {
420
+ functions: [{
421
+ name: fn.name,
422
+ source,
423
+ entrypoint: `${fn.name}/index.ts`,
424
+ }],
425
+ },
426
+ token: target.token!,
427
+ orgId: target.orgId,
428
+ environment: target.mode === "cloud" ? target.environment : undefined,
429
+ },
430
+ )
431
+
432
+ const duration = Date.now() - start
433
+ plain(` ${fn.name} ✓ deployed (${duration}ms)`)
434
+ } catch (err) {
435
+ plain(` ${fn.name} ✗ ${err instanceof Error ? err.message : "unknown error"}`)
436
+ }
371
437
  }
372
438
 
373
- console.log(`\n${fns.length} function(s) ready on disk.`)
374
- console.log("Restart the functions-worker container to load changes:")
375
- console.log(" supatype self-host compose restart functions-worker")
376
- console.log("\nKong → supatype-server → functions-worker (per-project worker).")
439
+ info(`Deployed ${fns.length} function(s)`)
440
+ void cwd
377
441
  }
378
442
 
379
- async function deployCloud(cwd: string, fns: DiscoveredFunction[]): Promise<void> {
443
+ async function deployCloud(cwd: string, fns: DiscoveredFunction[], env?: string): Promise<void> {
380
444
  const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers()
381
445
  const linked = getLinkedProject(cwd)
382
446
 
383
447
  if (!linked) {
384
- console.error("No linked project. Run: npx supatype cloud link")
448
+ error("No linked project. Run: npx supatype cloud link")
385
449
  process.exit(1)
386
450
  }
387
451
 
388
- const token = getCloudToken()
452
+ const token = getCloudToken(cwd)
389
453
  if (!token) {
390
- console.error("Not logged in. Run: npx supatype cloud login")
454
+ error("Not logged in. Run: npx supatype cloud login")
391
455
  process.exit(1)
392
456
  }
393
457
 
394
- const apiUrl = getCloudApiUrl()
395
- console.log(`Deploying to project: ${linked.ref}\n`)
458
+ const apiUrl = getCloudApiUrl(cwd)
459
+ info(`Deploying to project: ${linked.ref}`)
460
+ plain()
396
461
 
397
462
  for (const fn of fns) {
398
463
  const start = Date.now()
@@ -420,19 +485,19 @@ async function deployCloud(cwd: string, fns: DiscoveredFunction[]): Promise<void
420
485
 
421
486
  if (!res.ok) {
422
487
  const body = await res.json().catch(() => ({})) as Record<string, string>
423
- console.error(` ${fn.name} ✗ ${body["message"] ?? res.statusText}`)
488
+ plain(` ${fn.name} ✗ ${body["message"] ?? res.statusText}`)
424
489
  continue
425
490
  }
426
491
 
427
492
  const duration = Date.now() - start
428
- console.log(` ${fn.name} ✓ deployed (${duration}ms)`)
493
+ plain(` ${fn.name} ✓ deployed (${duration}ms)`)
429
494
  } catch (err) {
430
- console.error(` ${fn.name} ✗ ${err instanceof Error ? err.message : "unknown error"}`)
495
+ plain(` ${fn.name} ✗ ${err instanceof Error ? err.message : "unknown error"}`)
431
496
  }
432
497
  }
433
498
 
434
- console.log(`\nDeployed ${fns.length} function(s)`)
435
- console.log(`Invoke: https://${linked.ref}.supatype.dev/functions/v1/<name>`)
499
+ info(`Deployed ${fns.length} function(s)`)
500
+ info(`Invoke: https://${linked.ref}.supatype.dev/functions/v1/<name>`)
436
501
  }
437
502
 
438
503
  function readFunctionSource(fn: DiscoveredFunction): string {
@@ -463,24 +528,24 @@ async function listFunctions(cwd: string): Promise<void> {
463
528
  // Show local functions instead
464
529
  const fns = discoverFunctions(cwd)
465
530
  if (fns.length === 0) {
466
- console.log("No functions found locally or remotely.")
531
+ info("No functions found locally or remotely.")
467
532
  return
468
533
  }
469
- console.log("Local functions (not linked to a cloud project):\n")
534
+ plain("Local functions (not linked to a cloud project):\n")
470
535
  for (const fn of fns) {
471
- console.log(` ${fn.name.padEnd(30)} ${relative(cwd, fn.entrypoint)}`)
536
+ plain(` ${fn.name.padEnd(30)} ${relative(cwd, fn.entrypoint)}`)
472
537
  }
473
538
  return
474
539
  }
475
540
 
476
- const token = getCloudToken()
541
+ const token = getCloudToken(cwd)
477
542
  if (!token) {
478
- console.error("Not logged in. Run: npx supatype cloud login")
543
+ error("Not logged in. Run: npx supatype cloud login")
479
544
  process.exit(1)
480
545
  }
481
546
 
482
547
  try {
483
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions`, {
548
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions`, {
484
549
  headers: {
485
550
  Authorization: `Bearer ${token}`,
486
551
  "X-Org-Id": linked.orgId ?? "",
@@ -489,29 +554,29 @@ async function listFunctions(cwd: string): Promise<void> {
489
554
  })
490
555
 
491
556
  if (!res.ok) {
492
- console.error(`Failed to list functions: ${res.statusText}`)
557
+ error(`Failed to list functions: ${res.statusText}`)
493
558
  process.exit(1)
494
559
  }
495
560
 
496
561
  const { data } = await res.json() as { data: Array<{ name: string; deployedAt: string; invocations24h: number; avgDurationMs: number }> }
497
562
 
498
563
  if (data.length === 0) {
499
- console.log("No deployed functions.")
564
+ info("No deployed functions.")
500
565
  return
501
566
  }
502
567
 
503
- console.log("Deployed functions:\n")
504
- console.log(` ${"Name".padEnd(28)} ${"Last Deployed".padEnd(24)} ${"Invocations (24h)".padEnd(20)} Avg Duration`)
505
- console.log(` ${"─".repeat(28)} ${"─".repeat(24)} ${"─".repeat(20)} ${"─".repeat(12)}`)
568
+ plain("Deployed functions:\n")
569
+ plain(` ${"Name".padEnd(28)} ${"Last Deployed".padEnd(24)} ${"Invocations (24h)".padEnd(20)} Avg Duration`)
570
+ plain(` ${"─".repeat(28)} ${"─".repeat(24)} ${"─".repeat(20)} ${"─".repeat(12)}`)
506
571
 
507
572
  for (const fn of data) {
508
573
  const deployed = fn.deployedAt ? new Date(fn.deployedAt).toLocaleString() : "—"
509
- console.log(
574
+ plain(
510
575
  ` ${fn.name.padEnd(28)} ${deployed.padEnd(24)} ${String(fn.invocations24h ?? 0).padEnd(20)} ${fn.avgDurationMs ?? 0}ms`,
511
576
  )
512
577
  }
513
578
  } catch (err) {
514
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
579
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
515
580
  process.exit(1)
516
581
  }
517
582
  }
@@ -523,18 +588,18 @@ async function deleteFunction(cwd: string, name: string): Promise<void> {
523
588
  const linked = getLinkedProject(cwd)
524
589
 
525
590
  if (!linked) {
526
- console.error("No linked project. Run: npx supatype cloud link")
591
+ error("No linked project. Run: npx supatype cloud link")
527
592
  process.exit(1)
528
593
  }
529
594
 
530
- const token = getCloudToken()
595
+ const token = getCloudToken(cwd)
531
596
  if (!token) {
532
- console.error("Not logged in. Run: npx supatype cloud login")
597
+ error("Not logged in. Run: npx supatype cloud login")
533
598
  process.exit(1)
534
599
  }
535
600
 
536
601
  try {
537
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/${name}`, {
602
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/${name}`, {
538
603
  method: "DELETE",
539
604
  headers: {
540
605
  Authorization: `Bearer ${token}`,
@@ -545,13 +610,13 @@ async function deleteFunction(cwd: string, name: string): Promise<void> {
545
610
 
546
611
  if (!res.ok) {
547
612
  const body = await res.json().catch(() => ({})) as Record<string, string>
548
- console.error(`Failed to delete "${name}": ${body["message"] ?? res.statusText}`)
613
+ error(`Failed to delete "${name}": ${body["message"] ?? res.statusText}`)
549
614
  process.exit(1)
550
615
  }
551
616
 
552
- console.log(`Function "${name}" deleted. It will return 404 immediately.`)
617
+ info(`Function "${name}" deleted. It will return 404 immediately.`)
553
618
  } catch (err) {
554
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
619
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
555
620
  process.exit(1)
556
621
  }
557
622
  }
@@ -563,19 +628,19 @@ async function functionLogs(cwd: string, name: string, opts: { since: string }):
563
628
  const linked = getLinkedProject(cwd)
564
629
 
565
630
  if (!linked) {
566
- console.error("No linked project. Run: npx supatype cloud link")
631
+ error("No linked project. Run: npx supatype cloud link")
567
632
  process.exit(1)
568
633
  }
569
634
 
570
- const token = getCloudToken()
635
+ const token = getCloudToken(cwd)
571
636
  if (!token) {
572
- console.error("Not logged in. Run: npx supatype cloud login")
637
+ error("Not logged in. Run: npx supatype cloud login")
573
638
  process.exit(1)
574
639
  }
575
640
 
576
641
  try {
577
642
  const res = await fetch(
578
- `${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/${name}/logs?since=${opts.since}`,
643
+ `${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/${name}/logs?since=${opts.since}`,
579
644
  {
580
645
  headers: {
581
646
  Authorization: `Bearer ${token}`,
@@ -586,24 +651,24 @@ async function functionLogs(cwd: string, name: string, opts: { since: string }):
586
651
  )
587
652
 
588
653
  if (!res.ok) {
589
- console.error(`Failed to fetch logs: ${res.statusText}`)
654
+ error(`Failed to fetch logs: ${res.statusText}`)
590
655
  process.exit(1)
591
656
  }
592
657
 
593
658
  const { data } = await res.json() as { data: Array<{ timestamp: string; level: string; message: string }> }
594
659
 
595
660
  if (data.length === 0) {
596
- console.log(`No logs for "${name}" in the last ${opts.since}.`)
661
+ info(`No logs for "${name}" in the last ${opts.since}.`)
597
662
  return
598
663
  }
599
664
 
600
665
  for (const entry of data) {
601
666
  const ts = new Date(entry.timestamp).toISOString().slice(11, 23)
602
667
  const level = entry.level.toUpperCase().padEnd(5)
603
- console.log(`${ts} [${level}] ${entry.message}`)
668
+ plain(`${ts} [${level}] ${entry.message}`)
604
669
  }
605
670
  } catch (err) {
606
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
671
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
607
672
  process.exit(1)
608
673
  }
609
674
  }
@@ -625,7 +690,7 @@ async function invoke(
625
690
  const linked = getLinkedProject(cwd)
626
691
  if (linked) {
627
692
  url = `https://${linked.ref}.supatype.dev/functions/v1/${name}`
628
- const token = getCloudToken()
693
+ const token = getCloudToken(cwd)
629
694
  if (token && opts.auth) {
630
695
  headers["Authorization"] = `Bearer ${token}`
631
696
  }
@@ -646,7 +711,7 @@ async function invoke(
646
711
  JSON.parse(opts.data)
647
712
  body = opts.data
648
713
  } catch {
649
- console.error("Invalid JSON data. Use --data '{\"key\": \"value\"}'")
714
+ error("Invalid JSON data. Use --data '{\"key\": \"value\"}'")
650
715
  process.exit(1)
651
716
  }
652
717
 
@@ -661,22 +726,22 @@ async function invoke(
661
726
  const duration = Date.now() - start
662
727
  const responseBody = await res.text()
663
728
 
664
- console.log(`Status: ${res.status} (${duration}ms)`)
665
- console.log()
729
+ plain(`Status: ${res.status} (${duration}ms)`)
730
+ plain()
666
731
 
667
732
  // Try to pretty-print JSON
668
733
  try {
669
734
  const json = JSON.parse(responseBody)
670
- console.log(JSON.stringify(json, null, 2))
735
+ plain(JSON.stringify(json, null, 2))
671
736
  } catch {
672
- console.log(responseBody)
737
+ plain(responseBody)
673
738
  }
674
739
  } catch (err) {
675
740
  if (err instanceof TypeError && (err as Error).message.includes("fetch")) {
676
- console.error(`Cannot reach ${url}`)
677
- console.error("Is the function server running? Start it with: npx supatype functions serve")
741
+ error(`Cannot reach ${url}`)
742
+ error("Is the function server running? Start it with: npx supatype functions serve")
678
743
  } else {
679
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
744
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
680
745
  }
681
746
  process.exit(1)
682
747
  }
@@ -692,32 +757,32 @@ async function envList(cwd: string): Promise<void> {
692
757
  // Show local env vars
693
758
  const envPath = resolve(resolveFunctionsDir(cwd, "read"), ENV_LOCAL)
694
759
  if (!existsSync(envPath)) {
695
- console.log("No environment variables configured.")
760
+ info("No environment variables configured.")
696
761
  return
697
762
  }
698
763
 
699
764
  const lines = readFileSync(envPath, "utf8").split("\n")
700
- console.log("Local environment variables:\n")
765
+ plain("Local environment variables:\n")
701
766
  for (const line of lines) {
702
767
  const trimmed = line.trim()
703
768
  if (!trimmed || trimmed.startsWith("#")) continue
704
769
  const eqIdx = trimmed.indexOf("=")
705
770
  if (eqIdx > 0) {
706
771
  const key = trimmed.slice(0, eqIdx)
707
- console.log(` ${key} = ••••••••`)
772
+ plain(` ${key} = ••••••••`)
708
773
  }
709
774
  }
710
775
  return
711
776
  }
712
777
 
713
- const token = getCloudToken()
778
+ const token = getCloudToken(cwd)
714
779
  if (!token) {
715
- console.error("Not logged in. Run: npx supatype cloud login")
780
+ error("Not logged in. Run: npx supatype cloud login")
716
781
  process.exit(1)
717
782
  }
718
783
 
719
784
  try {
720
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env`, {
785
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/env`, {
721
786
  headers: {
722
787
  Authorization: `Bearer ${token}`,
723
788
  "X-Org-Id": linked.orgId ?? "",
@@ -726,23 +791,23 @@ async function envList(cwd: string): Promise<void> {
726
791
  })
727
792
 
728
793
  if (!res.ok) {
729
- console.error(`Failed to list env vars: ${res.statusText}`)
794
+ error(`Failed to list env vars: ${res.statusText}`)
730
795
  process.exit(1)
731
796
  }
732
797
 
733
798
  const { data } = await res.json() as { data: string[] }
734
799
 
735
800
  if (data.length === 0) {
736
- console.log("No environment variables set.")
801
+ info("No environment variables set.")
737
802
  return
738
803
  }
739
804
 
740
- console.log("Environment variables (values masked):\n")
805
+ plain("Environment variables (values masked):\n")
741
806
  for (const key of data) {
742
- console.log(` ${key} = ••••••••`)
807
+ plain(` ${key} = ••••••••`)
743
808
  }
744
809
  } catch (err) {
745
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
810
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
746
811
  process.exit(1)
747
812
  }
748
813
  }
@@ -750,7 +815,7 @@ async function envList(cwd: string): Promise<void> {
750
815
  async function envSet(cwd: string, keyvalue: string): Promise<void> {
751
816
  const eqIdx = keyvalue.indexOf("=")
752
817
  if (eqIdx <= 0) {
753
- console.error("Invalid format. Use: npx supatype functions env set KEY=value")
818
+ error("Invalid format. Use: npx supatype functions env set KEY=value")
754
819
  process.exit(1)
755
820
  }
756
821
 
@@ -774,18 +839,18 @@ async function envSet(cwd: string, keyvalue: string): Promise<void> {
774
839
  }
775
840
 
776
841
  writeFileSync(envPath, content, "utf8")
777
- console.log(`Set ${key} in local env file.`)
842
+ info(`Set ${key} in local env file.`)
778
843
  return
779
844
  }
780
845
 
781
- const token = getCloudToken()
846
+ const token = getCloudToken(cwd)
782
847
  if (!token) {
783
- console.error("Not logged in. Run: npx supatype cloud login")
848
+ error("Not logged in. Run: npx supatype cloud login")
784
849
  process.exit(1)
785
850
  }
786
851
 
787
852
  try {
788
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env`, {
853
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/env`, {
789
854
  method: "POST",
790
855
  headers: {
791
856
  Authorization: `Bearer ${token}`,
@@ -798,13 +863,13 @@ async function envSet(cwd: string, keyvalue: string): Promise<void> {
798
863
 
799
864
  if (!res.ok) {
800
865
  const body = await res.json().catch(() => ({})) as Record<string, string>
801
- console.error(`Failed to set env var: ${body["message"] ?? res.statusText}`)
866
+ error(`Failed to set env var: ${body["message"] ?? res.statusText}`)
802
867
  process.exit(1)
803
868
  }
804
869
 
805
- console.log(`Set ${key} for project ${linked.ref}.`)
870
+ info(`Set ${key} for project ${linked.ref}.`)
806
871
  } catch (err) {
807
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
872
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
808
873
  process.exit(1)
809
874
  }
810
875
  }
@@ -816,7 +881,7 @@ async function envUnset(cwd: string, key: string): Promise<void> {
816
881
  if (!linked) {
817
882
  const envPath = resolve(resolveFunctionsDir(cwd, "read"), ENV_LOCAL)
818
883
  if (!existsSync(envPath)) {
819
- console.error("No local env file found.")
884
+ error("No local env file found.")
820
885
  process.exit(1)
821
886
  }
822
887
 
@@ -824,18 +889,18 @@ async function envUnset(cwd: string, key: string): Promise<void> {
824
889
  const regex = new RegExp(`^${key}=.*\n?`, "m")
825
890
  content = content.replace(regex, "")
826
891
  writeFileSync(envPath, content, "utf8")
827
- console.log(`Removed ${key} from local env file.`)
892
+ info(`Removed ${key} from local env file.`)
828
893
  return
829
894
  }
830
895
 
831
- const token = getCloudToken()
896
+ const token = getCloudToken(cwd)
832
897
  if (!token) {
833
- console.error("Not logged in. Run: npx supatype cloud login")
898
+ error("Not logged in. Run: npx supatype cloud login")
834
899
  process.exit(1)
835
900
  }
836
901
 
837
902
  try {
838
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env/${key}`, {
903
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/env/${key}`, {
839
904
  method: "DELETE",
840
905
  headers: {
841
906
  Authorization: `Bearer ${token}`,
@@ -846,13 +911,13 @@ async function envUnset(cwd: string, key: string): Promise<void> {
846
911
 
847
912
  if (!res.ok) {
848
913
  const body = await res.json().catch(() => ({})) as Record<string, string>
849
- console.error(`Failed to unset env var: ${body["message"] ?? res.statusText}`)
914
+ error(`Failed to unset env var: ${body["message"] ?? res.statusText}`)
850
915
  process.exit(1)
851
916
  }
852
917
 
853
- console.log(`Removed ${key} for project ${linked.ref}.`)
918
+ info(`Removed ${key} for project ${linked.ref}.`)
854
919
  } catch (err) {
855
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
920
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`)
856
921
  process.exit(1)
857
922
  }
858
923
  }
@@ -860,32 +925,29 @@ async function envUnset(cwd: string, key: string): Promise<void> {
860
925
  // ─── Cloud helpers (lazy loaded) ─────────────────────────────────────────────
861
926
 
862
927
  interface CloudHelpers {
863
- getLinkedProject(cwd: string): { ref: string; orgId?: string } | null
864
- getCloudToken(): string | null
865
- getCloudApiUrl(): string
928
+ getLinkedProject(cwd: string): { ref: string; orgId?: string | undefined; kind?: string } | null
929
+ getCloudToken(cwd: string): string | null
930
+ getCloudApiUrl(cwd: string): string
866
931
  }
867
932
 
868
933
  async function loadCloudHelpers(): Promise<CloudHelpers> {
869
- // These helpers read the local .supatype/linked.json and auth token
870
934
  return {
871
- getLinkedProject(cwd: string): { ref: string; orgId?: string } | null {
872
- const linkedPath = resolve(cwd, ".supatype/linked.json")
873
- if (!existsSync(linkedPath)) return null
874
- try {
875
- const data = JSON.parse(readFileSync(linkedPath, "utf8")) as Record<string, string>
876
- const ref = data["ref"]
877
- const orgId = data["orgId"]
878
- return ref ? { ref, ...(orgId !== undefined ? { orgId } : {}) } : null
879
- } catch {
880
- return null
935
+ getLinkedProject(cwd: string): { ref: string; orgId?: string | undefined; kind?: string } | null {
936
+ const link = loadProjectLink(cwd)
937
+ if (!link?.projectRef) return null
938
+ return {
939
+ ref: link.projectRef,
940
+ kind: link.kind,
941
+ ...(link.orgId !== undefined ? { orgId: link.orgId } : {}),
881
942
  }
882
943
  },
883
944
 
884
- getCloudToken(): string | null {
885
- // Check env first, then config file
945
+ getCloudToken(cwd: string): string | null {
886
946
  if (process.env["SUPATYPE_ACCESS_TOKEN"]) {
887
947
  return process.env["SUPATYPE_ACCESS_TOKEN"]
888
948
  }
949
+ const link = loadProjectLink(cwd)
950
+ if (link?.token) return link.token
889
951
  const tokenPath = resolve(
890
952
  process.env["HOME"] ?? process.env["USERPROFILE"] ?? "~",
891
953
  ".supatype/token",
@@ -894,7 +956,9 @@ async function loadCloudHelpers(): Promise<CloudHelpers> {
894
956
  return readFileSync(tokenPath, "utf8").trim() || null
895
957
  },
896
958
 
897
- getCloudApiUrl(): string {
959
+ getCloudApiUrl(cwd: string): string {
960
+ const link = loadProjectLink(cwd)
961
+ if (link?.cloudApiUrl) return link.cloudApiUrl
898
962
  return process.env["SUPATYPE_API_URL"] ?? "https://api.supatype.com"
899
963
  },
900
964
  }