@xano/sdk 1.0.5 → 1.0.7

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 (277) hide show
  1. package/CHANGELOG.md +35 -5
  2. package/README.md +56 -20
  3. package/dist/.build-fingerprint +1 -1
  4. package/dist/{agent-file-refresh-KVLR7M5Y.js → agent-file-refresh-DGGSRPJ4.js} +15 -14
  5. package/dist/agent-skill-command-37DFYS7Q.js +414 -0
  6. package/dist/{answer-shape-XGR2DGWY.js → answer-shape-RBFDCNZ7.js} +5 -5
  7. package/dist/{backend-dir-IE4RMUFH.js → backend-dir-KDD43X7K.js} +16 -15
  8. package/dist/{backend-slot-6HBWG5FN.js → backend-slot-TBOVZXDE.js} +4 -4
  9. package/dist/bin.js +63 -61
  10. package/dist/{branch-T2APKPVG.js → branch-7PIKNUD7.js} +12 -11
  11. package/dist/{branch-commands-HXXTCSOO.js → branch-commands-EGY7ZEZE.js} +32 -32
  12. package/dist/bundle.js +9 -39
  13. package/dist/{capture-HBXFXZEW.js → capture-GW5KNKMB.js} +3 -3
  14. package/dist/{chunk-3BJYQGAZ.js → chunk-26LHXLD3.js} +2 -2
  15. package/dist/{chunk-N6BWB35H.js → chunk-2ACWDSAQ.js} +3 -3
  16. package/dist/{chunk-XIABDKFQ.js → chunk-2SD4LA22.js} +2 -2
  17. package/dist/{chunk-K6PRKPFX.js → chunk-2XWVZRL6.js} +7 -7
  18. package/dist/{chunk-ES5A66IH.js → chunk-2YER2J47.js} +13 -13
  19. package/dist/{chunk-G57RYMKB.js → chunk-3FRGNBOC.js} +2 -2
  20. package/dist/{chunk-BMCZQZMI.js → chunk-46PATL23.js} +13 -9
  21. package/dist/{chunk-MYLPOVX6.js → chunk-47XT6WQL.js} +8 -8
  22. package/dist/{chunk-AWQ7BQTQ.js → chunk-4GPIOIAC.js} +6 -1
  23. package/dist/{chunk-7GX445AE.js → chunk-4XHAT7C5.js} +2 -2
  24. package/dist/{chunk-QOLOQ35F.js → chunk-567KK6XF.js} +8 -8
  25. package/dist/{chunk-57HMNJGB.js → chunk-5GIOCDUM.js} +893 -922
  26. package/dist/{chunk-OKNE3TWU.js → chunk-5KJBWIDZ.js} +83 -5
  27. package/dist/{chunk-SRX6B544.js → chunk-5QMJOE2K.js} +5 -5
  28. package/dist/{chunk-AGD7F7YI.js → chunk-5SCPRXFB.js} +4 -4
  29. package/dist/{chunk-SNGFEESM.js → chunk-5ZG7V2VW.js} +3 -3
  30. package/dist/{chunk-XJU6UAFV.js → chunk-7FIMUFBP.js} +2 -2
  31. package/dist/{chunk-AESE434J.js → chunk-7M6JP3FS.js} +2 -2
  32. package/dist/{chunk-K6CB5TKM.js → chunk-7REDHC4N.js} +2 -2
  33. package/dist/chunk-7VR4IO5B.js +44 -0
  34. package/dist/{chunk-57B56I4B.js → chunk-7XXWKTCE.js} +65 -41
  35. package/dist/{chunk-PL7AIAWS.js → chunk-A4R5CAY4.js} +4 -111
  36. package/dist/{chunk-QZTJ2556.js → chunk-AKERAUNH.js} +4 -4
  37. package/dist/{chunk-JZWUAEMO.js → chunk-ARWMVNDJ.js} +6 -3
  38. package/dist/{chunk-WYS6XVZ3.js → chunk-AVS4WPPY.js} +2 -2
  39. package/dist/{chunk-KUU7T4ZE.js → chunk-B2URJBC4.js} +18 -18
  40. package/dist/chunk-B3P25SDP.js +78 -0
  41. package/dist/chunk-BRANWM4U.js +853 -0
  42. package/dist/{chunk-BBPAXOU6.js → chunk-BSVQEKHO.js} +6 -6
  43. package/dist/{chunk-3WHWOKU4.js → chunk-BZ6WTG3E.js} +4 -4
  44. package/dist/{chunk-XNZURZ7T.js → chunk-CH23ONYG.js} +77 -6
  45. package/dist/{chunk-SQPIECXD.js → chunk-CJDPSCMX.js} +45 -5
  46. package/dist/{chunk-M7GJ6YUF.js → chunk-CNZASQPL.js} +16 -2
  47. package/dist/{chunk-44CWK6YC.js → chunk-CPN6WSBH.js} +4 -4
  48. package/dist/{chunk-L3BDO2BI.js → chunk-CT3J5JRZ.js} +7 -7
  49. package/dist/{chunk-3HOGFGKG.js → chunk-D3KEPRRN.js} +2 -2
  50. package/dist/{chunk-OGUMHW2X.js → chunk-D5OZRJ3T.js} +7 -7
  51. package/dist/{chunk-S5KQIFKJ.js → chunk-DG3APBUJ.js} +208 -112
  52. package/dist/chunk-DIWF7L33.js +995 -0
  53. package/dist/{chunk-WRBKLYSJ.js → chunk-DNBP4GJN.js} +4 -3
  54. package/dist/{chunk-LZDA6SVD.js → chunk-DXZTL7NA.js} +141 -91
  55. package/dist/{chunk-XMDDBEEM.js → chunk-E763QI3G.js} +2 -2
  56. package/dist/{chunk-3VX7VAQT.js → chunk-EF4MHLEW.js} +26 -9
  57. package/dist/{chunk-AGSCOISO.js → chunk-ELPQTDW6.js} +108 -100
  58. package/dist/{chunk-Q22BMRPF.js → chunk-EPFDY5JU.js} +2 -2
  59. package/dist/{chunk-7DBM6XHR.js → chunk-EU32BC5B.js} +8 -8
  60. package/dist/{chunk-Y76ERHLK.js → chunk-FDTET7FZ.js} +6 -6
  61. package/dist/{chunk-Z3SNX45M.js → chunk-FENA7K7C.js} +3 -3
  62. package/dist/{chunk-WOGJB2F6.js → chunk-FNLTFOUD.js} +4 -9
  63. package/dist/{chunk-FV55SRQU.js → chunk-FQ53GTII.js} +9 -9
  64. package/dist/{chunk-DEVGLLNZ.js → chunk-GHMLRFRX.js} +8 -8
  65. package/dist/{chunk-GMVW6ZZK.js → chunk-H2K4GFUS.js} +4 -4
  66. package/dist/{chunk-NUU76247.js → chunk-HTQWAQRW.js} +3 -3
  67. package/dist/{chunk-ROY4YAEQ.js → chunk-HU7F56VF.js} +22 -2
  68. package/dist/{chunk-RXCT3OCU.js → chunk-HZ6ADG3O.js} +47 -8
  69. package/dist/{chunk-Z2BRSQ6M.js → chunk-I6XRUU6U.js} +91 -64
  70. package/dist/chunk-IPNN2KRW.js +257 -0
  71. package/dist/{chunk-SF2B7MZK.js → chunk-IYXL5NYU.js} +259 -31
  72. package/dist/chunk-JI3BLXWQ.js +107 -0
  73. package/dist/{chunk-4DJTQ6W4.js → chunk-JIKGT7DO.js} +2 -1
  74. package/dist/{chunk-OVV2HXJ6.js → chunk-JOOKM7AH.js} +2 -2
  75. package/dist/{chunk-65SW2BA5.js → chunk-JOWY6HFL.js} +3 -3
  76. package/dist/{chunk-I5VEROXW.js → chunk-JX6N73H3.js} +2 -2
  77. package/dist/{chunk-5D6DGF3W.js → chunk-L472YIGG.js} +8 -8
  78. package/dist/{chunk-HLQH3AXB.js → chunk-L6HZ67P6.js} +2 -2
  79. package/dist/{chunk-TM5LRSBB.js → chunk-LBJA7IEM.js} +370 -45
  80. package/dist/chunk-LCOCRJ4K.js +116 -0
  81. package/dist/{chunk-DGWHAVRG.js → chunk-LJM5CIY4.js} +16 -1
  82. package/dist/{chunk-5RLAF6RL.js → chunk-M2C54ZBC.js} +4 -4
  83. package/dist/{chunk-U6DR6464.js → chunk-M3NEK3LT.js} +4 -4
  84. package/dist/{chunk-5XVBT6CQ.js → chunk-MBL7CXJ7.js} +2 -2
  85. package/dist/{chunk-5YBNXNKU.js → chunk-MFWF2NZJ.js} +12 -5
  86. package/dist/{chunk-TEBS7FE6.js → chunk-MYZRMSPM.js} +2 -2
  87. package/dist/{chunk-YSLMMR2U.js → chunk-N3YFCFCO.js} +14 -14
  88. package/dist/{chunk-OJPZEUPH.js → chunk-NDJAKSE7.js} +11 -8
  89. package/dist/{chunk-PIPIA7K7.js → chunk-NV37YGOV.js} +7 -7
  90. package/dist/{chunk-ZHGWR45B.js → chunk-O56DQKPL.js} +9 -9
  91. package/dist/{chunk-4QBGE3EO.js → chunk-ORGNLQN6.js} +6 -6
  92. package/dist/{chunk-NNB7VUCH.js → chunk-PEIBGH2V.js} +55 -31
  93. package/dist/{chunk-UJ6ZZJDD.js → chunk-PEX4QZVI.js} +2 -2
  94. package/dist/{chunk-LLS2WO2K.js → chunk-PV25BDCH.js} +5 -5
  95. package/dist/{chunk-F3557PVM.js → chunk-PY722CHR.js} +2 -2
  96. package/dist/{chunk-4GDEEY2U.js → chunk-QGIZLFAS.js} +4 -4
  97. package/dist/{chunk-YI76TURL.js → chunk-QRQ54LUI.js} +16 -14
  98. package/dist/{chunk-JQOX6HW4.js → chunk-RBU2YX22.js} +3 -3
  99. package/dist/{chunk-4NEBBKOP.js → chunk-RRMH7WMY.js} +7 -7
  100. package/dist/{chunk-HOOOOJJP.js → chunk-S46ODQRA.js} +2 -2
  101. package/dist/{chunk-37FBPMNE.js → chunk-S56YBYMN.js} +5 -2
  102. package/dist/{chunk-4QFBEKXI.js → chunk-SDGV76HF.js} +2 -2
  103. package/dist/{chunk-CV54PASI.js → chunk-SGK3PTTM.js} +312 -132
  104. package/dist/{chunk-S5TEJIGP.js → chunk-SKEG3V2V.js} +2 -2
  105. package/dist/{chunk-VZ22VUAS.js → chunk-SLGJIWCY.js} +3 -3
  106. package/dist/{chunk-JSEVKRVJ.js → chunk-T4LJ5UR2.js} +29 -7
  107. package/dist/{chunk-JXKO6JT7.js → chunk-TWVUYS63.js} +24 -24
  108. package/dist/{chunk-UIEFE6FU.js → chunk-U5M7T6CI.js} +7 -7
  109. package/dist/{chunk-Z4VN347O.js → chunk-UYFUIHH3.js} +2 -2
  110. package/dist/{chunk-Y6NO3DLQ.js → chunk-V7MBRUK6.js} +3 -3
  111. package/dist/chunk-VAGSKUWC.js +67 -0
  112. package/dist/{chunk-A4NNCI4O.js → chunk-VIJ5D3RC.js} +3 -3
  113. package/dist/{chunk-3IYVHVM6.js → chunk-VJFMUJWZ.js} +4 -4
  114. package/dist/{chunk-V4IBHDIY.js → chunk-VNDR2T35.js} +7 -7
  115. package/dist/chunk-WAVNUTMT.js +9 -0
  116. package/dist/{chunk-KQLACS4Q.js → chunk-WNCW2RNB.js} +4 -4
  117. package/dist/chunk-WUEPP5HD.js +111 -0
  118. package/dist/{chunk-IV446ZLJ.js → chunk-Y453TW6J.js} +2 -2
  119. package/dist/{local-engine-command-73NHWD6V.js → chunk-YCUDOF6Q.js} +22 -76
  120. package/dist/{chunk-CJ76PSJT.js → chunk-YH2JVJAO.js} +12 -12
  121. package/dist/{chunk-GPI3OWRE.js → chunk-YHB34BN6.js} +2 -1
  122. package/dist/{chunk-AMBEITWL.js → chunk-ZGLNHA7T.js} +7 -7
  123. package/dist/{chunk-NGAODDLX.js → chunk-ZJOAWRED.js} +8 -8
  124. package/dist/{chunk-TUEFTRC2.js → chunk-ZXRDD3Q2.js} +50 -27
  125. package/dist/cli.d.ts +40 -11
  126. package/dist/cli.js +60 -56
  127. package/dist/{codegen-command-L2OO6OTE.js → codegen-command-T7TC7PQO.js} +79 -72
  128. package/dist/codegen.d.ts +2 -2
  129. package/dist/codegen.js +2 -2
  130. package/dist/{commands-2E4JB3DB.js → commands-JDENTDJS.js} +3 -3
  131. package/dist/{completion-LPJIH5VQ.js → completion-YFD5OVJW.js} +9 -5
  132. package/dist/{config-QDCRKEWD.js → config-YJFUTRJW.js} +8 -8
  133. package/dist/{deploy-command-HJZNYCUY.js → deploy-command-OEVEE6UG.js} +65 -63
  134. package/dist/deploy-source-HYVZEYXV.js +83 -0
  135. package/dist/{dev-env-sync-GZ4QQJGV.js → dev-env-sync-EFDCJ6KU.js} +63 -61
  136. package/dist/{diagnostics-LSMGB4TY.js → diagnostics-OMN5Y2AH.js} +2 -2
  137. package/dist/{display-name-hint-AHCNH6TF.js → display-name-hint-SW3GB3V7.js} +14 -13
  138. package/dist/{emit-DqG6qddr.d.ts → emit-Dov_92kn.d.ts} +66 -20
  139. package/dist/env-example-refresh-WNSOH534.js +134 -0
  140. package/dist/{env-pull-command-Z4RLVEGJ.js → env-pull-command-UYEXMQ3P.js} +53 -52
  141. package/dist/{env-target-ZHQUS5BO.js → env-target-JBSLBKNX.js} +15 -14
  142. package/dist/{env-var-command-FKQ4VVQ6.js → env-var-command-BJNRAXNV.js} +51 -49
  143. package/dist/{ephemeral-L4KUOGEU.js → ephemeral-CEOGMIEA.js} +11 -10
  144. package/dist/{ephemeral-command-GRPFI3TD.js → ephemeral-command-IPSGBCS5.js} +70 -69
  145. package/dist/{ephemeral-state-VLYU2BXR.js → ephemeral-state-MTBASPRS.js} +13 -12
  146. package/dist/{generate-command-XNODJFDQ.js → generate-command-XQXODBS6.js} +96 -86
  147. package/dist/{gitignore-VWRSZX5F.js → gitignore-RUVCIZO4.js} +21 -20
  148. package/dist/{guards-OPSGB6LG.js → guards-KYEOCVHN.js} +6 -6
  149. package/dist/{impersonate-command-AEKIZHHK.js → impersonate-command-MA27O7S5.js} +46 -44
  150. package/dist/{import-PHSSFFLA.js → import-XKRFHABE.js} +5 -5
  151. package/dist/index.d.ts +14 -20
  152. package/dist/index.js +13 -13
  153. package/dist/init-command-6RDTCMAB.js +143 -0
  154. package/dist/{init-modules-SGSX7XEY.js → init-modules-DHTBOCQT.js} +10 -9
  155. package/dist/{init-web-6HX3YLQP.js → init-web-ELBXSXDL.js} +3 -3
  156. package/dist/internal.d.ts +5 -5
  157. package/dist/internal.js +47 -20
  158. package/dist/{io-TAF4WXYQ.js → io-PGTCBSIQ.js} +6 -4
  159. package/dist/{keep-data-merge-GUGF7MVZ.js → keep-data-merge-TDJOIAVT.js} +33 -34
  160. package/dist/{lambda-config-reconcile-65U6I4KU.js → lambda-config-reconcile-47X5C2E4.js} +6 -5
  161. package/dist/{landed-QA6PRTV2.js → landed-F7PCHGCK.js} +3 -3
  162. package/dist/{landing-record-FCAWLCZU.js → landing-record-TPPYFQAS.js} +26 -25
  163. package/dist/{live-diff-IM4W3ELT.js → live-diff-5E2BQWQ7.js} +9 -8
  164. package/dist/local-engine-choice-S6VHPJRU.js +81 -0
  165. package/dist/local-engine-command-4EZCGZ6M.js +85 -0
  166. package/dist/{local-engine-config-W3KB7RWM.js → local-engine-config-2EBL3QKA.js} +3 -2
  167. package/dist/{local-engine-deploy-Y4OAWL7K.js → local-engine-deploy-FOPNWU7X.js} +18 -16
  168. package/dist/local-engine-lookup-GM3E3NPP.js +43 -0
  169. package/dist/local-engine-mcp-bridge-QKZHUGW3.js +423 -0
  170. package/dist/local-engine-mcp-command-BFQVLXZC.js +181 -0
  171. package/dist/{local-engine-process-6YPJHKYM.js → local-engine-process-XUQPQENQ.js} +12 -9
  172. package/dist/{local-engine-state-OCW5YDD7.js → local-engine-state-JQPKGB65.js} +4 -3
  173. package/dist/{local-engine-update-check-X7TZGRFL.js → local-engine-update-check-S7UF6ZF5.js} +7 -6
  174. package/dist/{lock-WXXC3QHL.js → lock-HDCHD2ON.js} +4 -2
  175. package/dist/{lock-commands-PKDBNRSD.js → lock-commands-HJ6Y5QVS.js} +66 -64
  176. package/dist/{login-command-V4U4FA5G.js → login-command-JO55NZAS.js} +34 -33
  177. package/dist/{logout-command-TV3P545Z.js → logout-command-MPRIRSJA.js} +18 -17
  178. package/dist/{loop-VKHGQ6MP.js → loop-SUB6C2LK.js} +8 -9
  179. package/dist/{marketplace-command-LEFOAEAV.js → marketplace-command-BM6G257N.js} +90 -54
  180. package/dist/{marketplace-resolve-ME7O7JBJ.js → marketplace-resolve-AWH3RG57.js} +7 -6
  181. package/dist/{meta-client-TEEECA5W.js → meta-client-AOSWODQQ.js} +16 -15
  182. package/dist/{module-manifest-7YLGIRCY.js → module-manifest-GXI46PEF.js} +7 -4
  183. package/dist/node.d.ts +5 -5
  184. package/dist/node.js +68 -67
  185. package/dist/operation-outcome-4UKPXTNC.js +53 -0
  186. package/dist/{output-target-5FWX3NGZ.js → output-target-RAZ4KN5J.js} +22 -21
  187. package/dist/{package-manager-PRAHUSCN.js → package-manager-K762W7XT.js} +2 -2
  188. package/dist/{plan-disclosure-QGL5UYQR.js → plan-disclosure-JR52DWXN.js} +21 -21
  189. package/dist/{plugin-contributions-GNFTWDEB.js → plugin-contributions-E6XHLQWK.js} +6 -6
  190. package/dist/{plugin-prompt-VEQGMZ4T.js → plugin-prompt-IODX5EU6.js} +5 -5
  191. package/dist/{plugin-questions-BGRL23GO.js → plugin-questions-AAAJ7POP.js} +4 -4
  192. package/dist/plugin.d.ts +254 -10
  193. package/dist/{preflight-command-VKJKXRRI.js → preflight-command-7GKJBWOQ.js} +71 -70
  194. package/dist/{profile-command-P7A3BH26.js → profile-command-CM6J7E2M.js} +35 -34
  195. package/dist/{profile-pointer-HG7IXE4I.js → profile-pointer-KTYXL6FU.js} +5 -4
  196. package/dist/{project-dependency-Z4CKOCJI.js → project-dependency-OQ5575QQ.js} +11 -8
  197. package/dist/{project-sdk-JWZWGXXR.js → project-sdk-2ESHHZVL.js} +4 -4
  198. package/dist/promote-command-BDRPG6UU.js +147 -0
  199. package/dist/{prompt-SURZOUUW.js → prompt-MQPGU4ZI.js} +4 -4
  200. package/dist/{publish-command-HGAB3H4A.js → publish-command-IEMYZ7LF.js} +69 -67
  201. package/dist/pull-command-S5E2ABZ4.js +169 -0
  202. package/dist/{pull-superseded-TOT5S4QU.js → pull-superseded-E34BZVLH.js} +4 -4
  203. package/dist/{raw-where-EoWl5fqY.d.ts → raw-where-ZMLND6AG.d.ts} +20 -3
  204. package/dist/release-command-7F5TBKO2.js +151 -0
  205. package/dist/{release-ns-command-WOQE2BDQ.js → release-ns-command-EK2ZQ4CC.js} +101 -100
  206. package/dist/{retry-command-JRGMZZAC.js → retry-command-GL5HCMVB.js} +10 -9
  207. package/dist/{routes-manifest-URFMAWJE.js → routes-manifest-YR4ZIMLM.js} +15 -7
  208. package/dist/routes-manifest-file-LCIKPDAG.js +41 -0
  209. package/dist/scaffold.js +4 -4
  210. package/dist/secrets-IV4N5HYI.js +20 -0
  211. package/dist/{secrets-file-YWZWVJ52.js → secrets-file-LXREYU3M.js} +21 -20
  212. package/dist/{secrets-fill-command-HIHK3VH2.js → secrets-fill-command-QHZS3KWM.js} +64 -62
  213. package/dist/{seed-24DTEY5S.js → seed-FRKMDN2Z.js} +9 -9
  214. package/dist/{source-resolve-OWD3MIEO.js → source-resolve-BBHYTOXI.js} +26 -24
  215. package/dist/{static-host-UIR2OLPQ.js → static-host-7LC7OZR4.js} +5 -5
  216. package/dist/{status-command-JKTHH5QE.js → status-command-TY253MJT.js} +54 -52
  217. package/dist/{store-zxw2go0f.d.ts → store-Boba9OOh.d.ts} +2 -2
  218. package/dist/{store-5YAQS6KU.js → store-VJ3OS6VO.js} +8 -7
  219. package/dist/sync-baseline-DOV5AGIO.js +36 -0
  220. package/dist/{sync-contributions-RBB6JVOL.js → sync-contributions-63542VE4.js} +20 -12
  221. package/dist/sync-record-RGHK7EAL.js +43 -0
  222. package/dist/{table-MQFVYA4K.js → table-OAYGFGEN.js} +8 -8
  223. package/dist/{tables-command-5Q4BSUNO.js → tables-command-PZIVDAH3.js} +45 -43
  224. package/dist/{tenant-Q3LPVSSM.js → tenant-Y3II4VY3.js} +12 -11
  225. package/dist/{tenant-command-BFVU2PEX.js → tenant-command-G6XON7CF.js} +113 -107
  226. package/dist/{test-command-F4VUU4QR.js → test-command-3FZOX7O3.js} +44 -42
  227. package/dist/{tests-5ZSDFVIJ.js → tests-KF6N6BZ7.js} +6 -6
  228. package/dist/{token-TERSTNU4.js → token-DJJUW5HY.js} +14 -13
  229. package/dist/toolchain-hooks-7PWCFLSU.js +46 -0
  230. package/dist/{toolchain-modules-FD5ANV2U.js → toolchain-modules-OTNSKK52.js} +8 -5
  231. package/dist/toolchain-peers-KQ7TQ2AR.js +28 -0
  232. package/dist/tracked-backend-AJCGTO5Y.js +82 -0
  233. package/dist/{update-check-O4C2LCZH.js → update-check-4E5L6GAW.js} +61 -59
  234. package/dist/{upgrade-command-NVFWLMTA.js → upgrade-command-BXMSQN4C.js} +68 -64
  235. package/dist/{whoami-command-YKNTISIV.js → whoami-command-NLCCIEUM.js} +17 -16
  236. package/dist/{workspace-GGVGE2S5.js → workspace-PNMJOXE4.js} +5 -5
  237. package/dist/{workspace-binding-OS4ZOX4S.js → workspace-binding-J5GWDFRI.js} +16 -15
  238. package/dist/{workspace-command-GTUNVN7K.js → workspace-command-MHIIY352.js} +125 -93
  239. package/dist/{workspace-env-467C5KHM.js → workspace-env-LLRWCHSA.js} +17 -16
  240. package/dist/{workspace-export-3XTVGQVM.js → workspace-export-BIKAYHWJ.js} +5 -5
  241. package/dist/{writable-7SSWUQJ3.js → writable-UOTO4WWC.js} +4 -4
  242. package/dist/{xano-6RS5XQZE.js → xano-LCI7VWPS.js} +8 -8
  243. package/dist/{xanosdk-import-E3WSIYUE.js → xanosdk-import-S7A3CVBN.js} +8 -8
  244. package/dist/{xanosdk-project-KH5TZ2KI.js → xanosdk-project-J4VCFRHP.js} +18 -17
  245. package/guides/README.md +2 -2
  246. package/guides/cli.md +73 -4
  247. package/guides/codegen.md +23 -5
  248. package/guides/codes.md +8 -2
  249. package/guides/coverage.md +5 -0
  250. package/guides/deploying.md +80 -0
  251. package/guides/marketplace.md +21 -0
  252. package/guides/module-contract.md +80 -4
  253. package/guides/scaffold.md +61 -10
  254. package/guides/typed-frontend.md +37 -0
  255. package/llms/client.md +11 -1
  256. package/llms/filters.md +4 -0
  257. package/llms/kinds-core.md +1 -1
  258. package/llms/statements-data.md +3 -2
  259. package/llms/toolchain.md +12 -0
  260. package/llms-full.txt +34 -7
  261. package/llms.txt +3 -3
  262. package/manifest.json +63 -5
  263. package/package.json +5 -2
  264. package/skills/xano-backend/SKILL.md +119 -0
  265. package/dist/chunk-F6IKWAIU.js +0 -664
  266. package/dist/chunk-M6ZFSTIZ.js +0 -630
  267. package/dist/chunk-MEIJDRHU.js +0 -243
  268. package/dist/deploy-source-5COWTBOC.js +0 -81
  269. package/dist/env-example-refresh-DWQIOQYR.js +0 -127
  270. package/dist/init-command-TI3HCKXZ.js +0 -126
  271. package/dist/local-engine-choice-FPJAZSSD.js +0 -79
  272. package/dist/operation-outcome-GNDD35WL.js +0 -51
  273. package/dist/promote-command-KHTIK44I.js +0 -141
  274. package/dist/pull-command-EUEWBRXZ.js +0 -162
  275. package/dist/release-command-WOVQAMUY.js +0 -147
  276. package/dist/toolchain-hooks-QVUZ6HZ4.js +0 -96
  277. package/dist/tracked-backend-B4HTME4S.js +0 -80
