@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
@@ -6,7 +6,11 @@ import { loadConfig } from "../config.js";
6
6
  import { ensureBinary } from "../ensure-binary.js";
7
7
  import { functionsPathCandidatesFromProject, preferredFunctionsPathFromProject, } from "../project-config.js";
8
8
  import { discoverTsFunctionsInDir, generateFunctionsRouterSource, } from "../functions-router-gen.js";
9
- import { selfHostComposePaths } from "../self-host-compose.js";
9
+ import { loadProjectLink } from "../link.js";
10
+ import { resolveTarget } from "../resolve-target.js";
11
+ import { targetFetch } from "../target-client.js";
12
+ import { error, info, plain } from "../ui/messages.js";
13
+ import { nextSteps } from "../ui/next-steps.js";
10
14
  // ─── Constants ───────────────────────────────────────────────────────────────
11
15
  const SHARED_DIR = "_shared";
12
16
  const ENV_LOCAL = ".env.local";
@@ -34,6 +38,7 @@ export function registerFunctions(program) {
34
38
  .command("deploy")
35
39
  .description("Deploy all functions (or --only <name> for one) to the linked project")
36
40
  .option("--only <name>", "Deploy a single function")
41
+ .option("--env <name>", "Target environment when linked")
37
42
  .option("--dry-run", "Show what would be deployed without deploying")
38
43
  .action(async (opts) => {
39
44
  await deploy(process.cwd(), opts);
@@ -93,7 +98,7 @@ function scaffoldFunction(cwd, name) {
93
98
  const functionsDir = resolveFunctionsDir(cwd, "write");
94
99
  const fnDir = resolve(functionsDir, name);
95
100
  if (existsSync(fnDir)) {
96
- console.error(`Function "${name}" already exists at ${relative(cwd, fnDir)}`);
101
+ error(`Function "${name}" already exists at ${relative(cwd, fnDir)}`);
97
102
  process.exit(1);
98
103
  }
99
104
  mkdirSync(fnDir, { recursive: true });
@@ -131,11 +136,12 @@ export default async function handler(req: Request): Promise<Response> {
131
136
  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
137
  }
133
138
  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
+ info(`Created function: ${functionsDirLabel}/${name}/index.ts`);
140
+ nextSteps("Next steps:", [
141
+ "Local dev: npx supatype functions serve",
142
+ `Invoke: npx supatype functions invoke ${name}`,
143
+ "Deploy: npx supatype functions deploy",
144
+ ]);
139
145
  }
140
146
  function resolveFunctionsDir(cwd, mode) {
141
147
  try {
@@ -199,15 +205,15 @@ async function serve(cwd, opts) {
199
205
  const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir);
200
206
  const routes = discoverTsFunctionsInDir(functionsDir);
201
207
  if (routes.length === 0) {
202
- console.error(`No functions found in ${functionsDirLabel}/`);
203
- console.error("Create one with: npx supatype functions new <name>");
208
+ error(`No functions found in ${functionsDirLabel}/`);
209
+ error("Create one with: npx supatype functions new <name>");
204
210
  process.exit(1);
205
211
  }
206
- console.log(`Discovered ${routes.length} function(s):`);
212
+ plain(`Discovered ${routes.length} function(s):`);
207
213
  for (const fn of routes) {
208
- console.log(` /${fn.name} → ${relative(cwd, fn.entrypoint)}`);
214
+ plain(` /${fn.name} → ${relative(cwd, fn.entrypoint)}`);
209
215
  }
210
- console.log();
216
+ plain();
211
217
  // Generate a Deno entry script that routes requests to the correct function
212
218
  const routerPath = resolve(functionsDir, ".serve-router.ts");
213
219
  const routerScript = generateFunctionsRouterSource(routerPath, routes);
@@ -217,14 +223,15 @@ async function serve(cwd, opts) {
217
223
  if (existsSync(envFilePath)) {
218
224
  envArgs.push("--env-file", envFilePath);
219
225
  }
220
- console.log(`Serving functions at http://localhost:${opts.port}/functions/v1/`);
221
- console.log("Watching for changes...\n");
226
+ info(`Serving functions at http://localhost:${opts.port}/functions/v1/`);
227
+ info("Watching for changes...");
228
+ plain();
222
229
  let denoBin;
223
230
  try {
224
231
  denoBin = await ensureBinary("deno", config);
225
232
  }
226
233
  catch (err) {
227
- console.error(`[supatype] Could not provision Deno v${config.versions.deno}: ${err.message}`);
234
+ error(`Could not provision Deno: ${err.message}`);
228
235
  process.exit(1);
229
236
  }
230
237
  const result = spawnSync(denoBin, [
@@ -254,7 +261,7 @@ async function serve(cwd, opts) {
254
261
  }
255
262
  catch { /* ignore */ }
256
263
  if (result.status !== 0) {
257
- console.error("Function server exited with errors.");
264
+ error("Function server exited with errors.");
258
265
  process.exit(result.status ?? 1);
259
266
  }
260
267
  }
@@ -268,53 +275,99 @@ async function deploy(cwd, opts) {
268
275
  const functionsDir = resolveFunctionsDir(cwd, "read");
269
276
  const functionsDirLabel = relativeFunctionsDir(cwd, functionsDir);
270
277
  if (opts.only) {
271
- console.error(`Function "${opts.only}" not found in ${functionsDirLabel}/`);
278
+ error(`Function "${opts.only}" not found in ${functionsDirLabel}/`);
272
279
  }
273
280
  else {
274
- console.error(`No functions found in ${functionsDirLabel}/`);
281
+ error(`No functions found in ${functionsDirLabel}/`);
275
282
  }
276
283
  process.exit(1);
277
284
  }
278
285
  if (opts.dryRun) {
279
- console.log("Dry run — the following functions would be deployed:\n");
286
+ plain("Dry run — the following functions would be deployed:\n");
280
287
  for (const fn of fns) {
281
- console.log(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`);
288
+ plain(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`);
282
289
  }
283
- console.log(`\nTotal: ${fns.length} function(s)`);
290
+ plain(`\nTotal: ${fns.length} function(s)`);
284
291
  return;
285
292
  }
293
+ const link = loadProjectLink(cwd);
294
+ if (link) {
295
+ try {
296
+ const target = resolveTarget(cwd, { env: opts.env });
297
+ if (target.mode !== "direct" && target.token) {
298
+ await deployViaTarget(cwd, target, fns);
299
+ return;
300
+ }
301
+ }
302
+ catch {
303
+ /* fall through to compose/local */
304
+ }
305
+ }
306
+ const { selfHostComposePaths } = await import("../self-host-compose.js");
286
307
  const composePath = selfHostComposePaths(cwd).composePath;
287
308
  if (existsSync(composePath)) {
288
309
  await deploySelfHosted(cwd, fns);
289
310
  return;
290
311
  }
291
- await deployCloud(cwd, fns);
312
+ await deployCloud(cwd, fns, opts.env);
292
313
  }
293
314
  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");
315
+ info("Self-host Compose deployment.");
316
+ plain("Functions are served from your project functions/ directory (no bundle step).\n");
296
317
  for (const fn of fns) {
297
- console.log(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`);
318
+ plain(` ${fn.name} → ${relative(cwd, fn.entrypoint)}`);
298
319
  }
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).");
320
+ plain(`\n${fns.length} function(s) ready on disk.`);
321
+ info("Restart the functions-worker container to load changes:");
322
+ plain(" supatype self-host compose restart functions-worker");
323
+ plain("\nKong → supatype-server → functions-worker (per-project worker).");
303
324
  }
304
- async function deployCloud(cwd, fns) {
325
+ async function deployViaTarget(cwd, target, fns) {
326
+ info(`Deploying to ${target.mode} project: ${target.projectRef} (${target.environment})`);
327
+ plain();
328
+ for (const fn of fns) {
329
+ const start = Date.now();
330
+ const source = readFunctionSource(fn);
331
+ try {
332
+ await targetFetch(target.apiBaseUrl, target.apiPrefix, {
333
+ method: "POST",
334
+ path: `/projects/${target.projectRef}/functions/deploy`,
335
+ body: {
336
+ functions: [{
337
+ name: fn.name,
338
+ source,
339
+ entrypoint: `${fn.name}/index.ts`,
340
+ }],
341
+ },
342
+ token: target.token,
343
+ orgId: target.orgId,
344
+ environment: target.mode === "cloud" ? target.environment : undefined,
345
+ });
346
+ const duration = Date.now() - start;
347
+ plain(` ${fn.name} ✓ deployed (${duration}ms)`);
348
+ }
349
+ catch (err) {
350
+ plain(` ${fn.name} ✗ ${err instanceof Error ? err.message : "unknown error"}`);
351
+ }
352
+ }
353
+ info(`Deployed ${fns.length} function(s)`);
354
+ void cwd;
355
+ }
356
+ async function deployCloud(cwd, fns, env) {
305
357
  const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
306
358
  const linked = getLinkedProject(cwd);
307
359
  if (!linked) {
308
- console.error("No linked project. Run: npx supatype cloud link");
360
+ error("No linked project. Run: npx supatype cloud link");
309
361
  process.exit(1);
310
362
  }
311
- const token = getCloudToken();
363
+ const token = getCloudToken(cwd);
312
364
  if (!token) {
313
- console.error("Not logged in. Run: npx supatype cloud login");
365
+ error("Not logged in. Run: npx supatype cloud login");
314
366
  process.exit(1);
315
367
  }
316
- const apiUrl = getCloudApiUrl();
317
- console.log(`Deploying to project: ${linked.ref}\n`);
368
+ const apiUrl = getCloudApiUrl(cwd);
369
+ info(`Deploying to project: ${linked.ref}`);
370
+ plain();
318
371
  for (const fn of fns) {
319
372
  const start = Date.now();
320
373
  // Read source code
@@ -338,18 +391,18 @@ async function deployCloud(cwd, fns) {
338
391
  });
339
392
  if (!res.ok) {
340
393
  const body = await res.json().catch(() => ({}));
341
- console.error(` ${fn.name} ✗ ${body["message"] ?? res.statusText}`);
394
+ plain(` ${fn.name} ✗ ${body["message"] ?? res.statusText}`);
342
395
  continue;
343
396
  }
344
397
  const duration = Date.now() - start;
345
- console.log(` ${fn.name} ✓ deployed (${duration}ms)`);
398
+ plain(` ${fn.name} ✓ deployed (${duration}ms)`);
346
399
  }
347
400
  catch (err) {
348
- console.error(` ${fn.name} ✗ ${err instanceof Error ? err.message : "unknown error"}`);
401
+ plain(` ${fn.name} ✗ ${err instanceof Error ? err.message : "unknown error"}`);
349
402
  }
350
403
  }
351
- console.log(`\nDeployed ${fns.length} function(s)`);
352
- console.log(`Invoke: https://${linked.ref}.supatype.dev/functions/v1/<name>`);
404
+ info(`Deployed ${fns.length} function(s)`);
405
+ info(`Invoke: https://${linked.ref}.supatype.dev/functions/v1/<name>`);
353
406
  }
354
407
  function readFunctionSource(fn) {
355
408
  const stat = statSync(fn.absPath);
@@ -375,22 +428,22 @@ async function listFunctions(cwd) {
375
428
  // Show local functions instead
376
429
  const fns = discoverFunctions(cwd);
377
430
  if (fns.length === 0) {
378
- console.log("No functions found locally or remotely.");
431
+ info("No functions found locally or remotely.");
379
432
  return;
380
433
  }
381
- console.log("Local functions (not linked to a cloud project):\n");
434
+ plain("Local functions (not linked to a cloud project):\n");
382
435
  for (const fn of fns) {
383
- console.log(` ${fn.name.padEnd(30)} ${relative(cwd, fn.entrypoint)}`);
436
+ plain(` ${fn.name.padEnd(30)} ${relative(cwd, fn.entrypoint)}`);
384
437
  }
385
438
  return;
386
439
  }
387
- const token = getCloudToken();
440
+ const token = getCloudToken(cwd);
388
441
  if (!token) {
389
- console.error("Not logged in. Run: npx supatype cloud login");
442
+ error("Not logged in. Run: npx supatype cloud login");
390
443
  process.exit(1);
391
444
  }
392
445
  try {
393
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions`, {
446
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions`, {
394
447
  headers: {
395
448
  Authorization: `Bearer ${token}`,
396
449
  "X-Org-Id": linked.orgId ?? "",
@@ -398,24 +451,24 @@ async function listFunctions(cwd) {
398
451
  signal: AbortSignal.timeout(10_000),
399
452
  });
400
453
  if (!res.ok) {
401
- console.error(`Failed to list functions: ${res.statusText}`);
454
+ error(`Failed to list functions: ${res.statusText}`);
402
455
  process.exit(1);
403
456
  }
404
457
  const { data } = await res.json();
405
458
  if (data.length === 0) {
406
- console.log("No deployed functions.");
459
+ info("No deployed functions.");
407
460
  return;
408
461
  }
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)}`);
462
+ plain("Deployed functions:\n");
463
+ plain(` ${"Name".padEnd(28)} ${"Last Deployed".padEnd(24)} ${"Invocations (24h)".padEnd(20)} Avg Duration`);
464
+ plain(` ${"─".repeat(28)} ${"─".repeat(24)} ${"─".repeat(20)} ${"─".repeat(12)}`);
412
465
  for (const fn of data) {
413
466
  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`);
467
+ plain(` ${fn.name.padEnd(28)} ${deployed.padEnd(24)} ${String(fn.invocations24h ?? 0).padEnd(20)} ${fn.avgDurationMs ?? 0}ms`);
415
468
  }
416
469
  }
417
470
  catch (err) {
418
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
471
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
419
472
  process.exit(1);
420
473
  }
421
474
  }
@@ -424,16 +477,16 @@ async function deleteFunction(cwd, name) {
424
477
  const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
425
478
  const linked = getLinkedProject(cwd);
426
479
  if (!linked) {
427
- console.error("No linked project. Run: npx supatype cloud link");
480
+ error("No linked project. Run: npx supatype cloud link");
428
481
  process.exit(1);
429
482
  }
430
- const token = getCloudToken();
483
+ const token = getCloudToken(cwd);
431
484
  if (!token) {
432
- console.error("Not logged in. Run: npx supatype cloud login");
485
+ error("Not logged in. Run: npx supatype cloud login");
433
486
  process.exit(1);
434
487
  }
435
488
  try {
436
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/${name}`, {
489
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/${name}`, {
437
490
  method: "DELETE",
438
491
  headers: {
439
492
  Authorization: `Bearer ${token}`,
@@ -443,13 +496,13 @@ async function deleteFunction(cwd, name) {
443
496
  });
444
497
  if (!res.ok) {
445
498
  const body = await res.json().catch(() => ({}));
446
- console.error(`Failed to delete "${name}": ${body["message"] ?? res.statusText}`);
499
+ error(`Failed to delete "${name}": ${body["message"] ?? res.statusText}`);
447
500
  process.exit(1);
448
501
  }
449
- console.log(`Function "${name}" deleted. It will return 404 immediately.`);
502
+ info(`Function "${name}" deleted. It will return 404 immediately.`);
450
503
  }
451
504
  catch (err) {
452
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
505
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
453
506
  process.exit(1);
454
507
  }
455
508
  }
@@ -458,16 +511,16 @@ async function functionLogs(cwd, name, opts) {
458
511
  const { getLinkedProject, getCloudToken, getCloudApiUrl } = await loadCloudHelpers();
459
512
  const linked = getLinkedProject(cwd);
460
513
  if (!linked) {
461
- console.error("No linked project. Run: npx supatype cloud link");
514
+ error("No linked project. Run: npx supatype cloud link");
462
515
  process.exit(1);
463
516
  }
464
- const token = getCloudToken();
517
+ const token = getCloudToken(cwd);
465
518
  if (!token) {
466
- console.error("Not logged in. Run: npx supatype cloud login");
519
+ error("Not logged in. Run: npx supatype cloud login");
467
520
  process.exit(1);
468
521
  }
469
522
  try {
470
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/${name}/logs?since=${opts.since}`, {
523
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/${name}/logs?since=${opts.since}`, {
471
524
  headers: {
472
525
  Authorization: `Bearer ${token}`,
473
526
  "X-Org-Id": linked.orgId ?? "",
@@ -475,22 +528,22 @@ async function functionLogs(cwd, name, opts) {
475
528
  signal: AbortSignal.timeout(10_000),
476
529
  });
477
530
  if (!res.ok) {
478
- console.error(`Failed to fetch logs: ${res.statusText}`);
531
+ error(`Failed to fetch logs: ${res.statusText}`);
479
532
  process.exit(1);
480
533
  }
481
534
  const { data } = await res.json();
482
535
  if (data.length === 0) {
483
- console.log(`No logs for "${name}" in the last ${opts.since}.`);
536
+ info(`No logs for "${name}" in the last ${opts.since}.`);
484
537
  return;
485
538
  }
486
539
  for (const entry of data) {
487
540
  const ts = new Date(entry.timestamp).toISOString().slice(11, 23);
488
541
  const level = entry.level.toUpperCase().padEnd(5);
489
- console.log(`${ts} [${level}] ${entry.message}`);
542
+ plain(`${ts} [${level}] ${entry.message}`);
490
543
  }
491
544
  }
492
545
  catch (err) {
493
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
546
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
494
547
  process.exit(1);
495
548
  }
496
549
  }
@@ -506,7 +559,7 @@ async function invoke(cwd, name, opts) {
506
559
  const linked = getLinkedProject(cwd);
507
560
  if (linked) {
508
561
  url = `https://${linked.ref}.supatype.dev/functions/v1/${name}`;
509
- const token = getCloudToken();
562
+ const token = getCloudToken(cwd);
510
563
  if (token && opts.auth) {
511
564
  headers["Authorization"] = `Bearer ${token}`;
512
565
  }
@@ -527,7 +580,7 @@ async function invoke(cwd, name, opts) {
527
580
  body = opts.data;
528
581
  }
529
582
  catch {
530
- console.error("Invalid JSON data. Use --data '{\"key\": \"value\"}'");
583
+ error("Invalid JSON data. Use --data '{\"key\": \"value\"}'");
531
584
  process.exit(1);
532
585
  }
533
586
  const start = Date.now();
@@ -539,24 +592,24 @@ async function invoke(cwd, name, opts) {
539
592
  });
540
593
  const duration = Date.now() - start;
541
594
  const responseBody = await res.text();
542
- console.log(`Status: ${res.status} (${duration}ms)`);
543
- console.log();
595
+ plain(`Status: ${res.status} (${duration}ms)`);
596
+ plain();
544
597
  // Try to pretty-print JSON
545
598
  try {
546
599
  const json = JSON.parse(responseBody);
547
- console.log(JSON.stringify(json, null, 2));
600
+ plain(JSON.stringify(json, null, 2));
548
601
  }
549
602
  catch {
550
- console.log(responseBody);
603
+ plain(responseBody);
551
604
  }
552
605
  }
553
606
  catch (err) {
554
607
  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");
608
+ error(`Cannot reach ${url}`);
609
+ error("Is the function server running? Start it with: npx supatype functions serve");
557
610
  }
558
611
  else {
559
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
612
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
560
613
  }
561
614
  process.exit(1);
562
615
  }
@@ -569,11 +622,11 @@ async function envList(cwd) {
569
622
  // Show local env vars
570
623
  const envPath = resolve(resolveFunctionsDir(cwd, "read"), ENV_LOCAL);
571
624
  if (!existsSync(envPath)) {
572
- console.log("No environment variables configured.");
625
+ info("No environment variables configured.");
573
626
  return;
574
627
  }
575
628
  const lines = readFileSync(envPath, "utf8").split("\n");
576
- console.log("Local environment variables:\n");
629
+ plain("Local environment variables:\n");
577
630
  for (const line of lines) {
578
631
  const trimmed = line.trim();
579
632
  if (!trimmed || trimmed.startsWith("#"))
@@ -581,18 +634,18 @@ async function envList(cwd) {
581
634
  const eqIdx = trimmed.indexOf("=");
582
635
  if (eqIdx > 0) {
583
636
  const key = trimmed.slice(0, eqIdx);
584
- console.log(` ${key} = ••••••••`);
637
+ plain(` ${key} = ••••••••`);
585
638
  }
586
639
  }
587
640
  return;
588
641
  }
589
- const token = getCloudToken();
642
+ const token = getCloudToken(cwd);
590
643
  if (!token) {
591
- console.error("Not logged in. Run: npx supatype cloud login");
644
+ error("Not logged in. Run: npx supatype cloud login");
592
645
  process.exit(1);
593
646
  }
594
647
  try {
595
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env`, {
648
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/env`, {
596
649
  headers: {
597
650
  Authorization: `Bearer ${token}`,
598
651
  "X-Org-Id": linked.orgId ?? "",
@@ -600,28 +653,28 @@ async function envList(cwd) {
600
653
  signal: AbortSignal.timeout(10_000),
601
654
  });
602
655
  if (!res.ok) {
603
- console.error(`Failed to list env vars: ${res.statusText}`);
656
+ error(`Failed to list env vars: ${res.statusText}`);
604
657
  process.exit(1);
605
658
  }
606
659
  const { data } = await res.json();
607
660
  if (data.length === 0) {
608
- console.log("No environment variables set.");
661
+ info("No environment variables set.");
609
662
  return;
610
663
  }
611
- console.log("Environment variables (values masked):\n");
664
+ plain("Environment variables (values masked):\n");
612
665
  for (const key of data) {
613
- console.log(` ${key} = ••••••••`);
666
+ plain(` ${key} = ••••••••`);
614
667
  }
615
668
  }
616
669
  catch (err) {
617
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
670
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
618
671
  process.exit(1);
619
672
  }
620
673
  }
621
674
  async function envSet(cwd, keyvalue) {
622
675
  const eqIdx = keyvalue.indexOf("=");
623
676
  if (eqIdx <= 0) {
624
- console.error("Invalid format. Use: npx supatype functions env set KEY=value");
677
+ error("Invalid format. Use: npx supatype functions env set KEY=value");
625
678
  process.exit(1);
626
679
  }
627
680
  const key = keyvalue.slice(0, eqIdx);
@@ -641,16 +694,16 @@ async function envSet(cwd, keyvalue) {
641
694
  content = content.trimEnd() + `\n${key}=${value}\n`;
642
695
  }
643
696
  writeFileSync(envPath, content, "utf8");
644
- console.log(`Set ${key} in local env file.`);
697
+ info(`Set ${key} in local env file.`);
645
698
  return;
646
699
  }
647
- const token = getCloudToken();
700
+ const token = getCloudToken(cwd);
648
701
  if (!token) {
649
- console.error("Not logged in. Run: npx supatype cloud login");
702
+ error("Not logged in. Run: npx supatype cloud login");
650
703
  process.exit(1);
651
704
  }
652
705
  try {
653
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env`, {
706
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/env`, {
654
707
  method: "POST",
655
708
  headers: {
656
709
  Authorization: `Bearer ${token}`,
@@ -662,13 +715,13 @@ async function envSet(cwd, keyvalue) {
662
715
  });
663
716
  if (!res.ok) {
664
717
  const body = await res.json().catch(() => ({}));
665
- console.error(`Failed to set env var: ${body["message"] ?? res.statusText}`);
718
+ error(`Failed to set env var: ${body["message"] ?? res.statusText}`);
666
719
  process.exit(1);
667
720
  }
668
- console.log(`Set ${key} for project ${linked.ref}.`);
721
+ info(`Set ${key} for project ${linked.ref}.`);
669
722
  }
670
723
  catch (err) {
671
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
724
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
672
725
  process.exit(1);
673
726
  }
674
727
  }
@@ -678,23 +731,23 @@ async function envUnset(cwd, key) {
678
731
  if (!linked) {
679
732
  const envPath = resolve(resolveFunctionsDir(cwd, "read"), ENV_LOCAL);
680
733
  if (!existsSync(envPath)) {
681
- console.error("No local env file found.");
734
+ error("No local env file found.");
682
735
  process.exit(1);
683
736
  }
684
737
  let content = readFileSync(envPath, "utf8");
685
738
  const regex = new RegExp(`^${key}=.*\n?`, "m");
686
739
  content = content.replace(regex, "");
687
740
  writeFileSync(envPath, content, "utf8");
688
- console.log(`Removed ${key} from local env file.`);
741
+ info(`Removed ${key} from local env file.`);
689
742
  return;
690
743
  }
691
- const token = getCloudToken();
744
+ const token = getCloudToken(cwd);
692
745
  if (!token) {
693
- console.error("Not logged in. Run: npx supatype cloud login");
746
+ error("Not logged in. Run: npx supatype cloud login");
694
747
  process.exit(1);
695
748
  }
696
749
  try {
697
- const res = await fetch(`${getCloudApiUrl()}/api/v1/projects/${linked.ref}/functions/env/${key}`, {
750
+ const res = await fetch(`${getCloudApiUrl(cwd)}/api/v1/projects/${linked.ref}/functions/env/${key}`, {
698
751
  method: "DELETE",
699
752
  headers: {
700
753
  Authorization: `Bearer ${token}`,
@@ -704,44 +757,44 @@ async function envUnset(cwd, key) {
704
757
  });
705
758
  if (!res.ok) {
706
759
  const body = await res.json().catch(() => ({}));
707
- console.error(`Failed to unset env var: ${body["message"] ?? res.statusText}`);
760
+ error(`Failed to unset env var: ${body["message"] ?? res.statusText}`);
708
761
  process.exit(1);
709
762
  }
710
- console.log(`Removed ${key} for project ${linked.ref}.`);
763
+ info(`Removed ${key} for project ${linked.ref}.`);
711
764
  }
712
765
  catch (err) {
713
- console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
766
+ error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
714
767
  process.exit(1);
715
768
  }
716
769
  }
717
770
  async function loadCloudHelpers() {
718
- // These helpers read the local .supatype/linked.json and auth token
719
771
  return {
720
772
  getLinkedProject(cwd) {
721
- const linkedPath = resolve(cwd, ".supatype/linked.json");
722
- if (!existsSync(linkedPath))
773
+ const link = loadProjectLink(cwd);
774
+ if (!link?.projectRef)
723
775
  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
- }
776
+ return {
777
+ ref: link.projectRef,
778
+ kind: link.kind,
779
+ ...(link.orgId !== undefined ? { orgId: link.orgId } : {}),
780
+ };
733
781
  },
734
- getCloudToken() {
735
- // Check env first, then config file
782
+ getCloudToken(cwd) {
736
783
  if (process.env["SUPATYPE_ACCESS_TOKEN"]) {
737
784
  return process.env["SUPATYPE_ACCESS_TOKEN"];
738
785
  }
786
+ const link = loadProjectLink(cwd);
787
+ if (link?.token)
788
+ return link.token;
739
789
  const tokenPath = resolve(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "~", ".supatype/token");
740
790
  if (!existsSync(tokenPath))
741
791
  return null;
742
792
  return readFileSync(tokenPath, "utf8").trim() || null;
743
793
  },
744
- getCloudApiUrl() {
794
+ getCloudApiUrl(cwd) {
795
+ const link = loadProjectLink(cwd);
796
+ if (link?.cloudApiUrl)
797
+ return link.cloudApiUrl;
745
798
  return process.env["SUPATYPE_API_URL"] ?? "https://api.supatype.com";
746
799
  },
747
800
  };