@supatype/cli 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test.log +221 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/assets/supatype-logo-wordmark.ascii.txt +6 -0
  5. package/bin/dev-entry.ts +2 -0
  6. package/bin/supatype.js +5 -0
  7. package/dist/app/framework.d.ts +44 -0
  8. package/dist/app/framework.d.ts.map +1 -0
  9. package/dist/app/framework.js +200 -0
  10. package/dist/app/framework.js.map +1 -0
  11. package/dist/app/proxy-dev-app.d.ts +13 -0
  12. package/dist/app/proxy-dev-app.d.ts.map +1 -0
  13. package/dist/app/proxy-dev-app.js +54 -0
  14. package/dist/app/proxy-dev-app.js.map +1 -0
  15. package/dist/app-config.d.ts +7 -0
  16. package/dist/app-config.d.ts.map +1 -0
  17. package/dist/app-config.js +113 -0
  18. package/dist/app-config.js.map +1 -0
  19. package/dist/assets/supatype-logo-wordmark.ascii.txt +6 -0
  20. package/dist/augmentation-generator.d.ts +2 -0
  21. package/dist/augmentation-generator.d.ts.map +1 -0
  22. package/dist/augmentation-generator.js +111 -0
  23. package/dist/augmentation-generator.js.map +1 -0
  24. package/dist/binary-cache.d.ts +98 -0
  25. package/dist/binary-cache.d.ts.map +1 -0
  26. package/dist/binary-cache.js +687 -0
  27. package/dist/binary-cache.js.map +1 -0
  28. package/dist/cli.d.ts +2 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +61 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/commands/admin.d.ts +4 -0
  33. package/dist/commands/admin.d.ts.map +1 -0
  34. package/dist/commands/admin.js +271 -0
  35. package/dist/commands/admin.js.map +1 -0
  36. package/dist/commands/app.d.ts +3 -0
  37. package/dist/commands/app.d.ts.map +1 -0
  38. package/dist/commands/app.js +82 -0
  39. package/dist/commands/app.js.map +1 -0
  40. package/dist/commands/cache.d.ts +6 -0
  41. package/dist/commands/cache.d.ts.map +1 -0
  42. package/dist/commands/cache.js +105 -0
  43. package/dist/commands/cache.js.map +1 -0
  44. package/dist/commands/cloud.d.ts +23 -0
  45. package/dist/commands/cloud.d.ts.map +1 -0
  46. package/dist/commands/cloud.js +254 -0
  47. package/dist/commands/cloud.js.map +1 -0
  48. package/dist/commands/db.d.ts +8 -0
  49. package/dist/commands/db.d.ts.map +1 -0
  50. package/dist/commands/db.js +116 -0
  51. package/dist/commands/db.js.map +1 -0
  52. package/dist/commands/deploy-types.d.ts +14 -0
  53. package/dist/commands/deploy-types.d.ts.map +1 -0
  54. package/dist/commands/deploy-types.js +38 -0
  55. package/dist/commands/deploy-types.js.map +1 -0
  56. package/dist/commands/deploy.d.ts +15 -0
  57. package/dist/commands/deploy.d.ts.map +1 -0
  58. package/dist/commands/deploy.js +322 -0
  59. package/dist/commands/deploy.js.map +1 -0
  60. package/dist/commands/dev.d.ts +14 -0
  61. package/dist/commands/dev.d.ts.map +1 -0
  62. package/dist/commands/dev.js +806 -0
  63. package/dist/commands/dev.js.map +1 -0
  64. package/dist/commands/diff.d.ts +3 -0
  65. package/dist/commands/diff.d.ts.map +1 -0
  66. package/dist/commands/diff.js +54 -0
  67. package/dist/commands/diff.js.map +1 -0
  68. package/dist/commands/engine.d.ts +7 -0
  69. package/dist/commands/engine.d.ts.map +1 -0
  70. package/dist/commands/engine.js +27 -0
  71. package/dist/commands/engine.js.map +1 -0
  72. package/dist/commands/functions.d.ts +3 -0
  73. package/dist/commands/functions.d.ts.map +1 -0
  74. package/dist/commands/functions.js +749 -0
  75. package/dist/commands/functions.js.map +1 -0
  76. package/dist/commands/generate.d.ts +3 -0
  77. package/dist/commands/generate.d.ts.map +1 -0
  78. package/dist/commands/generate.js +38 -0
  79. package/dist/commands/generate.js.map +1 -0
  80. package/dist/commands/init.d.ts +7 -0
  81. package/dist/commands/init.d.ts.map +1 -0
  82. package/dist/commands/init.js +228 -0
  83. package/dist/commands/init.js.map +1 -0
  84. package/dist/commands/keys.d.ts +4 -0
  85. package/dist/commands/keys.d.ts.map +1 -0
  86. package/dist/commands/keys.js +57 -0
  87. package/dist/commands/keys.js.map +1 -0
  88. package/dist/commands/logs.d.ts +6 -0
  89. package/dist/commands/logs.d.ts.map +1 -0
  90. package/dist/commands/logs.js +52 -0
  91. package/dist/commands/logs.js.map +1 -0
  92. package/dist/commands/migrate-from-v1.d.ts +5 -0
  93. package/dist/commands/migrate-from-v1.d.ts.map +1 -0
  94. package/dist/commands/migrate-from-v1.js +125 -0
  95. package/dist/commands/migrate-from-v1.js.map +1 -0
  96. package/dist/commands/migrate.d.ts +3 -0
  97. package/dist/commands/migrate.d.ts.map +1 -0
  98. package/dist/commands/migrate.js +75 -0
  99. package/dist/commands/migrate.js.map +1 -0
  100. package/dist/commands/pg.d.ts +8 -0
  101. package/dist/commands/pg.d.ts.map +1 -0
  102. package/dist/commands/pg.js +102 -0
  103. package/dist/commands/pg.js.map +1 -0
  104. package/dist/commands/plugins.d.ts +3 -0
  105. package/dist/commands/plugins.d.ts.map +1 -0
  106. package/dist/commands/plugins.js +431 -0
  107. package/dist/commands/plugins.js.map +1 -0
  108. package/dist/commands/pull.d.ts +3 -0
  109. package/dist/commands/pull.d.ts.map +1 -0
  110. package/dist/commands/pull.js +12 -0
  111. package/dist/commands/pull.js.map +1 -0
  112. package/dist/commands/push.d.ts +3 -0
  113. package/dist/commands/push.d.ts.map +1 -0
  114. package/dist/commands/push.js +179 -0
  115. package/dist/commands/push.js.map +1 -0
  116. package/dist/commands/seed.d.ts +5 -0
  117. package/dist/commands/seed.d.ts.map +1 -0
  118. package/dist/commands/seed.js +55 -0
  119. package/dist/commands/seed.js.map +1 -0
  120. package/dist/commands/self-host.d.ts +9 -0
  121. package/dist/commands/self-host.d.ts.map +1 -0
  122. package/dist/commands/self-host.js +310 -0
  123. package/dist/commands/self-host.js.map +1 -0
  124. package/dist/commands/self-update.d.ts +9 -0
  125. package/dist/commands/self-update.d.ts.map +1 -0
  126. package/dist/commands/self-update.js +33 -0
  127. package/dist/commands/self-update.js.map +1 -0
  128. package/dist/commands/status.d.ts +6 -0
  129. package/dist/commands/status.d.ts.map +1 -0
  130. package/dist/commands/status.js +70 -0
  131. package/dist/commands/status.js.map +1 -0
  132. package/dist/commands/types.d.ts +3 -0
  133. package/dist/commands/types.d.ts.map +1 -0
  134. package/dist/commands/types.js +62 -0
  135. package/dist/commands/types.js.map +1 -0
  136. package/dist/commands/update.d.ts +7 -0
  137. package/dist/commands/update.d.ts.map +1 -0
  138. package/dist/commands/update.js +118 -0
  139. package/dist/commands/update.js.map +1 -0
  140. package/dist/components.d.ts +5 -0
  141. package/dist/components.d.ts.map +1 -0
  142. package/dist/components.js +3 -0
  143. package/dist/components.js.map +1 -0
  144. package/dist/config.d.ts +65 -0
  145. package/dist/config.d.ts.map +1 -0
  146. package/dist/config.js +134 -0
  147. package/dist/config.js.map +1 -0
  148. package/dist/dev-compose.d.ts +19 -0
  149. package/dist/dev-compose.d.ts.map +1 -0
  150. package/dist/dev-compose.js +468 -0
  151. package/dist/dev-compose.js.map +1 -0
  152. package/dist/dev-log-bus.d.ts +30 -0
  153. package/dist/dev-log-bus.d.ts.map +1 -0
  154. package/dist/dev-log-bus.js +87 -0
  155. package/dist/dev-log-bus.js.map +1 -0
  156. package/dist/dev-log-filter.d.ts +10 -0
  157. package/dist/dev-log-filter.d.ts.map +1 -0
  158. package/dist/dev-log-filter.js +36 -0
  159. package/dist/dev-log-filter.js.map +1 -0
  160. package/dist/dev-logo.d.ts +12 -0
  161. package/dist/dev-logo.d.ts.map +1 -0
  162. package/dist/dev-logo.js +57 -0
  163. package/dist/dev-logo.js.map +1 -0
  164. package/dist/dev-session.d.ts +26 -0
  165. package/dist/dev-session.d.ts.map +1 -0
  166. package/dist/dev-session.js +106 -0
  167. package/dist/dev-session.js.map +1 -0
  168. package/dist/dev-shutdown.d.ts +9 -0
  169. package/dist/dev-shutdown.d.ts.map +1 -0
  170. package/dist/dev-shutdown.js +50 -0
  171. package/dist/dev-shutdown.js.map +1 -0
  172. package/dist/dev-task-colors.d.ts +14 -0
  173. package/dist/dev-task-colors.d.ts.map +1 -0
  174. package/dist/dev-task-colors.js +44 -0
  175. package/dist/dev-task-colors.js.map +1 -0
  176. package/dist/dev-tui.d.ts +24 -0
  177. package/dist/dev-tui.d.ts.map +1 -0
  178. package/dist/dev-tui.js +188 -0
  179. package/dist/dev-tui.js.map +1 -0
  180. package/dist/diff-output.d.ts +4 -0
  181. package/dist/diff-output.d.ts.map +1 -0
  182. package/dist/diff-output.js +12 -0
  183. package/dist/diff-output.js.map +1 -0
  184. package/dist/docker-postgres.d.ts +57 -0
  185. package/dist/docker-postgres.d.ts.map +1 -0
  186. package/dist/docker-postgres.js +208 -0
  187. package/dist/docker-postgres.js.map +1 -0
  188. package/dist/engine-client.d.ts +69 -0
  189. package/dist/engine-client.d.ts.map +1 -0
  190. package/dist/engine-client.js +157 -0
  191. package/dist/engine-client.js.map +1 -0
  192. package/dist/engine-push-output.d.ts +16 -0
  193. package/dist/engine-push-output.d.ts.map +1 -0
  194. package/dist/engine-push-output.js +61 -0
  195. package/dist/engine-push-output.js.map +1 -0
  196. package/dist/ensure-binary.d.ts +7 -0
  197. package/dist/ensure-binary.d.ts.map +1 -0
  198. package/dist/ensure-binary.js +17 -0
  199. package/dist/ensure-binary.js.map +1 -0
  200. package/dist/functions-router-gen.d.ts +14 -0
  201. package/dist/functions-router-gen.d.ts.map +1 -0
  202. package/dist/functions-router-gen.js +199 -0
  203. package/dist/functions-router-gen.js.map +1 -0
  204. package/dist/index.d.ts +11 -0
  205. package/dist/index.d.ts.map +1 -0
  206. package/dist/index.js +9 -0
  207. package/dist/index.js.map +1 -0
  208. package/dist/jwt.d.ts +3 -0
  209. package/dist/jwt.d.ts.map +1 -0
  210. package/dist/jwt.js +13 -0
  211. package/dist/jwt.js.map +1 -0
  212. package/dist/kong-config.d.ts +25 -0
  213. package/dist/kong-config.d.ts.map +1 -0
  214. package/dist/kong-config.js +71 -0
  215. package/dist/kong-config.js.map +1 -0
  216. package/dist/local-gateway.d.ts +7 -0
  217. package/dist/local-gateway.d.ts.map +1 -0
  218. package/dist/local-gateway.js +9 -0
  219. package/dist/local-gateway.js.map +1 -0
  220. package/dist/local-storage.d.ts +8 -0
  221. package/dist/local-storage.d.ts.map +1 -0
  222. package/dist/local-storage.js +14 -0
  223. package/dist/local-storage.js.map +1 -0
  224. package/dist/pgbouncer-userlist.d.ts +5 -0
  225. package/dist/pgbouncer-userlist.d.ts.map +1 -0
  226. package/dist/pgbouncer-userlist.js +14 -0
  227. package/dist/pgbouncer-userlist.js.map +1 -0
  228. package/dist/postgres-ctl.d.ts +44 -0
  229. package/dist/postgres-ctl.d.ts.map +1 -0
  230. package/dist/postgres-ctl.js +137 -0
  231. package/dist/postgres-ctl.js.map +1 -0
  232. package/dist/process-manager.d.ts +49 -0
  233. package/dist/process-manager.d.ts.map +1 -0
  234. package/dist/process-manager.js +177 -0
  235. package/dist/process-manager.js.map +1 -0
  236. package/dist/project-config.d.ts +238 -0
  237. package/dist/project-config.d.ts.map +1 -0
  238. package/dist/project-config.js +159 -0
  239. package/dist/project-config.js.map +1 -0
  240. package/dist/pull-utils.d.ts +31 -0
  241. package/dist/pull-utils.d.ts.map +1 -0
  242. package/dist/pull-utils.js +77 -0
  243. package/dist/pull-utils.js.map +1 -0
  244. package/dist/release-pins.d.ts +7 -0
  245. package/dist/release-pins.d.ts.map +1 -0
  246. package/dist/release-pins.js +27 -0
  247. package/dist/release-pins.js.map +1 -0
  248. package/dist/release-public-key.d.ts +8 -0
  249. package/dist/release-public-key.d.ts.map +1 -0
  250. package/dist/release-public-key.js +13 -0
  251. package/dist/release-public-key.js.map +1 -0
  252. package/dist/restore-system-relation-targets.d.ts +3 -0
  253. package/dist/restore-system-relation-targets.d.ts.map +1 -0
  254. package/dist/restore-system-relation-targets.js +45 -0
  255. package/dist/restore-system-relation-targets.js.map +1 -0
  256. package/dist/runtime-routes.d.ts +34 -0
  257. package/dist/runtime-routes.d.ts.map +1 -0
  258. package/dist/runtime-routes.js +252 -0
  259. package/dist/runtime-routes.js.map +1 -0
  260. package/dist/schema-ast-v2.d.ts +127 -0
  261. package/dist/schema-ast-v2.d.ts.map +1 -0
  262. package/dist/schema-ast-v2.js +226 -0
  263. package/dist/schema-ast-v2.js.map +1 -0
  264. package/dist/scripts/postinstall.d.ts +11 -0
  265. package/dist/scripts/postinstall.d.ts.map +1 -0
  266. package/dist/scripts/postinstall.js +47 -0
  267. package/dist/scripts/postinstall.js.map +1 -0
  268. package/dist/seed.d.ts +8 -0
  269. package/dist/seed.d.ts.map +1 -0
  270. package/dist/seed.js +32 -0
  271. package/dist/seed.js.map +1 -0
  272. package/dist/self-host-compose.d.ts +43 -0
  273. package/dist/self-host-compose.d.ts.map +1 -0
  274. package/dist/self-host-compose.js +400 -0
  275. package/dist/self-host-compose.js.map +1 -0
  276. package/dist/storage-provision.d.ts +24 -0
  277. package/dist/storage-provision.d.ts.map +1 -0
  278. package/dist/storage-provision.js +44 -0
  279. package/dist/storage-provision.js.map +1 -0
  280. package/dist/studio-admin-roles.d.ts +7 -0
  281. package/dist/studio-admin-roles.d.ts.map +1 -0
  282. package/dist/studio-admin-roles.js +14 -0
  283. package/dist/studio-admin-roles.js.map +1 -0
  284. package/dist/studio-dev-server.d.ts +22 -0
  285. package/dist/studio-dev-server.d.ts.map +1 -0
  286. package/dist/studio-dev-server.js +28 -0
  287. package/dist/studio-dev-server.js.map +1 -0
  288. package/dist/supatype-eval-1781522769253.d.mts +2 -0
  289. package/dist/supatype-eval-1781522769253.d.mts.map +1 -0
  290. package/dist/supatype-eval-1781522769253.mjs +3 -0
  291. package/dist/supatype-eval-1781522769253.mjs.map +1 -0
  292. package/dist/systemd.d.ts +26 -0
  293. package/dist/systemd.d.ts.map +1 -0
  294. package/dist/systemd.js +102 -0
  295. package/dist/systemd.js.map +1 -0
  296. package/dist/tsx-runner.d.ts +18 -0
  297. package/dist/tsx-runner.d.ts.map +1 -0
  298. package/dist/tsx-runner.js +69 -0
  299. package/dist/tsx-runner.js.map +1 -0
  300. package/dist/type-extractor.d.ts +4 -0
  301. package/dist/type-extractor.d.ts.map +1 -0
  302. package/dist/type-extractor.js +1213 -0
  303. package/dist/type-extractor.js.map +1 -0
  304. package/dist/type-resolver.d.ts +33 -0
  305. package/dist/type-resolver.d.ts.map +1 -0
  306. package/dist/type-resolver.js +338 -0
  307. package/dist/type-resolver.js.map +1 -0
  308. package/package.json +41 -0
  309. package/releases/deno/VERSION +1 -0
  310. package/scripts/mirror-deno-release.sh +76 -0
  311. package/src/TYPE-RESOLUTION.md +294 -0
  312. package/src/app/framework.ts +249 -0
  313. package/src/app/proxy-dev-app.ts +68 -0
  314. package/src/app-config.ts +128 -0
  315. package/src/augmentation-generator.ts +126 -0
  316. package/src/binary-cache.ts +845 -0
  317. package/src/cli.ts +63 -0
  318. package/src/commands/admin.ts +372 -0
  319. package/src/commands/app.ts +97 -0
  320. package/src/commands/cache.ts +117 -0
  321. package/src/commands/cloud.ts +325 -0
  322. package/src/commands/db.ts +136 -0
  323. package/src/commands/deploy-types.ts +49 -0
  324. package/src/commands/deploy.ts +400 -0
  325. package/src/commands/dev.ts +1009 -0
  326. package/src/commands/diff.ts +63 -0
  327. package/src/commands/engine.ts +30 -0
  328. package/src/commands/functions.ts +901 -0
  329. package/src/commands/generate.ts +44 -0
  330. package/src/commands/init.ts +253 -0
  331. package/src/commands/keys.ts +66 -0
  332. package/src/commands/logs.ts +58 -0
  333. package/src/commands/migrate-from-v1.ts +131 -0
  334. package/src/commands/migrate.ts +87 -0
  335. package/src/commands/pg.ts +133 -0
  336. package/src/commands/plugins.ts +508 -0
  337. package/src/commands/pull.ts +17 -0
  338. package/src/commands/push.ts +226 -0
  339. package/src/commands/seed.ts +68 -0
  340. package/src/commands/self-host.ts +364 -0
  341. package/src/commands/self-update.ts +45 -0
  342. package/src/commands/status.ts +84 -0
  343. package/src/commands/types.ts +76 -0
  344. package/src/commands/update.ts +136 -0
  345. package/src/components.ts +6 -0
  346. package/src/config.ts +223 -0
  347. package/src/dev-compose.ts +583 -0
  348. package/src/dev-log-bus.ts +101 -0
  349. package/src/dev-log-filter.ts +32 -0
  350. package/src/dev-logo.ts +62 -0
  351. package/src/dev-session.ts +130 -0
  352. package/src/dev-shutdown.ts +54 -0
  353. package/src/dev-task-colors.ts +47 -0
  354. package/src/dev-tui.ts +232 -0
  355. package/src/diff-output.ts +12 -0
  356. package/src/docker-postgres.ts +295 -0
  357. package/src/engine-client.ts +236 -0
  358. package/src/engine-push-output.ts +71 -0
  359. package/src/ensure-binary.ts +28 -0
  360. package/src/functions-router-gen.ts +224 -0
  361. package/src/index.ts +11 -0
  362. package/src/jwt.ts +14 -0
  363. package/src/kong-config.ts +93 -0
  364. package/src/local-gateway.ts +9 -0
  365. package/src/local-storage.ts +14 -0
  366. package/src/pgbouncer-userlist.ts +15 -0
  367. package/src/postgres-ctl.ts +171 -0
  368. package/src/process-manager.ts +220 -0
  369. package/src/project-config.ts +388 -0
  370. package/src/pull-utils.ts +81 -0
  371. package/src/release-pins.ts +31 -0
  372. package/src/release-public-key.ts +12 -0
  373. package/src/restore-system-relation-targets.ts +45 -0
  374. package/src/runtime-routes.ts +291 -0
  375. package/src/schema-ast-v2.ts +324 -0
  376. package/src/scripts/postinstall.ts +51 -0
  377. package/src/seed.ts +43 -0
  378. package/src/self-host-compose.ts +452 -0
  379. package/src/storage-provision.ts +58 -0
  380. package/src/studio-admin-roles.ts +16 -0
  381. package/src/studio-dev-server.ts +53 -0
  382. package/src/supatype-eval-1781522769253.mts +1 -0
  383. package/src/systemd.ts +137 -0
  384. package/src/tsx-runner.ts +89 -0
  385. package/src/type-extractor.ts +1479 -0
  386. package/src/type-resolver.ts +457 -0
  387. package/tests/app-command.test.ts +54 -0
  388. package/tests/augmentation-generator.test.ts +59 -0
  389. package/tests/binary-cache-cloud-overrides.test.ts +123 -0
  390. package/tests/cached-artifact-format.test.ts +84 -0
  391. package/tests/cli-help.test.ts +133 -0
  392. package/tests/config.test.ts +252 -0
  393. package/tests/dev-ui.test.ts +139 -0
  394. package/tests/docker-postgres.test.ts +39 -0
  395. package/tests/engine-distribution.test.ts +418 -0
  396. package/tests/engine-push-output.test.ts +67 -0
  397. package/tests/ensure-binary.test.ts +59 -0
  398. package/tests/init.test.ts +127 -0
  399. package/tests/keys.test.ts +160 -0
  400. package/tests/migrate-from-v1.test.ts +29 -0
  401. package/tests/normalize-admin-config.test.ts +48 -0
  402. package/tests/pg-spawn-env.test.ts +18 -0
  403. package/tests/postgres-archive-tag.test.ts +9 -0
  404. package/tests/proxy-dev-app.test.ts +33 -0
  405. package/tests/pull-utils.test.ts +150 -0
  406. package/tests/release-pins.test.ts +28 -0
  407. package/tests/runtime-contract.test.ts +370 -0
  408. package/tests/seed-discover.test.ts +31 -0
  409. package/tests/studio-admin-roles.test.ts +27 -0
  410. package/tests/tsconfig.json +9 -0
  411. package/tests/tsx-runner.test.ts +66 -0
  412. package/tests/type-extractor.test.ts +985 -0
  413. package/tests/type-resolver.test.ts +59 -0
  414. package/tsconfig.json +10 -0
  415. package/tsconfig.tsbuildinfo +1 -0
  416. package/vitest.config.ts +12 -0
