@supatype/cli 0.1.6 → 0.1.9

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 (477) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +152 -102
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/LICENSE +202 -0
  5. package/deno.d.ts +52 -0
  6. package/dist/app/framework.js +1 -1
  7. package/dist/app/framework.js.map +1 -1
  8. package/dist/augmentation-generator.d.ts +22 -0
  9. package/dist/augmentation-generator.d.ts.map +1 -1
  10. package/dist/augmentation-generator.js +19 -5
  11. package/dist/augmentation-generator.js.map +1 -1
  12. package/dist/binary-cache.d.ts +42 -6
  13. package/dist/binary-cache.d.ts.map +1 -1
  14. package/dist/binary-cache.js +76 -44
  15. package/dist/binary-cache.js.map +1 -1
  16. package/dist/cache-clean.d.ts +15 -0
  17. package/dist/cache-clean.d.ts.map +1 -0
  18. package/dist/cache-clean.js +76 -0
  19. package/dist/cache-clean.js.map +1 -0
  20. package/dist/cache-pins.d.ts +51 -0
  21. package/dist/cache-pins.d.ts.map +1 -0
  22. package/dist/cache-pins.js +184 -0
  23. package/dist/cache-pins.js.map +1 -0
  24. package/dist/cli-artifacts.d.ts +32 -0
  25. package/dist/cli-artifacts.d.ts.map +1 -0
  26. package/dist/cli-artifacts.js +49 -0
  27. package/dist/cli-artifacts.js.map +1 -0
  28. package/dist/cli-install-method.d.ts +27 -0
  29. package/dist/cli-install-method.d.ts.map +1 -0
  30. package/dist/cli-install-method.js +78 -0
  31. package/dist/cli-install-method.js.map +1 -0
  32. package/dist/cli-package-version.d.ts +1 -1
  33. package/dist/cli-package-version.d.ts.map +1 -1
  34. package/dist/cli-package-version.js +6 -1
  35. package/dist/cli-package-version.js.map +1 -1
  36. package/dist/cli-standalone.d.ts +13 -4
  37. package/dist/cli-standalone.d.ts.map +1 -1
  38. package/dist/cli-standalone.js +86 -31
  39. package/dist/cli-standalone.js.map +1 -1
  40. package/dist/cli-version-embedded.d.ts +10 -0
  41. package/dist/cli-version-embedded.d.ts.map +1 -0
  42. package/dist/cli-version-embedded.js +13 -0
  43. package/dist/cli-version-embedded.js.map +1 -0
  44. package/dist/cli.d.ts.map +1 -1
  45. package/dist/cli.js +7 -1
  46. package/dist/cli.js.map +1 -1
  47. package/dist/cloud-credentials.d.ts +34 -0
  48. package/dist/cloud-credentials.d.ts.map +1 -0
  49. package/dist/cloud-credentials.js +139 -0
  50. package/dist/cloud-credentials.js.map +1 -0
  51. package/dist/commands/add.js +1 -1
  52. package/dist/commands/add.js.map +1 -1
  53. package/dist/commands/admin.d.ts +11 -0
  54. package/dist/commands/admin.d.ts.map +1 -1
  55. package/dist/commands/admin.js +123 -21
  56. package/dist/commands/admin.js.map +1 -1
  57. package/dist/commands/adopt.js +1 -1
  58. package/dist/commands/adopt.js.map +1 -1
  59. package/dist/commands/app.js +2 -2
  60. package/dist/commands/app.js.map +1 -1
  61. package/dist/commands/cache.d.ts +1 -1
  62. package/dist/commands/cache.d.ts.map +1 -1
  63. package/dist/commands/cache.js +69 -73
  64. package/dist/commands/cache.js.map +1 -1
  65. package/dist/commands/cloud.d.ts.map +1 -1
  66. package/dist/commands/cloud.js +32 -8
  67. package/dist/commands/cloud.js.map +1 -1
  68. package/dist/commands/db.d.ts +3 -2
  69. package/dist/commands/db.d.ts.map +1 -1
  70. package/dist/commands/db.js +149 -3
  71. package/dist/commands/db.js.map +1 -1
  72. package/dist/commands/deploy.d.ts +9 -9
  73. package/dist/commands/deploy.js +12 -12
  74. package/dist/commands/deploy.js.map +1 -1
  75. package/dist/commands/dev.d.ts +3 -3
  76. package/dist/commands/dev.d.ts.map +1 -1
  77. package/dist/commands/dev.js +63 -23
  78. package/dist/commands/dev.js.map +1 -1
  79. package/dist/commands/doctor.d.ts +28 -0
  80. package/dist/commands/doctor.d.ts.map +1 -1
  81. package/dist/commands/doctor.js +60 -3
  82. package/dist/commands/doctor.js.map +1 -1
  83. package/dist/commands/engine.d.ts +1 -1
  84. package/dist/commands/engine.js +1 -1
  85. package/dist/commands/functions.d.ts +7 -0
  86. package/dist/commands/functions.d.ts.map +1 -1
  87. package/dist/commands/functions.js +45 -11
  88. package/dist/commands/functions.js.map +1 -1
  89. package/dist/commands/generate.d.ts.map +1 -1
  90. package/dist/commands/generate.js +5 -1
  91. package/dist/commands/generate.js.map +1 -1
  92. package/dist/commands/hooks.d.ts +12 -0
  93. package/dist/commands/hooks.d.ts.map +1 -0
  94. package/dist/commands/hooks.js +118 -0
  95. package/dist/commands/hooks.js.map +1 -0
  96. package/dist/commands/init.d.ts.map +1 -1
  97. package/dist/commands/init.js +64 -30
  98. package/dist/commands/init.js.map +1 -1
  99. package/dist/commands/internal.d.ts +6 -0
  100. package/dist/commands/internal.d.ts.map +1 -0
  101. package/dist/commands/internal.js +22 -0
  102. package/dist/commands/internal.js.map +1 -0
  103. package/dist/commands/link-helpers.d.ts.map +1 -1
  104. package/dist/commands/link-helpers.js +8 -2
  105. package/dist/commands/link-helpers.js.map +1 -1
  106. package/dist/commands/login.d.ts +7 -0
  107. package/dist/commands/login.d.ts.map +1 -0
  108. package/dist/commands/login.js +110 -0
  109. package/dist/commands/login.js.map +1 -0
  110. package/dist/commands/logs.d.ts +1 -1
  111. package/dist/commands/migrate.js +5 -5
  112. package/dist/commands/migrate.js.map +1 -1
  113. package/dist/commands/pg.d.ts +1 -1
  114. package/dist/commands/pg.js +1 -1
  115. package/dist/commands/plugins.js +1 -1
  116. package/dist/commands/plugins.js.map +1 -1
  117. package/dist/commands/pull.js +2 -2
  118. package/dist/commands/pull.js.map +1 -1
  119. package/dist/commands/push.d.ts.map +1 -1
  120. package/dist/commands/push.js +110 -7
  121. package/dist/commands/push.js.map +1 -1
  122. package/dist/commands/self-host.d.ts +1 -1
  123. package/dist/commands/self-host.js +1 -1
  124. package/dist/commands/self-update.d.ts +3 -2
  125. package/dist/commands/self-update.d.ts.map +1 -1
  126. package/dist/commands/self-update.js +31 -16
  127. package/dist/commands/self-update.js.map +1 -1
  128. package/dist/commands/status.d.ts +1 -1
  129. package/dist/commands/update.d.ts +1 -1
  130. package/dist/commands/update.js +1 -1
  131. package/dist/config.d.ts +1 -1
  132. package/dist/config.d.ts.map +1 -1
  133. package/dist/config.js +19 -4
  134. package/dist/config.js.map +1 -1
  135. package/dist/db-preflight.d.ts +78 -0
  136. package/dist/db-preflight.d.ts.map +1 -0
  137. package/dist/db-preflight.js +452 -0
  138. package/dist/db-preflight.js.map +1 -0
  139. package/dist/dev-compose.d.ts +4 -4
  140. package/dist/dev-compose.d.ts.map +1 -1
  141. package/dist/dev-compose.js +143 -88
  142. package/dist/dev-compose.js.map +1 -1
  143. package/dist/dev-log-filter.d.ts +1 -1
  144. package/dist/dev-log-filter.d.ts.map +1 -1
  145. package/dist/dev-log-filter.js +1 -1
  146. package/dist/dev-log-filter.js.map +1 -1
  147. package/dist/dev-ports.d.ts +2 -2
  148. package/dist/dev-ports.d.ts.map +1 -1
  149. package/dist/dev-ports.js +2 -2
  150. package/dist/dev-ports.js.map +1 -1
  151. package/dist/dev-session.d.ts +5 -5
  152. package/dist/dev-session.d.ts.map +1 -1
  153. package/dist/dev-session.js +6 -6
  154. package/dist/dev-session.js.map +1 -1
  155. package/dist/dev-shutdown.d.ts +5 -5
  156. package/dist/dev-shutdown.d.ts.map +1 -1
  157. package/dist/dev-shutdown.js +7 -7
  158. package/dist/dev-shutdown.js.map +1 -1
  159. package/dist/dev-task-colors.d.ts +1 -1
  160. package/dist/dev-task-colors.d.ts.map +1 -1
  161. package/dist/dev-task-colors.js +1 -1
  162. package/dist/dev-task-colors.js.map +1 -1
  163. package/dist/docker-postgres.d.ts +5 -5
  164. package/dist/docker-postgres.d.ts.map +1 -1
  165. package/dist/docker-postgres.js +5 -5
  166. package/dist/docker-postgres.js.map +1 -1
  167. package/dist/docker-runtime.d.ts +2 -2
  168. package/dist/docker-runtime.d.ts.map +1 -1
  169. package/dist/docker-runtime.js +5 -5
  170. package/dist/docker-runtime.js.map +1 -1
  171. package/dist/engine-client.d.ts +1 -1
  172. package/dist/engine-client.js +3 -3
  173. package/dist/engine-client.js.map +1 -1
  174. package/dist/engine-push-output.js +1 -1
  175. package/dist/engine-push-output.js.map +1 -1
  176. package/dist/ensure-binary.d.ts.map +1 -1
  177. package/dist/ensure-binary.js +17 -0
  178. package/dist/ensure-binary.js.map +1 -1
  179. package/dist/ensure-component-binaries.js +1 -1
  180. package/dist/ensure-component-binaries.js.map +1 -1
  181. package/dist/env-file.d.ts +40 -2
  182. package/dist/env-file.d.ts.map +1 -1
  183. package/dist/env-file.js +132 -11
  184. package/dist/env-file.js.map +1 -1
  185. package/dist/field-masking-tier.d.ts +50 -0
  186. package/dist/field-masking-tier.d.ts.map +1 -0
  187. package/dist/field-masking-tier.js +91 -0
  188. package/dist/field-masking-tier.js.map +1 -0
  189. package/dist/functions-deno-types.d.ts +24 -0
  190. package/dist/functions-deno-types.d.ts.map +1 -0
  191. package/dist/functions-deno-types.js +155 -0
  192. package/dist/functions-deno-types.js.map +1 -0
  193. package/dist/functions-router-gen.js +1 -1
  194. package/dist/gitignore.d.ts +2 -2
  195. package/dist/gitignore.d.ts.map +1 -1
  196. package/dist/gitignore.js +3 -3
  197. package/dist/gitignore.js.map +1 -1
  198. package/dist/hook-upload.d.ts +30 -0
  199. package/dist/hook-upload.d.ts.map +1 -0
  200. package/dist/hook-upload.js +86 -0
  201. package/dist/hook-upload.js.map +1 -0
  202. package/dist/hooks-generator.d.ts +8 -0
  203. package/dist/hooks-generator.d.ts.map +1 -0
  204. package/dist/hooks-generator.js +332 -0
  205. package/dist/hooks-generator.js.map +1 -0
  206. package/dist/index.d.ts +1 -1
  207. package/dist/index.js +1 -1
  208. package/dist/init-project-detect.d.ts +1 -1
  209. package/dist/init-project-detect.d.ts.map +1 -1
  210. package/dist/init-project-detect.js +1 -1
  211. package/dist/init-project-detect.js.map +1 -1
  212. package/dist/link.d.ts +4 -0
  213. package/dist/link.d.ts.map +1 -1
  214. package/dist/link.js +2 -0
  215. package/dist/link.js.map +1 -1
  216. package/dist/local-secrets.d.ts +71 -0
  217. package/dist/local-secrets.d.ts.map +1 -0
  218. package/dist/local-secrets.js +100 -0
  219. package/dist/local-secrets.js.map +1 -0
  220. package/dist/main.d.ts +2 -0
  221. package/dist/main.d.ts.map +1 -0
  222. package/dist/main.js +20 -0
  223. package/dist/main.js.map +1 -0
  224. package/dist/model-hooks.d.ts +73 -0
  225. package/dist/model-hooks.d.ts.map +1 -0
  226. package/dist/model-hooks.js +211 -0
  227. package/dist/model-hooks.js.map +1 -0
  228. package/dist/pgbouncer-userlist.d.ts +1 -1
  229. package/dist/pgbouncer-userlist.d.ts.map +1 -1
  230. package/dist/pgbouncer-userlist.js +2 -2
  231. package/dist/pgbouncer-userlist.js.map +1 -1
  232. package/dist/postgres-ctl.d.ts +12 -1
  233. package/dist/postgres-ctl.d.ts.map +1 -1
  234. package/dist/postgres-ctl.js +28 -5
  235. package/dist/postgres-ctl.js.map +1 -1
  236. package/dist/process-manager.d.ts +2 -2
  237. package/dist/process-manager.d.ts.map +1 -1
  238. package/dist/process-manager.js +4 -4
  239. package/dist/process-manager.js.map +1 -1
  240. package/dist/project-config.d.ts +122 -2
  241. package/dist/project-config.d.ts.map +1 -1
  242. package/dist/project-config.js +150 -1
  243. package/dist/project-config.js.map +1 -1
  244. package/dist/pull-utils.d.ts +2 -2
  245. package/dist/pull-utils.d.ts.map +1 -1
  246. package/dist/pull-utils.js +4 -4
  247. package/dist/pull-utils.js.map +1 -1
  248. package/dist/realtime-launch.js +1 -1
  249. package/dist/realtime-launch.js.map +1 -1
  250. package/dist/release-pins.d.ts +1 -1
  251. package/dist/release-pins.js +2 -2
  252. package/dist/release-pins.js.map +1 -1
  253. package/dist/resolve-api-url.js +1 -1
  254. package/dist/resolve-api-url.js.map +1 -1
  255. package/dist/resolve-target.d.ts +4 -0
  256. package/dist/resolve-target.d.ts.map +1 -1
  257. package/dist/resolve-target.js +69 -73
  258. package/dist/resolve-target.js.map +1 -1
  259. package/dist/rest-cache-admin.js +2 -2
  260. package/dist/rest-cache-admin.js.map +1 -1
  261. package/dist/runtime-routes.d.ts +1 -1
  262. package/dist/runtime-routes.js +1 -1
  263. package/dist/schema-ast-v2.d.ts +5 -4
  264. package/dist/schema-ast-v2.d.ts.map +1 -1
  265. package/dist/schema-ast-v2.js +5 -3
  266. package/dist/schema-ast-v2.js.map +1 -1
  267. package/dist/schema-push-lock.d.ts.map +1 -1
  268. package/dist/schema-push-lock.js +43 -16
  269. package/dist/schema-push-lock.js.map +1 -1
  270. package/dist/scripts/postinstall.d.ts +1 -1
  271. package/dist/scripts/postinstall.js +1 -1
  272. package/dist/self-host-compose.d.ts +26 -2
  273. package/dist/self-host-compose.d.ts.map +1 -1
  274. package/dist/self-host-compose.js +305 -73
  275. package/dist/self-host-compose.js.map +1 -1
  276. package/dist/service-role-check.d.ts +21 -0
  277. package/dist/service-role-check.d.ts.map +1 -0
  278. package/dist/service-role-check.js +85 -0
  279. package/dist/service-role-check.js.map +1 -0
  280. package/dist/storage-provision.d.ts +1 -1
  281. package/dist/storage-provision.js +3 -3
  282. package/dist/storage-provision.js.map +1 -1
  283. package/dist/studio-dev-server.d.ts +1 -1
  284. package/dist/studio-dev-server.d.ts.map +1 -1
  285. package/dist/systemd.d.ts +1 -1
  286. package/dist/systemd.js +1 -1
  287. package/dist/target-client.d.ts +17 -0
  288. package/dist/target-client.d.ts.map +1 -1
  289. package/dist/target-client.js +69 -17
  290. package/dist/target-client.js.map +1 -1
  291. package/dist/tsx-runner.js +1 -1
  292. package/dist/tsx-runner.js.map +1 -1
  293. package/dist/type-extractor.d.ts.map +1 -1
  294. package/dist/type-extractor.js +738 -34
  295. package/dist/type-extractor.js.map +1 -1
  296. package/dist/type-resolver.js +1 -1
  297. package/dist/type-resolver.js.map +1 -1
  298. package/dist/ui/brand.d.ts +1 -1
  299. package/dist/ui/brand.js +1 -1
  300. package/dist/ui/components/LogoWordmark.d.ts +1 -1
  301. package/dist/ui/components/LogoWordmark.d.ts.map +1 -1
  302. package/dist/ui/components/LogoWordmark.js +1 -1
  303. package/dist/ui/components/LogoWordmark.js.map +1 -1
  304. package/dist/ui/components/SelectField.js +1 -1
  305. package/dist/ui/components/SelectField.js.map +1 -1
  306. package/dist/ui/confirm.d.ts +1 -1
  307. package/dist/ui/confirm.js +1 -1
  308. package/dist/ui/fatal.d.ts +1 -1
  309. package/dist/ui/fatal.d.ts.map +1 -1
  310. package/dist/ui/fatal.js +1 -1
  311. package/dist/ui/fatal.js.map +1 -1
  312. package/dist/ui/flows/prompt-fields.js +1 -1
  313. package/dist/ui/flows/prompt-fields.js.map +1 -1
  314. package/dist/ui/interactive.d.ts +1 -1
  315. package/dist/ui/interactive.d.ts.map +1 -1
  316. package/dist/ui/interactive.js +1 -1
  317. package/dist/ui/interactive.js.map +1 -1
  318. package/dist/ui/progress.d.ts +1 -1
  319. package/dist/ui/progress.js +1 -1
  320. package/dist/ui/runtime/command-chrome.js +2 -2
  321. package/dist/ui/runtime/command-chrome.js.map +1 -1
  322. package/dist/ui/runtime/run-clack-flow.js +1 -1
  323. package/dist/ui/runtime/run-clack-flow.js.map +1 -1
  324. package/dist/ui/runtime/stdin-after-ink.d.ts.map +1 -1
  325. package/dist/ui/runtime/stdin-after-ink.js +4 -2
  326. package/dist/ui/runtime/stdin-after-ink.js.map +1 -1
  327. package/dist/ui/theme.d.ts +1 -1
  328. package/dist/ui/theme.js +1 -1
  329. package/dist/valkey-sidecar.d.ts +1 -1
  330. package/dist/valkey-sidecar.d.ts.map +1 -1
  331. package/dist/valkey-sidecar.js +2 -2
  332. package/dist/valkey-sidecar.js.map +1 -1
  333. package/package.json +6 -2
  334. package/scripts/build-release-artifacts.sh +112 -0
  335. package/scripts/generate-homebrew-formula.mjs +123 -0
  336. package/scripts/mirror-deno-release.sh +1 -1
  337. package/src/TYPE-RESOLUTION.md +31 -31
  338. package/src/app/framework.ts +1 -1
  339. package/src/augmentation-generator.ts +19 -6
  340. package/src/binary-cache.ts +94 -47
  341. package/src/cache-clean.ts +81 -0
  342. package/src/cache-pins.ts +243 -0
  343. package/src/cli-artifacts.ts +65 -0
  344. package/src/cli-install-method.ts +87 -0
  345. package/src/cli-package-version.ts +5 -1
  346. package/src/cli-standalone.ts +116 -34
  347. package/src/cli-version-embedded.ts +12 -0
  348. package/src/cli.ts +7 -1
  349. package/src/cloud-credentials.ts +183 -0
  350. package/src/commands/add.ts +1 -1
  351. package/src/commands/admin.ts +142 -27
  352. package/src/commands/adopt.ts +1 -1
  353. package/src/commands/app.ts +2 -2
  354. package/src/commands/cache.ts +92 -77
  355. package/src/commands/cloud.ts +32 -8
  356. package/src/commands/db.ts +164 -3
  357. package/src/commands/deploy.ts +12 -12
  358. package/src/commands/dev.ts +72 -23
  359. package/src/commands/doctor.ts +69 -3
  360. package/src/commands/engine.ts +1 -1
  361. package/src/commands/functions.ts +47 -10
  362. package/src/commands/generate.ts +5 -1
  363. package/src/commands/hooks.ts +138 -0
  364. package/src/commands/init.ts +65 -31
  365. package/src/commands/internal.ts +23 -0
  366. package/src/commands/link-helpers.ts +9 -2
  367. package/src/commands/login.ts +127 -0
  368. package/src/commands/logs.ts +1 -1
  369. package/src/commands/migrate.ts +5 -5
  370. package/src/commands/pg.ts +1 -1
  371. package/src/commands/plugins.ts +1 -1
  372. package/src/commands/pull.ts +2 -2
  373. package/src/commands/push.ts +124 -7
  374. package/src/commands/self-host.ts +1 -1
  375. package/src/commands/self-update.ts +41 -19
  376. package/src/commands/status.ts +1 -1
  377. package/src/commands/update.ts +1 -1
  378. package/src/config.ts +23 -4
  379. package/src/db-preflight.ts +575 -0
  380. package/src/dev-compose.ts +158 -89
  381. package/src/dev-log-filter.ts +1 -1
  382. package/src/dev-ports.ts +3 -3
  383. package/src/dev-session.ts +6 -6
  384. package/src/dev-shutdown.ts +8 -8
  385. package/src/dev-task-colors.ts +1 -1
  386. package/src/docker-postgres.ts +6 -6
  387. package/src/docker-runtime.ts +5 -5
  388. package/src/engine-client.ts +3 -3
  389. package/src/engine-push-output.ts +1 -1
  390. package/src/ensure-binary.ts +20 -0
  391. package/src/ensure-component-binaries.ts +1 -1
  392. package/src/env-file.ts +157 -11
  393. package/src/field-masking-tier.ts +107 -0
  394. package/src/functions-deno-types.ts +188 -0
  395. package/src/functions-router-gen.ts +1 -1
  396. package/src/gitignore.ts +3 -3
  397. package/src/hook-upload.ts +107 -0
  398. package/src/hooks-generator.ts +352 -0
  399. package/src/index.ts +1 -1
  400. package/src/init-project-detect.ts +1 -1
  401. package/src/link.ts +7 -0
  402. package/src/local-secrets.ts +104 -0
  403. package/src/main.ts +20 -0
  404. package/src/model-hooks.ts +260 -0
  405. package/src/pgbouncer-userlist.ts +2 -2
  406. package/src/postgres-ctl.ts +32 -5
  407. package/src/process-manager.ts +4 -4
  408. package/src/project-config.ts +237 -3
  409. package/src/pull-utils.ts +4 -4
  410. package/src/realtime-launch.ts +1 -1
  411. package/src/release-pins.ts +2 -2
  412. package/src/resolve-api-url.ts +1 -1
  413. package/src/resolve-target.ts +113 -68
  414. package/src/rest-cache-admin.ts +2 -2
  415. package/src/runtime-routes.ts +2 -2
  416. package/src/schema-ast-v2.ts +8 -5
  417. package/src/schema-push-lock.ts +56 -17
  418. package/src/scripts/postinstall.ts +1 -1
  419. package/src/self-host-compose.ts +348 -72
  420. package/src/service-role-check.ts +111 -0
  421. package/src/storage-provision.ts +3 -3
  422. package/src/studio-dev-server.ts +1 -1
  423. package/src/systemd.ts +1 -1
  424. package/src/target-client.ts +105 -18
  425. package/src/tsx-runner.ts +1 -1
  426. package/src/type-extractor.ts +885 -30
  427. package/src/type-resolver.ts +1 -1
  428. package/src/ui/README.md +1 -1
  429. package/src/ui/brand.ts +1 -1
  430. package/src/ui/components/LogoWordmark.tsx +1 -1
  431. package/src/ui/components/SelectField.tsx +1 -1
  432. package/src/ui/confirm.ts +1 -1
  433. package/src/ui/fatal.ts +1 -1
  434. package/src/ui/flows/prompt-fields.tsx +1 -1
  435. package/src/ui/interactive.ts +1 -1
  436. package/src/ui/progress.ts +1 -1
  437. package/src/ui/runtime/command-chrome.ts +2 -2
  438. package/src/ui/runtime/run-clack-flow.tsx +1 -1
  439. package/src/ui/runtime/stdin-after-ink.ts +4 -2
  440. package/src/ui/theme.ts +1 -1
  441. package/src/valkey-sidecar.ts +2 -2
  442. package/tests/access-composition.test.ts +667 -0
  443. package/tests/admin-studio-membership.test.ts +121 -0
  444. package/tests/api-schemas.test.ts +83 -0
  445. package/tests/archive-name-alias.test.ts +42 -0
  446. package/tests/augmentation-generator.test.ts +28 -0
  447. package/tests/cache-clean.test.ts +206 -0
  448. package/tests/cli-help.test.ts +11 -2
  449. package/tests/cli-install-method.test.ts +66 -0
  450. package/tests/command-chrome-coverage.test.ts +31 -26
  451. package/tests/command-chrome-wrap.test.ts +1 -0
  452. package/tests/db-preflight.test.ts +72 -0
  453. package/tests/doctor-render.test.ts +62 -0
  454. package/tests/doctor-service-role.test.ts +55 -0
  455. package/tests/engine-push-output.test.ts +1 -1
  456. package/tests/env-file.test.ts +121 -0
  457. package/tests/external-database-compose.test.ts +184 -0
  458. package/tests/external-database-config.test.ts +154 -0
  459. package/tests/field-masking-tier.test.ts +184 -0
  460. package/tests/functions-deno-types.test.ts +197 -0
  461. package/tests/homebrew-formula.test.ts +100 -0
  462. package/tests/hook-upload.test.ts +125 -0
  463. package/tests/hooks-generator.test.ts +212 -0
  464. package/tests/init.test.ts +5 -2
  465. package/tests/keys.test.ts +8 -2
  466. package/tests/local-secrets.test.ts +92 -0
  467. package/tests/model-hooks.test.ts +322 -0
  468. package/tests/runtime-contract.test.ts +113 -1
  469. package/tests/service-role-check.test.ts +109 -0
  470. package/tests/service-role-routes.test.ts +51 -0
  471. package/tests/storage-provision.test.ts +1 -1
  472. package/tests/target-client-refresh.test.ts +94 -0
  473. package/tests/type-extractor.test.ts +187 -0
  474. package/tsconfig.tsbuildinfo +1 -1
  475. package/vitest.config.ts +7 -1
  476. package/scripts/build-release-bundle.mjs +0 -27
  477. package/tests/engine-distribution.test.ts +0 -418
