@xano/sdk 1.0.6 → 1.0.8

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 (242) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +32 -4
  3. package/dist/.build-fingerprint +1 -1
  4. package/dist/{agent-file-refresh-67QIX45H.js → agent-file-refresh-QJO3MT6Q.js} +13 -13
  5. package/dist/agent-skill-command-GBR4KUUG.js +414 -0
  6. package/dist/{answer-shape-UCDUKPAN.js → answer-shape-UMQRXMCX.js} +5 -5
  7. package/dist/{backend-dir-3LIL6SCT.js → backend-dir-PFUIPCV3.js} +15 -15
  8. package/dist/{backend-slot-JREP27UD.js → backend-slot-TTRNOQF5.js} +4 -4
  9. package/dist/bin.js +54 -53
  10. package/dist/{branch-2IPHOAYS.js → branch-Q7CDJRU6.js} +12 -11
  11. package/dist/{branch-commands-KTKAXBAN.js → branch-commands-CR3SAHMV.js} +27 -26
  12. package/dist/bundle.js +5 -5
  13. package/dist/{chunk-YKP4ZKVO.js → chunk-2HZDWZM2.js} +3 -3
  14. package/dist/{chunk-ZDP6GDAB.js → chunk-33KELF2X.js} +103 -94
  15. package/dist/{chunk-7VR4IO5B.js → chunk-3P35HT64.js} +2 -2
  16. package/dist/{chunk-2FLIJGBZ.js → chunk-3UZQ5TMG.js} +47 -8
  17. package/dist/{chunk-AWQ7BQTQ.js → chunk-4GPIOIAC.js} +6 -1
  18. package/dist/{chunk-YYLUBYXM.js → chunk-4JKXGPXB.js} +3 -3
  19. package/dist/{chunk-EQFYOOO6.js → chunk-5GIOCDUM.js} +829 -893
  20. package/dist/{chunk-26MOFAJT.js → chunk-5QOV52V4.js} +6 -3
  21. package/dist/{chunk-Q22BMRPF.js → chunk-5Y5HWQ2P.js} +2 -2
  22. package/dist/{chunk-T4LJ5UR2.js → chunk-6BOKCTCM.js} +52 -22
  23. package/dist/{chunk-FNLTFOUD.js → chunk-6NEV2PEC.js} +2 -2
  24. package/dist/{chunk-QJM5XZ4K.js → chunk-6PTITS3M.js} +8 -8
  25. package/dist/{chunk-N5I37JFB.js → chunk-6S263KTM.js} +2 -2
  26. package/dist/{chunk-JI3BLXWQ.js → chunk-6YOH2L3G.js} +11 -5
  27. package/dist/{chunk-5QMJOE2K.js → chunk-6ZFJEJXZ.js} +5 -3
  28. package/dist/{chunk-NPODGBVJ.js → chunk-75MKIQON.js} +4 -4
  29. package/dist/{chunk-SPITRSOF.js → chunk-76UAME77.js} +2 -2
  30. package/dist/{chunk-JRVQ7M7W.js → chunk-77GV772V.js} +8 -8
  31. package/dist/{chunk-GWTFI3GA.js → chunk-7JKNWDYN.js} +2 -2
  32. package/dist/{chunk-6X6BJN6Y.js → chunk-7MPI7NIW.js} +3 -3
  33. package/dist/{chunk-3II44CUJ.js → chunk-7UWUEUVJ.js} +24 -24
  34. package/dist/{chunk-ENMBEXOP.js → chunk-AS4G2MIE.js} +3 -3
  35. package/dist/{chunk-PMMHSX4H.js → chunk-B3NH5UBI.js} +4 -4
  36. package/dist/{chunk-SLGJIWCY.js → chunk-B5N6EWOM.js} +2 -2
  37. package/dist/chunk-BRANWM4U.js +853 -0
  38. package/dist/{chunk-6X3MY2JP.js → chunk-C2GHFADU.js} +2 -2
  39. package/dist/{chunk-CCU5CCRX.js → chunk-C2I4GC36.js} +8 -8
  40. package/dist/{chunk-D7BUMOKU.js → chunk-C6KBZH7M.js} +82 -6
  41. package/dist/{chunk-LAOMN6QQ.js → chunk-CRE7P7P2.js} +3 -3
  42. package/dist/{chunk-AVS4WPPY.js → chunk-DER2CVNC.js} +2 -2
  43. package/dist/{chunk-UIVMR7UK.js → chunk-DY3EJWWH.js} +2 -2
  44. package/dist/{chunk-SKEG3V2V.js → chunk-EKTIGGFO.js} +2 -2
  45. package/dist/{chunk-PL7AIAWS.js → chunk-F3IA3YWI.js} +4 -111
  46. package/dist/{chunk-FQ53GTII.js → chunk-F5RPNTN7.js} +6 -6
  47. package/dist/{chunk-2WBH5HUY.js → chunk-FHQYXGAY.js} +7 -7
  48. package/dist/{chunk-ND43ZOS3.js → chunk-FN7E6XGD.js} +7 -7
  49. package/dist/{chunk-3BBIDW3Y.js → chunk-GN5SQMIQ.js} +5 -5
  50. package/dist/{chunk-SSITMX7I.js → chunk-H3ZBAR2L.js} +16 -14
  51. package/dist/{chunk-OIKLDDYC.js → chunk-HFOGQIII.js} +3 -3
  52. package/dist/chunk-HKLBDSML.js +995 -0
  53. package/dist/{chunk-JXVJGF3Y.js → chunk-HQPL34O6.js} +2 -2
  54. package/dist/{chunk-CHINR7WD.js → chunk-HTP2CLRQ.js} +5 -5
  55. package/dist/{chunk-ROY4YAEQ.js → chunk-HU7F56VF.js} +22 -2
  56. package/dist/{chunk-TECTL2NU.js → chunk-HVPSDQJB.js} +4 -4
  57. package/dist/{chunk-IYXL5NYU.js → chunk-I53OTC3O.js} +2 -2
  58. package/dist/{chunk-M5CSVB23.js → chunk-IB6SKACE.js} +11 -8
  59. package/dist/{chunk-UD2Z7K6W.js → chunk-JG642U5D.js} +4 -4
  60. package/dist/{chunk-ZJSTUD6D.js → chunk-JJGK7XGC.js} +8 -8
  61. package/dist/{local-engine-command-RYLGMQ2O.js → chunk-JPRZ4ZGU.js} +22 -77
  62. package/dist/{chunk-QZEAANWP.js → chunk-K75BFHQQ.js} +8 -8
  63. package/dist/chunk-LCOCRJ4K.js +116 -0
  64. package/dist/{chunk-3EDSPMXN.js → chunk-LJM5CIY4.js} +5 -1
  65. package/dist/{chunk-D3KEPRRN.js → chunk-LTPF25L2.js} +2 -1
  66. package/dist/{chunk-HCG7NDIL.js → chunk-M3RLLT4O.js} +5 -5
  67. package/dist/{chunk-IXFJORNH.js → chunk-NFSUGVDY.js} +4 -4
  68. package/dist/{chunk-GHQ4BVI4.js → chunk-NFZUXS7D.js} +14 -14
  69. package/dist/{chunk-LBJA7IEM.js → chunk-O376UAZS.js} +2 -2
  70. package/dist/{chunk-LD6ARK3A.js → chunk-OBJ7FQDX.js} +2 -2
  71. package/dist/{chunk-VJFMUJWZ.js → chunk-OHTHG3LL.js} +2 -2
  72. package/dist/{chunk-U35MTOXQ.js → chunk-P5W6DBV6.js} +3 -3
  73. package/dist/{chunk-A7MRZ4GF.js → chunk-PAS5HOG3.js} +5 -5
  74. package/dist/{chunk-WZHLMU6T.js → chunk-PBK257CI.js} +2 -2
  75. package/dist/{chunk-SPKA2LV6.js → chunk-PFW7WFAT.js} +4 -4
  76. package/dist/{chunk-GOLFAEUV.js → chunk-QC3MKMDK.js} +2 -2
  77. package/dist/{chunk-YGLMRH5U.js → chunk-QE2GNFMP.js} +12 -12
  78. package/dist/{chunk-763M6LX3.js → chunk-QL3ZJWGG.js} +2 -2
  79. package/dist/{chunk-ITC2R2OT.js → chunk-QRKBFXIB.js} +7 -7
  80. package/dist/{chunk-KPFS3RGM.js → chunk-QTMXJQZN.js} +4 -4
  81. package/dist/{chunk-BTVUYHWV.js → chunk-QXOBZSQD.js} +4 -4
  82. package/dist/{chunk-NDWVJ2QZ.js → chunk-R3LANPQZ.js} +3 -3
  83. package/dist/{chunk-QXYMDARD.js → chunk-R4NOZBOY.js} +4 -4
  84. package/dist/{chunk-YYC2DZMG.js → chunk-RYMGK2K5.js} +6 -6
  85. package/dist/{chunk-IF4PEGVD.js → chunk-S2F7KVUL.js} +11 -11
  86. package/dist/{chunk-I3VHW6XM.js → chunk-S3STXOAO.js} +18 -18
  87. package/dist/{chunk-JFBRXRJD.js → chunk-S3WN6GGO.js} +40 -40
  88. package/dist/{chunk-U6MTGB46.js → chunk-S42TFTM5.js} +5 -5
  89. package/dist/{chunk-7GAIJW62.js → chunk-TG65NWUR.js} +2 -2
  90. package/dist/{chunk-YR2I5HGE.js → chunk-TR7EOUQE.js} +2 -2
  91. package/dist/{chunk-I3H3HCPY.js → chunk-U7XNJ33Q.js} +34 -31
  92. package/dist/{chunk-FU3VCE5A.js → chunk-UKJFCEMI.js} +13 -9
  93. package/dist/{chunk-5TVFLG3C.js → chunk-ULUUOUQX.js} +2 -2
  94. package/dist/{chunk-PFBXSVZF.js → chunk-UU7EEREQ.js} +7 -7
  95. package/dist/{chunk-ATJ2W7DC.js → chunk-V7KMIEMF.js} +286 -126
  96. package/dist/{chunk-VDHA5SSQ.js → chunk-VD7YTLWL.js} +2 -2
  97. package/dist/{chunk-EADVVTDK.js → chunk-VHV25AAO.js} +7 -7
  98. package/dist/{chunk-BL3AZ3AP.js → chunk-VJTTTIIB.js} +2 -2
  99. package/dist/{chunk-TTEIDD5Q.js → chunk-W2BVP27L.js} +4 -4
  100. package/dist/{chunk-GZHLCUZ6.js → chunk-WEQFI55W.js} +7 -7
  101. package/dist/{chunk-WBH4KJWM.js → chunk-XQO4A4Q4.js} +3 -3
  102. package/dist/{chunk-Z4ZGTCCD.js → chunk-XYTVP4WI.js} +6 -6
  103. package/dist/{chunk-5YQV35C2.js → chunk-Y5ET37NN.js} +7 -7
  104. package/dist/{chunk-VW4CWVYX.js → chunk-YE7MHW45.js} +4 -4
  105. package/dist/{chunk-YHB34BN6.js → chunk-YEH5OIPF.js} +2 -1
  106. package/dist/{chunk-GLY552SI.js → chunk-YG7S3N7P.js} +128 -60
  107. package/dist/{chunk-MBDFH7XB.js → chunk-YP76ZCQ5.js} +4 -4
  108. package/dist/{chunk-XFBGXB7X.js → chunk-ZJCHS7FM.js} +163 -107
  109. package/dist/{chunk-IMELQ2I6.js → chunk-ZO3QWFNV.js} +3 -3
  110. package/dist/{chunk-RIN4YY34.js → chunk-ZQ5WZWHF.js} +106 -69
  111. package/dist/{chunk-GW5RHGOB.js → chunk-ZT2B22VQ.js} +9 -9
  112. package/dist/cli.d.ts +32 -4
  113. package/dist/cli.js +51 -48
  114. package/dist/{codegen-command-R5IASBFC.js → codegen-command-4YXDJSLU.js} +69 -68
  115. package/dist/{commands-H7CPMMHH.js → commands-FOHIPDKZ.js} +3 -3
  116. package/dist/{completion-W5ZAI6TN.js → completion-XUBGMKGV.js} +9 -5
  117. package/dist/{config-MZ5KG4EP.js → config-544VCRKP.js} +8 -8
  118. package/dist/{deploy-command-34T2LKQ5.js → deploy-command-FIDS56ZC.js} +56 -55
  119. package/dist/{deploy-source-YLQ7WMYR.js → deploy-source-FPNNNNOW.js} +34 -33
  120. package/dist/{dev-env-sync-TMJTNU3U.js → dev-env-sync-RBJ2U3HG.js} +54 -53
  121. package/dist/{diagnostics-OMN5Y2AH.js → diagnostics-FNVNRYMB.js} +2 -2
  122. package/dist/{display-name-hint-ZJGFNJKQ.js → display-name-hint-EZQK2PDU.js} +14 -13
  123. package/dist/{emit-D125xxty.d.ts → emit-8lcNcRrd.d.ts} +12 -12
  124. package/dist/env-example-refresh-6UTTMDOI.js +134 -0
  125. package/dist/{env-pull-command-UTG6IC2K.js → env-pull-command-P5MATITQ.js} +46 -45
  126. package/dist/{env-target-FZROWYFS.js → env-target-F75YF25S.js} +13 -12
  127. package/dist/{env-var-command-VYDBQJJW.js → env-var-command-H3GHROVB.js} +50 -49
  128. package/dist/{ephemeral-BIE6FMJV.js → ephemeral-H24NF6WP.js} +11 -10
  129. package/dist/{ephemeral-command-OZ26RGXF.js → ephemeral-command-NH2XW3YK.js} +64 -63
  130. package/dist/{ephemeral-state-SNZOX2YK.js → ephemeral-state-YLZQIOBF.js} +11 -10
  131. package/dist/{generate-command-4HR7MR36.js → generate-command-IANKN6WV.js} +84 -82
  132. package/dist/{gitignore-EWQBXNX2.js → gitignore-FT2LVOMI.js} +19 -19
  133. package/dist/{guards-KYEOCVHN.js → guards-4VPSEOAI.js} +6 -4
  134. package/dist/{impersonate-command-WC7OGKUM.js → impersonate-command-7B67ICPL.js} +42 -41
  135. package/dist/{import-7Z4GCCPO.js → import-TXYVFYJS.js} +5 -5
  136. package/dist/index.d.ts +4 -4
  137. package/dist/index.js +8 -8
  138. package/dist/{init-command-HAO3WXH3.js → init-command-QOA4TJI2.js} +68 -53
  139. package/dist/{init-modules-NSKD4ASY.js → init-modules-KEEJ4HAF.js} +8 -8
  140. package/dist/{init-web-MKFFOQUU.js → init-web-MSXDARRF.js} +3 -3
  141. package/dist/internal.d.ts +4 -4
  142. package/dist/internal.js +10 -10
  143. package/dist/{keep-data-merge-QR2TMKEO.js → keep-data-merge-BIBW4QR4.js} +28 -28
  144. package/dist/{lambda-config-reconcile-7FJXXV6V.js → lambda-config-reconcile-47X5C2E4.js} +6 -5
  145. package/dist/{landing-record-MWXFIRCP.js → landing-record-DO3PM7QP.js} +22 -22
  146. package/dist/{live-diff-5E2BQWQ7.js → live-diff-CGTGOH3S.js} +3 -3
  147. package/dist/{local-engine-choice-VD5LNXJU.js → local-engine-choice-2UF7S5QZ.js} +37 -36
  148. package/dist/local-engine-command-WGMMZRQL.js +85 -0
  149. package/dist/{local-engine-config-W3KB7RWM.js → local-engine-config-6CB6FOEJ.js} +3 -2
  150. package/dist/{local-engine-deploy-6O7NKZCA.js → local-engine-deploy-ID4JJXB5.js} +18 -16
  151. package/dist/local-engine-lookup-IC7BKAYP.js +43 -0
  152. package/dist/local-engine-mcp-bridge-3SOJMZ5T.js +423 -0
  153. package/dist/local-engine-mcp-command-RMVUH4FL.js +181 -0
  154. package/dist/{local-engine-process-ZLLZEIRF.js → local-engine-process-HG5BGG3F.js} +12 -9
  155. package/dist/{local-engine-state-OCW5YDD7.js → local-engine-state-JZHTKHDG.js} +4 -3
  156. package/dist/{local-engine-update-check-LVX4HBBI.js → local-engine-update-check-SKZR7YSC.js} +7 -6
  157. package/dist/{lock-commands-X2OECR4R.js → lock-commands-5NMQWBGH.js} +57 -56
  158. package/dist/{login-command-RLLKD565.js → login-command-GLLFZWHT.js} +33 -33
  159. package/dist/{logout-command-XDMSXCDO.js → logout-command-NCMKMJWF.js} +16 -15
  160. package/dist/{loop-SUB6C2LK.js → loop-XFDS65OD.js} +3 -3
  161. package/dist/{marketplace-command-2NHHY2X3.js → marketplace-command-Y3RRUEWL.js} +34 -34
  162. package/dist/{marketplace-resolve-OTZYT4FG.js → marketplace-resolve-PWEYJ2XS.js} +6 -6
  163. package/dist/{meta-client-TMHVBZFY.js → meta-client-Y7N6WDS2.js} +14 -13
  164. package/dist/{module-manifest-FNMW23IX.js → module-manifest-KY7J63HG.js} +4 -4
  165. package/dist/node.d.ts +4 -4
  166. package/dist/node.js +60 -59
  167. package/dist/operation-outcome-4BFISK2R.js +53 -0
  168. package/dist/{output-target-MOLCTPBP.js → output-target-MFANTVGZ.js} +20 -20
  169. package/dist/{plan-disclosure-CY7AF6KP.js → plan-disclosure-GNLDYV2A.js} +17 -16
  170. package/dist/{plugin-contributions-WR26U7NT.js → plugin-contributions-PAGG6SUP.js} +6 -6
  171. package/dist/{plugin-prompt-ZUYQQIX4.js → plugin-prompt-2MX6LF6X.js} +5 -5
  172. package/dist/{plugin-questions-HAZOQ67R.js → plugin-questions-AP6VUTOB.js} +4 -4
  173. package/dist/{preflight-command-OHJXYND3.js → preflight-command-Q6XOKRM6.js} +61 -60
  174. package/dist/{profile-command-6JWT2BTL.js → profile-command-XPQIXFWN.js} +34 -34
  175. package/dist/{profile-pointer-PDA5XBIB.js → profile-pointer-4HJQH5ZR.js} +5 -4
  176. package/dist/{project-dependency-GZWWGWEW.js → project-dependency-ORX45I74.js} +7 -7
  177. package/dist/{project-sdk-3W72H5QO.js → project-sdk-IYMFVQRC.js} +4 -4
  178. package/dist/promote-command-DN64QK7O.js +147 -0
  179. package/dist/{prompt-U37K5RPQ.js → prompt-ZZUYWFQX.js} +4 -4
  180. package/dist/{publish-command-BUS27HGB.js → publish-command-SLE46MQX.js} +61 -60
  181. package/dist/{pull-command-ZGUNP27P.js → pull-command-UVK3IOXM.js} +72 -71
  182. package/dist/{pull-superseded-EZBGYRZF.js → pull-superseded-UZ3MB53B.js} +4 -4
  183. package/dist/{release-command-BQ6OHS3P.js → release-command-MKNESNGB.js} +67 -66
  184. package/dist/{release-ns-command-ATGVBVIU.js → release-ns-command-HLR46IKP.js} +92 -91
  185. package/dist/{retry-command-QJ57WVW7.js → retry-command-VZYLYDVX.js} +10 -9
  186. package/dist/{routes-manifest-YR4ZIMLM.js → routes-manifest-RIZGSOZC.js} +4 -4
  187. package/dist/{routes-manifest-file-UALYSZLY.js → routes-manifest-file-UHVVL2YB.js} +8 -8
  188. package/dist/scaffold.js +4 -4
  189. package/dist/secrets-IV4N5HYI.js +20 -0
  190. package/dist/{secrets-file-LMS7KX3E.js → secrets-file-HST7BMQC.js} +19 -19
  191. package/dist/{secrets-fill-command-QNBDGCGM.js → secrets-fill-command-FQJ4QFBP.js} +55 -54
  192. package/dist/{seed-SZ6OS5DQ.js → seed-KEPIS7UZ.js} +6 -6
  193. package/dist/{source-resolve-MKLNYFWG.js → source-resolve-LNRUITLS.js} +24 -22
  194. package/dist/{static-host-ONEHA4LI.js → static-host-JAOT3N3E.js} +5 -5
  195. package/dist/{status-command-XKIFKBGM.js → status-command-S5CBG2SW.js} +53 -52
  196. package/dist/{store-Bg4Na6Sm.d.ts → store-CuD1k4kV.d.ts} +1 -1
  197. package/dist/{store-X6ZH7EC3.js → store-YFNDD6GZ.js} +8 -7
  198. package/dist/{sync-baseline-DOV5AGIO.js → sync-baseline-3CDL4PKT.js} +7 -5
  199. package/dist/{sync-contributions-HNVHDIQW.js → sync-contributions-O5ZRM2JN.js} +10 -10
  200. package/dist/{sync-record-PRXHLK4S.js → sync-record-U65BCPSP.js} +14 -13
  201. package/dist/{table-DC36QA4Y.js → table-E5YTK7QX.js} +7 -7
  202. package/dist/{tables-command-UQLKTELN.js → tables-command-7KI2KZOS.js} +40 -39
  203. package/dist/{tenant-EKNQGG5A.js → tenant-DAXJ4P4D.js} +12 -11
  204. package/dist/{tenant-command-2LWP2MPB.js → tenant-command-MQTLNETR.js} +97 -96
  205. package/dist/{test-command-IU5MBBXY.js → test-command-NLYMAAPD.js} +42 -41
  206. package/dist/{tests-RG2Y5EQ4.js → tests-CLDZWLKF.js} +6 -6
  207. package/dist/{token-7AWSJLKO.js → token-3IPTVEEW.js} +12 -11
  208. package/dist/{toolchain-hooks-4ZMQLBPQ.js → toolchain-hooks-3ZAAAWPL.js} +7 -7
  209. package/dist/{toolchain-modules-VU7SURVJ.js → toolchain-modules-K46KYJ4G.js} +5 -5
  210. package/dist/{toolchain-peers-CIDNEEQV.js → toolchain-peers-AIKWKJH7.js} +8 -8
  211. package/dist/{tracked-backend-4BHSV7NC.js → tracked-backend-FQFXTTYZ.js} +37 -36
  212. package/dist/{update-check-A7FXIINW.js → update-check-FHRRUDEC.js} +52 -51
  213. package/dist/{upgrade-command-C5KBITFI.js → upgrade-command-WNBPKUXN.js} +58 -55
  214. package/dist/{whoami-command-7WQII2H4.js → whoami-command-DPGDK35H.js} +15 -14
  215. package/dist/{workspace-Z46PUZNI.js → workspace-2GMONZ2A.js} +5 -5
  216. package/dist/{workspace-binding-JE6YNDZJ.js → workspace-binding-PAUOIK3V.js} +14 -13
  217. package/dist/{workspace-command-FC4IMLAE.js → workspace-command-KEKL27Y4.js} +99 -103
  218. package/dist/{workspace-env-N4ZPFT6A.js → workspace-env-GGEZVZDY.js} +16 -16
  219. package/dist/{workspace-export-3A5BZTPS.js → workspace-export-UHY22VBI.js} +5 -5
  220. package/dist/{writable-D7KCZI5N.js → writable-2A6MBSFD.js} +4 -4
  221. package/dist/{xano-LCI7VWPS.js → xano-6T6L7TTI.js} +5 -5
  222. package/dist/{xanosdk-import-P2A2KSXM.js → xanosdk-import-HYHABD5U.js} +6 -6
  223. package/dist/{xanosdk-project-6AGMW2SL.js → xanosdk-project-2T56DRYS.js} +16 -16
  224. package/guides/README.md +2 -2
  225. package/guides/cli.md +69 -0
  226. package/guides/codegen.md +23 -5
  227. package/guides/codes.md +5 -1
  228. package/guides/coverage.md +5 -0
  229. package/guides/deploying.md +45 -1
  230. package/guides/scaffold.md +61 -10
  231. package/llms/errors.md +1 -1
  232. package/llms/kinds-agent-mcp.md +1 -1
  233. package/llms-full.txt +3 -3
  234. package/llms.txt +1 -1
  235. package/manifest.json +67 -5
  236. package/package.json +5 -2
  237. package/skills/xano-backend/SKILL.md +119 -0
  238. package/dist/chunk-LL7SGTRC.js +0 -663
  239. package/dist/chunk-M6ZFSTIZ.js +0 -630
  240. package/dist/env-example-refresh-CQP3ZMKM.js +0 -133
  241. package/dist/operation-outcome-RN62735X.js +0 -51
  242. package/dist/promote-command-UYAMUXKB.js +0 -146