@@ -0,0 +1,294 @@
1
+ # Type Resolution in the Schema Extractor
2
+
3
+ `type-extractor.ts` converts TypeScript type definitions into `ExtractedSchemaAst` —
4
+ the JSON handed to the engine binary for SQL generation and client type output.
5
+
6
+ This document explains how type names are resolved, what patterns are supported,
7
+ and how the three-tier fallback chain works.
8
+
9
+ ---
10
+
11
+ ## The Problem
12
+
13
+ The extractor uses the TypeScript **parser only** (`ts.createSourceFile`), not the
14
+ full type checker. This is fast and requires no `tsconfig.json`, but it means the
15
+ extractor only sees raw source text — it cannot evaluate what a type alias resolves to.
16
+
17
+ The consequence is that any indirection breaks resolution:
18
+
19
+ ```typescript
20
+ // Works — extractor sees "Optional" literally
21
+ type Post = Model<{ email: Optional<Email> }>
22
+
23
+ // Previously broken — extractor sees "Nullable", not "Optional"
24
+ type Nullable<T> = Optional<T>
25
+ type Post = Model<{ email: Nullable<Email> }>
26
+
27
+ // Previously broken — import rename
28
+ import { Optional as Maybe } from "@supatype/types"
29
+ type Post = Model<{ email: Maybe<Email> }>
30
+ ```
31
+
32
+ Failures were silent — unknown types fell through to `{ kind: "text", pgType: "TEXT" }`
33
+ instead of throwing an error.
34
+
35
+ ---
36
+
37
+ ## Three-Tier Resolution
38
+
39
+ Every type name encountered in a field definition is resolved through three tiers
40
+ in order. The first tier to succeed wins. If all three fail, an error is thrown.
41
+
42
+ ```
43
+ Tier 1 — syntactic switch instant inline primitives and modifiers by name
44
+ Tier 2 — alias registry instant user-defined type aliases, import renames
45
+ Tier 3 — TypeScript checker ~300ms† conditional types, mapped types
46
+ ```
47
+
48
+ † Tier 3 is **lazy** — the `ts.Program` and `TypeChecker` are only created the first
49
+ time a conditional or mapped type is encountered. Schemas that use only tiers 1 and 2
50
+ pay no cost.
51
+
52
+ ---
53
+
54
+ ## Tier 1 — Syntactic Switch
55
+
56
+ The existing behaviour. The extractor walks the type reference chain and matches
57
+ names exactly against a hardcoded switch:
58
+
59
+ ```typescript
60
+ switch (typeName) {
61
+ case "Optional": flags.required = false; unwrap(); continue
62
+ case "Unique": flags.unique = true; unwrap(); continue
63
+ case "PrimaryKey": flags.primaryKey = true; unwrap(); continue
64
+ case "UUID": return { kind: "uuid", pgType: "UUID" }
65
+ case "Email": return { kind: "email", pgType: "TEXT" }
66
+ // ... all @supatype/types primitives and modifiers
67
+ }
68
+ ```
69
+
70
+ This covers all types used inline with their canonical names.
71
+
72
+ ---
73
+
74
+ ## Tier 2 — Alias Registry
75
+
76
+ Built once at startup from all source files loaded by `loadSchemaSourceFiles`.
77
+ Covers two sub-cases:
78
+
79
+ ### 2a — Type alias declarations
80
+
81
+ Any `type X = ...` that is not a `Model<>` declaration is indexed by name:
82
+
83
+ ```typescript
84
+ // These all become entries in the alias registry:
85
+ type Nullable<T> = Optional<T>
86
+ type UniqueSlug = Unique<Slug<"title">>
87
+ type AuditId = PrimaryKey<UUID>
88
+ type MyEnum = "draft" | "published" | "archived"
89
+ ```
90
+
91
+ When the extractor encounters an unknown name, it looks it up in the registry,
92
+ substitutes any type parameters via text replacement, and re-enters tier 1 with
93
+ the resolved node.
94
+
95
+ Multi-hop aliases work because the resolution recurses:
96
+
97
+ ```typescript
98
+ type A = B
99
+ type B = Optional<Email>
100
+ // A → B → Optional<Email> → resolved by tier 1
101
+ ```
102
+
103
+ Cycle detection via a `resolving: Set<string>` guard prevents infinite loops and
104
+ throws a descriptive error instead.
105
+
106
+ ### 2b — Import renames
107
+
108
+ Explicit `as` renames in import statements are indexed per file:
109
+
110
+ ```typescript
111
+ import { Optional as Maybe } from "@supatype/types"
112
+ import { Nullable as MaybeNull } from "./shared/field-types"
113
+ ```
114
+
115
+ Before the tier 1 switch runs, each name is checked against the rename map for
116
+ the current file. `Maybe` becomes `Optional`, `MaybeNull` becomes `Nullable`
117
+ (which is then resolved by 2a).
118
+
119
+ ### File loading
120
+
121
+ `loadSchemaSourceFiles` follows both `export` declarations (existing) and local
122
+ `import` declarations (new), ensuring that files referenced via import are loaded
123
+ into the source file set and their aliases are available in the registry.
124
+
125
+ Only relative specifiers (`.`-prefixed) are followed. Bare specifiers and scoped
126
+ packages (`@supatype/types`, `node_modules/*`) are not loaded — their exported
127
+ names are already covered by the tier 1 switch.
128
+
129
+ ---
130
+
131
+ ## Tier 3 — TypeScript Checker
132
+
133
+ Required for types that cannot be evaluated syntactically:
134
+
135
+ - **Conditional types**: `T extends U ? A : B` — requires evaluating the constraint
136
+ - **Mapped types**: `{ [K in keyof T]: F<T[K]> }` — requires enumerating `keyof T`
137
+
138
+ ### How it works
139
+
140
+ 1. A lazy `ts.Program` is created from the already-loaded source files using a
141
+ custom `CompilerHost` that serves them from memory (no disk re-reads).
142
+
143
+ 2. Because our lightweight parse tree and the Program's parse tree are different
144
+ objects (even for the same file), the node with the unresolvable type is located
145
+ in the Program's source file by matching `pos`/`end` character positions.
146
+
147
+ 3. `checker.getTypeAtLocation(programNode)` resolves the type fully.
148
+
149
+ 4. `checker.typeToString(type, ..., TypeFormatFlags.UseAliasDefinedOutsideCurrentScope)`
150
+ converts it back to a string with **alias names preserved** — so `Optional<Email>`
151
+ stays as `Optional<Email>` rather than expanding to the underlying branded
152
+ intersection type.
153
+
154
+ 5. The string is re-parsed via `ts.createSourceFile` into a proper TypeNode with
155
+ valid `pos`/`end` values (so downstream `getText()` calls work).
156
+
157
+ 6. The resolved TypeNode is fed back into the tier 1 switch.
158
+
159
+ ### When tier 3 fires
160
+
161
+ - A field type is directly a conditional or mapped expression
162
+ - A tier 2 alias body contains a conditional or mapped type (detected by
163
+ `needsChecker()` before text substitution is attempted — the original node,
164
+ which has valid source positions, is passed to the checker instead)
165
+ - The `Model<>` fields argument is a mapped type alias:
166
+ ```typescript
167
+ type AllOptional<T> = { [K in keyof T]: Optional<T[K]> }
168
+ type Post = Model<AllOptional<{ email: Email; name: Text }>>
169
+ ```
170
+ This is handled in `unwrapModelFields`, which also participates in the
171
+ three-tier chain.
172
+
173
+ ---
174
+
175
+ ## What Is Supported
176
+
177
+ ```typescript
178
+ // Tier 1 — inline, canonical names
179
+ email: Optional<Email>
180
+ slug: Unique<Slug<"title">>
181
+ id: PrimaryKey<UUID>
182
+
183
+ // Tier 2a — simple alias
184
+ type Nullable<T> = Optional<T>
185
+ type UniqueSlug = Unique<Slug<"title">>
186
+ email: Nullable<Email>
187
+ slug: UniqueSlug
188
+
189
+ // Tier 2a — multi-hop
190
+ type A = B
191
+ type B = Nullable<Email>
192
+ email: A
193
+
194
+ // Tier 2b — import rename of primitive
195
+ import { Optional as Maybe } from "@supatype/types"
196
+ email: Maybe<Email>
197
+
198
+ // Tier 2b — import rename of local alias
199
+ import { Nullable as MaybeNull } from "./field-types"
200
+ email: MaybeNull<Email>
201
+
202
+ // Tier 2b — cross-file alias (no rename)
203
+ // helpers.ts: export type Nullable<T> = Optional<T>
204
+ import { Nullable } from "./helpers"
205
+ email: Nullable<Email>
206
+
207
+ // Tier 3 — conditional type
208
+ type NullableStr<T> = T extends string ? Optional<T> : T
209
+ email: NullableStr<Email>
210
+
211
+ // Tier 3 — mapped type as fields object
212
+ type AllOptional<T> = { [K in keyof T]: Optional<T[K]> }
213
+ type Post = Model<AllOptional<{ email: Email; name: Text }>>
214
+ ```
215
+
216
+ ---
217
+
218
+ ## What Is Not Supported
219
+
220
+ ```typescript
221
+ // Imports from node_modules other than @supatype/types
222
+ import { SomeHelper } from "some-library"
223
+
224
+ // Conditional / mapped types in alias bodies that reference
225
+ // symbols only available in node_modules (other than @supatype/types)
226
+
227
+ // TypeScript utility types used as field types
228
+ email: NonNullable<string> // error — not a @supatype/types primitive
229
+
230
+ // Namespace-qualified names
231
+ email: Types.Optional<Email> // error — only identifier references are resolved
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Error Behaviour
237
+
238
+ Unknown types now **throw** instead of silently falling back to
239
+ `{ kind: "text", pgType: "TEXT" }`:
240
+
241
+ ```
242
+ Error: Unknown Supatype type "SomeType" in field "email".
243
+ If this is a type alias, confirm the file defining it is reachable
244
+ from your schema entry point.
245
+ ```
246
+
247
+ Cycles in alias chains throw:
248
+
249
+ ```
250
+ Error: Field "email": circular alias chain detected resolving "A".
251
+ ```
252
+
253
+ Unresolvable conditional/mapped types throw:
254
+
255
+ ```
256
+ Error: Field "email": could not resolve conditional/mapped type via type checker.
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Data Structures
262
+
263
+ ```typescript
264
+ // One entry per non-Model type alias declaration across all loaded source files
265
+ type AliasEntry = {
266
+ typeParams: string[] // ["T"] for Nullable<T> = Optional<T>
267
+ body: ts.TypeNode // the RHS of the declaration
268
+ sourceFile: ts.SourceFile // getText() context for body
269
+ }
270
+
271
+ // Rename map: sf.fileName → (localName → canonicalName)
272
+ // Only populated for explicit `import { X as Y }` renames
273
+ type ImportRenameMap = Map<string, Map<string, string>>
274
+
275
+ // Passed to every resolution function; checker is lazy
276
+ type ResolveContext = {
277
+ aliasRegistry: Map<string, AliasEntry>
278
+ renameMap: ImportRenameMap
279
+ getChecker: () => CheckerContext
280
+ }
281
+
282
+ type CheckerContext = {
283
+ program: ts.Program
284
+ checker: ts.TypeChecker
285
+ }
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Adding a New Tier 1 Primitive
291
+
292
+ When a new type is added to `@supatype/types`, add a `case` to the `switch` in
293
+ `parseScalarType`. No other changes are needed — tier 2 and tier 3 handle
294
+ aliases and compositions of it automatically.
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Framework auto-detection and build configuration.
3
+ * Inspects package.json to determine the framework, then resolves
4
+ * build command, output directory, and SPA mode defaults.
5
+ */
6
+
7
+ import { existsSync, readFileSync } from "node:fs"
8
+ import { join, resolve } from "node:path"
9
+ import type { AppConfig, AppFramework } from "../config.js"
10
+
11
+ export interface ResolvedAppConfig {
12
+ framework: AppFramework
13
+ directory: string
14
+ buildCommand: string
15
+ outputDirectory: string
16
+ spa: boolean
17
+ env: Record<string, string>
18
+ headers: Record<string, string>
19
+ }
20
+
21
+ interface FrameworkDefaults {
22
+ buildCommand: string
23
+ outputDirectory: string
24
+ spa: boolean
25
+ }
26
+
27
+ const FRAMEWORK_DEFAULTS: Record<AppFramework, FrameworkDefaults> = {
28
+ nextjs: { buildCommand: "next build", outputDirectory: "out", spa: false },
29
+ astro: { buildCommand: "astro build", outputDirectory: "dist", spa: false },
30
+ vite: { buildCommand: "vite build", outputDirectory: "dist", spa: true },
31
+ "remix-spa": { buildCommand: "remix vite:build", outputDirectory: "build/client", spa: true },
32
+ sveltekit: { buildCommand: "vite build", outputDirectory: "build", spa: false },
33
+ nuxt: { buildCommand: "nuxt generate", outputDirectory: "dist", spa: false },
34
+ static: { buildCommand: "", outputDirectory: ".", spa: false },
35
+ }
36
+
37
+ // Maps package.json dependency names to framework identifiers
38
+ const FRAMEWORK_DETECTION: Array<{ dep: string; framework: AppFramework }> = [
39
+ { dep: "next", framework: "nextjs" },
40
+ { dep: "astro", framework: "astro" },
41
+ { dep: "@remix-run/react", framework: "remix-spa" },
42
+ { dep: "@sveltejs/kit", framework: "sveltekit" },
43
+ { dep: "nuxt", framework: "nuxt" },
44
+ // Vite last — many frameworks use Vite under the hood
45
+ { dep: "vite", framework: "vite" },
46
+ ]
47
+
48
+ /**
49
+ * Detect the framework from package.json dependencies.
50
+ */
51
+ export function detectFramework(appDir: string): AppFramework | undefined {
52
+ const pkgPath = join(appDir, "package.json")
53
+ if (!existsSync(pkgPath)) return undefined
54
+
55
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as {
56
+ dependencies?: Record<string, string>
57
+ devDependencies?: Record<string, string>
58
+ }
59
+
60
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }
61
+
62
+ for (const { dep, framework } of FRAMEWORK_DETECTION) {
63
+ if (dep in allDeps) return framework
64
+ }
65
+
66
+ // Check for plain HTML
67
+ if (existsSync(join(appDir, "index.html"))) return "static"
68
+
69
+ return undefined
70
+ }
71
+
72
+ /**
73
+ * Detect if the project is a monorepo.
74
+ */
75
+ export function detectMonorepo(cwd: string): { isMonorepo: boolean; tool?: string } {
76
+ if (existsSync(join(cwd, "turbo.json"))) return { isMonorepo: true, tool: "turbo" }
77
+ if (existsSync(join(cwd, "pnpm-workspace.yaml"))) return { isMonorepo: true, tool: "pnpm" }
78
+ if (existsSync(join(cwd, "nx.json"))) return { isMonorepo: true, tool: "nx" }
79
+ return { isMonorepo: false }
80
+ }
81
+
82
+ /**
83
+ * Detect package manager from lockfiles.
84
+ */
85
+ export function detectPackageManager(dir: string): "npm" | "pnpm" | "yarn" {
86
+ if (existsSync(join(dir, "pnpm-lock.yaml"))) return "pnpm"
87
+ if (existsSync(join(dir, "yarn.lock"))) return "yarn"
88
+ return "npm"
89
+ }
90
+
91
+ /**
92
+ * Resolve the full app configuration from user config + auto-detection.
93
+ */
94
+ export function resolveAppConfig(
95
+ appConfig: AppConfig | undefined,
96
+ cwd: string,
97
+ ): ResolvedAppConfig {
98
+ const directory = resolve(cwd, appConfig?.directory || ".")
99
+
100
+ // Framework detection
101
+ let framework = appConfig?.framework
102
+ if (!framework) {
103
+ framework = detectFramework(directory)
104
+ if (!framework) {
105
+ throw new Error(
106
+ "Could not detect frontend framework.\n" +
107
+ "Set app.framework in supatype.config.ts, or ensure package.json is present.",
108
+ )
109
+ }
110
+ }
111
+
112
+ const defaults = FRAMEWORK_DEFAULTS[framework]
113
+
114
+ // Build command
115
+ let buildCommand = appConfig?.buildCommand || defaults.buildCommand
116
+ const mono = detectMonorepo(cwd)
117
+ if (mono.isMonorepo && mono.tool === "turbo" && !appConfig?.buildCommand) {
118
+ // In a Turborepo, run build via turbo from workspace root
119
+ const appDirRelative = appConfig?.directory || "."
120
+ if (appDirRelative !== ".") {
121
+ const pkgName = getPackageName(directory)
122
+ if (pkgName) {
123
+ buildCommand = `turbo run build --filter=${pkgName}`
124
+ }
125
+ }
126
+ }
127
+
128
+ return {
129
+ framework,
130
+ directory,
131
+ buildCommand,
132
+ outputDirectory: resolve(directory, appConfig?.outputDirectory || defaults.outputDirectory),
133
+ spa: appConfig?.spa ?? defaults.spa,
134
+ env: appConfig?.env ?? {},
135
+ headers: appConfig?.headers ?? {},
136
+ }
137
+ }
138
+
139
+ function getPackageName(dir: string): string | undefined {
140
+ const pkgPath = join(dir, "package.json")
141
+ if (!existsSync(pkgPath)) return undefined
142
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as { name?: string }
143
+ return pkg.name
144
+ }
145
+
146
+ /**
147
+ * Validate that the framework is configured for static output.
148
+ * Returns an error message if SSR mode is detected.
149
+ */
150
+ export function validateStaticMode(framework: AppFramework, appDir: string): string | null {
151
+ if (framework === "nextjs") {
152
+ // Check for output: 'export' in next.config.js/mjs/ts
153
+ for (const name of ["next.config.js", "next.config.mjs", "next.config.ts"]) {
154
+ const configPath = join(appDir, name)
155
+ if (existsSync(configPath)) {
156
+ const content = readFileSync(configPath, "utf8")
157
+ if (!content.includes("export")) {
158
+ return (
159
+ "Supatype currently supports Next.js static export only.\n" +
160
+ "Add `output: 'export'` to your next.config.js,\n" +
161
+ "or deploy your frontend to Vercel for SSR support."
162
+ )
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ if (framework === "astro") {
169
+ const configPath = join(appDir, "astro.config.mjs")
170
+ if (existsSync(configPath)) {
171
+ const content = readFileSync(configPath, "utf8")
172
+ if (content.includes("output: 'server'") || content.includes("output: \"server\"")) {
173
+ return (
174
+ "Supatype currently supports Astro static sites only.\n" +
175
+ "Remove `output: 'server'` from astro.config.mjs,\n" +
176
+ "or deploy your frontend separately for SSR support."
177
+ )
178
+ }
179
+ }
180
+ }
181
+
182
+ if (framework === "sveltekit") {
183
+ const pkgPath = join(appDir, "package.json")
184
+ if (existsSync(pkgPath)) {
185
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as {
186
+ devDependencies?: Record<string, string>
187
+ }
188
+ if (!pkg.devDependencies?.["@sveltejs/adapter-static"]) {
189
+ return (
190
+ "Supatype requires @sveltejs/adapter-static for SvelteKit.\n" +
191
+ "Install it: npm install -D @sveltejs/adapter-static"
192
+ )
193
+ }
194
+ }
195
+ }
196
+
197
+ return null
198
+ }
199
+
200
+ /**
201
+ * Validate the build output.
202
+ */
203
+ export function validateBuildOutput(outputDir: string, maxSizeMb: number): string | null {
204
+ if (!existsSync(outputDir)) {
205
+ return `Build output directory not found: ${outputDir}`
206
+ }
207
+
208
+ // Check for at least one HTML file
209
+ const hasHtml = findHtmlFile(outputDir)
210
+ if (!hasHtml) {
211
+ return `No HTML files found in build output: ${outputDir}`
212
+ }
213
+
214
+ // Check total size
215
+ const sizeMb = getDirSizeMb(outputDir)
216
+ if (sizeMb > maxSizeMb) {
217
+ return `Build output ${sizeMb.toFixed(1)}MB exceeds limit of ${maxSizeMb}MB`
218
+ }
219
+
220
+ if (sizeMb > 500) {
221
+ console.warn(
222
+ `Warning: Build output is ${sizeMb.toFixed(1)}MB. This may include unoptimised assets or node_modules.`,
223
+ )
224
+ }
225
+
226
+ return null
227
+ }
228
+
229
+ function findHtmlFile(dir: string): boolean {
230
+ const { readdirSync, statSync } = require("node:fs") as typeof import("node:fs")
231
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
232
+ if (entry.isFile() && entry.name.endsWith(".html")) return true
233
+ if (entry.isDirectory()) {
234
+ if (findHtmlFile(join(dir, entry.name))) return true
235
+ }
236
+ }
237
+ return false
238
+ }
239
+
240
+ function getDirSizeMb(dir: string): number {
241
+ const { readdirSync, statSync } = require("node:fs") as typeof import("node:fs")
242
+ let size = 0
243
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
244
+ const path = join(dir, entry.name)
245
+ if (entry.isFile()) size += statSync(path).size
246
+ else if (entry.isDirectory()) size += getDirSizeMb(path) * 1024 * 1024
247
+ }
248
+ return size / (1024 * 1024)
249
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Spawn the frontend dev server during `supatype dev` when app.mode is proxy.
3
+ */
4
+
5
+ import { existsSync, readFileSync } from "node:fs"
6
+ import { join } from "node:path"
7
+ import { detectPackageManager } from "./framework.js"
8
+ import { appendDevTaskLog } from "../dev-session.js"
9
+ import { ProcessManager } from "../process-manager.js"
10
+ import { projectRootFromConfig, type SupatypeProjectConfig } from "../project-config.js"
11
+
12
+ const DEFAULT_PROXY_DEV_SCRIPT = "start"
13
+
14
+ /** package.json script name to run (only when app.mode is proxy). */
15
+ export function resolveProxyDevScript(config: SupatypeProjectConfig): string | null {
16
+ if (config.app?.mode !== "proxy") return null
17
+ const script = config.app.start?.trim()
18
+ return script && script.length > 0 ? script : DEFAULT_PROXY_DEV_SCRIPT
19
+ }
20
+
21
+ /**
22
+ * Start the configured package.json script for proxy dev.
23
+ * Returns null when not in proxy mode or when the script is missing.
24
+ */
25
+ export function startProxyDevApp(
26
+ cwd: string,
27
+ config: SupatypeProjectConfig,
28
+ pidDir: string,
29
+ ): ProcessManager | null {
30
+ const script = resolveProxyDevScript(config)
31
+ if (!script) return null
32
+
33
+ const appDir = projectRootFromConfig(config, cwd)
34
+ const pkgPath = join(appDir, "package.json")
35
+ if (!existsSync(pkgPath)) {
36
+ console.warn(`[supatype] app.mode=proxy but no package.json at ${appDir}; skipping dev app`)
37
+ return null
38
+ }
39
+
40
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as {
41
+ scripts?: Record<string, string>
42
+ }
43
+ if (!pkg.scripts?.[script]) {
44
+ console.warn(
45
+ `[supatype] app.mode=proxy: package.json has no "${script}" script.\n` +
46
+ ` Add "scripts.${script}" or set app.start in supatype.config.ts`,
47
+ )
48
+ return null
49
+ }
50
+
51
+ const pm = detectPackageManager(appDir)
52
+ const bin = pm
53
+ const args = pm === "yarn" ? [script] : ["run", script]
54
+ // pnpm/npm/yarn are .cmd shims on Windows — spawn via shell so PATH resolution works.
55
+ const useShell = process.platform === "win32"
56
+
57
+ appendDevTaskLog("app", "app", `Proxy mode: running ${bin} ${args.join(" ")} (${appDir})`)
58
+
59
+ const manager = new ProcessManager(bin, args, {
60
+ label: "app",
61
+ pidDir,
62
+ cwd: appDir,
63
+ colour: "\x1b[33m",
64
+ shell: useShell,
65
+ })
66
+ manager.start()
67
+ return manager
68
+ }