@@ -1,5 +1,5 @@
1
1
  /**
2
- * docker-postgres manage a supatype/postgres Docker container for local dev.
2
+ * docker-postgres: manage a supatype/postgres Docker container for local dev.
3
3
  *
4
4
  * Used by `supatype dev` when database.provider = "docker".
5
5
  * The container is named supatype-{projectName} and persists data in a
@@ -11,7 +11,7 @@ import { spawnSync } from "node:child_process"
11
11
  export interface DockerPgOptions {
12
12
  /** Docker image to run. Defaults to supatype/postgres:latest. */
13
13
  image: string
14
- /** Project name used to derive the container and volume names. */
14
+ /** Project name: used to derive the container and volume names. */
15
15
  projectName: string
16
16
  /** Host port to bind to container's 5432. */
17
17
  port: number
@@ -85,7 +85,7 @@ export function dockerPgStart(opts: DockerPgOptions): void {
85
85
  }
86
86
 
87
87
  /**
88
- * Stop the container (fast does not remove it or the data volume).
88
+ * Stop the container (fast, does not remove it or the data volume).
89
89
  * Safe to call even if the container is not running.
90
90
  */
91
91
  export function dockerPgStop(projectName: string): void {
@@ -120,7 +120,7 @@ export function dockerPgPostInitServing(logs: string): boolean {
120
120
 
121
121
  const initDone = logs.lastIndexOf("PostgreSQL init process complete")
122
122
  if (initDone === -1) {
123
- // Reused data volume this run did not re-run entrypoint init.
123
+ // Reused data volume: this run did not re-run entrypoint init.
124
124
  return true
125
125
  }
126
126
  return initDone < lastReady
@@ -240,7 +240,7 @@ export function dockerDbUrl(projectName: string, port: number, password = DEFAUL
240
240
  /**
241
241
  * DB URL for processes sharing the Postgres container network namespace
242
242
  * (supatype-server migrate in a one-shot container). Uses loopback inside the
243
- * container where pg_hba grants trust avoids host-published-port SCRAM/SSL issues.
243
+ * container where pg_hba grants trust, avoids host-published-port SCRAM/SSL issues.
244
244
  */
245
245
  export function dockerPgLoopbackDbUrl(projectName: string, password = DEFAULT_DEV_PASSWORD): string {
246
246
  return `postgres://${PG_USER}:${password}@127.0.0.1:5432/${projectName}?sslmode=disable`
@@ -254,7 +254,7 @@ export const DEFAULT_SERVER_DOCKER_IMAGE = "supatype/server:latest"
254
254
 
255
255
  /**
256
256
  * Run `supatype-server migrate` on the Postgres container network (loopback trust).
257
- * Used on Windows + database.provider docker host-published :5432 breaks libpq TLS there.
257
+ * Used on Windows + database.provider docker, host-published :5432 breaks libpq TLS there.
258
258
  */
259
259
  export function runGotrueMigrationsViaDocker(
260
260
  pgContainerName: string,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Docker daemon availability used before `docker compose` and other docker CLI calls.
2
+ * Docker daemon availability: used before `docker compose` and other docker CLI calls.
3
3
  */
4
4
 
5
5
  import { spawnSync } from "node:child_process"
@@ -41,7 +41,7 @@ export function probeDockerDaemon(): DockerDaemonProbe {
41
41
  const versionStderr = (version.stderr ?? "").trim()
42
42
  const versionDetail = `${versionStderr}${version.stdout ?? ""}`.trim()
43
43
 
44
- // No client version CLI missing or broken.
44
+ // No client version: CLI missing or broken.
45
45
  if (!clientVersion) {
46
46
  return {
47
47
  ok: false,
@@ -51,7 +51,7 @@ export function probeDockerDaemon(): DockerDaemonProbe {
51
51
  }
52
52
 
53
53
  // Client is present but daemon refused (paused/stopped). `docker info` can hang
54
- // while paused on Docker Desktop use the version stderr and skip info.
54
+ // while paused on Docker Desktop, use the version stderr and skip info.
55
55
  if (version.status !== 0 && versionStderr) {
56
56
  return { ok: false, reason: "daemon_unavailable", detail: versionStderr }
57
57
  }
@@ -104,7 +104,7 @@ function dockerUnavailableHints(probe: Extract<DockerDaemonProbe, { ok: false }>
104
104
  return hints
105
105
  }
106
106
 
107
- /** @deprecated Tests only use `reportDockerUnavailable`. */
107
+ /** @deprecated Tests only: use `reportDockerUnavailable`. */
108
108
  export function formatDockerUnavailableMessage(
109
109
  probe: Extract<DockerDaemonProbe, { ok: false }>,
110
110
  ): string {
@@ -142,7 +142,7 @@ export function reportDockerUnavailable(
142
142
  export function requireDockerDaemon(opts?: DockerReportOptions): void {
143
143
  const probe = probeDockerDaemon()
144
144
  if (probe.ok) return
145
- // Dev TUI patches console restore stderr before printing a fatal message.
145
+ // Dev TUI patches console, restore stderr before printing a fatal message.
146
146
  if (getActiveDevSession()) {
147
147
  endDevSession()
148
148
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * engine-client.ts subprocess-based engine invocation.
2
+ * engine-client.ts: subprocess-based engine invocation.
3
3
  *
4
4
  * Replaces the former HTTP-based engine client (Docker container API).
5
5
  * All callers use the same interface; only the transport changed.
@@ -99,7 +99,7 @@ async function getEngineBin(): Promise<string> {
99
99
  // Otherwise (no valid project config) fall through to default cache scan.
100
100
  }
101
101
 
102
- // No config found scan the cache for any available engine binary.
102
+ // No config found: scan the cache for any available engine binary.
103
103
  const platform = currentPlatform()
104
104
  const engineCacheDir = join(homedir(), ".supatype", "cache", "engine")
105
105
  try {
@@ -208,7 +208,7 @@ export async function engineRequest<T = unknown>(
208
208
  try {
209
209
  return JSON.parse(result.stdout) as T
210
210
  } catch {
211
- // Non-JSON stdout return as message.
211
+ // Non-JSON stdout: return as message.
212
212
  return { message: result.stdout.trim() } as T
213
213
  }
214
214
  }
@@ -43,7 +43,7 @@ export function parseEnginePushOutput(output: string): EnginePushResult | null {
43
43
  export function formatEnginePushMessage(result: EnginePushResult): string {
44
44
  if (result.status === "up_to_date") {
45
45
  if (result.admin_refreshed) {
46
- return "Schema up to date Studio metadata synced."
46
+ return "Schema up to date, Studio metadata synced."
47
47
  }
48
48
  return "Schema up to date."
49
49
  }
@@ -11,8 +11,26 @@ import {
11
11
  type Component,
12
12
  } from "./binary-cache.js"
13
13
  import { isDownloadInProgress, waitForComponentDownload } from "./binary-download-lock.js"
14
+ import { currentLibc } from "./cli-artifacts.js"
14
15
  import type { SupatypeProjectConfig } from "./project-config.js"
15
16
 
17
+ /**
18
+ * Components are published for glibc only, so on Alpine the CLI itself runs (it has a musl
19
+ * build) while everything it downloads cannot start. Said once, before the first download,
20
+ * because the alternative is a dynamic loader error naming a file the user never asked for.
21
+ */
22
+ let warnedAboutMusl = false
23
+ function warnIfMusl(component: Component): void {
24
+ if (warnedAboutMusl || currentLibc() !== "musl") return
25
+ warnedAboutMusl = true
26
+ console.warn(
27
+ `[supatype] This is a musl system (Alpine). Component binaries such as ${component} are ` +
28
+ "published for glibc only, so they may fail to start here.\n" +
29
+ "[supatype] Use a glibc image (for example node:22-bookworm) for local stacks, or run " +
30
+ "against a remote target with `supatype link`.",
31
+ )
32
+ }
33
+
16
34
  export async function ensureBinary(
17
35
  component: Component,
18
36
  config: SupatypeProjectConfig,
@@ -26,6 +44,8 @@ export async function ensureBinary(
26
44
  }
27
45
  }
28
46
 
47
+ warnIfMusl(component)
48
+
29
49
  const version = await resolveVersionFor(component, config)
30
50
  const platform = currentPlatform()
31
51
 
@@ -37,7 +37,7 @@ export async function ensureComponentBinaries(
37
37
  const list = describeRequiredHostComponents(components)
38
38
  if (provider === "docker") {
39
39
  info(
40
- `Preparing host CLI tools (${list}) Compose still runs Postgres and the API stack.`,
40
+ `Preparing host CLI tools (${list}), Compose still runs Postgres and the API stack.`,
41
41
  )
42
42
  } else {
43
43
  info(`Preparing local runtime components (${list})…`)
package/src/env-file.ts CHANGED
@@ -1,23 +1,162 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from "node:fs"
2
2
  import { join } from "node:path"
3
3
 
4
- /** Merge key/value updates into a project `.env` without dropping unrelated lines. */
4
+ /**
5
+ * Marks a value the CLI wrote from `versions` in `supatype.config.ts`.
6
+ *
7
+ * Provenance, so that removing a pin from config can clean up the stale image reference it left
8
+ * behind *without* deleting a value the operator wrote by hand. Before this, the image keys derived
9
+ * from config were removed unconditionally on every compose run: an operator could override
10
+ * `SUPATYPE_REALTIME_IMAGE` from `.env` and could not override `SUPATYPE_SERVER_IMAGE`, because the
11
+ * latter is derivable from a pin and the former is not. Same file, same shape, different rules.
12
+ */
13
+ export const MANAGED_MARKER = "# supatype:managed, value from versions in supatype.config.ts"
14
+
15
+ interface EnvLine {
16
+ /** `KEY` for an assignment, undefined for comments and blanks. */
17
+ key?: string
18
+ text: string
19
+ /** True when the preceding line is the managed marker. */
20
+ managed: boolean
21
+ }
22
+
23
+ function parseLines(text: string): EnvLine[] {
24
+ const out: EnvLine[] = []
25
+ if (text === "") return out
26
+ let markerPending = false
27
+ // A file ending in a newline yields a final empty element; keeping it would put a blank line
28
+ // between the existing content and anything appended.
29
+ const raws = text.split(/\r?\n/)
30
+ while (raws.length > 0 && raws[raws.length - 1] === "") raws.pop()
31
+ for (const raw of raws) {
32
+ const trimmed = raw.trim()
33
+ if (trimmed === MANAGED_MARKER) {
34
+ markerPending = true
35
+ out.push({ text: raw, managed: false })
36
+ continue
37
+ }
38
+ const eq = raw.indexOf("=")
39
+ const key = eq > 0 ? raw.slice(0, eq).trim() : undefined
40
+ const isAssignment = key !== undefined && /^[A-Za-z_][A-Za-z0-9_]*$/.test(key)
41
+ out.push({ ...(isAssignment && { key }), text: raw, managed: isAssignment && markerPending })
42
+ if (!isAssignment && trimmed !== "") markerPending = false
43
+ else if (isAssignment) markerPending = false
44
+ }
45
+ return out
46
+ }
47
+
48
+ export interface UpsertOptions {
49
+ /**
50
+ * Keys to delete: but only where the CLI wrote them (see [`MANAGED_MARKER`]). A hand-written value
51
+ * is left alone, because the operator putting an image tag in `.env` is the documented way to run a
52
+ * local build and deleting it silently sent them back to `:latest`.
53
+ */
54
+ removeManaged?: readonly string[]
55
+ /** Keys in `updates` that come from config and may later be cleaned up. Written with the marker. */
56
+ managed?: readonly string[]
57
+ /** Keys to delete outright, whoever wrote them. For secrets being rotated out. */
58
+ remove?: readonly string[]
59
+ }
60
+
61
+ /**
62
+ * Merge key/value updates into a project `.env`.
63
+ *
64
+ * Comments, blank lines and ordering are preserved: this file is edited by hand, and the previous
65
+ * implementation rebuilt it from the assignments alone, so every comment an operator had written
66
+ * disappeared the first time they ran anything that touched `.env`.
67
+ */
5
68
  export function upsertEnvFile(
6
69
  cwd: string,
7
70
  updates: Record<string, string>,
8
- removeKeys: readonly string[] = [],
71
+ options: UpsertOptions | readonly string[] = {},
9
72
  ): void {
73
+ // Historically the third argument was a plain list of keys to remove unconditionally.
74
+ const opts: UpsertOptions = Array.isArray(options)
75
+ ? { remove: options as readonly string[] }
76
+ : (options as UpsertOptions)
77
+ const removeManaged = new Set(opts.removeManaged ?? [])
78
+ const removeAlways = new Set(opts.remove ?? [])
79
+ const managed = new Set(opts.managed ?? [])
80
+
10
81
  const envPath = join(cwd, ".env")
11
82
  const existing = existsSync(envPath) ? readFileSync(envPath, "utf8") : ""
12
- const keys = new Set([...Object.keys(updates), ...removeKeys])
13
- const kept = existing
14
- .split("\n")
15
- .filter((line) => {
16
- const key = line.split("=")[0]?.trim()
17
- return key && line.includes("=") && !keys.has(key)
18
- })
19
- const merged = [...kept, ...Object.entries(updates).map(([key, value]) => `${key}=${value}`)]
20
- writeFileSync(envPath, `${merged.join("\n").trimEnd()}\n`, "utf8")
83
+ const lines = parseLines(existing)
84
+
85
+ const written = new Set<string>()
86
+ const kept: EnvLine[] = []
87
+
88
+ for (let i = 0; i < lines.length; i++) {
89
+ const line = lines[i]!
90
+ const key = line.key
91
+
92
+ if (key === undefined) {
93
+ kept.push(line)
94
+ continue
95
+ }
96
+
97
+ if (removeAlways.has(key) || (removeManaged.has(key) && line.managed)) {
98
+ // Drop the marker that introduced it, so no orphan comment is left behind.
99
+ if (line.managed && kept[kept.length - 1]?.text.trim() === MANAGED_MARKER) kept.pop()
100
+ continue
101
+ }
102
+
103
+ if (key in updates) {
104
+ const wantsMarker = managed.has(key)
105
+ if (wantsMarker && kept[kept.length - 1]?.text.trim() !== MANAGED_MARKER) {
106
+ kept.push({ text: MANAGED_MARKER, managed: false })
107
+ }
108
+ if (!wantsMarker && line.managed && kept[kept.length - 1]?.text.trim() === MANAGED_MARKER) {
109
+ kept.pop()
110
+ }
111
+ kept.push({ key, text: `${key}=${updates[key]}`, managed: wantsMarker })
112
+ written.add(key)
113
+ continue
114
+ }
115
+
116
+ kept.push(line)
117
+ }
118
+
119
+ const appended: string[] = []
120
+ for (const [key, value] of Object.entries(updates)) {
121
+ if (written.has(key)) continue
122
+ if (managed.has(key)) appended.push(MANAGED_MARKER)
123
+ appended.push(`${key}=${value}`)
124
+ }
125
+
126
+ const body = [...kept.map((l) => l.text), ...appended].join("\n")
127
+ writeFileSync(envPath, `${body.replace(/\n+$/, "")}\n`, "utf8")
128
+ }
129
+
130
+ /**
131
+ * Parse a project `.env` into key/value pairs.
132
+ *
133
+ * Deliberately small: `KEY=value`, `#` comments, one optional layer of surrounding quotes. No
134
+ * interpolation and no `export` handling, because Compose's own parser does not do those either and
135
+ * a `.env` that means two different things depending on who reads it is worse than a limited one.
136
+ */
137
+ export function readEnvFile(cwd: string): Record<string, string> {
138
+ const envPath = join(cwd, ".env")
139
+ if (!existsSync(envPath)) return {}
140
+
141
+ const out: Record<string, string> = {}
142
+ for (const line of readFileSync(envPath, "utf8").split(/\r?\n/)) {
143
+ const trimmed = line.trim()
144
+ if (trimmed.length === 0 || trimmed.startsWith("#")) continue
145
+ const eq = trimmed.indexOf("=")
146
+ if (eq <= 0) continue
147
+ const key = trimmed.slice(0, eq).trim()
148
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue
149
+ let value = trimmed.slice(eq + 1).trim()
150
+ if (
151
+ value.length >= 2 &&
152
+ ((value.startsWith('"') && value.endsWith('"')) ||
153
+ (value.startsWith("'") && value.endsWith("'")))
154
+ ) {
155
+ value = value.slice(1, -1)
156
+ }
157
+ out[key] = value
158
+ }
159
+ return out
21
160
  }
22
161
 
23
162
  export function readEnvValue(cwd: string, key: string, fallback: string): string {
@@ -29,6 +168,13 @@ export function readEnvValue(cwd: string, key: string, fallback: string): string
29
168
  return fallback
30
169
  }
31
170
 
171
+ /** Whether `.env` carries a non-empty value for `key`. Distinguishes absent from defaulted. */
172
+ export function hasEnvValue(cwd: string, key: string): boolean {
173
+ const envPath = join(cwd, ".env")
174
+ if (!existsSync(envPath)) return false
175
+ return new RegExp(`^${key}=(.+)$`, "m").test(readFileSync(envPath, "utf8"))
176
+ }
177
+
32
178
  export function readEnvInt(cwd: string, key: string): number | null {
33
179
  const raw = readEnvValue(cwd, key, "")
34
180
  if (!raw) return null
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Which mechanism will enforce this project's per-column rules, decided offline.
3
+ *
4
+ * The engine makes the same decision at push time by asking the database whether `supatype_mask` is
5
+ * installed. The CLI has to answer earlier: it writes `PGRST_DB_SCHEMA` when it generates compose,
6
+ * before any database necessarily exists. It can, because the extension needs
7
+ * `shared_preload_libraries` and a compiled library on the host, so exactly one path ships it,
8
+ * `supatype/postgres`. Everything else gets the view tier:
9
+ *
10
+ * | Config | Ships the extension | Tier |
11
+ * | -------------------------------------------- | ------------------- | --------- |
12
+ * | `database.provider: "docker"` | yes | extension |
13
+ * | `provider: native` | no | views |
14
+ * | `database.external` | no | views |
15
+ * | `provider: docker` + `database.image` override | no | views |
16
+ *
17
+ * Deliberately **not** "is the database external": a native `supatype dev` has no extension either,
18
+ * and treating it as tier 1 would point PostgREST at a schema whose tables the API roles no longer
19
+ * hold privileges on: every request denied.
20
+ *
21
+ * The one case this cannot call is a self-managed Postgres where the operator compiled and installed
22
+ * the extension themselves and points at it with `database.external`. They set `schema.api_schemas`
23
+ * explicitly; `supatype db check` reports the mismatch either way.
24
+ */
25
+
26
+ import { existsSync } from "node:fs"
27
+ // Statically imported: these packages are ESM, where `require` does not exist. The first attempt used
28
+ // it for a lazy import and every command that generates compose would have thrown at runtime, caught
29
+ // by the tests that run the built binary rather than the source.
30
+ import { loadSchemaAst } from "./config.js"
31
+ export { nativeMaskLibraryPresent } from "./postgres-ctl.js"
32
+ import type { SupatypeProjectConfig } from "./project-config.js"
33
+ import {
34
+ resolveRuntimeProvider,
35
+ schemaPathFromProject,
36
+ usesExternalDatabase,
37
+ } from "./project-config.js"
38
+
39
+ export type FieldMaskingTier = "none" | "extension" | "views"
40
+
41
+
42
+ /** Postgres image this project would run, when it runs one at all. */
43
+ function postgresImage(config: SupatypeProjectConfig): string | undefined {
44
+ if (usesExternalDatabase(config)) return undefined
45
+ if (config.database.provider !== "docker" && resolveRuntimeProvider(config) !== "docker") {
46
+ return undefined
47
+ }
48
+ return config.database.image?.trim() || "supatype/postgres:latest"
49
+ }
50
+
51
+ /** True when the Postgres this project runs is one that carries `supatype_mask`. */
52
+ export function imageShipsMaskExtension(config: SupatypeProjectConfig): boolean {
53
+ const image = postgresImage(config)
54
+ return image !== undefined && /^supatype\/postgres(:|$)/.test(image)
55
+ }
56
+
57
+ /**
58
+ * Whether any model masks a column.
59
+ *
60
+ * Read from the extracted AST rather than the config, because that is where field rules live. Shaped
61
+ * loosely on purpose: the CLI's AST type carries `platform.access` as an opaque record, and this only
62
+ * needs to know whether a `fields` map is present and non-empty.
63
+ */
64
+ export function schemaHasFieldRules(ast: unknown): boolean {
65
+ const models = (ast as { models?: unknown[] } | null)?.models
66
+ if (!Array.isArray(models)) return false
67
+ return models.some((model) => {
68
+ const access = (
69
+ model as { annotations?: { platform?: { access?: Record<string, unknown> } } } | null
70
+ )?.annotations?.platform?.access
71
+ const fields = access?.["fields"]
72
+ return typeof fields === "object" && fields !== null && Object.keys(fields).length > 0
73
+ })
74
+ }
75
+
76
+ /** The tier this project's next push will use. */
77
+ export function fieldMaskingTier(
78
+ config: SupatypeProjectConfig,
79
+ ast: unknown,
80
+ /** Set on the native path once the Postgres install is known, see [`nativeMaskLibraryPresent`]. */
81
+ maskLibraryPresent?: boolean,
82
+ ): FieldMaskingTier {
83
+ if (!schemaHasFieldRules(ast)) return "none"
84
+ if (maskLibraryPresent === true) return "extension"
85
+ return imageShipsMaskExtension(config) ? "extension" : "views"
86
+ }
87
+
88
+ /**
89
+ * The tier for a project on disk, loading its schema to see whether any column is masked.
90
+ *
91
+ * A schema that fails to load falls back to `"none"`, the default exposed-schema list. Deciding the
92
+ * tier is the wrong moment to report a syntax error, and `push`/`dev` do it properly moments later
93
+ * with the file and line.
94
+ */
95
+ export function fieldMaskingTierFromProject(
96
+ cwd: string,
97
+ config: SupatypeProjectConfig,
98
+ maskLibraryPresent?: boolean,
99
+ ): FieldMaskingTier {
100
+ try {
101
+ const schemaPath = schemaPathFromProject(config, cwd)
102
+ if (!existsSync(schemaPath)) return "none"
103
+ return fieldMaskingTier(config, loadSchemaAst(schemaPath, cwd), maskLibraryPresent)
104
+ } catch {
105
+ return "none"
106
+ }
107
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Scaffold Deno IDE types for edge functions so tsserver / Cursor stop
3
+ * reporting "Cannot find name 'Deno'" under the project root tsconfig.
4
+ *
5
+ * We ship a curated ambient declaration (not `@types/deno` at the app root):
6
+ * installing `@types/deno` as a project dependency auto-includes it in the
7
+ * whole app when root `tsconfig` omits `"types"`, which pollutes React/Next.
8
+ */
9
+
10
+ import {
11
+ existsSync,
12
+ mkdirSync,
13
+ readFileSync,
14
+ writeFileSync,
15
+ } from "node:fs"
16
+ import { join, relative } from "node:path"
17
+ import ts from "typescript"
18
+
19
+ const MARKER = "Supatype edge functions (IDE / tsserver)"
20
+
21
+ /** Ambient Deno types written into `functions/deno.d.ts`. */
22
+ export function functionsDenoAmbientSource(): string {
23
+ return `/**
24
+ * ${MARKER}.
25
+ * Runtime is Deno; this file covers APIs edge functions commonly use.
26
+ * Do not add \`@types/deno\` to the app package.json, it leaks into the
27
+ * whole project when root tsconfig has no \`"types"\` field.
28
+ *
29
+ * Optional: for the full Deno API, install the Deno VS Code/Cursor extension
30
+ * and open \`functions/\` as a Deno-enabled workspace folder.
31
+ */
32
+ /* eslint-disable @typescript-eslint/no-unused-vars */
33
+
34
+ interface DenoEnv {
35
+ /** Returns the value of the environment variable, or \`undefined\` if unset. */
36
+ get(key: string): string | undefined
37
+ set(key: string, value: string): void
38
+ delete(key: string): void
39
+ has(key: string): boolean
40
+ toObject(): { [key: string]: string }
41
+ }
42
+
43
+ declare namespace Deno {
44
+ const env: DenoEnv
45
+
46
+ namespace errors {
47
+ class NotFound extends Error {}
48
+ class PermissionDenied extends Error {}
49
+ }
50
+
51
+ interface DirEntry {
52
+ name: string
53
+ isFile: boolean
54
+ isDirectory: boolean
55
+ isSymlink: boolean
56
+ }
57
+
58
+ interface FileInfo {
59
+ isFile: boolean
60
+ isDirectory: boolean
61
+ isSymlink: boolean
62
+ size: number
63
+ mtime: Date | null
64
+ }
65
+
66
+ function readDir(path: string): AsyncIterable<DirEntry>
67
+ function readTextFile(path: string): Promise<string>
68
+ function stat(path: string): Promise<FileInfo>
69
+
70
+ function serve(
71
+ options: { port: number; hostname?: string; onListen?: (params: { hostname: string; port: number }) => void },
72
+ handler: (req: Request) => Response | Promise<Response>,
73
+ ): void
74
+ }
75
+ `
76
+ }
77
+
78
+ /** `functions/tsconfig.json`: owns function files so the app config can exclude them. */
79
+ export function functionsTsConfigSource(): string {
80
+ return `{
81
+ "compilerOptions": {
82
+ "target": "ES2022",
83
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
84
+ "strict": true,
85
+ "noEmit": true,
86
+ "module": "ESNext",
87
+ "moduleResolution": "bundler",
88
+ "isolatedModules": true,
89
+ "skipLibCheck": true,
90
+ "allowImportingTsExtensions": true,
91
+ "types": []
92
+ },
93
+ "include": ["./**/*.ts", "./deno.d.ts"]
94
+ }
95
+ `
96
+ }
97
+
98
+ export type FunctionsDenoTypesResult = {
99
+ wroteDenoDts: boolean
100
+ wroteTsconfig: boolean
101
+ rootExclude: "updated" | "already" | "missing" | "manual"
102
+ hints: string[]
103
+ }
104
+
105
+ /**
106
+ * Ensure `functions/deno.d.ts` + `functions/tsconfig.json` exist, and try to
107
+ * exclude `functions` from the project-root `tsconfig.json`.
108
+ */
109
+ export function ensureFunctionsDenoTypes(
110
+ projectRoot: string,
111
+ functionsDir: string,
112
+ ): FunctionsDenoTypesResult {
113
+ mkdirSync(functionsDir, { recursive: true })
114
+
115
+ const denoDtsPath = join(functionsDir, "deno.d.ts")
116
+ const tsconfigPath = join(functionsDir, "tsconfig.json")
117
+
118
+ let wroteDenoDts = false
119
+ if (!existsSync(denoDtsPath)) {
120
+ writeFileSync(denoDtsPath, functionsDenoAmbientSource(), "utf8")
121
+ wroteDenoDts = true
122
+ }
123
+
124
+ let wroteTsconfig = false
125
+ if (!existsSync(tsconfigPath)) {
126
+ writeFileSync(tsconfigPath, functionsTsConfigSource(), "utf8")
127
+ wroteTsconfig = true
128
+ }
129
+
130
+ const rootExclude = ensureRootTsconfigExcludesFunctions(projectRoot)
131
+ const hints: string[] = []
132
+ const fnRel = toPosix(relative(projectRoot, functionsDir)) || "functions"
133
+
134
+ if (rootExclude === "manual") {
135
+ hints.push(
136
+ `Add "functions" to the root tsconfig.json "exclude" array so the app checker skips ${fnRel}/.`,
137
+ )
138
+ } else if (rootExclude === "missing") {
139
+ hints.push(
140
+ `If you add a root tsconfig.json, exclude "${fnRel}" (or "functions") so app typecheck stays separate.`,
141
+ )
142
+ }
143
+
144
+ return { wroteDenoDts, wroteTsconfig, rootExclude, hints }
145
+ }
146
+
147
+ function ensureRootTsconfigExcludesFunctions(
148
+ projectRoot: string,
149
+ ): FunctionsDenoTypesResult["rootExclude"] {
150
+ const path = join(projectRoot, "tsconfig.json")
151
+ if (!existsSync(path)) return "missing"
152
+
153
+ const raw = readFileSync(path, "utf8")
154
+ const parsed = ts.parseConfigFileTextToJson(path, raw)
155
+ if (parsed.error || parsed.config === undefined || typeof parsed.config !== "object") {
156
+ return "manual"
157
+ }
158
+
159
+ const cfg = parsed.config as { exclude?: unknown }
160
+ const exclude = Array.isArray(cfg.exclude) ? cfg.exclude.map(String) : []
161
+ if (exclude.some(isFunctionsExcludeEntry)) return "already"
162
+
163
+ try {
164
+ const asJson = JSON.parse(raw) as { exclude?: string[] }
165
+ asJson.exclude = [...(Array.isArray(asJson.exclude) ? asJson.exclude : []), "functions"]
166
+ writeFileSync(path, `${JSON.stringify(asJson, null, 2)}\n`, "utf8")
167
+ return "updated"
168
+ } catch {
169
+ // JSONC / trailing commas, try a conservative string splice into an existing exclude array.
170
+ if (/"exclude"\s*:\s*\[/.test(raw)) {
171
+ const next = raw.replace(/("exclude"\s*:\s*\[)/, `$1\n "functions",`)
172
+ if (next !== raw) {
173
+ writeFileSync(path, next, "utf8")
174
+ return "updated"
175
+ }
176
+ }
177
+ return "manual"
178
+ }
179
+ }
180
+
181
+ function isFunctionsExcludeEntry(entry: string): boolean {
182
+ const n = entry.replace(/\\/g, "/").replace(/^\.\//, "")
183
+ return n === "functions" || n === "functions/**" || n.startsWith("functions/")
184
+ }
185
+
186
+ function toPosix(path: string): string {
187
+ return path.replace(/\\/g, "/")
188
+ }
@@ -58,7 +58,7 @@ export function generateFunctionsRouterSource(
58
58
  )
59
59
  const routes = fns.map((fn, i) => ` "${fn.name}": handler_${i},`)
60
60
 
61
- return `// Auto-generated do not edit (regenerated by supatype dev / functions serve)
61
+ return `// Auto-generated: do not edit (regenerated by supatype dev / functions serve)
62
62
  ${imports.join("\n")}
63
63
 
64
64
  const handlers: Record<string, (req: Request) => Response | Promise<Response>> = {