@@ -1,15 +1,11 @@
1
- import {
2
- decodeMarkerWith,
3
- iconLibraryOf,
4
- reactPreset
5
- } from "./chunk-M6ZFSTIZ.js";
6
1
  import {
7
2
  blockVersion,
8
3
  composeBlock,
9
4
  gitattributesSpec,
5
+ gitignoreSpec,
10
6
  htmlDialect,
11
7
  upsertBlock
12
- } from "./chunk-3EDSPMXN.js";
8
+ } from "./chunk-LJM5CIY4.js";
13
9
  import {
14
10
  colorTokens,
15
11
  defaultThemeChoice,
@@ -18,6 +14,182 @@ import {
18
14
  fontThemeVars,
19
15
  orderedTokens
20
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
+ }
21
193
 
22
194
  // src/emit/init-templates.ts
23
195
  var STANDALONE_NPM = { manager: "npm", member: "", declared: false };
@@ -28,12 +200,112 @@ function sdkDep(sdkVersion) {
28
200
  const ceiling = major > 0 ? `${major + 1}.0.0` : `0.${minor + 1}.0`;
29
201
  return `>=${sdkVersion} <${ceiling}`;
30
202
  }
203
+ var npmKeyOrder = (a, b) => a.localeCompare(b, "en");
31
204
  function sortedKeys(map) {
32
- 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";
33
306
  }
34
307
  function renderPackageJson({ appName, sdkVersion }, preset, choice = defaultThemeChoice()) {
35
308
  const check = `${preset.checkCmd} && tsc -p xano/lambdas`;
36
- const routes = "xanosdk routes ./xano/index.ts --emit xano/routes.gen.ts";
37
309
  const pkg = {
38
310
  name: appName,
39
311
  version: "0.1.0",
@@ -44,75 +316,7 @@ function renderPackageJson({ appName, sdkVersion }, preset, choice = defaultThem
44
316
  build: `npm run xano:routes && ${check} && vite build`,
45
317
  preview: "vite preview",
46
318
  typecheck: `npm run xano:routes && ${check}`,
47
- "xano:routes": routes,
48
- // Both are prefixed with a typecheck: the export pass validates what it
49
- // can see in the encoded bundle, and TypeScript validates the rest. With
50
- // `tsc` on `build` alone, anyone following the documented workflow would
51
- // ship with the compiler's half of the checks never run.
52
- // No `--lock` on either of these: every build maintains `xano/xano.lock`
53
- // by default, so the flag would be redundant here and would read as
54
- // though the lock were something a project opts into. It is not — object
55
- // identity derives from `(type, name)`, and without a lock a rename
56
- // re-derives the guid and the engine does delete-and-recreate instead of
57
- // rename-in-place, so the file has to exist before the identities matter.
58
- // Scaffolds written before the default flipped still pass `--lock`, and
59
- // it stays accepted for exactly that reason.
60
- "xano:export": `npm run xano:routes && ${check} && xanosdk export ./xano/index.ts --out workspace.json`,
61
- // The default deploy, and the tight loop: redeploy the backend to the
62
- // Xano Engine on this machine. It needs no Xano account, so a fresh
63
- // scaffold runs it before anyone signs in.
64
- //
65
- // No `--static` and no `npm run build`, and both omissions are the point
66
- // rather than an economy: there is no frontend to ship here. The dev
67
- // server is still serving it, and the deploy points that server at the
68
- // engine on its way past, so the loop is backend-only by design.
69
- // (`--static` does work on a Xano Engine, for a built frontend the
70
- // engine itself should serve; this loop has none.)
71
- //
72
- // No `--local`: the Xano Engine is where a bare deploy goes, and the
73
- // project's pinned version is what it runs. Baking an engine version or
74
- // URL into a scaffolded project would ship a coordinate that is not this
75
- // project's to carry.
76
- //
77
- // `--keep-data`, because the engine is the developer's own backend and
78
- // this loop runs once per code change: each run merges into what the last
79
- // one left, so rows entered through the app survive the edit. The first
80
- // run, and the first after the engine restarts, replaces and seeds.
81
- // `--reset` on the command line still gives a clean slate.
82
- "xano:deploy": `npm run xano:routes && ${check} && xanosdk deploy ./xano/index.ts --keep-data`,
83
- // The cloud deploy: backend and built frontend to an ephemeral.
84
- // Runs `build` rather than `check` directly: `--static ./frontend/dist`
85
- // needs that directory to EXIST, and only `vite build` writes it. Pointing
86
- // the flag at a directory the script never produced meant a fresh clone
87
- // running the documented command had no `dist` to ship.
88
- // `build` already prefixes the same typecheck, so this is one check, not
89
- // two.
90
- "xano:deploy:ephemeral": `npm run build && xanosdk deploy ./xano/index.ts --ephemeral --static ./frontend/dist`,
91
- // The frontend-only loop: rebuild and republish to the environment this
92
- // project last deployed to, without recompiling or re-importing the
93
- // backend. `build` runs first because publish ships only what is on disk.
94
- "xano:deploy:frontend": "npm run build && xanosdk publish ./frontend/dist",
95
- // The CI guard: fails instead of changing xano.lock, so an uncommitted
96
- // identity change is caught in review rather than on a deploy. An
97
- // installed toolchain module's own check rides on the same run: a module
98
- // that owns a generated tree verifies it under this same flag.
99
- // `--strict` fails on a stale or missing committed manifest rather than
100
- // rewriting it, the same way `--frozen-lock` treats xano.lock.
101
- //
102
- // `export --check`, not an export to a file: a CI checkout has no
103
- // `xano/.env` and no `xano/.secrets.json`, and a real export refuses a
104
- // declared documentation gate it cannot supply. The check writes nothing
105
- // — no bundle, no lock — so there is nothing a missing secret could clear,
106
- // and it needs none. It implies `--frozen-lock`. `--strict` as the grounding
107
- // tells every CI and unattended build to: a build warning is a hard
108
- // failure. Env values never reach it — a declared name with no value is
109
- // `""`, which only `deploy` refuses — so a checkout with no `xano/.env`
110
- // passes it (a fresh scaffold and an `init --from` tree both do).
111
- "xano:check": `${routes} --strict && ${check} && xanosdk export ./xano/index.ts --check --strict`,
112
- // No compile step and no entry file: this runs what is DEPLOYED, so it
113
- // pairs with `xano:deploy` rather than repeating its work. Exits 5 on a
114
- // failing suite, which is what makes it usable as a CI gate.
115
- "xano:test": "xanosdk test run-all",
319
+ ...xanoScripts(check, true),
116
320
  // Framework-owned scripts, last so a preset can add to the set but the
117
321
  // shared xano:* contract above stays the same in every scaffold.
118
322
  ...preset.extraScripts
@@ -178,10 +382,33 @@ function renderTsconfig(preset) {
178
382
  };
179
383
  return JSON.stringify(tsconfig, null, 2) + "\n";
180
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
+ }
181
406
  var LAMBDA_GLOBALS_TYPES = "@xano/sdk/lambda-globals";
182
- function renderLambdaTsconfig() {
407
+ function renderLambdaTsconfig(base = "project") {
183
408
  const tsconfig = {
184
- 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",
185
412
  // No DOM and no node types: a lambda body runs in neither.
186
413
  compilerOptions: { lib: ["ES2022"], types: [LAMBDA_GLOBALS_TYPES] },
187
414
  files: [],
@@ -284,6 +511,25 @@ ${framework}
284
511
  # it means each build mints identities that are thrown away and re-invented.
285
512
  `;
286
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
+ }
287
533
  var NODE_MIN = "20.19";
288
534
  function renderGitattributes(contributions = []) {
289
535
  let text = `# The export writes LF. Normalizing here keeps generated output
@@ -441,6 +687,67 @@ function refreshReadmeBuiltWith(existing, sdkVersion) {
441
687
  function renderReadmeDescriptionSlot(appName) {
442
688
  return `_Describe ${appName} here: what it does and who it is for._`;
443
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.`;
444
751
  function renderReadme({ appName, install, sdkVersion }, preset, choice = defaultThemeChoice()) {
445
752
  return `# ${appName}
446
753
 
@@ -474,22 +781,7 @@ It prints the backend URL, a link that opens Xano's visual builder on the engine
474
781
  points \`npm run dev\` at it through \`.env.local\` (restart the dev server if it was already
475
782
  running).
476
783
 
477
- - **It works on a fresh machine with nothing set.** The first run downloads the latest
478
- engine once per machine and pins its version in \`package.json\`. Commit that change, so
479
- everyone on the project runs the same engine.
480
- - **It keeps your table rows across redeploys** (\`--keep-data\`). The first run seeds and
481
- later runs merge your changes in without re-seeding. Rows survive only in tables and columns that keep
482
- their names (a rename drops the old one with its rows), and only while the engine runs. An
483
- engine update or restart starts it empty and the next run seeds again.
484
- \`npm run xano:deploy -- --reset\` gives a clean, re-seeded slate.
485
- - **Updates are yours to take.** When a newer engine ships, a deploy offers it and never
486
- applies it without a yes. \`npx xanosdk local update\` moves the pin on purpose,
487
- and \`npx xanosdk local cache clear\` reclaims the disk space. To try another engine
488
- without moving the pin, export \`XANOSDK_ENGINE_OVERRIDE\` with a version (\`v0.1.5\`)
489
- or an engine archive path.
490
- - **The rest of the CLI follows.** After a local deploy, \`npm run xano:test\`,
491
- \`npx xanosdk tables\` and \`npx xanosdk status\` reach the engine with no flag.
492
- \`npx xanosdk local stop <name>\` shuts it down.
784
+ ${README_ENGINE_BULLETS}
493
785
 
494
786
  ## Deploy to Xano's cloud
495
787
 
@@ -521,32 +813,7 @@ The other scripts:
521
813
  ./xano/index.ts --test\` does both in one step.
522
814
  - \`npm run xano:export\` compiles the backend to \`workspace.json\` (don't commit it).
523
815
 
524
- ## \`xano.lock\` \u2014 commit it
525
-
526
- Object identity derives from \`(type, name)\`, so a rename would otherwise change
527
- an object's guid and the engine would **delete and recreate** it rather than
528
- renaming it in place \u2014 losing its rows on a record-preserving import.
529
- [\`xano/xano.lock\`](xano/xano.lock) freezes each guid and each API group's
530
- canonical slug, so renames and re-deploys keep the same identities (and the same
531
- public URLs).
532
-
533
- Every build writes it \u2014 no flag \u2014 and it **must be committed**. Ignoring it means
534
- each build mints identities and public URLs that are thrown away and re-invented
535
- next time. If you release to a workspace that already exists, adopt what it
536
- already serves first with \`npx xanosdk lock import <live-bundle.json> --lock=xano/xano.lock\`;
537
- that is also the recovery path once identities have drifted.
538
-
539
- \`\`\`bash
540
- npm run xano:check # CI: fail on ANY build warning (it runs --strict), if the export
541
- # would change xano.lock, or if the lock carries an entry no
542
- # object matches \u2014 writes nothing and needs no secrets, so a
543
- # fresh clone runs it as-is
544
- \`\`\`
545
-
546
- To rename an object: rename it in code and run \`npm run xano:export\`. Only if it
547
- warns of an orphaned entry, run the \`npx xanosdk lock rename <kind> <old> <new>\` it prints, then
548
- export again. Every \`lock\` subcommand finds \`xano/xano.lock\` from the project entry, as
549
- \`export\` does \u2014 \`--entry=<file>\` names another entry, \`--lock=<path>\` the lock itself.
816
+ ${README_LOCK_SECTION}
550
817
 
551
818
  ## The one contract
552
819
 
@@ -575,25 +842,76 @@ ${preset.readmeFrontendSection(choice.icons)}
575
842
 
576
843
  ${renderReadmeThemingSection(choice)}
577
844
 
578
- ## Add-ons
845
+ ${README_ADD_ONS_SECTION}
579
846
 
580
- Xano SDK is composable with other \`@xano-sdk/*\` packages:
847
+ ${renderReadmeBuiltWith(sdkVersion)}
848
+ `;
849
+ }
850
+ function renderBackendReadme({ appName, install, sdkVersion }) {
851
+ return `# ${appName}
581
852
 
582
- - **[\`@xano-sdk/auth\`](https://www.npmjs.com/package/@xano-sdk/auth)** \u2014 turnkey
583
- authentication (user/login/signup tables and endpoints). Install it with
584
- \`npx xanosdk marketplace install @xano-sdk/auth\`, then register it in
585
- \`xano/index.ts\`. Authentication only \u2014 **not** authorization: it has no
586
- roles, permissions, or route guards, and its tokens carry no role claim.
587
- Enforce roles off the caller's row with \`@xano/sdk\`: spread
588
- \`...guard.role(userTable, "admin")\` into the endpoint's stack.
589
- - More \`@xano-sdk/*\` packages register onto the same workspace. This list
590
- does not update itself \u2014 run \`npx xanosdk marketplace list\` for the live
591
- catalogue, \`npx xanosdk marketplace search <words>\` to narrow it, and
592
- \`npx xanosdk marketplace details <package>\` to see what an add-on installs and
593
- how to register it. All three work before you log in.
853
+ ${XANO_BADGE}
594
854
 
595
- None of these ship with the scaffold. Install one only when you need it \u2014 an
596
- 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.
860
+
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}
597
915
 
598
916
  ${renderReadmeBuiltWith(sdkVersion)}
599
917
  `;
@@ -843,18 +1161,18 @@ ${XANO_BADGE}
843
1161
  ${renderReadmeDescriptionSlot(appName)}
844
1162
 
845
1163
  The backend under [\`xano/\`](xano/) is TypeScript pulled from ${describeCommittedOrigin(origin)}
846
- with the [Xano SDK](https://github.com/xano-sdk/sdk), and runs on [Xano](https://xano.com). The
1164
+ with the [Xano SDK](https://github.com/xano-sdk/sdk), and runs on [Xano](https://xano.com).${preset === null ? "" : ` The
847
1165
  ${preset.label} frontend under [\`frontend/\`](frontend/) is a starter \u2014 the pull carries a
848
- backend, not a UI.
1166
+ backend, not a UI.`}
849
1167
 
850
1168
  ## Run it
851
1169
 
852
1170
  \`\`\`bash
853
1171
  npm run xano:deploy # on the Xano Engine, on this machine (no account needed)
854
- npm run dev # the starter frontend, pointed at it
855
-
1172
+ ${preset === null ? "" : `npm run dev # the starter frontend, pointed at it
1173
+ `}
856
1174
  npx xanosdk login # once, to authenticate against your Xano account
857
- 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"}
858
1176
  \`\`\`
859
1177
 
860
1178
  ## Read this before deploying
@@ -875,7 +1193,11 @@ translate cleanly on this pull. Read it before trusting the tree.
875
1193
  ${secrets}
876
1194
  ## Working on it
877
1195
 
878
- \`\`\`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
879
1201
  npm run dev # run the starter frontend
880
1202
  npm run typecheck # the whole project, both halves
881
1203
  npm run xano:export # compile the backend to workspace.json (don't commit it)
@@ -883,7 +1205,7 @@ npm run xano:routes # regenerate xano/routes.gen.ts: the frontend's paths and
883
1205
  \`\`\`
884
1206
 
885
1207
  [\`frontend/src/lib/api.ts\`](frontend/src/lib/api.ts) shows the one contract: paths
886
- and request types from \`xano/routes.gen.ts\`, response types from the query defs in \`xano/\`.
1208
+ and request types from \`xano/routes.gen.ts\`, response types from the query defs in \`xano/\`.`}
887
1209
 
888
1210
  ${renderReadmeBuiltWith(sdkVersion)}
889
1211
  `;
@@ -1194,346 +1516,122 @@ export const XANO_HOST: string =
1194
1516
  `;
1195
1517
  }
1196
1518
 
1197
- // src/emit/frontend-svelte.ts
1519
+ // src/emit/frontend-react.ts
1198
1520
  var CODE_CLASS = "bg-muted rounded px-1.5 py-0.5 font-mono text-sm";
1199
- function htmlText(s) {
1200
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1201
- }
1202
- function svelteText(s) {
1203
- 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;");
1204
1523
  }
1205
1524
  function renderNode(node) {
1206
- 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);
1207
1526
  }
1208
1527
  function renderNodes(nodes) {
1209
1528
  return nodes.map(renderNode).join("");
1210
1529
  }
1211
1530
  function renderApp(landing, choice) {
1212
- 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");
1213
1532
  const toggle = choice.dark === "toggle";
1214
- const icons = iconLibraryOf(choice.icons).svelte;
1215
- return `<script lang="ts">
1216
- ${icons.arrowImport}
1217
-
1218
- import { Button } from "$lib/components/ui/button/index.js";
1219
- import * as Card from "$lib/components/ui/card/index.js";${toggle ? `
1220
- import ModeToggle from "$lib/components/mode-toggle.svelte";` : ""}
1221
- </script>
1222
-
1223
- <main class="mx-auto flex min-h-screen max-w-2xl flex-col justify-center p-8">${toggle ? `
1224
- <div class="mb-4 flex justify-end">
1225
- <ModeToggle />
1226
- </div>` : ""}
1227
- <Card.Root>
1228
- <Card.Header>
1229
- <Card.Title class="text-3xl tracking-tight">${svelteText(landing.title)}</Card.Title>
1230
- <Card.Description class="text-base">
1231
- ${renderNodes(landing.lead)}
1232
- </Card.Description>
1233
- </Card.Header>
1234
- <Card.Content>
1235
- <ol class="text-muted-foreground list-inside list-decimal space-y-2">
1236
- ${steps}
1237
- </ol>
1238
- </Card.Content>
1239
- <Card.Footer>
1240
- <!-- Components come from shadcn-svelte \u2014 add more with
1241
- \`npx shadcn-svelte@latest add <name>\`. -->
1242
- <Button href="${landing.cta.href}" target="_blank" rel="noreferrer">
1243
- ${svelteText(landing.cta.label)}
1244
- <${icons.arrowComponent} />
1245
- </Button>
1246
- </Card.Footer>
1247
- </Card.Root>
1248
- </main>
1249
- `;
1250
- }
1251
- function renderSvelteKitPlugin() {
1252
- return `sveltekit({
1253
- // RUNES MODE, FORCED \u2014 not left to Svelte 5's per-component detection.
1254
- //
1255
- // By default a component that uses \`export let\` and \`<slot>\` simply
1256
- // compiles in legacy mode and works, so the Svelte 4 API an assistant
1257
- // reaches for from older training data produces no error at all. Pinning
1258
- // runes here turns that into a compile failure naming the file, which is
1259
- // the same guidance the agent brief gives, enforced instead of stated.
1260
- //
1261
- // \`node_modules\` is exempted (returning undefined restores detection):
1262
- // an installed library compiles under whatever mode ITS author wrote for,
1263
- // and forcing ours onto it would break dependencies this project does not
1264
- // own. Removable in Svelte 6, where runes stop being opt-in.
1265
- compilerOptions: {
1266
- runes: ({ filename }) =>
1267
- filename.split(/[/\\\\]/).includes("node_modules") ? undefined : true,
1268
- },
1269
- // No \`preprocess\`. vite-plugin-svelte 7 compiles \`<script lang="ts">\`
1270
- // itself, so \`vitePreprocess()\` is the no-op it looks like \u2014 \`sv create\`
1271
- // emits none either. Verified against a real build: components typecheck
1272
- // and compile without it.
1273
- //
1274
- // The deploy target is a static host with NO server runtime \u2014 Xano is the
1275
- // backend. Routes are PRERENDERED (see frontend/src/routes/+layout.ts):
1276
- // each becomes its own HTML file at build time, and the host resolves a URL
1277
- // to it by trying the exact key, then \`{path}.html\`, then
1278
- // \`{path}/index.html\`. That is why no \`trailingSlash\` is configured \u2014 both
1279
- // output shapes resolve, so this stays on SvelteKit's default.
1280
- //
1281
- // The SDK's adapter, writing to frontend/dist. Every prerendered route is
1282
- // its own file; a route that sets \`prerender = false\` (a detail page for
1283
- // rows created at runtime) has no file, so the host answers it with
1284
- // 404.html, which the adapter writes as the app shell whenever such a
1285
- // route exists: the shell boots the app and renders the route in the
1286
- // browser, so a reload or a deep link works. While every route is
1287
- // prerendered, 404.html stays the prerendered /404 page.
1288
- //
1289
- // Do not swap it for \`@sveltejs/adapter-static\` with a \`fallback\`: that
1290
- // writes the shell at index.html, over the prerendered home page.
1291
- //
1292
- // \`xanosdk deploy --static-env\` still finds its anchor: every document
1293
- // renders from app.html, so each has a <head> that gets the injected globals.
1294
- adapter: adapter({ out: "frontend/dist" }),
1295
- // Absolute asset URLs, pinned rather than left to the default. Prerendered
1296
- // pages live at varying URL depths, and a relative \`../_app/\u2026\` computed for
1297
- // one depth 404s at another.
1298
- paths: { relative: false },
1299
- prerender: {
1300
- // A hash link in the shared layout \u2014 \`<a href="#services">\`, the default
1301
- // shape of a one-page site's nav \u2014 renders into EVERY prerendered route,
1302
- // including the scaffold's own /404. There it resolves to /404#services,
1303
- // an anchor that by definition is not on that page, and SvelteKit's
1304
- // default handler THROWS: the vite build succeeds and the prerender pass
1305
- // after it kills the build, with a stack trace naming only files inside
1306
- // node_modules and a route the author never wrote.
1307
- //
1308
- // So ignore a missing id on /404 specifically, rather than reaching for a
1309
- // blanket \`handleMissingId: "warn"\`. A hash link that is genuinely broken
1310
- // on a real route still fails the build, which is the check worth keeping.
1311
- handleMissingId: ({ path, message }) => {
1312
- if (path === "/404") return;
1313
- throw new Error(message);
1314
- },
1315
- },
1316
- // SvelteKit's project layout, redirected under frontend/ so this stays a
1317
- // single-root project: one package.json, one tsconfig.json, and xano/
1318
- // sitting alongside as the backend half. NOTE these are what make
1319
- // frontend/src/routes the routes directory \u2014 a file added under a
1320
- // top-level src/routes/ is not a route and will not be served.
1321
- files: {
1322
- routes: "frontend/src/routes",
1323
- lib: "frontend/src/lib",
1324
- appTemplate: "frontend/src/app.html",
1325
- assets: "frontend/static",
1326
- },
1327
- })`;
1328
- }
1329
- function renderAppHtml({ appName }, choice) {
1330
- return `<!doctype html>
1331
- <html lang="en">
1332
- <head>
1333
- <meta charset="utf-8" />
1334
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
1335
- <title>${htmlText(appName)}</title>
1336
- ${renderThemeScript(choice.dark)}
1337
- <!-- Drop a favicon.png into frontend/static/ and link it here:
1338
- <link rel="icon" href="%sveltekit.assets%/favicon.png" />
1339
- Everything in that directory is copied to the site root verbatim. -->
1340
- <!-- Keep this inside <head>: \`xanosdk deploy --static-env\` injects the
1341
- backend URL here as a window global that frontend/src/lib/api.ts reads. -->
1342
- %sveltekit.head%
1343
- </head>
1344
- <body data-sveltekit-preload-data="hover">
1345
- <div style="display: contents">%sveltekit.body%</div>
1346
- </body>
1347
- </html>
1348
- `;
1349
- }
1350
- function renderModeToggleSvelte(icons) {
1351
- return `<script lang="ts">
1352
- ${icons.modeImports.join("\n ")}
1353
-
1354
- import { Button } from "$lib/components/ui/button/index.js";
1355
- import { getMode, setMode, watchMode, type Mode } from "$lib/theme.js";
1533
+ const icons = iconLibraryOf(choice.icons).react;
1534
+ return `${icons.arrowImport}
1356
1535
 
1357
- /** system \u2192 light \u2192 dark \u2192 system. */
1358
- const next: Record<Mode, Mode> = { system: "light", light: "dark", dark: "system" };
1359
-
1360
- const icons = {
1361
- system: ${icons.modeComponents.system},
1362
- light: ${icons.modeComponents.light},
1363
- dark: ${icons.modeComponents.dark},
1364
- };
1365
-
1366
- // Starts at "system" so the prerendered HTML is deterministic; the effect
1367
- // corrects it in the browser, after the inline script has already applied
1368
- // the right class.
1369
- let mode = $state<Mode>("system");
1370
-
1371
- $effect(() => {
1372
- mode = getMode();
1373
- return watchMode((m) => (mode = m));
1374
- });
1375
-
1376
- function change() {
1377
- const target = next[mode];
1378
- setMode(target);
1379
- mode = target;
1380
- }
1381
-
1382
- const Icon = $derived(icons[mode]);
1383
- </script>
1384
-
1385
- <Button variant="ghost" size="icon" onclick={change} aria-label="Switch to {next[mode]} theme">
1386
- <Icon />
1387
- </Button>
1388
- `;
1389
- }
1390
- function renderAppDts() {
1391
- return `// See https://svelte.dev/docs/kit/types#app.d.ts
1392
- declare global {
1393
- namespace App {
1394
- // interface Error {}
1395
- // interface Locals {}
1396
- // interface PageData {}
1397
- // interface PageState {}
1398
- // interface Platform {}
1399
- }
1400
- }
1401
-
1402
- export {};
1403
- `;
1404
- }
1405
- function renderLayoutTs() {
1406
- return `// There is no server. The backend is Xano, reached through $lib/api.ts,
1407
- // and \`npm run xano:deploy:ephemeral\` ships this app to a static host with no runtime.
1408
- //
1409
- // prerender: true \u2014 every route is rendered to its own HTML file AT BUILD TIME
1410
- // and served as a real document. That is what makes each page load as itself
1411
- // rather than as an empty shell that fills in afterwards.
1412
- //
1413
- // Prerendering IS server-rendering, just at build time rather than per request.
1414
- // So module-scope \`window\`/\`document\` access now fails the BUILD instead of the
1415
- // browser \u2014 which is the better place to find out. Reach for browser globals
1416
- // inside onMount, or guard with \`import { browser } from "$app/environment"\`.
1417
- //
1418
- // A route with dynamic segments (e.g. /posts/[id]) cannot be prerendered unless
1419
- // the build knows which ones exist, so THE BUILD FAILS and names the route.
1420
- // In that route's +page.ts, either list the ids (only those get a page):
1421
- //
1422
- // export const entries = () => [{ id: "1" }, { id: "2" }];
1423
- //
1424
- // or, for rows created at runtime, render it in the browser instead:
1425
- //
1426
- // export const prerender = false;
1427
- //
1428
- // Inherited by every route below this one.
1429
- export const prerender = true;
1430
- `;
1431
- }
1432
- function renderErrorState() {
1433
- return `<script lang="ts">
1434
- // Shared by the prerendered /404 route and +error.svelte.
1435
- let { status = 404, message = "" }: { status?: number; message?: string } = $props();
1436
- </script>
1437
-
1438
- <main class="grid min-h-screen place-items-center p-8">
1439
- <div class="max-w-md space-y-4 text-center">
1440
- <p class="text-6xl font-semibold tracking-tight">{status}</p>
1441
- <h1 class="text-xl font-medium">
1442
- {status === 404 ? "We can't find that page." : "Something went wrong."}
1443
- </h1>
1444
- <p class="text-muted-foreground text-sm">
1445
- {message !== "" ? message : "The link may be broken, or the page may have moved."}
1446
- </p>
1447
- <a
1448
- href="/"
1449
- 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"
1450
- >
1451
- Back to safety
1452
- </a>
1453
- </div>
1454
- </main>
1455
- `;
1456
- }
1457
- function renderNotFoundRoute() {
1458
- return `<script lang="ts">
1459
- // Prerendered to 404.html, which is what tells the static host to answer an
1460
- // unmatched path with a real 404 instead of quietly serving the app shell
1461
- // with a 200 (a missing asset would then reach the browser as HTML, which it
1462
- // reports as "Unexpected token '<'").
1463
- //
1464
- // It must be a route, not +error.svelte: SvelteKit never prerenders the error
1465
- // component to a file, so relying on it would ship no 404.html at all.
1466
- //
1467
- // Delete this directory and an unmatched path serves the home page with a 200
1468
- // instead \u2014 which is worse, not better, so keep it unless you have a reason.
1469
- import ErrorState from "$lib/components/error-state.svelte";
1470
- </script>
1471
-
1472
- <svelte:head>
1473
- <title>Page not found</title>
1474
- </svelte:head>
1475
-
1476
- <ErrorState status={404} />
1477
- `;
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
+ );
1478
1577
  }
1479
- function renderErrorSvelte() {
1480
- return `<script lang="ts">
1481
- // Rendered when a client-side navigation or load fails inside the running
1482
- // app. The static host never sees these \u2014 for a path that matched no
1483
- // document at all, it serves the prerendered routes/404 page instead.
1484
- import { page } from "$app/state";
1485
- import ErrorState from "$lib/components/error-state.svelte";
1486
- </script>
1487
-
1488
- <svelte:head>
1489
- <title>{page.status === 404 ? "Page not found" : "Something went wrong"}</title>
1490
- </svelte:head>
1491
-
1492
- <ErrorState status={page.status} message={page.error?.message ?? ""} />
1493
1578
  `;
1494
1579
  }
1495
- function renderLayoutSvelte() {
1496
- return `<script lang="ts">
1497
- // The shared token stylesheet \u2014 semantic colors (bg-primary,
1498
- // text-muted-foreground) plus the Tailwind v4 theme. Imported once here so
1499
- // every route gets it.
1500
- import "../index.css";
1501
-
1502
- let { children } = $props();
1503
- </script>
1504
-
1505
- {@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
+ );
1506
1591
  `;
1507
1592
  }
1508
1593
  function renderComponentsJson(choice) {
1509
1594
  const config = {
1510
- $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,
1511
1599
  tailwind: {
1512
- // v4 has no config file; the theme lives in the stylesheet — the same
1513
- // shared one the React preset points at.
1600
+ // v4 has no config file; the theme lives in the stylesheet.
1601
+ config: "",
1514
1602
  css: "frontend/src/index.css",
1515
- // Tracks the theme the stylesheet was rendered from — see the React
1516
- // preset's note; the shadcn-svelte CLI reads it the same way.
1517
- 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: ""
1518
1611
  },
1519
1612
  aliases: {
1520
- components: "$lib/components",
1521
- utils: "$lib/utils",
1522
- ui: "$lib/components/ui",
1523
- hooks: "$lib/hooks",
1524
- lib: "$lib"
1613
+ components: "@/components",
1614
+ utils: "@/lib/utils",
1615
+ ui: "@/components/ui",
1616
+ lib: "@/lib",
1617
+ hooks: "@/hooks"
1525
1618
  },
1526
- typescript: true,
1527
- 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 }
1528
1623
  };
1529
1624
  return JSON.stringify(config, null, 2) + "\n";
1530
1625
  }
1531
- function renderButtonSvelte() {
1532
- return `<script lang="ts" module>
1533
- 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"
1534
1631
 
1535
- export const buttonVariants = tv({
1536
- 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
+ {
1537
1635
  variants: {
1538
1636
  variant: {
1539
1637
  default: "bg-primary text-primary-foreground hover:bg-primary/90",
@@ -1541,503 +1639,344 @@ function renderButtonSvelte() {
1541
1639
  "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
1542
1640
  outline:
1543
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",
1544
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
1545
- 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",
1546
1646
  link: "text-primary underline-offset-4 hover:underline",
1547
1647
  },
1548
1648
  size: {
1549
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",
1550
1651
  sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
1551
1652
  lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
1552
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",
1553
1657
  },
1554
1658
  },
1555
1659
  defaultVariants: {
1556
1660
  variant: "default",
1557
1661
  size: "default",
1558
1662
  },
1559
- });
1560
-
1561
- export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
1562
- export type ButtonSize = VariantProps<typeof buttonVariants>["size"];
1563
-
1564
- export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
1565
- WithElementRef<HTMLAnchorAttributes> & {
1566
- variant?: ButtonVariant;
1567
- size?: ButtonSize;
1568
- };
1569
- </script>
1570
-
1571
- <script lang="ts">
1572
- import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements";
1573
- import type { WithElementRef } from "bits-ui";
1574
- import { cn } from "$lib/utils.js";
1575
-
1576
- let {
1577
- class: className,
1578
- variant = "default",
1579
- size = "default",
1580
- ref = $bindable(null),
1581
- href = undefined,
1582
- type = "button",
1583
- children,
1584
- ...restProps
1585
- }: ButtonProps = $props();
1586
- </script>
1587
-
1588
- {#if href}
1589
- <a
1590
- bind:this={ref}
1591
- data-slot="button"
1592
- class={cn(buttonVariants({ variant, size }), className)}
1593
- {href}
1594
- {...restProps}
1595
- >
1596
- {@render children?.()}
1597
- </a>
1598
- {:else}
1599
- <button
1600
- bind:this={ref}
1601
- data-slot="button"
1602
- class={cn(buttonVariants({ variant, size }), className)}
1603
- {type}
1604
- {...restProps}
1605
- >
1606
- {@render children?.()}
1607
- </button>
1608
- {/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 }
1609
1690
  `;
1610
1691
  }
1611
- function renderButtonIndex() {
1612
- return `export {
1613
- default as Button,
1614
- buttonVariants,
1615
- type ButtonProps,
1616
- type ButtonSize,
1617
- type ButtonVariant,
1618
- } from "./button.svelte";
1619
- `;
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
+ );
1620
1730
  }
1621
- function cardPart(slot, tag, classes) {
1622
- return `<script lang="ts">
1623
- import type { HTMLAttributes } from "svelte/elements";
1624
- import type { WithElementRef } from "bits-ui";
1625
- import { cn } from "$lib/utils.js";
1626
-
1627
- let {
1628
- class: className,
1629
- ref = $bindable(null),
1630
- children,
1631
- ...restProps
1632
- }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
1633
- </script>
1634
-
1635
- <${tag}
1636
- bind:this={ref}
1637
- data-slot="${slot}"
1638
- class={cn("${classes}", className)}
1639
- {...restProps}
1640
- >
1641
- {@render children?.()}
1642
- </${tag}>
1643
1731
  `;
1644
1732
  }
1645
- function renderCardIndex() {
1646
- return `import Root from "./card.svelte";
1647
- import Content from "./card-content.svelte";
1648
- import Description from "./card-description.svelte";
1649
- import Footer from "./card-footer.svelte";
1650
- import Header from "./card-header.svelte";
1651
- 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
+ }
1652
1815
 
1653
1816
  export {
1654
- Root,
1655
- Content,
1656
- Description,
1657
- Footer,
1658
- Header,
1659
- Title,
1660
- //
1661
- Root as Card,
1662
- Content as CardContent,
1663
- Description as CardDescription,
1664
- Footer as CardFooter,
1665
- Header as CardHeader,
1666
- Title as CardTitle,
1667
- };
1817
+ Card,
1818
+ CardHeader,
1819
+ CardFooter,
1820
+ CardTitle,
1821
+ CardAction,
1822
+ CardDescription,
1823
+ CardContent,
1824
+ }
1668
1825
  `;
1669
1826
  }
1670
- var sveltePreset = {
1671
- id: "svelte",
1672
- label: "SvelteKit",
1827
+ var reactPreset = {
1828
+ id: "react",
1829
+ label: "React + Vite",
1673
1830
  dependencies: {
1674
- // shadcn-svelte's runtime surface. `bits-ui` is the headless primitive
1675
- // library its components are built on (the Radix equivalent), and
1676
- // `tailwind-variants` types the variants (the cva equivalent). clsx +
1677
- // tailwind-merge back the `cn()` its components import from `$lib/utils`.
1678
- // Pre-installed so `npx shadcn-svelte@latest add <component>` works
1679
- // 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.
1680
1838
  //
1681
- // The icon package is `--icons`, merged in by renderPackageJson from
1682
- // `iconBinding` below — see the React preset's note.
1683
- "bits-ui": "^2.18.1",
1684
- clsx: "^2.1.1",
1685
- "tailwind-merge": "^3.0.1",
1686
- "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"
1687
1847
  },
1688
1848
  devDependencies: {
1689
- // The SDK's adapter (`@xano/sdk/sveltekit`) bundles its server half with
1690
- // esbuild; Vite 8 does not install it.
1691
- esbuild: "^0.28.1",
1692
- // 2.70 peer-accepts vite ^8 and vite-plugin-svelte ^7 — the versions
1693
- // pinned below. Bump this line and those two together.
1694
- "@sveltejs/kit": "^2.70.2",
1695
- // 7.x, matching what `sv create` installs. It peer-requires vite ^8, so
1696
- // this line and the `vite` pin move together or not at all — and the React
1697
- // preset's plugin has the same constraint, which is why the two presets
1698
- // share one Vite major rather than each choosing.
1699
- "@sveltejs/vite-plugin-svelte": "^7.1.2",
1700
1849
  "@tailwindcss/vite": "^4.1.5",
1701
1850
  "@types/node": "^20.19.43",
1702
- svelte: "^5.56.9",
1703
- "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",
1704
1860
  tailwindcss: "^4.1.5",
1705
1861
  "tw-animate-css": "^1.2.4",
1706
1862
  tsx: "^4.19.2",
1707
- // 6.x, the major `sv create` pins. svelte-check peer-accepts `^5 || ^6`;
1708
- // 7 is out but not yet in that range, so this tracks the canonical
1709
- // 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.
1710
1866
  typescript: "^6.0.3",
1711
1867
  vite: "^8.0.16"
1712
1868
  },
1713
- // svelte-check REPLACES `tsc --noEmit` here rather than joining it.
1714
- //
1715
- // It is a superset: reading the same tsconfig, it checks `xano/`'s TypeScript
1716
- // exactly as `tsc` would AND the components `tsc` cannot parse at all. Running
1717
- // both is not merely redundant — `tsc` fails outright on the UI kit's barrels,
1718
- // which re-export types from `.svelte` modules it only knows as default
1719
- // exports. Verified against a real scaffold: a type error planted in
1720
- // `xano/index.ts` and one planted in `App.svelte` are each caught by this
1721
- // command alone.
1722
- //
1723
- // `svelte-kit sync` runs first, and is not optional: it generates
1724
- // `.svelte-kit/tsconfig.json` (which the project's tsconfig extends) and the
1725
- // route types. Without it svelte-check fails on a missing extends target
1726
- // rather than on anything the user wrote.
1727
- checkCmd: "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
1728
- // SvelteKit supplies `$lib` on both sides — the Vite alias from its plugin
1729
- // and the tsconfig path from the config it generates. Declaring either by
1730
- // hand would be a second source of truth that can silently disagree.
1731
- aliasName: null,
1732
- aliasTarget: "frontend/src/lib",
1733
- tsconfigPaths: {},
1734
- tsconfigExtends: "./.svelte-kit/tsconfig.json",
1735
- // What `svelte-kit sync` generates and the extended config lists — re-added
1736
- // because our `include` replaces that config's rather than merging with it.
1737
- // These are the declarations behind `$app/*`, `$env/*`, and `./$types`.
1738
- tsconfigInclude: [
1739
- ".svelte-kit/ambient.d.ts",
1740
- ".svelte-kit/env.d.ts",
1741
- ".svelte-kit/non-ambient.d.ts",
1742
- ".svelte-kit/types/**/$types.d.ts"
1743
- ],
1744
- // `prepare` runs on `npm install`, so a fresh clone has `.svelte-kit/`
1745
- // before anything reads tsconfig.json.
1746
- extraScripts: { prepare: "svelte-kit sync" },
1747
- // shadcn-svelte's generated components import these from `$lib/utils.js`
1748
- // alongside `cn()`. Without them the scaffold type-checks until the first
1749
- // `npx shadcn-svelte@latest add <name>` — which the agent guidance tells
1750
- // assistants to run — and then fails inside components the user never wrote,
1751
- // with an error naming a file they have no reason to suspect.
1752
- //
1753
- // Verbatim from shadcn-svelte's own utils.ts, so a component the CLI writes
1754
- // resolves against exactly what upstream expects.
1755
- libUtilsExtra: `
1756
- export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
1757
- export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
1758
- export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
1759
- export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
1760
- `,
1761
- gitignoreEntries: [".svelte-kit/"],
1762
- // No `jsx`. `verbatimModuleSyntax` is what svelte-check expects so that
1763
- // type-only imports in components are erased rather than emitted.
1764
- 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" },
1765
1877
  viteImports: [
1766
- `import { sveltekit } from "@sveltejs/kit/vite";`,
1767
- `import adapter from "@xano/sdk/sveltekit";`,
1878
+ `import react from "@vitejs/plugin-react";`,
1768
1879
  `import tailwindcss from "@tailwindcss/vite";`
1769
1880
  ],
1770
- // tailwindcss() before sveltekit() — the order Tailwind v4 documents for
1771
- // SvelteKit, so the stylesheet is processed before Kit consumes the graph.
1772
- //
1773
- // The whole SvelteKit config rides in the sveltekit() call. There is no
1774
- // svelte.config.js by design — see renderSvelteKitPlugin().
1775
- vitePlugins: ["tailwindcss()", renderSvelteKitPlugin()],
1776
- // SvelteKit resolves its own paths from this file's directory and redirects
1777
- // them into frontend/ via `files`; moving Vite's root under it puts the two
1778
- // into disagreement. Output is the adapter's job, not `build.outDir`.
1779
- viteRoot: null,
1780
- viteBuild: null,
1781
- // SvelteKit owns the page template — frontend/src/app.html. No `entryScript`
1782
- // follows: there is no shared index.html for it to point at.
1783
- ownsHtmlEntry: true,
1784
- files(vars, landing, choice = defaultThemeChoice()) {
1785
- 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()) {
1786
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`.
1787
1889
  { path: "components.json", content: renderComponentsJson(choice) },
1788
- { path: "frontend/src/app.html", content: renderAppHtml(vars, choice) },
1789
- // 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.
1790
1894
  ...choice.dark === "toggle" ? [
1791
1895
  {
1792
- path: "frontend/src/lib/components/mode-toggle.svelte",
1793
- content: renderModeToggleSvelte(iconLibraryOf(choice.icons).svelte)
1896
+ path: "frontend/src/components/mode-toggle.tsx",
1897
+ content: renderModeToggleTsx(iconLibraryOf(choice.icons).react)
1794
1898
  }
1795
1899
  ] : [],
1796
- { path: "frontend/src/app.d.ts", content: renderAppDts() },
1797
- { path: "frontend/src/routes/+layout.ts", content: renderLayoutTs() },
1798
- { path: "frontend/src/routes/+layout.svelte", content: renderLayoutSvelte() },
1799
- { path: "frontend/src/routes/+page.svelte", content: renderApp(landing, choice) },
1800
- { path: "frontend/src/routes/+error.svelte", content: renderErrorSvelte() },
1801
- { path: "frontend/src/routes/404/+page.svelte", content: renderNotFoundRoute() },
1802
- { path: "frontend/src/lib/components/error-state.svelte", content: renderErrorState() },
1803
- // `kit.files.assets` points here: static files copied to the site root
1804
- // verbatim. A README rather than a .gitkeep because this one gets
1805
- // PUBLISHED — everything here lands in frontend/dist, so the placeholder
1806
- // that keeps the directory in git is a file real users will see deployed.
1807
- {
1808
- path: "frontend/static/README.md",
1809
- content: `Files here are copied to the site root as-is \u2014 \`favicon.png\` is served
1810
- at \`/favicon.png\`. Reference them from a component with a root-relative
1811
- path, or from \`app.html\` via \`%sveltekit.assets%\`.
1812
-
1813
- Delete this file once you add something real.
1814
- `
1815
- },
1816
- { path: `${ui}/button/button.svelte`, content: renderButtonSvelte() },
1817
- { path: `${ui}/button/index.ts`, content: renderButtonIndex() },
1818
- {
1819
- path: `${ui}/card/card.svelte`,
1820
- content: cardPart(
1821
- "card",
1822
- "div",
1823
- "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm"
1824
- )
1825
- },
1826
- {
1827
- path: `${ui}/card/card-header.svelte`,
1828
- content: cardPart(
1829
- "card-header",
1830
- "div",
1831
- "@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"
1832
- )
1833
- },
1834
- {
1835
- path: `${ui}/card/card-title.svelte`,
1836
- content: cardPart("card-title", "div", "leading-none font-semibold")
1837
- },
1838
- {
1839
- path: `${ui}/card/card-description.svelte`,
1840
- content: cardPart("card-description", "div", "text-sm text-muted-foreground")
1841
- },
1842
- {
1843
- path: `${ui}/card/card-content.svelte`,
1844
- content: cardPart("card-content", "div", "px-6")
1845
- },
1846
- {
1847
- path: `${ui}/card/card-footer.svelte`,
1848
- content: cardPart("card-footer", "div", "flex items-center px-6 [.border-t]:pt-6")
1849
- },
1850
- { 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() }
1851
1904
  ];
1852
1905
  },
1853
1906
  iconBinding(id) {
1854
- return iconLibraryOf(id).svelte;
1907
+ return iconLibraryOf(id).react;
1855
1908
  },
1856
1909
  readmeFrontendSection(icons) {
1857
- return `[SvelteKit](https://svelte.dev/docs/kit) with Svelte 5, styled with
1858
- [Tailwind CSS](https://tailwindcss.com) v4 and
1859
- [shadcn-svelte](https://shadcn-svelte.com).
1860
-
1861
- Pages live in [\`frontend/src/routes/\`](frontend/src/routes/) \u2014 \`+page.svelte\`
1862
- is a page, a subdirectory is a nested route. Routes are **prerendered**: each
1863
- becomes its own HTML document at build time, so a page loads as itself rather
1864
- than as a shell that fills in afterwards, and an unmatched path returns a real
1865
- 404 from [\`+error.svelte\`](frontend/src/routes/+error.svelte).
1866
-
1867
- > **There is no server.** \`npm run xano:deploy:ephemeral\` ships this app to a static host
1868
- > with no runtime of its own; Xano is the backend, reached through
1869
- > [\`frontend/src/lib/api.ts\`](frontend/src/lib/api.ts). So \`+page.server.ts\`,
1870
- > form actions, and server \`load\` have nothing to run on \u2014 and **nothing warns
1871
- > you**: a project using them builds and deploys green, then fails in the
1872
- > browser. Treat them as unavailable. That is the trade \u2014 the backend is
1873
- > authored in [\`xano/\`](xano/) as TypeScript and deployed alongside the
1874
- > frontend, so it is a real backend, just not this one.
1875
- >
1876
- > \`frontend/src/routes/+layout.ts\` sets \`prerender = true\` for the whole app.
1877
- > Because prerendering renders at build time, module-scope \`window\`/\`document\`
1878
- > access now fails the **build** rather than the browser \u2014 use \`onMount\`, or
1879
- > guard with \`import { browser } from "$app/environment"\`.
1880
-
1881
- **A dynamic route fails the build until it says how it renders.** A route like
1882
- \`/posts/[id]\` cannot be prerendered unless the build knows which ids exist, so
1883
- the build stops and names it. For rows created at runtime (the usual detail
1884
- page), render it in the browser:
1885
-
1886
- \`\`\`ts
1887
- // frontend/src/routes/posts/[id]/+page.ts
1888
- export const prerender = false;
1889
- \`\`\`
1890
-
1891
- The host has no file for \`/posts/42\`, so it answers with \`404.html\`, which the
1892
- SDK's adapter (\`@xano/sdk/sveltekit\`, in \`vite.config.ts\`) writes as the app
1893
- shell: it boots the app and renders the route, so a reload or a deep link works
1894
- (the response status is still 404). Only for ids known at build time, list them
1895
- instead \u2014 each gets its own page, and no other id has one:
1896
- \`export const entries = () => [{ id: "1" }, { id: "2" }];\`
1897
-
1898
- [\`frontend/src/routes/404/+page.svelte\`](frontend/src/routes/404/+page.svelte)
1899
- prerenders to \`404.html\` while every route is prerendered, which is what makes
1900
- an unmatched path return a real 404. It has to be a route: SvelteKit never
1901
- prerenders \`+error.svelte\` to a file. Once a route sets \`prerender = false\`,
1902
- the adapter writes the app shell there instead, and an unmatched path renders
1903
- \`+error.svelte\` in the browser, still with a 404.
1904
-
1905
- shadcn-svelte is not a dependency \u2014
1906
- its components are copied into
1907
- [\`frontend/src/lib/components/ui/\`](frontend/src/lib/components/ui/) and owned by
1908
- this project, so edit them freely. \`Button\` and \`Card\` are already there; add
1909
- 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:
1910
1915
 
1911
1916
  \`\`\`bash
1912
- npx shadcn-svelte@latest add dialog input form
1917
+ npx shadcn@latest add dialog input form
1913
1918
  \`\`\`
1914
1919
 
1915
1920
  [\`components.json\`](components.json) is pre-configured, so that works with no
1916
- \`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.
1917
1923
 
1918
- \`\`\`ts
1919
- ${iconLibraryOf(icons).svelte.arrowImport}
1920
- \`\`\`
1921
-
1922
- [\`frontend/src/routes/+page.svelte\`](frontend/src/routes/+page.svelte) already
1923
- does, and that is the form \`npx shadcn-svelte@latest add\` writes too.
1924
-
1925
- Components import through the \`$lib\` alias
1926
- (\`$lib/components/ui/button\`, \`$lib/utils\`), which SvelteKit points at
1927
- \`frontend/src/lib/\` via \`kit.files\` in
1928
- [\`vite.config.ts\`](vite.config.ts) \u2014 there is no \`paths\` entry to keep in
1929
- 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.
1930
1928
 
1931
1929
  Colors come from the theme tokens in
1932
- [\`frontend/src/index.css\`](frontend/src/index.css) \u2014 see **Theming** below.
1933
-
1934
- > \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, not \`tsc\`. It
1935
- > checks both halves \u2014 the backend's TypeScript and the components \u2014 where
1936
- > \`tsc\` cannot read \`.svelte\` files at all. Keep it in the script: it is what
1937
- > makes the frontend unable to drift from the backend defs. \`sync\` regenerates
1938
- > \`.svelte-kit/\`, which \`tsconfig.json\` extends; \`npm install\` runs it too.`;
1930
+ [\`frontend/src/index.css\`](frontend/src/index.css) \u2014 see **Theming** below.`;
1939
1931
  },
1940
1932
  agentGuidanceSection(icons) {
1941
- return `- \`frontend/src/\` \u2014 the SvelteKit app. Svelte 5 + Tailwind v4 + shadcn-svelte.
1942
- - **There is no server.** This deploys to a static host with no runtime, and
1943
- Xano is the backend. Never write \`+page.server.ts\`, \`+layout.server.ts\`,
1944
- form actions, or server \`load\` \u2014 reach the backend through
1945
- \`frontend/src/lib/api.ts\` instead, and never stand up a second backend here.
1946
- - **The build will not stop you.** A project containing \`+page.server.ts\`
1947
- compiles and deploys green, then fails in the browser on the live site. A
1948
- passing build is not evidence that a server feature works \u2014 there is
1949
- nothing to run it.
1950
- - \`frontend/src/routes/\` \u2014 file-based routing. A page is \`+page.svelte\`, a
1951
- nested route is a subdirectory. **Routes live under \`frontend/src/\`, not a
1952
- top-level \`src/\`** \u2014 \`files\` in the \`sveltekit()\` plugin config in
1953
- \`vite.config.ts\` points SvelteKit here. A file added under a top-level
1954
- \`src/routes/\` is not a route and is never served.
1955
- - **Routes are prerendered.** \`frontend/src/routes/+layout.ts\` sets
1956
- \`prerender = true\` for the whole app, so every route is rendered to its own
1957
- HTML document at build time and served as a real page. A static route needs
1958
- nothing registered \u2014 add \`+page.svelte\` and it works.
1959
- - **Prerendering renders at BUILD time**, so module-scope \`window\`/\`document\`
1960
- access now breaks the build, not the browser. Use \`onMount\`, or guard with
1961
- \`import { browser } from "$app/environment"\`. This is a page option, not a
1962
- server \u2014 do not "fix" it by reaching for \`ssr\` or a server file.
1963
- - **A dynamic route fails the build until it says how it renders.**
1964
- \`/posts/[id]\` cannot be prerendered unless the build knows which ids exist.
1965
- For rows created at runtime (a detail page), export
1966
- \`const prerender = false\` from that route's \`+page.ts\`: the host answers
1967
- it with the \`404.html\` app shell the SDK's adapter writes, which renders it
1968
- in the browser, so reloads and deep links work. \`entries\` only fits ids
1969
- known at build time \u2014 any other id has no page.
1970
- - \`frontend/src/routes/404/+page.svelte\` prerenders to \`404.html\`, which is
1971
- what makes an unmatched path return a real 404 instead of silently serving a
1972
- page with a 200. Keep it: without it a missing asset comes back as HTML and
1973
- the browser reports \`Unexpected token '<'\`. It has to be a route \u2014 SvelteKit
1974
- never prerenders \`+error.svelte\` to a file, so that alone would ship no
1975
- \`404.html\`.
1976
- - Keep the adapter in \`vite.config.ts\` (\`@xano/sdk/sveltekit\`). Do NOT
1977
- swap in \`@sveltejs/adapter-static\` with a \`fallback\`: it writes an empty
1978
- shell over the prerendered home page.
1979
- - Data loading: call \`api.ts\` from the component, or from a universal
1980
- \`+page.ts\` \`load\` if you need it before render. Both run in the browser.
1981
- - \`frontend/src/lib/components/ui/\` \u2014 shadcn-svelte components, **copied in and
1982
- owned by this project**. Edit them directly; there is no library to configure
1983
- around.
1984
- - Need one that isn't there? \`npx shadcn-svelte@latest add <name>\` \u2014 do not
1985
- hand-roll it, and do not add a different component library. Note the
1986
- \`-svelte\` suffix: the plain \`shadcn\` CLI writes React and will not work here.
1987
- - ${iconLibraryOf(icons).guidance.svelte.replace(/\n/g, "\n ")}
1988
- - That import form is what \`frontend/src/routes/+page.svelte\` already uses and
1989
- what \`npx shadcn-svelte@latest add\` writes, so matching it keeps what you
1990
- write consistent with what the CLI generates beside it. Do not add another
1991
- icon library and do not paste raw inline \`<svg>\` markup.
1992
- - Import via the \`$lib\` alias (\`$lib/components/ui/button\`, \`$lib/utils\`),
1993
- which SvelteKit generates for both TypeScript and the bundler. Do not add a
1994
- \`paths\` entry for it \u2014 a hand-written one is a second source of truth that
1995
- can disagree with the generated one.
1996
- - Components are Svelte 5 **runes** (\`$props()\`, \`$bindable()\`,
1997
- \`{@render children?.()}\`) \u2014 not the Svelte 4 \`export let\` / slot API. Runes
1998
- mode is FORCED in \`vite.config.ts\`, so \`export let\` is a compile error
1999
- naming the file rather than a component that quietly builds in legacy mode.
2000
- Do not "fix" that error by relaxing \`compilerOptions.runes\` \u2014 write the
2001
- rune.
2002
- - \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, which checks both
2003
- \`xano/\` and the components. Do not swap it for \`tsc --noEmit\`: \`tsc\` cannot
2004
- read \`.svelte\` files and fails on the UI kit's barrels. \`sync\` regenerates
2005
- \`.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).`;
2006
1952
  }
2007
1953
  };
2008
1954
 
2009
- // src/emit/frontend-presets.ts
2010
- var FRAMEWORKS = ["react", "svelte"];
2011
- var DEFAULT_FRAMEWORK = "react";
2012
- var PRESETS = {
2013
- react: reactPreset,
2014
- svelte: sveltePreset
2015
- };
2016
- function findFrontendPreset(id) {
2017
- const normalized = id.trim().toLowerCase();
2018
- return FRAMEWORKS.includes(normalized) ? PRESETS[normalized] : void 0;
2019
- }
2020
- function allFrontendPresets() {
2021
- return FRAMEWORKS.map((id) => PRESETS[id]);
2022
- }
2023
- function resolveFrameworkFlag(raw) {
2024
- const preset = findFrontendPreset(raw);
2025
- if (preset === void 0) {
2026
- throw new Error(
2027
- `Unknown --framework "${raw}". Valid frameworks: ${FRAMEWORKS.join(", ")}.`
2028
- );
2029
- }
2030
- return preset;
2031
- }
2032
-
2033
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,
2034
1967
  sdkDep,
1968
+ sortedKeys,
1969
+ isSorted,
1970
+ renderBackendPackageJson,
2035
1971
  renderPackageJson,
2036
1972
  renderTsconfig,
1973
+ BACKEND_TSCONFIG_PATH,
1974
+ renderBackendTsconfig,
2037
1975
  renderLambdaTsconfig,
2038
1976
  renderViteConfig,
2039
1977
  renderIndexHtml,
2040
1978
  renderGitignore,
1979
+ mergeGitignore,
2041
1980
  NODE_MIN,
2042
1981
  renderGitattributes,
2043
1982
  checkJobDir,
@@ -2049,6 +1988,7 @@ export {
2049
1988
  readmeBuiltWithVersion,
2050
1989
  refreshReadmeBuiltWith,
2051
1990
  renderReadme,
1991
+ renderBackendReadme,
2052
1992
  renderXanoIndex,
2053
1993
  renderXanoExampleMd,
2054
1994
  describeOrigin,
@@ -2057,13 +1997,9 @@ export {
2057
1997
  initLanding,
2058
1998
  codegenLanding,
2059
1999
  renderIndexCss,
2000
+ renderThemeScript,
2060
2001
  renderThemeModule,
2061
2002
  renderCnUtil,
2062
- renderApiTs,
2063
- FRAMEWORKS,
2064
- DEFAULT_FRAMEWORK,
2065
- findFrontendPreset,
2066
- allFrontendPresets,
2067
- resolveFrameworkFlag
2003
+ renderApiTs
2068
2004
  };
2069
- //# sourceMappingURL=chunk-EQFYOOO6.js.map
2005
+ //# sourceMappingURL=chunk-5GIOCDUM.js.map