@@ -1,13 +1,11 @@
1
1
  import {
2
- decodeMarkerWith,
3
- iconLibraryOf,
4
- reactPreset
5
- } from "./chunk-M6ZFSTIZ.js";
6
- import {
2
+ blockVersion,
7
3
  composeBlock,
8
4
  gitattributesSpec,
5
+ gitignoreSpec,
6
+ htmlDialect,
9
7
  upsertBlock
10
- } from "./chunk-DGWHAVRG.js";
8
+ } from "./chunk-LJM5CIY4.js";
11
9
  import {
12
10
  colorTokens,
13
11
  defaultThemeChoice,
@@ -16,6 +14,182 @@ import {
16
14
  fontThemeVars,
17
15
  orderedTokens
18
16
  } from "./chunk-TFFGOFVZ.js";
17
+ import {
18
+ md5Hex
19
+ } from "./chunk-OHX6MIUZ.js";
20
+
21
+ // src/emit/icon-presets.ts
22
+ var ICON_LIBRARIES = ["lucide", "tabler", "phosphor"];
23
+ var DEFAULT_ICON_LIBRARY = "lucide";
24
+ var LIBRARIES = {
25
+ lucide: {
26
+ id: "lucide",
27
+ label: "Lucide",
28
+ componentsJson: "lucide",
29
+ react: {
30
+ dependency: { "lucide-react": "^0.475.0" },
31
+ arrowImport: `import { ArrowRight } from "lucide-react";`,
32
+ arrowComponent: "ArrowRight",
33
+ modeImports: [`import { Monitor, Moon, Sun } from "lucide-react";`],
34
+ modeComponents: { system: "Monitor", light: "Sun", dark: "Moon" }
35
+ },
36
+ svelte: {
37
+ // Not the same version line as `lucide-react`: the Svelte icons ship from
38
+ // a separate package on their own 1.x.
39
+ dependency: { "@lucide/svelte": "^1.31.0" },
40
+ arrowImport: `import ArrowRight from "@lucide/svelte/icons/arrow-right";`,
41
+ arrowComponent: "ArrowRight",
42
+ modeImports: [
43
+ `import Monitor from "@lucide/svelte/icons/monitor";`,
44
+ `import Moon from "@lucide/svelte/icons/moon";`,
45
+ `import Sun from "@lucide/svelte/icons/sun";`
46
+ ],
47
+ modeComponents: { system: "Monitor", light: "Sun", dark: "Moon" }
48
+ },
49
+ guidance: {
50
+ react: `Icons are [Lucide](https://lucide.dev/icons), installed as \`lucide-react\` and
51
+ imported by name from the package root \u2014
52
+ \`import { ArrowRight } from "lucide-react";\`.`,
53
+ svelte: `Icons are [Lucide](https://lucide.dev/icons), installed as \`@lucide/svelte\` \u2014
54
+ **not** \`lucide-react\`, which is the wrong package here in the same way the
55
+ plain \`shadcn\` CLI is. Import them one per module, and kebab-case the name into
56
+ the path: the icon is that module's DEFAULT export, and \`ArrowRight\` lives at
57
+ \`arrow-right\` \u2014 \`import ArrowRight from "@lucide/svelte/icons/arrow-right";\`.
58
+ Never from the package root, which pulls the whole set into the bundle.`
59
+ }
60
+ },
61
+ tabler: {
62
+ id: "tabler",
63
+ label: "Tabler",
64
+ componentsJson: "tabler",
65
+ react: {
66
+ dependency: { "@tabler/icons-react": "^3.31.0" },
67
+ // Every Tabler component is prefixed `Icon`, so the name in markup is not
68
+ // the name on the website — the single most common mistake with this set.
69
+ arrowImport: `import { IconArrowRight } from "@tabler/icons-react";`,
70
+ arrowComponent: "IconArrowRight",
71
+ modeImports: [
72
+ `import { IconDeviceDesktop, IconMoon, IconSun } from "@tabler/icons-react";`
73
+ ],
74
+ modeComponents: {
75
+ system: "IconDeviceDesktop",
76
+ light: "IconSun",
77
+ dark: "IconMoon"
78
+ }
79
+ },
80
+ svelte: {
81
+ dependency: { "@tabler/icons-svelte": "^3.31.0" },
82
+ arrowImport: `import { IconArrowRight } from "@tabler/icons-svelte";`,
83
+ arrowComponent: "IconArrowRight",
84
+ modeImports: [
85
+ `import { IconDeviceDesktop, IconMoon, IconSun } from "@tabler/icons-svelte";`
86
+ ],
87
+ modeComponents: {
88
+ system: "IconDeviceDesktop",
89
+ light: "IconSun",
90
+ dark: "IconMoon"
91
+ }
92
+ },
93
+ guidance: {
94
+ react: `Icons are [Tabler](https://tabler.io/icons), installed as \`@tabler/icons-react\`.
95
+ Every component is prefixed \`Icon\` \u2014 the site lists \`arrow-right\`, the import is
96
+ \`import { IconArrowRight } from "@tabler/icons-react";\`.`,
97
+ svelte: `Icons are [Tabler](https://tabler.io/icons), installed as \`@tabler/icons-svelte\` \u2014
98
+ **not** \`@tabler/icons-react\`, which is the wrong package here in the same way
99
+ the plain \`shadcn\` CLI is. Every component is prefixed \`Icon\`, so the name in
100
+ markup is not the name on the site: \`arrow-right\` is
101
+ \`import { IconArrowRight } from "@tabler/icons-svelte";\`.`
102
+ }
103
+ },
104
+ phosphor: {
105
+ id: "phosphor",
106
+ label: "Phosphor",
107
+ // shadcn/ui's CLI does not know this set. Left off components.json rather
108
+ // than guessed — see IconLibrary.componentsJson.
109
+ componentsJson: void 0,
110
+ react: {
111
+ dependency: { "@phosphor-icons/react": "^2.1.7" },
112
+ arrowImport: `import { ArrowRight } from "@phosphor-icons/react";`,
113
+ arrowComponent: "ArrowRight",
114
+ modeImports: [`import { Desktop, Moon, Sun } from "@phosphor-icons/react";`],
115
+ modeComponents: { system: "Desktop", light: "Sun", dark: "Moon" }
116
+ },
117
+ svelte: {
118
+ dependency: { "phosphor-svelte": "^3.0.1" },
119
+ arrowImport: `import ArrowRight from "phosphor-svelte/lib/ArrowRight";`,
120
+ arrowComponent: "ArrowRight",
121
+ modeImports: [
122
+ `import Desktop from "phosphor-svelte/lib/Desktop";`,
123
+ `import Moon from "phosphor-svelte/lib/Moon";`,
124
+ `import Sun from "phosphor-svelte/lib/Sun";`
125
+ ],
126
+ modeComponents: { system: "Desktop", light: "Sun", dark: "Moon" }
127
+ },
128
+ guidance: {
129
+ react: `Icons are [Phosphor](https://phosphoricons.com), installed as
130
+ \`@phosphor-icons/react\` and imported by name \u2014
131
+ \`import { ArrowRight } from "@phosphor-icons/react";\`. Each takes a \`weight\` prop
132
+ (\`regular\`, \`bold\`, \`duotone\`, \u2026) rather than only a stroke width.`,
133
+ svelte: `Icons are [Phosphor](https://phosphoricons.com), installed as \`phosphor-svelte\` \u2014
134
+ **not** \`@phosphor-icons/react\`, which is the wrong package here in the same way
135
+ the plain \`shadcn\` CLI is. Import them one per module, and PascalCase the name
136
+ into the path: \`import ArrowRight from "phosphor-svelte/lib/ArrowRight";\`.
137
+ Never from the package root, which pulls the whole set into the bundle.`
138
+ }
139
+ }
140
+ };
141
+ function findIconLibrary(id) {
142
+ const normalized = id.trim().toLowerCase();
143
+ return ICON_LIBRARIES.includes(normalized) ? LIBRARIES[normalized] : void 0;
144
+ }
145
+ function allIconLibraries() {
146
+ return ICON_LIBRARIES.map((id) => LIBRARIES[id]);
147
+ }
148
+ function defaultIconLibrary() {
149
+ return LIBRARIES[DEFAULT_ICON_LIBRARY];
150
+ }
151
+ function resolveIconsFlag(raw) {
152
+ const library = findIconLibrary(raw);
153
+ if (library === void 0) {
154
+ throw new Error(
155
+ `Unknown --icons "${raw}". Valid icon libraries: ${ICON_LIBRARIES.join(", ")}.`
156
+ );
157
+ }
158
+ return library;
159
+ }
160
+ function iconLibraryOf(id) {
161
+ return id === void 0 ? defaultIconLibrary() : LIBRARIES[id];
162
+ }
163
+
164
+ // src/emit/decode-record.ts
165
+ function decodeDigest(content) {
166
+ return md5Hex(content);
167
+ }
168
+ function decodeMarkerWith(previous, files) {
169
+ const sorted = [...files].sort((a, b) => a.path.localeCompare(b.path));
170
+ return {
171
+ ...previous,
172
+ files: sorted.map((f) => f.path),
173
+ digests: Object.fromEntries(sorted.map((f) => [f.path, decodeDigest(f.content)]))
174
+ };
175
+ }
176
+ var SOURCE_KINDS = /* @__PURE__ */ new Set(["workspace", "ephemeral", "local", "tenant", "release"]);
177
+ function decodeMarkerHead(previous, command, provenance, sdkVersion, report) {
178
+ const colon = provenance.indexOf(":");
179
+ const kind = colon === -1 ? provenance : provenance.slice(0, colon);
180
+ const origin = SOURCE_KINDS.has(kind) ? { source: kind, origin: colon === -1 ? kind : provenance.slice(colon + 1) } : { source: "file", origin: provenance };
181
+ const { generatedBy: _generatedBy, report: _previousReport, files: _files, digests: _digests, ...kept } = previous;
182
+ return {
183
+ ...kept,
184
+ ...origin,
185
+ sdkVersion,
186
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
187
+ note: `Written by \`xanosdk ${command}\`. Its presence lets a later \`pull\`, \`generate --force\` or \`init --from\` refresh this tree in place.`,
188
+ // The findings of THIS decode — a previous one's would describe a source
189
+ // the tree no longer reflects. Dropped when this command has none to say.
190
+ ...report !== void 0 ? { report } : {}
191
+ };
192
+ }
19
193
 
20
194
  // src/emit/init-templates.ts
21
195
  var STANDALONE_NPM = { manager: "npm", member: "", declared: false };
@@ -26,12 +200,112 @@ function sdkDep(sdkVersion) {
26
200
  const ceiling = major > 0 ? `${major + 1}.0.0` : `0.${minor + 1}.0`;
27
201
  return `>=${sdkVersion} <${ceiling}`;
28
202
  }
203
+ var npmKeyOrder = (a, b) => a.localeCompare(b, "en");
29
204
  function sortedKeys(map) {
30
- return Object.fromEntries(Object.entries(map).sort(([a], [b]) => a.localeCompare(b, "en")));
205
+ return Object.fromEntries(Object.entries(map).sort(([a], [b]) => npmKeyOrder(a, b)));
206
+ }
207
+ function isSorted(keys) {
208
+ return keys.every((key, i) => i === 0 || npmKeyOrder(keys[i - 1], key) <= 0);
209
+ }
210
+ var BACKEND_CHECK = "tsc -p xano && tsc -p xano/lambdas";
211
+ function xanoScripts(check, frontend) {
212
+ const routes = "xanosdk routes ./xano/index.ts --emit xano/routes.gen.ts";
213
+ return {
214
+ "xano:routes": routes,
215
+ // Both are prefixed with a typecheck: the export pass validates what it
216
+ // can see in the encoded bundle, and TypeScript validates the rest. With
217
+ // `tsc` on `build` alone, anyone following the documented workflow would
218
+ // ship with the compiler's half of the checks never run.
219
+ // No `--lock` on either of these: every build maintains `xano/xano.lock`
220
+ // by default, so the flag would be redundant here and would read as
221
+ // though the lock were something a project opts into. It is not — object
222
+ // identity derives from `(type, name)`, and without a lock a rename
223
+ // re-derives the guid and the engine does delete-and-recreate instead of
224
+ // rename-in-place, so the file has to exist before the identities matter.
225
+ // Scaffolds written before the default flipped still pass `--lock`, and
226
+ // it stays accepted for exactly that reason.
227
+ "xano:export": `npm run xano:routes && ${check} && xanosdk export ./xano/index.ts --out workspace.json`,
228
+ // The default deploy, and the tight loop: redeploy the backend to the
229
+ // Xano Engine on this machine. It needs no Xano account, so a fresh
230
+ // scaffold runs it before anyone signs in.
231
+ //
232
+ // No `--static` and no `npm run build`, and both omissions are the point
233
+ // rather than an economy: there is no frontend to ship here. The dev
234
+ // server is still serving it, and the deploy points that server at the
235
+ // engine on its way past, so the loop is backend-only by design.
236
+ // (`--static` does work on a Xano Engine, for a built frontend the
237
+ // engine itself should serve; this loop has none.)
238
+ //
239
+ // No `--local`: the Xano Engine is where a bare deploy goes, and the
240
+ // project's pinned version is what it runs. Baking an engine version or
241
+ // URL into a scaffolded project would ship a coordinate that is not this
242
+ // project's to carry.
243
+ //
244
+ // `--keep-data`, because the engine is the developer's own backend and
245
+ // this loop runs once per code change: each run merges into what the last
246
+ // one left, so rows entered through the app survive the edit. The first
247
+ // run, and the first after the engine restarts, replaces and seeds.
248
+ // `--reset` on the command line still gives a clean slate.
249
+ "xano:deploy": `npm run xano:routes && ${check} && xanosdk deploy ./xano/index.ts --keep-data`,
250
+ // The cloud deploy: backend and built frontend to an ephemeral.
251
+ // Runs `build` rather than `check` directly: `--static ./frontend/dist`
252
+ // needs that directory to EXIST, and only `vite build` writes it. Pointing
253
+ // the flag at a directory the script never produced meant a fresh clone
254
+ // running the documented command had no `dist` to ship.
255
+ // `build` already prefixes the same typecheck, so this is one check, not
256
+ // two. With no frontend, the backend goes alone.
257
+ "xano:deploy:ephemeral": frontend ? `npm run build && xanosdk deploy ./xano/index.ts --ephemeral --static ./frontend/dist` : `npm run xano:routes && ${check} && xanosdk deploy ./xano/index.ts --ephemeral`,
258
+ // The frontend-only loop: rebuild and republish to the environment this
259
+ // project last deployed to, without recompiling or re-importing the
260
+ // backend. `build` runs first because publish ships only what is on disk.
261
+ ...frontend ? { "xano:deploy:frontend": "npm run build && xanosdk publish ./frontend/dist" } : {},
262
+ // The CI guard: fails instead of changing xano.lock, so an uncommitted
263
+ // identity change is caught in review rather than on a deploy. An
264
+ // installed toolchain module's own check rides on the same run: a module
265
+ // that owns a generated tree verifies it under this same flag.
266
+ // `--strict` fails on a stale or missing committed manifest rather than
267
+ // rewriting it, the same way `--frozen-lock` treats xano.lock.
268
+ //
269
+ // `export --check`, not an export to a file: a CI checkout has no
270
+ // `xano/.env` and no `xano/.secrets.json`, and a real export refuses a
271
+ // declared documentation gate it cannot supply. The check writes nothing
272
+ // — no bundle, no lock — so there is nothing a missing secret could clear,
273
+ // and it needs none. It implies `--frozen-lock`. `--strict` as the grounding
274
+ // tells every CI and unattended build to: a build warning is a hard
275
+ // failure. Env values never reach it — a declared name with no value is
276
+ // `""`, which only `deploy` refuses — so a checkout with no `xano/.env`
277
+ // passes it (a fresh scaffold and an `init --from` tree both do).
278
+ "xano:check": `${routes} --strict && ${check} && xanosdk export ./xano/index.ts --check --strict`,
279
+ // No compile step and no entry file: this runs what is DEPLOYED, so it
280
+ // pairs with `xano:deploy` rather than repeating its work. Exits 5 on a
281
+ // failing suite, which is what makes it usable as a CI gate.
282
+ "xano:test": "xanosdk test run-all"
283
+ };
284
+ }
285
+ function backendScripts() {
286
+ const scripts = xanoScripts(BACKEND_CHECK, false);
287
+ return { "xano:routes": scripts["xano:routes"], "xano:typecheck": `npm run xano:routes && ${BACKEND_CHECK}`, ...scripts };
288
+ }
289
+ var BACKEND_DEV_DEPENDENCIES = {
290
+ "@types/node": "^20.19.43",
291
+ tsx: "^4.19.2",
292
+ typescript: "^6.0.3"
293
+ };
294
+ function renderBackendPackageJson({ appName, sdkVersion }) {
295
+ const pkg = {
296
+ name: appName,
297
+ version: "0.1.0",
298
+ private: true,
299
+ type: "module",
300
+ scripts: backendScripts(),
301
+ dependencies: { "@xano/sdk": sdkDep(sdkVersion) },
302
+ devDependencies: sortedKeys({ ...BACKEND_DEV_DEPENDENCIES }),
303
+ engines: { node: `>=${NODE_MIN}` }
304
+ };
305
+ return JSON.stringify(pkg, null, 2) + "\n";
31
306
  }
32
307
  function renderPackageJson({ appName, sdkVersion }, preset, choice = defaultThemeChoice()) {
33
308
  const check = `${preset.checkCmd} && tsc -p xano/lambdas`;
34
- const routes = "xanosdk routes ./xano/index.ts --emit xano/routes.gen.ts";
35
309
  const pkg = {
36
310
  name: appName,
37
311
  version: "0.1.0",
@@ -42,75 +316,7 @@ function renderPackageJson({ appName, sdkVersion }, preset, choice = defaultThem
42
316
  build: `npm run xano:routes && ${check} && vite build`,
43
317
  preview: "vite preview",
44
318
  typecheck: `npm run xano:routes && ${check}`,
45
- "xano:routes": routes,
46
- // Both are prefixed with a typecheck: the export pass validates what it
47
- // can see in the encoded bundle, and TypeScript validates the rest. With
48
- // `tsc` on `build` alone, anyone following the documented workflow would
49
- // ship with the compiler's half of the checks never run.
50
- // No `--lock` on either of these: every build maintains `xano/xano.lock`
51
- // by default, so the flag would be redundant here and would read as
52
- // though the lock were something a project opts into. It is not — object
53
- // identity derives from `(type, name)`, and without a lock a rename
54
- // re-derives the guid and the engine does delete-and-recreate instead of
55
- // rename-in-place, so the file has to exist before the identities matter.
56
- // Scaffolds written before the default flipped still pass `--lock`, and
57
- // it stays accepted for exactly that reason.
58
- "xano:export": `npm run xano:routes && ${check} && xanosdk export ./xano/index.ts --out workspace.json`,
59
- // The default deploy, and the tight loop: redeploy the backend to the
60
- // Xano Engine on this machine. It needs no Xano account, so a fresh
61
- // scaffold runs it before anyone signs in.
62
- //
63
- // No `--static` and no `npm run build`, and both omissions are the point
64
- // rather than an economy: there is no frontend to ship here. The dev
65
- // server is still serving it, and the deploy points that server at the
66
- // engine on its way past, so the loop is backend-only by design.
67
- // (`--static` does work on a Xano Engine, for a built frontend the
68
- // engine itself should serve; this loop has none.)
69
- //
70
- // No `--local`: the Xano Engine is where a bare deploy goes, and the
71
- // project's pinned version is what it runs. Baking an engine version or
72
- // URL into a scaffolded project would ship a coordinate that is not this
73
- // project's to carry.
74
- //
75
- // `--keep-data`, because the engine is the developer's own backend and
76
- // this loop runs once per code change: each run merges into what the last
77
- // one left, so rows entered through the app survive the edit. The first
78
- // run, and the first after the engine restarts, replaces and seeds.
79
- // `--reset` on the command line still gives a clean slate.
80
- "xano:deploy": `npm run xano:routes && ${check} && xanosdk deploy ./xano/index.ts --keep-data`,
81
- // The cloud deploy: backend and built frontend to an ephemeral.
82
- // Runs `build` rather than `check` directly: `--static ./frontend/dist`
83
- // needs that directory to EXIST, and only `vite build` writes it. Pointing
84
- // the flag at a directory the script never produced meant a fresh clone
85
- // running the documented command had no `dist` to ship.
86
- // `build` already prefixes the same typecheck, so this is one check, not
87
- // two.
88
- "xano:deploy:ephemeral": `npm run build && xanosdk deploy ./xano/index.ts --ephemeral --static ./frontend/dist`,
89
- // The frontend-only loop: rebuild and republish to the environment this
90
- // project last deployed to, without recompiling or re-importing the
91
- // backend. `build` runs first because publish ships only what is on disk.
92
- "xano:deploy:frontend": "npm run build && xanosdk publish ./frontend/dist",
93
- // The CI guard: fails instead of changing xano.lock, so an uncommitted
94
- // identity change is caught in review rather than on a deploy. An
95
- // installed toolchain module's own check rides on the same run: a module
96
- // that owns a generated tree verifies it under this same flag.
97
- // `--strict` fails on a stale or missing committed manifest rather than
98
- // rewriting it, the same way `--frozen-lock` treats xano.lock.
99
- //
100
- // `export --check`, not an export to a file: a CI checkout has no
101
- // `xano/.env` and no `xano/.secrets.json`, and a real export refuses a
102
- // declared documentation gate it cannot supply. The check writes nothing
103
- // — no bundle, no lock — so there is nothing a missing secret could clear,
104
- // and it needs none. It implies `--frozen-lock`. `--strict` as the grounding
105
- // tells every CI and unattended build to: a build warning is a hard
106
- // failure. Env values never reach it — a declared name with no value is
107
- // `""`, which only `deploy` refuses — so a checkout with no `xano/.env`
108
- // passes it (a fresh scaffold and an `init --from` tree both do).
109
- "xano:check": `${routes} --strict && ${check} && xanosdk export ./xano/index.ts --check --strict`,
110
- // No compile step and no entry file: this runs what is DEPLOYED, so it
111
- // pairs with `xano:deploy` rather than repeating its work. Exits 5 on a
112
- // failing suite, which is what makes it usable as a CI gate.
113
- "xano:test": "xanosdk test run-all",
319
+ ...xanoScripts(check, true),
114
320
  // Framework-owned scripts, last so a preset can add to the set but the
115
321
  // shared xano:* contract above stays the same in every scaffold.
116
322
  ...preset.extraScripts
@@ -176,10 +382,33 @@ function renderTsconfig(preset) {
176
382
  };
177
383
  return JSON.stringify(tsconfig, null, 2) + "\n";
178
384
  }
385
+ var BACKEND_TSCONFIG_PATH = "xano/tsconfig.json";
386
+ function renderBackendTsconfig() {
387
+ const tsconfig = {
388
+ compilerOptions: {
389
+ target: "ES2022",
390
+ lib: ["ES2022", "DOM", "DOM.Iterable"],
391
+ module: "ESNext",
392
+ moduleResolution: "bundler",
393
+ strict: true,
394
+ noEmit: true,
395
+ esModuleInterop: true,
396
+ skipLibCheck: true,
397
+ resolveJsonModule: true,
398
+ isolatedModules: true,
399
+ types: ["node"]
400
+ },
401
+ include: ["**/*.ts"],
402
+ exclude: ["lambdas"]
403
+ };
404
+ return JSON.stringify(tsconfig, null, 2) + "\n";
405
+ }
179
406
  var LAMBDA_GLOBALS_TYPES = "@xano/sdk/lambda-globals";
180
- function renderLambdaTsconfig() {
407
+ function renderLambdaTsconfig(base = "project") {
181
408
  const tsconfig = {
182
- extends: "../../tsconfig.json",
409
+ // A project with no frontend has no root tsconfig: `xano/tsconfig.json` is
410
+ // the config the backend checks under, and the lambdas build on that.
411
+ extends: base === "backend" ? "../tsconfig.json" : "../../tsconfig.json",
183
412
  // No DOM and no node types: a lambda body runs in neither.
184
413
  compilerOptions: { lib: ["ES2022"], types: [LAMBDA_GLOBALS_TYPES] },
185
414
  files: [],
@@ -282,6 +511,25 @@ ${framework}
282
511
  # it means each build mints identities that are thrown away and re-invented.
283
512
  `;
284
513
  }
514
+ function renderGitignoreBlock(version) {
515
+ return composeBlock(
516
+ gitignoreSpec(),
517
+ [
518
+ "# What the Xano backend writes. xano/ itself, and xano/xano.lock, are committed.",
519
+ "node_modules/",
520
+ "/workspace.json",
521
+ "/.xano/",
522
+ "xano/.env",
523
+ "xano/.env.tmp-*",
524
+ "xano/.secrets.json",
525
+ "xano/.secrets.json.tmp-*"
526
+ ],
527
+ version
528
+ );
529
+ }
530
+ function mergeGitignore(existing, version) {
531
+ return upsertBlock(existing, gitignoreSpec(), renderGitignoreBlock(version)).text;
532
+ }
285
533
  var NODE_MIN = "20.19";
286
534
  function renderGitattributes(contributions = []) {
287
535
  let text = `# The export writes LF. Normalizing here keeps generated output
@@ -412,25 +660,106 @@ VITE_XANO_HOST=https://your-instance.xano.io
412
660
  `;
413
661
  }
414
662
  var XANO_BADGE = "[![Built on Xano](https://img.shields.io/badge/built_on-Xano-0055FF)](https://xano.com)";
415
- function renderReadmeLearnMore() {
416
- return `## Learn more
663
+ var README_PATH = "README.md";
664
+ var README_BUILT_WITH_BLOCK = {
665
+ dialect: htmlDialect("xanosdk-built-with"),
666
+ pkg: "xanosdk-built-with",
667
+ file: README_PATH
668
+ };
669
+ var README_BUILT_WITH_BODY = `## Built with
417
670
 
418
- - [Xano SDK guides](https://github.com/xano-sdk/sdk/blob/main/guides/README.md) \u2014 signing in
419
- and deploying, releasing to production, the typed frontend, every CLI command.
420
- - [Xano](https://xano.com) is the platform this app deploys to: the database, APIs, auth,
421
- background tasks, realtime, file storage and AI agents behind \`xano/\`, with
422
- [docs](https://docs.xano.com) and a [community](https://community.xano.com).`;
671
+ - [Xano](https://xano.com) hosts everything under [\`xano/\`](xano/): the database, APIs,
672
+ auth, background tasks, realtime, file storage and AI agents. It runs on your machine as
673
+ the Xano Engine and in the cloud from the same command. [Docs](https://docs.xano.com) \xB7
674
+ [Community](https://community.xano.com)
675
+ - [Xano SDK](https://github.com/xano-sdk/sdk) is the TypeScript the backend is authored in.
676
+ The [guides](https://github.com/xano-sdk/sdk/blob/main/guides/README.md) cover signing in
677
+ and deploying, releasing to production, the typed frontend, and every CLI command.`;
678
+ function renderReadmeBuiltWith(sdkVersion) {
679
+ return composeBlock(README_BUILT_WITH_BLOCK, [README_BUILT_WITH_BODY], sdkVersion);
680
+ }
681
+ function readmeBuiltWithVersion(text) {
682
+ return blockVersion(text, README_BUILT_WITH_BLOCK);
423
683
  }
424
- function renderReadme({ appName, install }, preset, choice = defaultThemeChoice()) {
684
+ function refreshReadmeBuiltWith(existing, sdkVersion) {
685
+ return upsertBlock(existing, README_BUILT_WITH_BLOCK, renderReadmeBuiltWith(sdkVersion)).text;
686
+ }
687
+ function renderReadmeDescriptionSlot(appName) {
688
+ return `_Describe ${appName} here: what it does and who it is for._`;
689
+ }
690
+ var README_ENGINE_BULLETS = `- **It works on a fresh machine with nothing set.** The first run downloads the latest
691
+ engine once per machine and pins its version in \`package.json\`. Commit that change, so
692
+ everyone on the project runs the same engine.
693
+ - **It keeps your table rows across redeploys** (\`--keep-data\`). The first run seeds and
694
+ later runs merge your changes in without re-seeding. Rows survive only in tables and columns that keep
695
+ their names (a rename drops the old one with its rows), and only while the engine runs. An
696
+ engine update or restart starts it empty and the next run seeds again.
697
+ \`npm run xano:deploy -- --reset\` gives a clean, re-seeded slate.
698
+ - **Updates are yours to take.** When a newer engine ships, a deploy offers it and never
699
+ applies it without a yes. \`npx xanosdk local update\` moves the pin on purpose,
700
+ and \`npx xanosdk local cache clear\` reclaims the disk space. To try another engine
701
+ without moving the pin, export \`XANOSDK_ENGINE_OVERRIDE\` with a version (\`v0.1.5\`)
702
+ or an engine archive path.
703
+ - **The rest of the CLI follows.** After a local deploy, \`npm run xano:test\`,
704
+ \`npx xanosdk tables\` and \`npx xanosdk status\` reach the engine with no flag.
705
+ \`npx xanosdk local stop <name>\` shuts it down.`;
706
+ var README_LOCK_SECTION = `## \`xano.lock\` \u2014 commit it
707
+
708
+ Object identity derives from \`(type, name)\`, so a rename would otherwise change
709
+ an object's guid and the engine would **delete and recreate** it rather than
710
+ renaming it in place \u2014 losing its rows on a record-preserving import.
711
+ [\`xano/xano.lock\`](xano/xano.lock) freezes each guid and each API group's
712
+ canonical slug, so renames and re-deploys keep the same identities (and the same
713
+ public URLs).
714
+
715
+ Every build writes it \u2014 no flag \u2014 and it **must be committed**. Ignoring it means
716
+ each build mints identities and public URLs that are thrown away and re-invented
717
+ next time. If you release to a workspace that already exists, adopt what it
718
+ already serves first with \`npx xanosdk lock import <live-bundle.json> --lock=xano/xano.lock\`;
719
+ that is also the recovery path once identities have drifted.
720
+
721
+ \`\`\`bash
722
+ npm run xano:check # CI: fail on ANY build warning (it runs --strict), if the export
723
+ # would change xano.lock, or if the lock carries an entry no
724
+ # object matches \u2014 writes nothing and needs no secrets, so a
725
+ # fresh clone runs it as-is
726
+ \`\`\`
727
+
728
+ To rename an object: rename it in code and run \`npm run xano:export\`. Only if it
729
+ warns of an orphaned entry, run the \`npx xanosdk lock rename <kind> <old> <new>\` it prints, then
730
+ export again. Every \`lock\` subcommand finds \`xano/xano.lock\` from the project entry, as
731
+ \`export\` does \u2014 \`--entry=<file>\` names another entry, \`--lock=<path>\` the lock itself.`;
732
+ var README_ADD_ONS_SECTION = `## Add-ons
733
+
734
+ Xano SDK is composable with other \`@xano-sdk/*\` packages:
735
+
736
+ - **[\`@xano-sdk/auth\`](https://www.npmjs.com/package/@xano-sdk/auth)** \u2014 turnkey
737
+ authentication (user/login/signup tables and endpoints). Install it with
738
+ \`npx xanosdk marketplace install @xano-sdk/auth\`, then register it in
739
+ \`xano/index.ts\`. Authentication only \u2014 **not** authorization: it has no
740
+ roles, permissions, or route guards, and its tokens carry no role claim.
741
+ Enforce roles off the caller's row with \`@xano/sdk\`: spread
742
+ \`...guard.role(userTable, "admin")\` into the endpoint's stack.
743
+ - More \`@xano-sdk/*\` packages register onto the same workspace. This list
744
+ does not update itself \u2014 run \`npx xanosdk marketplace list\` for the live
745
+ catalogue, \`npx xanosdk marketplace search <words>\` to narrow it, and
746
+ \`npx xanosdk marketplace details <package>\` to see what an add-on installs and
747
+ how to register it. All three work before you log in.
748
+
749
+ None of these ship with the scaffold. Install one only when you need it \u2014 an
750
+ add-on you never register is weight in \`package.json\` for nothing.`;
751
+ function renderReadme({ appName, install, sdkVersion }, preset, choice = defaultThemeChoice()) {
425
752
  return `# ${appName}
426
753
 
427
754
  ${XANO_BADGE}
428
755
 
429
- A full-stack app on [Xano](https://xano.com). The backend is TypeScript under
430
- [\`xano/\`](xano/), authored with the [Xano SDK](https://github.com/xano-sdk/sdk). It runs on
431
- your machine on the **Xano Engine**, and one command deploys it to Xano's cloud. The
756
+ ${renderReadmeDescriptionSlot(appName)}
757
+
758
+ The backend under [\`xano/\`](xano/) is TypeScript, authored with the
759
+ [Xano SDK](https://github.com/xano-sdk/sdk) and running on [Xano](https://xano.com). It runs
760
+ on your machine as the **Xano Engine** and ships to Xano's cloud with the same command. The
432
761
  ${preset.label} frontend under [\`frontend/\`](frontend/) takes its request paths and types
433
- from the backend defs, so the two can't drift.
762
+ from the backend defs rather than hand-typing them.
434
763
 
435
764
  ## Quick start
436
765
 
@@ -452,22 +781,7 @@ It prints the backend URL, a link that opens Xano's visual builder on the engine
452
781
  points \`npm run dev\` at it through \`.env.local\` (restart the dev server if it was already
453
782
  running).
454
783
 
455
- - **It works on a fresh machine with nothing set.** The first run downloads the latest
456
- engine once per machine and pins its version in \`package.json\`. Commit that change, so
457
- everyone on the project runs the same engine.
458
- - **It keeps your table rows across redeploys** (\`--keep-data\`). The first run seeds and
459
- later runs merge your changes in without re-seeding. Rows survive only in tables and columns that keep
460
- their names (a rename drops the old one with its rows), and only while the engine runs. An
461
- engine update or restart starts it empty and the next run seeds again.
462
- \`npm run xano:deploy -- --reset\` gives a clean, re-seeded slate.
463
- - **Updates are yours to take.** When a newer engine ships, a deploy offers it and never
464
- applies it without a yes. \`npx xanosdk local update\` moves the pin on purpose,
465
- and \`npx xanosdk local cache clear\` reclaims the disk space. To try another engine
466
- without moving the pin, export \`XANOSDK_ENGINE_OVERRIDE\` with a version (\`v0.1.5\`)
467
- or an engine archive path.
468
- - **The rest of the CLI follows.** After a local deploy, \`npm run xano:test\`,
469
- \`npx xanosdk tables\` and \`npx xanosdk status\` reach the engine with no flag.
470
- \`npx xanosdk local stop <name>\` shuts it down.
784
+ ${README_ENGINE_BULLETS}
471
785
 
472
786
  ## Deploy to Xano's cloud
473
787
 
@@ -499,38 +813,14 @@ The other scripts:
499
813
  ./xano/index.ts --test\` does both in one step.
500
814
  - \`npm run xano:export\` compiles the backend to \`workspace.json\` (don't commit it).
501
815
 
502
- ## \`xano.lock\` \u2014 commit it
503
-
504
- Object identity derives from \`(type, name)\`, so a rename would otherwise change
505
- an object's guid and the engine would **delete and recreate** it rather than
506
- renaming it in place \u2014 losing its rows on a record-preserving import.
507
- [\`xano/xano.lock\`](xano/xano.lock) freezes each guid and each API group's
508
- canonical slug, so renames and re-deploys keep the same identities (and the same
509
- public URLs).
510
-
511
- Every build writes it \u2014 no flag \u2014 and it **must be committed**. Ignoring it means
512
- each build mints identities and public URLs that are thrown away and re-invented
513
- next time. If you release to a workspace that already exists, adopt what it
514
- already serves first with \`npx xanosdk lock import <live-bundle.json> --lock=xano/xano.lock\`;
515
- that is also the recovery path once identities have drifted.
516
-
517
- \`\`\`bash
518
- npm run xano:check # CI: fail on ANY build warning (it runs --strict), if the export
519
- # would change xano.lock, or if the lock carries an entry no
520
- # object matches \u2014 writes nothing and needs no secrets, so a
521
- # fresh clone runs it as-is
522
- \`\`\`
523
-
524
- To rename an object: rename it in code and run \`npm run xano:export\`. Only if it
525
- warns of an orphaned entry, run the \`npx xanosdk lock rename <kind> <old> <new>\` it prints, then
526
- export again. Every \`lock\` subcommand finds \`xano/xano.lock\` from the project entry, as
527
- \`export\` does \u2014 \`--entry=<file>\` names another entry, \`--lock=<path>\` the lock itself.
816
+ ${README_LOCK_SECTION}
528
817
 
529
818
  ## The one contract
530
819
 
531
820
  [\`frontend/src/lib/api.ts\`](frontend/src/lib/api.ts) takes request paths from
532
- \`xano/routes.gen.ts\` (\`routePath("GET notes/{id}", { id })\`) and request/response
533
- types from the query defs (\`import type\` + \`InferInput\` / \`InferResponse\`).
821
+ \`xano/routes.gen.ts\` (\`routePath("GET notes/{id}", { id })\`), request types from the
822
+ same file (\`RouteInputs["POST create_note"]\`, \`MessageInputs[...]\` for realtime), and
823
+ response types from the query defs (\`import type\` + \`InferResponse\`).
534
824
  Never hand-type a URL or a request body \u2014 change a def and the frontend follows.
535
825
 
536
826
  \`npm run xano:routes\` writes \`xano/routes.gen.ts\` from the defs; \`dev\`, \`build\`
@@ -552,27 +842,78 @@ ${preset.readmeFrontendSection(choice.icons)}
552
842
 
553
843
  ${renderReadmeThemingSection(choice)}
554
844
 
555
- ## Add-ons
845
+ ${README_ADD_ONS_SECTION}
556
846
 
557
- Xano SDK is composable with other \`@xano-sdk/*\` packages:
847
+ ${renderReadmeBuiltWith(sdkVersion)}
848
+ `;
849
+ }
850
+ function renderBackendReadme({ appName, install, sdkVersion }) {
851
+ return `# ${appName}
558
852
 
559
- - **[\`@xano-sdk/auth\`](https://www.npmjs.com/package/@xano-sdk/auth)** \u2014 turnkey
560
- authentication (user/login/signup tables and endpoints). Install it with
561
- \`npx xanosdk marketplace install @xano-sdk/auth\`, then register it in
562
- \`xano/index.ts\`. Authentication only \u2014 **not** authorization: it has no
563
- roles, permissions, or route guards, and its tokens carry no role claim.
564
- Enforce roles off the caller's row with \`@xano/sdk\`: spread
565
- \`...guard.role(userTable, "admin")\` into the endpoint's stack.
566
- - More \`@xano-sdk/*\` packages register onto the same workspace. This list
567
- does not update itself \u2014 run \`npx xanosdk marketplace list\` for the live
568
- catalogue, \`npx xanosdk marketplace search <words>\` to narrow it, and
569
- \`npx xanosdk marketplace details <package>\` to see what an add-on installs and
570
- how to register it. All three work before you log in.
853
+ ${XANO_BADGE}
571
854
 
572
- None of these ship with the scaffold. Install one only when you need it \u2014 an
573
- add-on you never register is weight in \`package.json\` for nothing.
855
+ ${renderReadmeDescriptionSlot(appName)}
856
+
857
+ The backend under [\`xano/\`](xano/) is TypeScript, authored with the
858
+ [Xano SDK](https://github.com/xano-sdk/sdk) and running on [Xano](https://xano.com). It runs
859
+ on your machine as the **Xano Engine** and ships to Xano's cloud with the same command.
574
860
 
575
- ${renderReadmeLearnMore()}
861
+ ## Quick start
862
+
863
+ \`\`\`bash
864
+ ${install?.manager ?? "npm"} install${install?.ignoreWorkspace === true ? " --ignore-workspace" : ""}
865
+ npm run xano:deploy # run the backend on the Xano Engine, on this machine
866
+ \`\`\`
867
+
868
+ No Xano account needed. Then author your backend in [\`xano/index.ts\`](xano/index.ts),
869
+ starting with the walkthrough in [\`xano/EXAMPLE.md\`](xano/EXAMPLE.md), and rerun
870
+ \`npm run xano:deploy\` after each change.
871
+
872
+ ## Run it on your machine
873
+
874
+ The Xano Engine is Xano running on your machine. \`npm run xano:deploy\` typechecks the
875
+ backend and deploys it to the engine: no sign-in, and no network round-trip.
876
+ It prints the backend URL and a link that opens Xano's visual builder on the engine.
877
+
878
+ ${README_ENGINE_BULLETS}
879
+
880
+ ## Deploy to Xano's cloud
881
+
882
+ \`\`\`bash
883
+ npx xanosdk login # once, to authenticate against your Xano account
884
+ npm run xano:deploy:ephemeral # typecheck, then ship the backend to an ephemeral
885
+ \`\`\`
886
+
887
+ That deploys the backend to a live **ephemeral** environment on Xano and prints its URL.
888
+ Run it again to refresh the same environment; if it expired, a fresh one is created and
889
+ the new URL is called out. \`npx xanosdk status\` says who you are signed in as, which
890
+ workspace you are bound to, and which environment this project last deployed to. Your
891
+ **workspace** is reached through a release (\`deploy --ephemeral --test\`, \`release create\`,
892
+ \`promote\`); see the
893
+ [deploying guide](https://github.com/xano-sdk/sdk/blob/main/guides/deploying.md).
894
+
895
+ The other scripts:
896
+
897
+ - \`npm run xano:test\` runs the tests the DEPLOYED environment carries \u2014 the \`tests\`
898
+ on a query/function/middleware and any \`workflowTest()\`. It compiles nothing, so
899
+ deploy first. A failing suite exits 5, distinct from a crash. \`npx xanosdk deploy
900
+ ./xano/index.ts --test\` does both in one step.
901
+ - \`npm run xano:typecheck\` type-checks \`xano/\` and its lambdas.
902
+ - \`npm run xano:export\` compiles the backend to \`workspace.json\` (don't commit it).
903
+
904
+ ${README_LOCK_SECTION}
905
+
906
+ ## Calling the backend
907
+
908
+ \`npm run xano:routes\` writes \`xano/routes.gen.ts\` from the defs: every endpoint's verb,
909
+ path (\`routePath("GET notes/{id}", { id })\`) and request type (\`RouteInputs["POST create_note"]\`).
910
+ A client takes them from there, and response types from the query defs (\`import type\` +
911
+ \`InferResponse\`), rather than hand-typing a URL. \`xano:check\` fails on a missing or stale
912
+ copy \u2014 commit it. \`npx xanosdk routes xano/index.ts\` lists every endpoint's verb + path.
913
+
914
+ ${README_ADD_ONS_SECTION}
915
+
916
+ ${renderReadmeBuiltWith(sdkVersion)}
576
917
  `;
577
918
  }
578
919
  function renderXanoIndex({ appName }) {
@@ -743,8 +1084,11 @@ URL or a request body:
743
1084
  groups share is keyed \`"<group>:<VERB> <name>"\`). Run
744
1085
  \`npm run xano:routes\` after adding or renaming an endpoint (\`dev\`, \`build\` and
745
1086
  \`typecheck\` also run it) and commit the file.
746
- - **Shapes** come from the defs with \`import type\` \u2014 \`InferInput\`/\`InferResponse\`
747
- erase to nothing.
1087
+ - **Request types** come from the same file: \`RouteInputs["POST create_note"]\`
1088
+ (\`ChannelInputs\`/\`MessageInputs\` for realtime). For runtime validation,
1089
+ \`npx xanosdk marketplace install zod\` adds zod schemas under the same keys.
1090
+ - **Response types** come from the defs with \`import type\` \u2014 \`InferResponse\`
1091
+ erases to nothing.
748
1092
  - Never import a def as a value in the frontend. Its \`s.*\`/\`c.*\` stack calls run
749
1093
  at module load, so one import for its \`getPath()\` pulls the backend graph it
750
1094
  references and the SDK runtime into the bundle.
@@ -785,7 +1129,7 @@ function renderCodegenMarker({ sdkVersion }, origin, generatedAt, report, files)
785
1129
  };
786
1130
  return JSON.stringify(files === void 0 ? head : decodeMarkerWith(head, files), null, 2) + "\n";
787
1131
  }
788
- function renderCodegenReadme({ appName }, origin, envNames, preset) {
1132
+ function renderCodegenReadme({ appName, sdkVersion }, origin, envNames, preset) {
789
1133
  const secrets = envNames.length === 0 ? "" : `
790
1134
  ## Fill in the backend env values
791
1135
 
@@ -814,19 +1158,21 @@ cleartext, which is why it is gitignored too.
814
1158
 
815
1159
  ${XANO_BADGE}
816
1160
 
817
- A full-stack app on [Xano](https://xano.com), pulled from
818
- ${describeCommittedOrigin(origin)} with the [Xano SDK](https://github.com/xano-sdk/sdk). The Xano
819
- backend lives in [\`xano/\`](xano/) as readable TypeScript; the ${preset.label} frontend
820
- under [\`frontend/\`](frontend/) is a starter \u2014 the pull carries a backend, not a UI.
1161
+ ${renderReadmeDescriptionSlot(appName)}
1162
+
1163
+ The backend under [\`xano/\`](xano/) is TypeScript pulled from ${describeCommittedOrigin(origin)}
1164
+ with the [Xano SDK](https://github.com/xano-sdk/sdk), and runs on [Xano](https://xano.com).${preset === null ? "" : ` The
1165
+ ${preset.label} frontend under [\`frontend/\`](frontend/) is a starter \u2014 the pull carries a
1166
+ backend, not a UI.`}
821
1167
 
822
1168
  ## Run it
823
1169
 
824
1170
  \`\`\`bash
825
1171
  npm run xano:deploy # on the Xano Engine, on this machine (no account needed)
826
- npm run dev # the starter frontend, pointed at it
827
-
1172
+ ${preset === null ? "" : `npm run dev # the starter frontend, pointed at it
1173
+ `}
828
1174
  npx xanosdk login # once, to authenticate against your Xano account
829
- npm run xano:deploy:ephemeral # typecheck, build the frontend, ship both to an ephemeral
1175
+ ${preset === null ? "npm run xano:deploy:ephemeral # typecheck, ship the backend to an ephemeral" : "npm run xano:deploy:ephemeral # typecheck, build the frontend, ship both to an ephemeral"}
830
1176
  \`\`\`
831
1177
 
832
1178
  ## Read this before deploying
@@ -847,17 +1193,21 @@ translate cleanly on this pull. Read it before trusting the tree.
847
1193
  ${secrets}
848
1194
  ## Working on it
849
1195
 
850
- \`\`\`bash
1196
+ ${preset === null ? `\`\`\`bash
1197
+ npm run xano:typecheck # xano/ and its lambdas
1198
+ npm run xano:export # compile the backend to workspace.json (don't commit it)
1199
+ npm run xano:routes # regenerate xano/routes.gen.ts: every endpoint's path and request type
1200
+ \`\`\`` : `\`\`\`bash
851
1201
  npm run dev # run the starter frontend
852
1202
  npm run typecheck # the whole project, both halves
853
1203
  npm run xano:export # compile the backend to workspace.json (don't commit it)
854
- npm run xano:routes # regenerate xano/routes.gen.ts, the frontend's paths
1204
+ npm run xano:routes # regenerate xano/routes.gen.ts: the frontend's paths and request types
855
1205
  \`\`\`
856
1206
 
857
1207
  [\`frontend/src/lib/api.ts\`](frontend/src/lib/api.ts) shows the one contract: paths
858
- from \`routePath()\` in \`xano/routes.gen.ts\`, types from the query defs in \`xano/\`.
1208
+ and request types from \`xano/routes.gen.ts\`, response types from the query defs in \`xano/\`.`}
859
1209
 
860
- ${renderReadmeLearnMore()}
1210
+ ${renderReadmeBuiltWith(sdkVersion)}
861
1211
  `;
862
1212
  }
863
1213
  function renderReadmeThemingSection(choice) {
@@ -1107,9 +1457,9 @@ export function cn(...inputs: ClassValue[]) {
1107
1457
  ${extra}`;
1108
1458
  }
1109
1459
  function renderApiTs() {
1110
- return `// The one contract: endpoint paths come from the generated route manifest, and
1111
- // request/response *types* from your xanosdk query defs. Never hand-type a URL
1112
- // or a request body: change a def and everything here follows.
1460
+ return `// The one contract: endpoint paths and request types come from the generated
1461
+ // route manifest, and response *types* from your xanosdk query defs. Never
1462
+ // hand-type a URL or a request body: change a def and everything here follows.
1113
1463
  //
1114
1464
  // Keep the backend out of the browser bundle:
1115
1465
  // \u2022 Paths and verbs: \`routePath()\` / \`ROUTES\` from xano/routes.gen.ts, plain data
@@ -1117,16 +1467,20 @@ function renderApiTs() {
1117
1467
  // regenerate it). Never import a def as a VALUE for its getPath()/verb:
1118
1468
  // its s.*/c.* factory calls run at module load, so one import pulls in the
1119
1469
  // backend graph it references and the SDK runtime that builds it.
1120
- // \u2022 Shapes: \`import type\` only. InferInput/InferResponse erase to nothing.
1470
+ // \u2022 Request types: \`RouteInputs["<VERB> <name>"]\` from the same file
1471
+ // (\`ChannelInputs\` / \`MessageInputs\` for realtime), types only. For
1472
+ // runtime validation, \`npx xanosdk marketplace install zod\` adds zod
1473
+ // schemas under the same keys.
1474
+ // \u2022 Response types: \`import type\` the def. InferResponse erases to nothing.
1121
1475
  //
1122
1476
  // Nothing here imports the manifest yet \u2014 an add-on's endpoints may already be
1123
1477
  // in it. Wire an endpoint (one in xano/, or an add-on's) like:
1124
1478
  //
1125
- // import type { InferInput, InferResponse } from "@xano/sdk";
1479
+ // import type { InferResponse } from "@xano/sdk";
1126
1480
  // import type { createNoteQuery } from "../../../xano/api/create-note.js";
1127
- // import { ROUTES, routePath } from "../../../xano/routes.gen.js";
1481
+ // import { ROUTES, routePath, type RouteInputs } from "../../../xano/routes.gen.js";
1128
1482
  //
1129
- // export type CreateNoteBody = InferInput<typeof createNoteQuery>;
1483
+ // export type CreateNoteBody = RouteInputs["POST create_note"];
1130
1484
  // export type Note = InferResponse<typeof createNoteQuery>;
1131
1485
  //
1132
1486
  // export async function createNote(body: CreateNoteBody): Promise<Note> {
@@ -1162,346 +1516,122 @@ export const XANO_HOST: string =
1162
1516
  `;
1163
1517
  }
1164
1518
 
1165
- // src/emit/frontend-svelte.ts
1519
+ // src/emit/frontend-react.ts
1166
1520
  var CODE_CLASS = "bg-muted rounded px-1.5 py-0.5 font-mono text-sm";
1167
- function htmlText(s) {
1168
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1169
- }
1170
- function svelteText(s) {
1171
- return htmlText(s).replace(/\{/g, "&#123;").replace(/\}/g, "&#125;");
1521
+ function jsxText(s) {
1522
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\{/g, "&#123;").replace(/\}/g, "&#125;");
1172
1523
  }
1173
1524
  function renderNode(node) {
1174
- return "code" in node ? `<code class="${CODE_CLASS}">${svelteText(node.code)}</code>` : svelteText(node.text);
1525
+ return "code" in node ? `<code className="${CODE_CLASS}">${jsxText(node.code)}</code>` : jsxText(node.text);
1175
1526
  }
1176
1527
  function renderNodes(nodes) {
1177
1528
  return nodes.map(renderNode).join("");
1178
1529
  }
1179
1530
  function renderApp(landing, choice) {
1180
- const steps = landing.steps.map((step) => ` <li>${renderNodes(step)}</li>`).join("\n");
1531
+ const steps = landing.steps.map((step) => ` <li>${renderNodes(step)}</li>`).join("\n");
1181
1532
  const toggle = choice.dark === "toggle";
1182
- const icons = iconLibraryOf(choice.icons).svelte;
1183
- return `<script lang="ts">
1184
- ${icons.arrowImport}
1185
-
1186
- import { Button } from "$lib/components/ui/button/index.js";
1187
- import * as Card from "$lib/components/ui/card/index.js";${toggle ? `
1188
- import ModeToggle from "$lib/components/mode-toggle.svelte";` : ""}
1189
- </script>
1190
-
1191
- <main class="mx-auto flex min-h-screen max-w-2xl flex-col justify-center p-8">${toggle ? `
1192
- <div class="mb-4 flex justify-end">
1193
- <ModeToggle />
1194
- </div>` : ""}
1195
- <Card.Root>
1196
- <Card.Header>
1197
- <Card.Title class="text-3xl tracking-tight">${svelteText(landing.title)}</Card.Title>
1198
- <Card.Description class="text-base">
1199
- ${renderNodes(landing.lead)}
1200
- </Card.Description>
1201
- </Card.Header>
1202
- <Card.Content>
1203
- <ol class="text-muted-foreground list-inside list-decimal space-y-2">
1204
- ${steps}
1205
- </ol>
1206
- </Card.Content>
1207
- <Card.Footer>
1208
- <!-- Components come from shadcn-svelte \u2014 add more with
1209
- \`npx shadcn-svelte@latest add <name>\`. -->
1210
- <Button href="${landing.cta.href}" target="_blank" rel="noreferrer">
1211
- ${svelteText(landing.cta.label)}
1212
- <${icons.arrowComponent} />
1213
- </Button>
1214
- </Card.Footer>
1215
- </Card.Root>
1216
- </main>
1217
- `;
1218
- }
1219
- function renderSvelteKitPlugin() {
1220
- return `sveltekit({
1221
- // RUNES MODE, FORCED \u2014 not left to Svelte 5's per-component detection.
1222
- //
1223
- // By default a component that uses \`export let\` and \`<slot>\` simply
1224
- // compiles in legacy mode and works, so the Svelte 4 API an assistant
1225
- // reaches for from older training data produces no error at all. Pinning
1226
- // runes here turns that into a compile failure naming the file, which is
1227
- // the same guidance the agent brief gives, enforced instead of stated.
1228
- //
1229
- // \`node_modules\` is exempted (returning undefined restores detection):
1230
- // an installed library compiles under whatever mode ITS author wrote for,
1231
- // and forcing ours onto it would break dependencies this project does not
1232
- // own. Removable in Svelte 6, where runes stop being opt-in.
1233
- compilerOptions: {
1234
- runes: ({ filename }) =>
1235
- filename.split(/[/\\\\]/).includes("node_modules") ? undefined : true,
1236
- },
1237
- // No \`preprocess\`. vite-plugin-svelte 7 compiles \`<script lang="ts">\`
1238
- // itself, so \`vitePreprocess()\` is the no-op it looks like \u2014 \`sv create\`
1239
- // emits none either. Verified against a real build: components typecheck
1240
- // and compile without it.
1241
- //
1242
- // The deploy target is a static host with NO server runtime \u2014 Xano is the
1243
- // backend. Routes are PRERENDERED (see frontend/src/routes/+layout.ts):
1244
- // each becomes its own HTML file at build time, and the host resolves a URL
1245
- // to it by trying the exact key, then \`{path}.html\`, then
1246
- // \`{path}/index.html\`. That is why no \`trailingSlash\` is configured \u2014 both
1247
- // output shapes resolve, so this stays on SvelteKit's default.
1248
- //
1249
- // The SDK's adapter, writing to frontend/dist. Every prerendered route is
1250
- // its own file; a route that sets \`prerender = false\` (a detail page for
1251
- // rows created at runtime) has no file, so the host answers it with
1252
- // 404.html, which the adapter writes as the app shell whenever such a
1253
- // route exists: the shell boots the app and renders the route in the
1254
- // browser, so a reload or a deep link works. While every route is
1255
- // prerendered, 404.html stays the prerendered /404 page.
1256
- //
1257
- // Do not swap it for \`@sveltejs/adapter-static\` with a \`fallback\`: that
1258
- // writes the shell at index.html, over the prerendered home page.
1259
- //
1260
- // \`xanosdk deploy --static-env\` still finds its anchor: every document
1261
- // renders from app.html, so each has a <head> that gets the injected globals.
1262
- adapter: adapter({ out: "frontend/dist" }),
1263
- // Absolute asset URLs, pinned rather than left to the default. Prerendered
1264
- // pages live at varying URL depths, and a relative \`../_app/\u2026\` computed for
1265
- // one depth 404s at another.
1266
- paths: { relative: false },
1267
- prerender: {
1268
- // A hash link in the shared layout \u2014 \`<a href="#services">\`, the default
1269
- // shape of a one-page site's nav \u2014 renders into EVERY prerendered route,
1270
- // including the scaffold's own /404. There it resolves to /404#services,
1271
- // an anchor that by definition is not on that page, and SvelteKit's
1272
- // default handler THROWS: the vite build succeeds and the prerender pass
1273
- // after it kills the build, with a stack trace naming only files inside
1274
- // node_modules and a route the author never wrote.
1275
- //
1276
- // So ignore a missing id on /404 specifically, rather than reaching for a
1277
- // blanket \`handleMissingId: "warn"\`. A hash link that is genuinely broken
1278
- // on a real route still fails the build, which is the check worth keeping.
1279
- handleMissingId: ({ path, message }) => {
1280
- if (path === "/404") return;
1281
- throw new Error(message);
1282
- },
1283
- },
1284
- // SvelteKit's project layout, redirected under frontend/ so this stays a
1285
- // single-root project: one package.json, one tsconfig.json, and xano/
1286
- // sitting alongside as the backend half. NOTE these are what make
1287
- // frontend/src/routes the routes directory \u2014 a file added under a
1288
- // top-level src/routes/ is not a route and will not be served.
1289
- files: {
1290
- routes: "frontend/src/routes",
1291
- lib: "frontend/src/lib",
1292
- appTemplate: "frontend/src/app.html",
1293
- assets: "frontend/static",
1294
- },
1295
- })`;
1296
- }
1297
- function renderAppHtml({ appName }, choice) {
1298
- return `<!doctype html>
1299
- <html lang="en">
1300
- <head>
1301
- <meta charset="utf-8" />
1302
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
1303
- <title>${htmlText(appName)}</title>
1304
- ${renderThemeScript(choice.dark)}
1305
- <!-- Drop a favicon.png into frontend/static/ and link it here:
1306
- <link rel="icon" href="%sveltekit.assets%/favicon.png" />
1307
- Everything in that directory is copied to the site root verbatim. -->
1308
- <!-- Keep this inside <head>: \`xanosdk deploy --static-env\` injects the
1309
- backend URL here as a window global that frontend/src/lib/api.ts reads. -->
1310
- %sveltekit.head%
1311
- </head>
1312
- <body data-sveltekit-preload-data="hover">
1313
- <div style="display: contents">%sveltekit.body%</div>
1314
- </body>
1315
- </html>
1316
- `;
1317
- }
1318
- function renderModeToggleSvelte(icons) {
1319
- return `<script lang="ts">
1320
- ${icons.modeImports.join("\n ")}
1321
-
1322
- import { Button } from "$lib/components/ui/button/index.js";
1323
- import { getMode, setMode, watchMode, type Mode } from "$lib/theme.js";
1324
-
1325
- /** system \u2192 light \u2192 dark \u2192 system. */
1326
- const next: Record<Mode, Mode> = { system: "light", light: "dark", dark: "system" };
1327
-
1328
- const icons = {
1329
- system: ${icons.modeComponents.system},
1330
- light: ${icons.modeComponents.light},
1331
- dark: ${icons.modeComponents.dark},
1332
- };
1333
-
1334
- // Starts at "system" so the prerendered HTML is deterministic; the effect
1335
- // corrects it in the browser, after the inline script has already applied
1336
- // the right class.
1337
- let mode = $state<Mode>("system");
1338
-
1339
- $effect(() => {
1340
- mode = getMode();
1341
- return watchMode((m) => (mode = m));
1342
- });
1343
-
1344
- function change() {
1345
- const target = next[mode];
1346
- setMode(target);
1347
- mode = target;
1348
- }
1349
-
1350
- const Icon = $derived(icons[mode]);
1351
- </script>
1352
-
1353
- <Button variant="ghost" size="icon" onclick={change} aria-label="Switch to {next[mode]} theme">
1354
- <Icon />
1355
- </Button>
1356
- `;
1357
- }
1358
- function renderAppDts() {
1359
- return `// See https://svelte.dev/docs/kit/types#app.d.ts
1360
- declare global {
1361
- namespace App {
1362
- // interface Error {}
1363
- // interface Locals {}
1364
- // interface PageData {}
1365
- // interface PageState {}
1366
- // interface Platform {}
1367
- }
1368
- }
1533
+ const icons = iconLibraryOf(choice.icons).react;
1534
+ return `${icons.arrowImport}
1369
1535
 
1370
- export {};
1371
- `;
1372
- }
1373
- function renderLayoutTs() {
1374
- return `// There is no server. The backend is Xano, reached through $lib/api.ts,
1375
- // and \`npm run xano:deploy:ephemeral\` ships this app to a static host with no runtime.
1376
- //
1377
- // prerender: true \u2014 every route is rendered to its own HTML file AT BUILD TIME
1378
- // and served as a real document. That is what makes each page load as itself
1379
- // rather than as an empty shell that fills in afterwards.
1380
- //
1381
- // Prerendering IS server-rendering, just at build time rather than per request.
1382
- // So module-scope \`window\`/\`document\` access now fails the BUILD instead of the
1383
- // browser \u2014 which is the better place to find out. Reach for browser globals
1384
- // inside onMount, or guard with \`import { browser } from "$app/environment"\`.
1385
- //
1386
- // A route with dynamic segments (e.g. /posts/[id]) cannot be prerendered unless
1387
- // the build knows which ones exist, so THE BUILD FAILS and names the route.
1388
- // In that route's +page.ts, either list the ids (only those get a page):
1389
- //
1390
- // export const entries = () => [{ id: "1" }, { id: "2" }];
1391
- //
1392
- // or, for rows created at runtime, render it in the browser instead:
1393
- //
1394
- // export const prerender = false;
1395
- //
1396
- // Inherited by every route below this one.
1397
- export const prerender = true;
1398
- `;
1399
- }
1400
- function renderErrorState() {
1401
- return `<script lang="ts">
1402
- // Shared by the prerendered /404 route and +error.svelte.
1403
- let { status = 404, message = "" }: { status?: number; message?: string } = $props();
1404
- </script>
1405
-
1406
- <main class="grid min-h-screen place-items-center p-8">
1407
- <div class="max-w-md space-y-4 text-center">
1408
- <p class="text-6xl font-semibold tracking-tight">{status}</p>
1409
- <h1 class="text-xl font-medium">
1410
- {status === 404 ? "We can't find that page." : "Something went wrong."}
1411
- </h1>
1412
- <p class="text-muted-foreground text-sm">
1413
- {message !== "" ? message : "The link may be broken, or the page may have moved."}
1414
- </p>
1415
- <a
1416
- href="/"
1417
- class="bg-primary text-primary-foreground ring-offset-background focus-visible:ring-ring inline-flex h-10 items-center rounded-md px-5 text-sm font-medium transition-opacity hover:opacity-90 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
1418
- >
1419
- Back to safety
1420
- </a>
1421
- </div>
1422
- </main>
1423
- `;
1536
+ import { Button } from "@/components/ui/button";${toggle ? `
1537
+ import { ModeToggle } from "@/components/mode-toggle";` : ""}
1538
+ import {
1539
+ Card,
1540
+ CardContent,
1541
+ CardDescription,
1542
+ CardFooter,
1543
+ CardHeader,
1544
+ CardTitle,
1545
+ } from "@/components/ui/card";
1546
+
1547
+ export default function App() {
1548
+ return (
1549
+ <main className="mx-auto flex min-h-screen max-w-2xl flex-col justify-center p-8">${toggle ? `
1550
+ <div className="mb-4 flex justify-end">
1551
+ <ModeToggle />
1552
+ </div>` : ""}
1553
+ <Card>
1554
+ <CardHeader>
1555
+ <CardTitle className="text-3xl tracking-tight">${jsxText(landing.title)}</CardTitle>
1556
+ <CardDescription className="text-base">
1557
+ ${renderNodes(landing.lead)}
1558
+ </CardDescription>
1559
+ </CardHeader>
1560
+ <CardContent>
1561
+ <ol className="text-muted-foreground list-inside list-decimal space-y-2">
1562
+ ${steps}
1563
+ </ol>
1564
+ </CardContent>
1565
+ <CardFooter>
1566
+ {/* asChild renders the Button's styles onto the anchor. Components come
1567
+ from shadcn/ui \u2014 add more with \`npx shadcn@latest add <name>\`. */}
1568
+ <Button asChild>
1569
+ <a href="${landing.cta.href}" target="_blank" rel="noreferrer">
1570
+ ${jsxText(landing.cta.label)} <${icons.arrowComponent} />
1571
+ </a>
1572
+ </Button>
1573
+ </CardFooter>
1574
+ </Card>
1575
+ </main>
1576
+ );
1424
1577
  }
1425
- function renderNotFoundRoute() {
1426
- return `<script lang="ts">
1427
- // Prerendered to 404.html, which is what tells the static host to answer an
1428
- // unmatched path with a real 404 instead of quietly serving the app shell
1429
- // with a 200 (a missing asset would then reach the browser as HTML, which it
1430
- // reports as "Unexpected token '<'").
1431
- //
1432
- // It must be a route, not +error.svelte: SvelteKit never prerenders the error
1433
- // component to a file, so relying on it would ship no 404.html at all.
1434
- //
1435
- // Delete this directory and an unmatched path serves the home page with a 200
1436
- // instead \u2014 which is worse, not better, so keep it unless you have a reason.
1437
- import ErrorState from "$lib/components/error-state.svelte";
1438
- </script>
1439
-
1440
- <svelte:head>
1441
- <title>Page not found</title>
1442
- </svelte:head>
1443
-
1444
- <ErrorState status={404} />
1445
1578
  `;
1446
1579
  }
1447
- function renderErrorSvelte() {
1448
- return `<script lang="ts">
1449
- // Rendered when a client-side navigation or load fails inside the running
1450
- // app. The static host never sees these \u2014 for a path that matched no
1451
- // document at all, it serves the prerendered routes/404 page instead.
1452
- import { page } from "$app/state";
1453
- import ErrorState from "$lib/components/error-state.svelte";
1454
- </script>
1455
-
1456
- <svelte:head>
1457
- <title>{page.status === 404 ? "Page not found" : "Something went wrong"}</title>
1458
- </svelte:head>
1459
-
1460
- <ErrorState status={page.status} message={page.error?.message ?? ""} />
1461
- `;
1462
- }
1463
- function renderLayoutSvelte() {
1464
- return `<script lang="ts">
1465
- // The shared token stylesheet \u2014 semantic colors (bg-primary,
1466
- // text-muted-foreground) plus the Tailwind v4 theme. Imported once here so
1467
- // every route gets it.
1468
- import "../index.css";
1469
-
1470
- let { children } = $props();
1471
- </script>
1472
-
1473
- {@render children()}
1580
+ function renderMainTsx() {
1581
+ return `import { StrictMode } from "react";
1582
+ import { createRoot } from "react-dom/client";
1583
+ import App from "./App.js";
1584
+ import "./index.css";
1585
+
1586
+ createRoot(document.getElementById("root")!).render(
1587
+ <StrictMode>
1588
+ <App />
1589
+ </StrictMode>,
1590
+ );
1474
1591
  `;
1475
1592
  }
1476
1593
  function renderComponentsJson(choice) {
1477
1594
  const config = {
1478
- $schema: "https://shadcn-svelte.com/schema.json",
1595
+ $schema: "https://ui.shadcn.com/schema.json",
1596
+ style: "new-york",
1597
+ rsc: false,
1598
+ tsx: true,
1479
1599
  tailwind: {
1480
- // v4 has no config file; the theme lives in the stylesheet — the same
1481
- // shared one the React preset points at.
1600
+ // v4 has no config file; the theme lives in the stylesheet.
1601
+ config: "",
1482
1602
  css: "frontend/src/index.css",
1483
- // Tracks the theme the stylesheet was rendered from — see the React
1484
- // preset's note; the shadcn-svelte CLI reads it the same way.
1485
- baseColor: choice.theme.baseColor ?? "neutral"
1603
+ // The base color the scaffold's stylesheet was rendered from. The CLI
1604
+ // reads it for the few colors a generated component hard-codes rather
1605
+ // than tokenises, so a value that disagrees with index.css produces
1606
+ // components that clash with everything already there. An imported
1607
+ // registry theme belongs to no upstream base and falls back to neutral.
1608
+ baseColor: choice.theme.baseColor ?? "neutral",
1609
+ cssVariables: true,
1610
+ prefix: ""
1486
1611
  },
1487
1612
  aliases: {
1488
- components: "$lib/components",
1489
- utils: "$lib/utils",
1490
- ui: "$lib/components/ui",
1491
- hooks: "$lib/hooks",
1492
- lib: "$lib"
1613
+ components: "@/components",
1614
+ utils: "@/lib/utils",
1615
+ ui: "@/components/ui",
1616
+ lib: "@/lib",
1617
+ hooks: "@/hooks"
1493
1618
  },
1494
- typescript: true,
1495
- registry: "https://shadcn-svelte.com/registry"
1619
+ // Omitted entirely for a set the CLI does not know — writing an
1620
+ // unrecognised value would break `add` for every component, which is worse
1621
+ // than icons defaulting to lucide. See IconLibrary.componentsJson.
1622
+ ...iconLibraryOf(choice.icons).componentsJson === void 0 ? {} : { iconLibrary: iconLibraryOf(choice.icons).componentsJson }
1496
1623
  };
1497
1624
  return JSON.stringify(config, null, 2) + "\n";
1498
1625
  }
1499
- function renderButtonSvelte() {
1500
- return `<script lang="ts" module>
1501
- import { type VariantProps, tv } from "tailwind-variants";
1626
+ function renderButtonTsx() {
1627
+ return `import * as React from "react"
1628
+ import { cva, type VariantProps } from "class-variance-authority"
1629
+ import { cn } from "cn"
1630
+ import { Slot } from "radix-ui"
1502
1631
 
1503
- export const buttonVariants = tv({
1504
- base: "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1632
+ const buttonVariants = cva(
1633
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1634
+ {
1505
1635
  variants: {
1506
1636
  variant: {
1507
1637
  default: "bg-primary text-primary-foreground hover:bg-primary/90",
@@ -1509,503 +1639,344 @@ function renderButtonSvelte() {
1509
1639
  "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
1510
1640
  outline:
1511
1641
  "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
1512
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
1513
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
1642
+ secondary:
1643
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
1644
+ ghost:
1645
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
1514
1646
  link: "text-primary underline-offset-4 hover:underline",
1515
1647
  },
1516
1648
  size: {
1517
1649
  default: "h-9 px-4 py-2 has-[>svg]:px-3",
1650
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
1518
1651
  sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
1519
1652
  lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
1520
1653
  icon: "size-9",
1654
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
1655
+ "icon-sm": "size-8",
1656
+ "icon-lg": "size-10",
1521
1657
  },
1522
1658
  },
1523
1659
  defaultVariants: {
1524
1660
  variant: "default",
1525
1661
  size: "default",
1526
1662
  },
1527
- });
1528
-
1529
- export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
1530
- export type ButtonSize = VariantProps<typeof buttonVariants>["size"];
1531
-
1532
- export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
1533
- WithElementRef<HTMLAnchorAttributes> & {
1534
- variant?: ButtonVariant;
1535
- size?: ButtonSize;
1536
- };
1537
- </script>
1538
-
1539
- <script lang="ts">
1540
- import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements";
1541
- import type { WithElementRef } from "bits-ui";
1542
- import { cn } from "$lib/utils.js";
1543
-
1544
- let {
1545
- class: className,
1546
- variant = "default",
1547
- size = "default",
1548
- ref = $bindable(null),
1549
- href = undefined,
1550
- type = "button",
1551
- children,
1552
- ...restProps
1553
- }: ButtonProps = $props();
1554
- </script>
1555
-
1556
- {#if href}
1557
- <a
1558
- bind:this={ref}
1559
- data-slot="button"
1560
- class={cn(buttonVariants({ variant, size }), className)}
1561
- {href}
1562
- {...restProps}
1563
- >
1564
- {@render children?.()}
1565
- </a>
1566
- {:else}
1567
- <button
1568
- bind:this={ref}
1569
- data-slot="button"
1570
- class={cn(buttonVariants({ variant, size }), className)}
1571
- {type}
1572
- {...restProps}
1573
- >
1574
- {@render children?.()}
1575
- </button>
1576
- {/if}
1663
+ }
1664
+ )
1665
+
1666
+ function Button({
1667
+ className,
1668
+ variant = "default",
1669
+ size = "default",
1670
+ asChild = false,
1671
+ ...props
1672
+ }: React.ComponentProps<"button"> &
1673
+ VariantProps<typeof buttonVariants> & {
1674
+ asChild?: boolean
1675
+ }) {
1676
+ const Comp = asChild ? Slot.Root : "button"
1677
+
1678
+ return (
1679
+ <Comp
1680
+ data-slot="button"
1681
+ data-variant={variant}
1682
+ data-size={size}
1683
+ className={cn(buttonVariants({ variant, size, className }))}
1684
+ {...props}
1685
+ />
1686
+ )
1687
+ }
1688
+
1689
+ export { Button, buttonVariants }
1577
1690
  `;
1578
1691
  }
1579
- function renderButtonIndex() {
1580
- return `export {
1581
- default as Button,
1582
- buttonVariants,
1583
- type ButtonProps,
1584
- type ButtonSize,
1585
- type ButtonVariant,
1586
- } from "./button.svelte";
1587
- `;
1692
+ function renderModeToggleTsx(icons) {
1693
+ return `import { useEffect, useState } from "react";
1694
+ ${icons.modeImports.join("\n")}
1695
+
1696
+ import { Button } from "@/components/ui/button";
1697
+ import { getMode, setMode, watchMode, type Mode } from "@/lib/theme";
1698
+
1699
+ /** system \u2192 light \u2192 dark \u2192 system. */
1700
+ const NEXT: Record<Mode, Mode> = { system: "light", light: "dark", dark: "system" };
1701
+
1702
+ const ICON = {
1703
+ system: ${icons.modeComponents.system},
1704
+ light: ${icons.modeComponents.light},
1705
+ dark: ${icons.modeComponents.dark},
1706
+ };
1707
+
1708
+ export function ModeToggle() {
1709
+ // Read on mount, not during render: the inline script in index.html has
1710
+ // already applied the class, and touching localStorage while rendering would
1711
+ // break if this component is ever server-rendered.
1712
+ const [mode, setLocal] = useState<Mode>("system");
1713
+ useEffect(() => {
1714
+ setLocal(getMode());
1715
+ return watchMode(setLocal);
1716
+ }, []);
1717
+
1718
+ const Icon = ICON[mode];
1719
+ const change = () => {
1720
+ const next = NEXT[mode];
1721
+ setMode(next);
1722
+ setLocal(next);
1723
+ };
1724
+
1725
+ return (
1726
+ <Button variant="ghost" size="icon" onClick={change} aria-label={\`Switch to \${NEXT[mode]} theme\`}>
1727
+ <Icon />
1728
+ </Button>
1729
+ );
1588
1730
  }
1589
- function cardPart(slot, tag, classes) {
1590
- return `<script lang="ts">
1591
- import type { HTMLAttributes } from "svelte/elements";
1592
- import type { WithElementRef } from "bits-ui";
1593
- import { cn } from "$lib/utils.js";
1594
-
1595
- let {
1596
- class: className,
1597
- ref = $bindable(null),
1598
- children,
1599
- ...restProps
1600
- }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
1601
- </script>
1602
-
1603
- <${tag}
1604
- bind:this={ref}
1605
- data-slot="${slot}"
1606
- class={cn("${classes}", className)}
1607
- {...restProps}
1608
- >
1609
- {@render children?.()}
1610
- </${tag}>
1611
1731
  `;
1612
1732
  }
1613
- function renderCardIndex() {
1614
- return `import Root from "./card.svelte";
1615
- import Content from "./card-content.svelte";
1616
- import Description from "./card-description.svelte";
1617
- import Footer from "./card-footer.svelte";
1618
- import Header from "./card-header.svelte";
1619
- import Title from "./card-title.svelte";
1733
+ function renderCardTsx() {
1734
+ return `import * as React from "react"
1735
+ import { cn } from "cn"
1736
+
1737
+ function Card({ className, ...props }: React.ComponentProps<"div">) {
1738
+ return (
1739
+ <div
1740
+ data-slot="card"
1741
+ className={cn(
1742
+ "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm",
1743
+ className
1744
+ )}
1745
+ {...props}
1746
+ />
1747
+ )
1748
+ }
1749
+
1750
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
1751
+ return (
1752
+ <div
1753
+ data-slot="card-header"
1754
+ className={cn(
1755
+ "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
1756
+ className
1757
+ )}
1758
+ {...props}
1759
+ />
1760
+ )
1761
+ }
1762
+
1763
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
1764
+ return (
1765
+ <div
1766
+ data-slot="card-title"
1767
+ className={cn("leading-none font-semibold", className)}
1768
+ {...props}
1769
+ />
1770
+ )
1771
+ }
1772
+
1773
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
1774
+ return (
1775
+ <div
1776
+ data-slot="card-description"
1777
+ className={cn("text-sm text-muted-foreground", className)}
1778
+ {...props}
1779
+ />
1780
+ )
1781
+ }
1782
+
1783
+ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
1784
+ return (
1785
+ <div
1786
+ data-slot="card-action"
1787
+ className={cn(
1788
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
1789
+ className
1790
+ )}
1791
+ {...props}
1792
+ />
1793
+ )
1794
+ }
1795
+
1796
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
1797
+ return (
1798
+ <div
1799
+ data-slot="card-content"
1800
+ className={cn("px-6", className)}
1801
+ {...props}
1802
+ />
1803
+ )
1804
+ }
1805
+
1806
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
1807
+ return (
1808
+ <div
1809
+ data-slot="card-footer"
1810
+ className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
1811
+ {...props}
1812
+ />
1813
+ )
1814
+ }
1620
1815
 
1621
1816
  export {
1622
- Root,
1623
- Content,
1624
- Description,
1625
- Footer,
1626
- Header,
1627
- Title,
1628
- //
1629
- Root as Card,
1630
- Content as CardContent,
1631
- Description as CardDescription,
1632
- Footer as CardFooter,
1633
- Header as CardHeader,
1634
- Title as CardTitle,
1635
- };
1817
+ Card,
1818
+ CardHeader,
1819
+ CardFooter,
1820
+ CardTitle,
1821
+ CardAction,
1822
+ CardDescription,
1823
+ CardContent,
1824
+ }
1636
1825
  `;
1637
1826
  }
1638
- var sveltePreset = {
1639
- id: "svelte",
1640
- label: "SvelteKit",
1827
+ var reactPreset = {
1828
+ id: "react",
1829
+ label: "React + Vite",
1641
1830
  dependencies: {
1642
- // shadcn-svelte's runtime surface. `bits-ui` is the headless primitive
1643
- // library its components are built on (the Radix equivalent), and
1644
- // `tailwind-variants` types the variants (the cva equivalent). clsx +
1645
- // tailwind-merge back the `cn()` its components import from `$lib/utils`.
1646
- // Pre-installed so `npx shadcn-svelte@latest add <component>` works
1647
- // without a separate npm i.
1831
+ // shadcn/ui's runtime surface. `radix-ui` is the unified primitives
1832
+ // package current components import (`Slot.Root` powers `asChild`) — not
1833
+ // the per-primitive `@radix-ui/react-*` packages, which it superseded.
1834
+ // cva types the variants, and `cn` is shadcn's own class merger, which its
1835
+ // components import directly (it replaced clsx + tailwind-merge upstream).
1836
+ // Pre-installed so `npx shadcn@latest add <component>` works without a
1837
+ // separate npm i.
1648
1838
  //
1649
- // The icon package is `--icons`, merged in by renderPackageJson from
1650
- // `iconBinding` below — see the React preset's note.
1651
- "bits-ui": "^2.18.1",
1652
- clsx: "^2.1.1",
1653
- "tailwind-merge": "^3.0.1",
1654
- "tailwind-variants": "^3.3.1"
1839
+ // The icon package is deliberately absent: it is `--icons`, merged in by
1840
+ // renderPackageJson from `iconBinding` below. Naming lucide here too would
1841
+ // install it alongside whatever the user actually chose.
1842
+ "class-variance-authority": "^0.7.1",
1843
+ cn: "^0.4.0",
1844
+ "radix-ui": "^1.6.7",
1845
+ react: "^19.1.0",
1846
+ "react-dom": "^19.1.0"
1655
1847
  },
1656
1848
  devDependencies: {
1657
- // The SDK's adapter (`@xano/sdk/sveltekit`) bundles its server half with
1658
- // esbuild; Vite 8 does not install it.
1659
- esbuild: "^0.28.1",
1660
- // 2.70 peer-accepts vite ^8 and vite-plugin-svelte ^7 — the versions
1661
- // pinned below. Bump this line and those two together.
1662
- "@sveltejs/kit": "^2.70.2",
1663
- // 7.x, matching what `sv create` installs. It peer-requires vite ^8, so
1664
- // this line and the `vite` pin move together or not at all — and the React
1665
- // preset's plugin has the same constraint, which is why the two presets
1666
- // share one Vite major rather than each choosing.
1667
- "@sveltejs/vite-plugin-svelte": "^7.1.2",
1668
1849
  "@tailwindcss/vite": "^4.1.5",
1669
1850
  "@types/node": "^20.19.43",
1670
- svelte: "^5.56.9",
1671
- "svelte-check": "^4.7.6",
1851
+ "@types/react": "^19.1.0",
1852
+ "@types/react-dom": "^19.1.0",
1853
+ // 6.x, which peer-requires vite ^8 — the same constraint the Svelte
1854
+ // preset's plugin has, which is why both presets share one Vite major.
1855
+ // Its `@rolldown/plugin-babel` and `babel-plugin-react-compiler` peers are
1856
+ // OPTIONAL (they back the React Compiler path, which this scaffold does
1857
+ // not enable), so neither is shipped: verified by a clean install with no
1858
+ // unmet-peer warnings.
1859
+ "@vitejs/plugin-react": "^6.0.5",
1672
1860
  tailwindcss: "^4.1.5",
1673
1861
  "tw-animate-css": "^1.2.4",
1674
1862
  tsx: "^4.19.2",
1675
- // 6.x, the major `sv create` pins. svelte-check peer-accepts `^5 || ^6`;
1676
- // 7 is out but not yet in that range, so this tracks the canonical
1677
- // scaffold rather than latest.
1863
+ // Kept in step with the Svelte preset — the major `sv create` pins. 7 is
1864
+ // out, but svelte-check's peer range stops at 6 and the two presets track
1865
+ // one TypeScript major so the shared tsconfig means the same thing in both.
1678
1866
  typescript: "^6.0.3",
1679
1867
  vite: "^8.0.16"
1680
1868
  },
1681
- // svelte-check REPLACES `tsc --noEmit` here rather than joining it.
1682
- //
1683
- // It is a superset: reading the same tsconfig, it checks `xano/`'s TypeScript
1684
- // exactly as `tsc` would AND the components `tsc` cannot parse at all. Running
1685
- // both is not merely redundant — `tsc` fails outright on the UI kit's barrels,
1686
- // which re-export types from `.svelte` modules it only knows as default
1687
- // exports. Verified against a real scaffold: a type error planted in
1688
- // `xano/index.ts` and one planted in `App.svelte` are each caught by this
1689
- // command alone.
1690
- //
1691
- // `svelte-kit sync` runs first, and is not optional: it generates
1692
- // `.svelte-kit/tsconfig.json` (which the project's tsconfig extends) and the
1693
- // route types. Without it svelte-check fails on a missing extends target
1694
- // rather than on anything the user wrote.
1695
- checkCmd: "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
1696
- // SvelteKit supplies `$lib` on both sides — the Vite alias from its plugin
1697
- // and the tsconfig path from the config it generates. Declaring either by
1698
- // hand would be a second source of truth that can silently disagree.
1699
- aliasName: null,
1700
- aliasTarget: "frontend/src/lib",
1701
- tsconfigPaths: {},
1702
- tsconfigExtends: "./.svelte-kit/tsconfig.json",
1703
- // What `svelte-kit sync` generates and the extended config lists — re-added
1704
- // because our `include` replaces that config's rather than merging with it.
1705
- // These are the declarations behind `$app/*`, `$env/*`, and `./$types`.
1706
- tsconfigInclude: [
1707
- ".svelte-kit/ambient.d.ts",
1708
- ".svelte-kit/env.d.ts",
1709
- ".svelte-kit/non-ambient.d.ts",
1710
- ".svelte-kit/types/**/$types.d.ts"
1711
- ],
1712
- // `prepare` runs on `npm install`, so a fresh clone has `.svelte-kit/`
1713
- // before anything reads tsconfig.json.
1714
- extraScripts: { prepare: "svelte-kit sync" },
1715
- // shadcn-svelte's generated components import these from `$lib/utils.js`
1716
- // alongside `cn()`. Without them the scaffold type-checks until the first
1717
- // `npx shadcn-svelte@latest add <name>` — which the agent guidance tells
1718
- // assistants to run — and then fails inside components the user never wrote,
1719
- // with an error naming a file they have no reason to suspect.
1720
- //
1721
- // Verbatim from shadcn-svelte's own utils.ts, so a component the CLI writes
1722
- // resolves against exactly what upstream expects.
1723
- libUtilsExtra: `
1724
- export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
1725
- export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
1726
- export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
1727
- export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
1728
- `,
1729
- gitignoreEntries: [".svelte-kit/"],
1730
- // No `jsx`. `verbatimModuleSyntax` is what svelte-check expects so that
1731
- // type-only imports in components are erased rather than emitted.
1732
- tsconfigOptions: { verbatimModuleSyntax: true },
1869
+ // `tsc` checks .tsx natively, so React needs nothing beyond it.
1870
+ checkCmd: "tsc --noEmit",
1871
+ aliasName: "@",
1872
+ aliasTarget: "frontend/src",
1873
+ // `./`-rooted: with no `baseUrl` (deprecated in TypeScript 6), a `paths`
1874
+ // target resolves against tsconfig.json's own directory.
1875
+ tsconfigPaths: { "@/*": ["./frontend/src/*"] },
1876
+ tsconfigOptions: { jsx: "react-jsx" },
1733
1877
  viteImports: [
1734
- `import { sveltekit } from "@sveltejs/kit/vite";`,
1735
- `import adapter from "@xano/sdk/sveltekit";`,
1878
+ `import react from "@vitejs/plugin-react";`,
1736
1879
  `import tailwindcss from "@tailwindcss/vite";`
1737
1880
  ],
1738
- // tailwindcss() before sveltekit() — the order Tailwind v4 documents for
1739
- // SvelteKit, so the stylesheet is processed before Kit consumes the graph.
1740
- //
1741
- // The whole SvelteKit config rides in the sveltekit() call. There is no
1742
- // svelte.config.js by design — see renderSvelteKitPlugin().
1743
- vitePlugins: ["tailwindcss()", renderSvelteKitPlugin()],
1744
- // SvelteKit resolves its own paths from this file's directory and redirects
1745
- // them into frontend/ via `files`; moving Vite's root under it puts the two
1746
- // into disagreement. Output is the adapter's job, not `build.outDir`.
1747
- viteRoot: null,
1748
- viteBuild: null,
1749
- // SvelteKit owns the page template — frontend/src/app.html. No `entryScript`
1750
- // follows: there is no shared index.html for it to point at.
1751
- ownsHtmlEntry: true,
1752
- files(vars, landing, choice = defaultThemeChoice()) {
1753
- const ui = "frontend/src/lib/components/ui";
1881
+ vitePlugins: ["react()", "tailwindcss()"],
1882
+ entryScript: "/src/main.tsx",
1883
+ libUtils: `export { cn, type ClassValue } from "cn";
1884
+ `,
1885
+ files(_vars, landing, choice = defaultThemeChoice()) {
1754
1886
  return [
1887
+ // The shadcn/ui CLI's config — lets `npx shadcn@latest add <component>`
1888
+ // work in a fresh scaffold without a separate `shadcn init`.
1755
1889
  { path: "components.json", content: renderComponentsJson(choice) },
1756
- { path: "frontend/src/app.html", content: renderAppHtml(vars, choice) },
1757
- // Only for `--dark toggle` — see the React preset's note.
1890
+ { path: "frontend/src/main.tsx", content: renderMainTsx() },
1891
+ { path: "frontend/src/App.tsx", content: renderApp(landing, choice) },
1892
+ // Only for `--dark toggle`. `system` needs no component: the inline
1893
+ // script in index.html is the whole implementation.
1758
1894
  ...choice.dark === "toggle" ? [
1759
1895
  {
1760
- path: "frontend/src/lib/components/mode-toggle.svelte",
1761
- content: renderModeToggleSvelte(iconLibraryOf(choice.icons).svelte)
1896
+ path: "frontend/src/components/mode-toggle.tsx",
1897
+ content: renderModeToggleTsx(iconLibraryOf(choice.icons).react)
1762
1898
  }
1763
1899
  ] : [],
1764
- { path: "frontend/src/app.d.ts", content: renderAppDts() },
1765
- { path: "frontend/src/routes/+layout.ts", content: renderLayoutTs() },
1766
- { path: "frontend/src/routes/+layout.svelte", content: renderLayoutSvelte() },
1767
- { path: "frontend/src/routes/+page.svelte", content: renderApp(landing, choice) },
1768
- { path: "frontend/src/routes/+error.svelte", content: renderErrorSvelte() },
1769
- { path: "frontend/src/routes/404/+page.svelte", content: renderNotFoundRoute() },
1770
- { path: "frontend/src/lib/components/error-state.svelte", content: renderErrorState() },
1771
- // `kit.files.assets` points here: static files copied to the site root
1772
- // verbatim. A README rather than a .gitkeep because this one gets
1773
- // PUBLISHED — everything here lands in frontend/dist, so the placeholder
1774
- // that keeps the directory in git is a file real users will see deployed.
1775
- {
1776
- path: "frontend/static/README.md",
1777
- content: `Files here are copied to the site root as-is \u2014 \`favicon.png\` is served
1778
- at \`/favicon.png\`. Reference them from a component with a root-relative
1779
- path, or from \`app.html\` via \`%sveltekit.assets%\`.
1780
-
1781
- Delete this file once you add something real.
1782
- `
1783
- },
1784
- { path: `${ui}/button/button.svelte`, content: renderButtonSvelte() },
1785
- { path: `${ui}/button/index.ts`, content: renderButtonIndex() },
1786
- {
1787
- path: `${ui}/card/card.svelte`,
1788
- content: cardPart(
1789
- "card",
1790
- "div",
1791
- "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm"
1792
- )
1793
- },
1794
- {
1795
- path: `${ui}/card/card-header.svelte`,
1796
- content: cardPart(
1797
- "card-header",
1798
- "div",
1799
- "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6"
1800
- )
1801
- },
1802
- {
1803
- path: `${ui}/card/card-title.svelte`,
1804
- content: cardPart("card-title", "div", "leading-none font-semibold")
1805
- },
1806
- {
1807
- path: `${ui}/card/card-description.svelte`,
1808
- content: cardPart("card-description", "div", "text-sm text-muted-foreground")
1809
- },
1810
- {
1811
- path: `${ui}/card/card-content.svelte`,
1812
- content: cardPart("card-content", "div", "px-6")
1813
- },
1814
- {
1815
- path: `${ui}/card/card-footer.svelte`,
1816
- content: cardPart("card-footer", "div", "flex items-center px-6 [.border-t]:pt-6")
1817
- },
1818
- { path: `${ui}/card/index.ts`, content: renderCardIndex() }
1900
+ // The two components the landing page uses. Every other shadcn component
1901
+ // is one `npx shadcn@latest add` away and lands beside these.
1902
+ { path: "frontend/src/components/ui/button.tsx", content: renderButtonTsx() },
1903
+ { path: "frontend/src/components/ui/card.tsx", content: renderCardTsx() }
1819
1904
  ];
1820
1905
  },
1821
1906
  iconBinding(id) {
1822
- return iconLibraryOf(id).svelte;
1907
+ return iconLibraryOf(id).react;
1823
1908
  },
1824
1909
  readmeFrontendSection(icons) {
1825
- return `[SvelteKit](https://svelte.dev/docs/kit) with Svelte 5, styled with
1826
- [Tailwind CSS](https://tailwindcss.com) v4 and
1827
- [shadcn-svelte](https://shadcn-svelte.com).
1828
-
1829
- Pages live in [\`frontend/src/routes/\`](frontend/src/routes/) \u2014 \`+page.svelte\`
1830
- is a page, a subdirectory is a nested route. Routes are **prerendered**: each
1831
- becomes its own HTML document at build time, so a page loads as itself rather
1832
- than as a shell that fills in afterwards, and an unmatched path returns a real
1833
- 404 from [\`+error.svelte\`](frontend/src/routes/+error.svelte).
1834
-
1835
- > **There is no server.** \`npm run xano:deploy:ephemeral\` ships this app to a static host
1836
- > with no runtime of its own; Xano is the backend, reached through
1837
- > [\`frontend/src/lib/api.ts\`](frontend/src/lib/api.ts). So \`+page.server.ts\`,
1838
- > form actions, and server \`load\` have nothing to run on \u2014 and **nothing warns
1839
- > you**: a project using them builds and deploys green, then fails in the
1840
- > browser. Treat them as unavailable. That is the trade \u2014 the backend is
1841
- > authored in [\`xano/\`](xano/) as TypeScript and deployed alongside the
1842
- > frontend, so it is a real backend, just not this one.
1843
- >
1844
- > \`frontend/src/routes/+layout.ts\` sets \`prerender = true\` for the whole app.
1845
- > Because prerendering renders at build time, module-scope \`window\`/\`document\`
1846
- > access now fails the **build** rather than the browser \u2014 use \`onMount\`, or
1847
- > guard with \`import { browser } from "$app/environment"\`.
1848
-
1849
- **A dynamic route fails the build until it says how it renders.** A route like
1850
- \`/posts/[id]\` cannot be prerendered unless the build knows which ids exist, so
1851
- the build stops and names it. For rows created at runtime (the usual detail
1852
- page), render it in the browser:
1853
-
1854
- \`\`\`ts
1855
- // frontend/src/routes/posts/[id]/+page.ts
1856
- export const prerender = false;
1857
- \`\`\`
1858
-
1859
- The host has no file for \`/posts/42\`, so it answers with \`404.html\`, which the
1860
- SDK's adapter (\`@xano/sdk/sveltekit\`, in \`vite.config.ts\`) writes as the app
1861
- shell: it boots the app and renders the route, so a reload or a deep link works
1862
- (the response status is still 404). Only for ids known at build time, list them
1863
- instead \u2014 each gets its own page, and no other id has one:
1864
- \`export const entries = () => [{ id: "1" }, { id: "2" }];\`
1865
-
1866
- [\`frontend/src/routes/404/+page.svelte\`](frontend/src/routes/404/+page.svelte)
1867
- prerenders to \`404.html\` while every route is prerendered, which is what makes
1868
- an unmatched path return a real 404. It has to be a route: SvelteKit never
1869
- prerenders \`+error.svelte\` to a file. Once a route sets \`prerender = false\`,
1870
- the adapter writes the app shell there instead, and an unmatched path renders
1871
- \`+error.svelte\` in the browser, still with a 404.
1872
-
1873
- shadcn-svelte is not a dependency \u2014
1874
- its components are copied into
1875
- [\`frontend/src/lib/components/ui/\`](frontend/src/lib/components/ui/) and owned by
1876
- this project, so edit them freely. \`Button\` and \`Card\` are already there; add
1877
- more with:
1910
+ return `React + Vite, styled with [Tailwind CSS](https://tailwindcss.com) v4 and
1911
+ [shadcn/ui](https://ui.shadcn.com). shadcn is not a dependency \u2014 its components
1912
+ are copied into [\`frontend/src/components/ui/\`](frontend/src/components/ui/) and
1913
+ owned by this project, so edit them freely. \`Button\` and \`Card\` are already
1914
+ there; add more with:
1878
1915
 
1879
1916
  \`\`\`bash
1880
- npx shadcn-svelte@latest add dialog input form
1917
+ npx shadcn@latest add dialog input form
1881
1918
  \`\`\`
1882
1919
 
1883
1920
  [\`components.json\`](components.json) is pre-configured, so that works with no
1884
- \`shadcn-svelte init\` step. ${iconLibraryOf(icons).guidance.svelte}
1921
+ \`shadcn init\` step. ${iconLibraryOf(icons).guidance.react}
1922
+ [\`frontend/src/App.tsx\`](frontend/src/App.tsx) already uses one.
1885
1923
 
1886
- \`\`\`ts
1887
- ${iconLibraryOf(icons).svelte.arrowImport}
1888
- \`\`\`
1889
-
1890
- [\`frontend/src/routes/+page.svelte\`](frontend/src/routes/+page.svelte) already
1891
- does, and that is the form \`npx shadcn-svelte@latest add\` writes too.
1892
-
1893
- Components import through the \`$lib\` alias
1894
- (\`$lib/components/ui/button\`, \`$lib/utils\`), which SvelteKit points at
1895
- \`frontend/src/lib/\` via \`kit.files\` in
1896
- [\`vite.config.ts\`](vite.config.ts) \u2014 there is no \`paths\` entry to keep in
1897
- sync, and adding one would just be a second answer that can disagree.
1924
+ Components import through the \`@/\` alias (\`@/components/ui/button\`), which
1925
+ maps to \`frontend/src/\` in both \`tsconfig.json\` and \`vite.config.ts\` \u2014 change
1926
+ one and change the other. \`cn()\` comes from shadcn's \`cn\` package, which is
1927
+ what the CLI writes into every component it adds.
1898
1928
 
1899
1929
  Colors come from the theme tokens in
1900
- [\`frontend/src/index.css\`](frontend/src/index.css) \u2014 see **Theming** below.
1901
-
1902
- > \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, not \`tsc\`. It
1903
- > checks both halves \u2014 the backend's TypeScript and the components \u2014 where
1904
- > \`tsc\` cannot read \`.svelte\` files at all. Keep it in the script: it is what
1905
- > makes the frontend unable to drift from the backend defs. \`sync\` regenerates
1906
- > \`.svelte-kit/\`, which \`tsconfig.json\` extends; \`npm install\` runs it too.`;
1930
+ [\`frontend/src/index.css\`](frontend/src/index.css) \u2014 see **Theming** below.`;
1907
1931
  },
1908
1932
  agentGuidanceSection(icons) {
1909
- return `- \`frontend/src/\` \u2014 the SvelteKit app. Svelte 5 + Tailwind v4 + shadcn-svelte.
1910
- - **There is no server.** This deploys to a static host with no runtime, and
1911
- Xano is the backend. Never write \`+page.server.ts\`, \`+layout.server.ts\`,
1912
- form actions, or server \`load\` \u2014 reach the backend through
1913
- \`frontend/src/lib/api.ts\` instead, and never stand up a second backend here.
1914
- - **The build will not stop you.** A project containing \`+page.server.ts\`
1915
- compiles and deploys green, then fails in the browser on the live site. A
1916
- passing build is not evidence that a server feature works \u2014 there is
1917
- nothing to run it.
1918
- - \`frontend/src/routes/\` \u2014 file-based routing. A page is \`+page.svelte\`, a
1919
- nested route is a subdirectory. **Routes live under \`frontend/src/\`, not a
1920
- top-level \`src/\`** \u2014 \`files\` in the \`sveltekit()\` plugin config in
1921
- \`vite.config.ts\` points SvelteKit here. A file added under a top-level
1922
- \`src/routes/\` is not a route and is never served.
1923
- - **Routes are prerendered.** \`frontend/src/routes/+layout.ts\` sets
1924
- \`prerender = true\` for the whole app, so every route is rendered to its own
1925
- HTML document at build time and served as a real page. A static route needs
1926
- nothing registered \u2014 add \`+page.svelte\` and it works.
1927
- - **Prerendering renders at BUILD time**, so module-scope \`window\`/\`document\`
1928
- access now breaks the build, not the browser. Use \`onMount\`, or guard with
1929
- \`import { browser } from "$app/environment"\`. This is a page option, not a
1930
- server \u2014 do not "fix" it by reaching for \`ssr\` or a server file.
1931
- - **A dynamic route fails the build until it says how it renders.**
1932
- \`/posts/[id]\` cannot be prerendered unless the build knows which ids exist.
1933
- For rows created at runtime (a detail page), export
1934
- \`const prerender = false\` from that route's \`+page.ts\`: the host answers
1935
- it with the \`404.html\` app shell the SDK's adapter writes, which renders it
1936
- in the browser, so reloads and deep links work. \`entries\` only fits ids
1937
- known at build time \u2014 any other id has no page.
1938
- - \`frontend/src/routes/404/+page.svelte\` prerenders to \`404.html\`, which is
1939
- what makes an unmatched path return a real 404 instead of silently serving a
1940
- page with a 200. Keep it: without it a missing asset comes back as HTML and
1941
- the browser reports \`Unexpected token '<'\`. It has to be a route \u2014 SvelteKit
1942
- never prerenders \`+error.svelte\` to a file, so that alone would ship no
1943
- \`404.html\`.
1944
- - Keep the adapter in \`vite.config.ts\` (\`@xano/sdk/sveltekit\`). Do NOT
1945
- swap in \`@sveltejs/adapter-static\` with a \`fallback\`: it writes an empty
1946
- shell over the prerendered home page.
1947
- - Data loading: call \`api.ts\` from the component, or from a universal
1948
- \`+page.ts\` \`load\` if you need it before render. Both run in the browser.
1949
- - \`frontend/src/lib/components/ui/\` \u2014 shadcn-svelte components, **copied in and
1950
- owned by this project**. Edit them directly; there is no library to configure
1951
- around.
1952
- - Need one that isn't there? \`npx shadcn-svelte@latest add <name>\` \u2014 do not
1953
- hand-roll it, and do not add a different component library. Note the
1954
- \`-svelte\` suffix: the plain \`shadcn\` CLI writes React and will not work here.
1955
- - ${iconLibraryOf(icons).guidance.svelte.replace(/\n/g, "\n ")}
1956
- - That import form is what \`frontend/src/routes/+page.svelte\` already uses and
1957
- what \`npx shadcn-svelte@latest add\` writes, so matching it keeps what you
1958
- write consistent with what the CLI generates beside it. Do not add another
1959
- icon library and do not paste raw inline \`<svg>\` markup.
1960
- - Import via the \`$lib\` alias (\`$lib/components/ui/button\`, \`$lib/utils\`),
1961
- which SvelteKit generates for both TypeScript and the bundler. Do not add a
1962
- \`paths\` entry for it \u2014 a hand-written one is a second source of truth that
1963
- can disagree with the generated one.
1964
- - Components are Svelte 5 **runes** (\`$props()\`, \`$bindable()\`,
1965
- \`{@render children?.()}\`) \u2014 not the Svelte 4 \`export let\` / slot API. Runes
1966
- mode is FORCED in \`vite.config.ts\`, so \`export let\` is a compile error
1967
- naming the file rather than a component that quietly builds in legacy mode.
1968
- Do not "fix" that error by relaxing \`compilerOptions.runes\` \u2014 write the
1969
- rune.
1970
- - \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, which checks both
1971
- \`xano/\` and the components. Do not swap it for \`tsc --noEmit\`: \`tsc\` cannot
1972
- read \`.svelte\` files and fails on the UI kit's barrels. \`sync\` regenerates
1973
- \`.svelte-kit/\`, which \`tsconfig.json\` extends \u2014 run it after adding a route.`;
1933
+ return `- \`frontend/src/\` \u2014 the React app. Tailwind v4 + shadcn/ui.
1934
+ - \`frontend/src/components/ui/\` \u2014 shadcn components, **copied in and owned by
1935
+ this project**. Edit them directly; there is no library to configure around.
1936
+ - Need one that isn't there? \`npx shadcn@latest add <name>\` \u2014 do not hand-roll
1937
+ it, and do not add a different component library.
1938
+ - ${iconLibraryOf(icons).guidance.react.replace(/\n/g, "\n ")}
1939
+ \`frontend/src/App.tsx\` already uses one. Do not add another icon library and
1940
+ do not paste raw inline \`<svg>\` markup \u2014 search the set before concluding an
1941
+ icon is missing.
1942
+ - Import via the \`@/\` alias (\`@/components/ui/button\`), declared in both
1943
+ \`tsconfig.json\` and \`vite.config.ts\`. \`cn()\` is \`import { cn } from "cn"\`
1944
+ (shadcn's own package, which the CLI writes into every component it adds);
1945
+ \`@/lib/utils\` re-exports it. Leave a generated component's imports as the
1946
+ CLI wrote them.
1947
+ - \`npx shadcn@latest add sonner\` writes a \`Toaster\` that reads the mode from
1948
+ \`next-themes\`, which this project does not use. Drop that import and
1949
+ uninstall \`next-themes\`, then pass \`theme\` from the project's own mode:
1950
+ \`getMode()\` + \`watchMode()\` from \`@/lib/theme\` when that module exists,
1951
+ otherwise \`"system"\` (or \`"light"\` if nothing applies the \`dark\` class).`;
1974
1952
  }
1975
1953
  };
1976
1954
 
1977
- // src/emit/frontend-presets.ts
1978
- var FRAMEWORKS = ["react", "svelte"];
1979
- var DEFAULT_FRAMEWORK = "react";
1980
- var PRESETS = {
1981
- react: reactPreset,
1982
- svelte: sveltePreset
1983
- };
1984
- function findFrontendPreset(id) {
1985
- const normalized = id.trim().toLowerCase();
1986
- return FRAMEWORKS.includes(normalized) ? PRESETS[normalized] : void 0;
1987
- }
1988
- function allFrontendPresets() {
1989
- return FRAMEWORKS.map((id) => PRESETS[id]);
1990
- }
1991
- function resolveFrameworkFlag(raw) {
1992
- const preset = findFrontendPreset(raw);
1993
- if (preset === void 0) {
1994
- throw new Error(
1995
- `Unknown --framework "${raw}". Valid frameworks: ${FRAMEWORKS.join(", ")}.`
1996
- );
1997
- }
1998
- return preset;
1999
- }
2000
-
2001
1955
  export {
1956
+ ICON_LIBRARIES,
1957
+ DEFAULT_ICON_LIBRARY,
1958
+ findIconLibrary,
1959
+ allIconLibraries,
1960
+ defaultIconLibrary,
1961
+ resolveIconsFlag,
1962
+ iconLibraryOf,
1963
+ reactPreset,
1964
+ decodeDigest,
1965
+ decodeMarkerWith,
1966
+ decodeMarkerHead,
2002
1967
  sdkDep,
1968
+ sortedKeys,
1969
+ isSorted,
1970
+ renderBackendPackageJson,
2003
1971
  renderPackageJson,
2004
1972
  renderTsconfig,
1973
+ BACKEND_TSCONFIG_PATH,
1974
+ renderBackendTsconfig,
2005
1975
  renderLambdaTsconfig,
2006
1976
  renderViteConfig,
2007
1977
  renderIndexHtml,
2008
1978
  renderGitignore,
1979
+ mergeGitignore,
2009
1980
  NODE_MIN,
2010
1981
  renderGitattributes,
2011
1982
  checkJobDir,
@@ -2013,7 +1984,11 @@ export {
2013
1984
  checkWorkflowPath,
2014
1985
  renderCheckWorkflow,
2015
1986
  renderEnvExample,
1987
+ README_PATH,
1988
+ readmeBuiltWithVersion,
1989
+ refreshReadmeBuiltWith,
2016
1990
  renderReadme,
1991
+ renderBackendReadme,
2017
1992
  renderXanoIndex,
2018
1993
  renderXanoExampleMd,
2019
1994
  describeOrigin,
@@ -2022,13 +1997,9 @@ export {
2022
1997
  initLanding,
2023
1998
  codegenLanding,
2024
1999
  renderIndexCss,
2000
+ renderThemeScript,
2025
2001
  renderThemeModule,
2026
2002
  renderCnUtil,
2027
- renderApiTs,
2028
- FRAMEWORKS,
2029
- DEFAULT_FRAMEWORK,
2030
- findFrontendPreset,
2031
- allFrontendPresets,
2032
- resolveFrameworkFlag
2003
+ renderApiTs
2033
2004
  };
2034
- //# sourceMappingURL=chunk-57HMNJGB.js.map
2005
+ //# sourceMappingURL=chunk-5GIOCDUM.js.map