@xano/sdk 1.0.0

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 (336) hide show
  1. package/CHANGELOG.md +788 -0
  2. package/LICENSE +21 -0
  3. package/README.md +541 -0
  4. package/dist/.build-fingerprint +1 -0
  5. package/dist/agent-file-refresh-ZEMK33AX.js +38 -0
  6. package/dist/answer-shape-K67TAAPY.js +33 -0
  7. package/dist/backend-dir-2U53CIAL.js +39 -0
  8. package/dist/backend-slot-7QXW2QYC.js +28 -0
  9. package/dist/bin.d.ts +1 -0
  10. package/dist/bin.js +255 -0
  11. package/dist/branch-NCRNWQBQ.js +61 -0
  12. package/dist/branch-commands-ACIRCEQJ.js +79 -0
  13. package/dist/bundle.d.ts +223 -0
  14. package/dist/bundle.js +153 -0
  15. package/dist/capture-WAXPD7DR.js +41 -0
  16. package/dist/chunk-27GWNP2I.js +23 -0
  17. package/dist/chunk-2CMJZDCL.js +177 -0
  18. package/dist/chunk-2EZ3ZJZZ.js +302 -0
  19. package/dist/chunk-2GNFDZA2.js +390 -0
  20. package/dist/chunk-2MNLRIOX.js +11 -0
  21. package/dist/chunk-2TFRR6JV.js +104 -0
  22. package/dist/chunk-2ZUEE4EK.js +408 -0
  23. package/dist/chunk-36JUQZVQ.js +22 -0
  24. package/dist/chunk-3DRXWLJ5.js +83 -0
  25. package/dist/chunk-3JDU4VRL.js +137 -0
  26. package/dist/chunk-3KZCLN4Z.js +241 -0
  27. package/dist/chunk-3LDULPRE.js +168 -0
  28. package/dist/chunk-3M4LFYNQ.js +111 -0
  29. package/dist/chunk-3XI5CTUE.js +22 -0
  30. package/dist/chunk-3YW23UFH.js +50 -0
  31. package/dist/chunk-45UIT5T2.js +862 -0
  32. package/dist/chunk-4BW2SG2N.js +46 -0
  33. package/dist/chunk-4KHEMC32.js +79 -0
  34. package/dist/chunk-4POWHT2K.js +321 -0
  35. package/dist/chunk-4Q2GN7NW.js +192 -0
  36. package/dist/chunk-5A2PLKZB.js +70 -0
  37. package/dist/chunk-5FBYXK5P.js +159 -0
  38. package/dist/chunk-5HVXPTU4.js +323 -0
  39. package/dist/chunk-5QU2P5CA.js +304 -0
  40. package/dist/chunk-5V5XU32D.js +191 -0
  41. package/dist/chunk-5ZSO4T2G.js +10 -0
  42. package/dist/chunk-622HUCZT.js +10 -0
  43. package/dist/chunk-65HWOMGV.js +177 -0
  44. package/dist/chunk-6ELFRN3P.js +365 -0
  45. package/dist/chunk-6HO3NCSJ.js +1055 -0
  46. package/dist/chunk-6IUMKYWI.js +457 -0
  47. package/dist/chunk-6KEB3C3U.js +65 -0
  48. package/dist/chunk-6MR5TI5V.js +987 -0
  49. package/dist/chunk-6NNTNXN7.js +157 -0
  50. package/dist/chunk-6PBR37LN.js +97 -0
  51. package/dist/chunk-6QXLMMT3.js +155 -0
  52. package/dist/chunk-6ZGJCBZS.js +224 -0
  53. package/dist/chunk-73IVBKMA.js +250 -0
  54. package/dist/chunk-7G3CTU7I.js +286 -0
  55. package/dist/chunk-A3UDOZB6.js +222 -0
  56. package/dist/chunk-A6E77GDW.js +85 -0
  57. package/dist/chunk-AHJWCYQO.js +660 -0
  58. package/dist/chunk-AKNCFVKZ.js +36 -0
  59. package/dist/chunk-AM4FKL4J.js +237 -0
  60. package/dist/chunk-AN6BL47T.js +26 -0
  61. package/dist/chunk-AOSYVMUS.js +147 -0
  62. package/dist/chunk-APWXY5SL.js +182 -0
  63. package/dist/chunk-AWEIIR2U.js +218 -0
  64. package/dist/chunk-AWQ7BQTQ.js +73 -0
  65. package/dist/chunk-BAUZOWGX.js +393 -0
  66. package/dist/chunk-BHACRS6R.js +940 -0
  67. package/dist/chunk-BWPNT55T.js +680 -0
  68. package/dist/chunk-C6RIMRU4.js +187 -0
  69. package/dist/chunk-CGVQZXYG.js +263 -0
  70. package/dist/chunk-CIMQZRRE.js +162 -0
  71. package/dist/chunk-CJHQKJU4.js +113 -0
  72. package/dist/chunk-CTMO46PK.js +1897 -0
  73. package/dist/chunk-D53J55C5.js +106 -0
  74. package/dist/chunk-D7VGG3WS.js +90 -0
  75. package/dist/chunk-DAD3ONIS.js +245 -0
  76. package/dist/chunk-DGWHAVRG.js +162 -0
  77. package/dist/chunk-DX4QR4B2.js +483 -0
  78. package/dist/chunk-EHP3WPEG.js +21 -0
  79. package/dist/chunk-ELP2HMXC.js +432 -0
  80. package/dist/chunk-ERVIASGL.js +21 -0
  81. package/dist/chunk-ET4Y4XCB.js +865 -0
  82. package/dist/chunk-ETO6LGLD.js +4750 -0
  83. package/dist/chunk-EUUUMY7J.js +24 -0
  84. package/dist/chunk-FQJ2TTHP.js +218 -0
  85. package/dist/chunk-FQOF7E2E.js +133 -0
  86. package/dist/chunk-FWD7AL6N.js +21 -0
  87. package/dist/chunk-FXFV3KU6.js +138 -0
  88. package/dist/chunk-FXRQOWTE.js +171 -0
  89. package/dist/chunk-G554NZNI.js +210 -0
  90. package/dist/chunk-GSGDWJB5.js +13 -0
  91. package/dist/chunk-H2V3N23D.js +66 -0
  92. package/dist/chunk-H5C7MBCR.js +159 -0
  93. package/dist/chunk-HHN734BU.js +371 -0
  94. package/dist/chunk-HRVBLCVJ.js +243 -0
  95. package/dist/chunk-HVRUQXGD.js +1264 -0
  96. package/dist/chunk-I4F5TCJH.js +130 -0
  97. package/dist/chunk-IDOTCMDV.js +57 -0
  98. package/dist/chunk-IGOLHKWF.js +427 -0
  99. package/dist/chunk-JGE7CAWB.js +148 -0
  100. package/dist/chunk-JTUKLCXS.js +92 -0
  101. package/dist/chunk-JZGVVJSI.js +66 -0
  102. package/dist/chunk-K4WX6UUU.js +923 -0
  103. package/dist/chunk-K5BBGTYZ.js +217 -0
  104. package/dist/chunk-K6RXBGUB.js +427 -0
  105. package/dist/chunk-KTSDSD36.js +165 -0
  106. package/dist/chunk-L5JYN3NM.js +1038 -0
  107. package/dist/chunk-LIEOKXKD.js +354 -0
  108. package/dist/chunk-LLNZGEFK.js +51 -0
  109. package/dist/chunk-LPECSJ2J.js +55 -0
  110. package/dist/chunk-LQCMKAJ7.js +413 -0
  111. package/dist/chunk-LRN4ZJCQ.js +1145 -0
  112. package/dist/chunk-MJ4ZVHKN.js +17 -0
  113. package/dist/chunk-MXHSQOC4.js +3061 -0
  114. package/dist/chunk-N5GKCWE5.js +367 -0
  115. package/dist/chunk-NA3PXMEF.js +10 -0
  116. package/dist/chunk-NAQDMEHV.js +76 -0
  117. package/dist/chunk-NWKXM5RD.js +109 -0
  118. package/dist/chunk-NZOWWHU5.js +196 -0
  119. package/dist/chunk-OHX6MIUZ.js +184 -0
  120. package/dist/chunk-OOXWYAA4.js +15 -0
  121. package/dist/chunk-OPHB5ORL.js +1990 -0
  122. package/dist/chunk-OXA6PSZT.js +1725 -0
  123. package/dist/chunk-P2HAGF6H.js +73 -0
  124. package/dist/chunk-PTHVMXZI.js +3036 -0
  125. package/dist/chunk-PZ5AY32C.js +10 -0
  126. package/dist/chunk-Q325JKYB.js +189 -0
  127. package/dist/chunk-Q7DGTQ5G.js +255 -0
  128. package/dist/chunk-QCNYHBL7.js +601 -0
  129. package/dist/chunk-QO6BVGS5.js +145 -0
  130. package/dist/chunk-QXTKSOFI.js +76 -0
  131. package/dist/chunk-ROY4YAEQ.js +66 -0
  132. package/dist/chunk-RTJRZFFY.js +447 -0
  133. package/dist/chunk-SAVJUS2X.js +128 -0
  134. package/dist/chunk-SFLHVCKX.js +173 -0
  135. package/dist/chunk-STSFNCY4.js +127 -0
  136. package/dist/chunk-SWBF2LTK.js +170 -0
  137. package/dist/chunk-T5KELPAR.js +109 -0
  138. package/dist/chunk-TFFGOFVZ.js +1481 -0
  139. package/dist/chunk-TLHIFK4M.js +256 -0
  140. package/dist/chunk-TLQE7ZN3.js +156 -0
  141. package/dist/chunk-TPHWJ7UG.js +1981 -0
  142. package/dist/chunk-TRJCALW3.js +291 -0
  143. package/dist/chunk-TTEIYD5P.js +133 -0
  144. package/dist/chunk-U64O2MXY.js +407 -0
  145. package/dist/chunk-UCQ2VUTG.js +630 -0
  146. package/dist/chunk-UTI5G6OJ.js +44 -0
  147. package/dist/chunk-UVHDMMIP.js +188 -0
  148. package/dist/chunk-UZ6QQWJT.js +120 -0
  149. package/dist/chunk-VAX3UZOY.js +686 -0
  150. package/dist/chunk-W3HBUKFO.js +57 -0
  151. package/dist/chunk-WKQLGKCL.js +2823 -0
  152. package/dist/chunk-WQFNASK4.js +560 -0
  153. package/dist/chunk-WRBKLYSJ.js +224 -0
  154. package/dist/chunk-WTPZRR4I.js +17 -0
  155. package/dist/chunk-WZDJ2LLX.js +2385 -0
  156. package/dist/chunk-X2NL4KUO.js +14 -0
  157. package/dist/chunk-X4DVXBFY.js +38 -0
  158. package/dist/chunk-X677DMZM.js +7050 -0
  159. package/dist/chunk-XBKMWY7F.js +612 -0
  160. package/dist/chunk-XNCP4KYO.js +78 -0
  161. package/dist/chunk-XVBGLISP.js +35 -0
  162. package/dist/chunk-XW6KISBB.js +1192 -0
  163. package/dist/chunk-YGZHHAAB.js +8156 -0
  164. package/dist/chunk-YHEFQUQB.js +186 -0
  165. package/dist/chunk-YLDALTWZ.js +653 -0
  166. package/dist/chunk-YU4HSQW7.js +229 -0
  167. package/dist/chunk-ZDPP6RKB.js +27 -0
  168. package/dist/chunk-ZFDZKNGG.js +194 -0
  169. package/dist/chunk-ZIY7RNUT.js +49 -0
  170. package/dist/chunk-ZYJP6BOO.js +30 -0
  171. package/dist/cli.d.ts +1111 -0
  172. package/dist/cli.js +165 -0
  173. package/dist/codegen-command-VR2GWR6C.js +173 -0
  174. package/dist/codegen.d.ts +115 -0
  175. package/dist/codegen.js +19 -0
  176. package/dist/commands-GJMJ4XYZ.js +76 -0
  177. package/dist/completion-ZQLO6PB6.js +738 -0
  178. package/dist/config-MBYGCAFK.js +136 -0
  179. package/dist/deploy-command-JVZPWHMK.js +180 -0
  180. package/dist/deploy-source-3W45CXMP.js +81 -0
  181. package/dist/dev-env-sync-HN44K4D5.js +188 -0
  182. package/dist/diagnostics-UEAAHWVF.js +30 -0
  183. package/dist/display-name-hint-ABBPVQIR.js +46 -0
  184. package/dist/emit-CyhBDxli.d.ts +7007 -0
  185. package/dist/env-example-refresh-ET5HMMDW.js +126 -0
  186. package/dist/env-pull-command-TNMNB3CV.js +323 -0
  187. package/dist/env-target-O4HRKTGZ.js +40 -0
  188. package/dist/env-var-command-ZIRDCAZA.js +427 -0
  189. package/dist/ephemeral-P7F3PMAD.js +54 -0
  190. package/dist/ephemeral-command-CLJJKOFT.js +592 -0
  191. package/dist/ephemeral-state-PYCBSOGX.js +61 -0
  192. package/dist/file-lock-PT74GWYW.js +10 -0
  193. package/dist/generate-command-AYEOLA26.js +510 -0
  194. package/dist/gitignore-3SJ3WNRG.js +51 -0
  195. package/dist/guards-4EBNCZDC.js +162 -0
  196. package/dist/hosted-file-PSHJB3HX.js +28 -0
  197. package/dist/impersonate-command-5JAS3WSV.js +152 -0
  198. package/dist/import-EQSFU6JC.js +19 -0
  199. package/dist/index.d.ts +5470 -0
  200. package/dist/index.js +371 -0
  201. package/dist/init-command-X2FR4UAK.js +125 -0
  202. package/dist/init-modules-RY7UHAOL.js +50 -0
  203. package/dist/init-web-M4YZSZK6.js +42 -0
  204. package/dist/internal.d.ts +179 -0
  205. package/dist/internal.js +2634 -0
  206. package/dist/io-RC56QSN5.js +26 -0
  207. package/dist/keep-data-merge-7MPLVAVI.js +1119 -0
  208. package/dist/lambda-config-reconcile-OUZ4OYAB.js +116 -0
  209. package/dist/landed-753YLJ5H.js +40 -0
  210. package/dist/landing-record-SU52SKXU.js +61 -0
  211. package/dist/live-diff-YONW2VI3.js +65 -0
  212. package/dist/local-engine-choice-CH5X3W7E.js +79 -0
  213. package/dist/local-engine-command-Z3OL7VOD.js +766 -0
  214. package/dist/local-engine-config-5U3SC434.js +39 -0
  215. package/dist/local-engine-deploy-PCQ4SNPB.js +39 -0
  216. package/dist/local-engine-process-EHTE5LLU.js +63 -0
  217. package/dist/local-engine-state-A4FTRFAF.js +32 -0
  218. package/dist/local-engine-update-check-6L645VBL.js +162 -0
  219. package/dist/lock-MRRHW5GS.js +87 -0
  220. package/dist/lock-commands-2QG25HL7.js +963 -0
  221. package/dist/login-command-QPYRWOXZ.js +538 -0
  222. package/dist/logout-command-WOIQLDP6.js +56 -0
  223. package/dist/loop-ALIZLOSX.js +191 -0
  224. package/dist/marketplace-command-K5YL42NO.js +977 -0
  225. package/dist/marketplace-resolve-LY32JES5.js +40 -0
  226. package/dist/meta-client-YXGPW53C.js +244 -0
  227. package/dist/module-manifest-JFGHU2TC.js +38 -0
  228. package/dist/near-key.d.ts +13 -0
  229. package/dist/near-key.js +8 -0
  230. package/dist/node.d.ts +95 -0
  231. package/dist/node.js +969 -0
  232. package/dist/operation-outcome-TZSESNC7.js +51 -0
  233. package/dist/output-target-AL3I44GG.js +47 -0
  234. package/dist/package-manager-PRAHUSCN.js +34 -0
  235. package/dist/plan-disclosure-6G4MLZKD.js +114 -0
  236. package/dist/plugin-contributions-WRNY5ABG.js +28 -0
  237. package/dist/plugin-prompt-4VA3B4FF.js +20 -0
  238. package/dist/plugin-questions-JTSYA74Q.js +24 -0
  239. package/dist/plugin.d.ts +396 -0
  240. package/dist/plugin.js +1 -0
  241. package/dist/preflight-command-2T5Z36MI.js +321 -0
  242. package/dist/profile-command-AH3PIM4X.js +800 -0
  243. package/dist/profile-pointer-GRWJU3YD.js +31 -0
  244. package/dist/profile-select-74TRDEPD.js +23 -0
  245. package/dist/project-dependency-KSH63ODT.js +35 -0
  246. package/dist/project-sdk-REPPOIBD.js +24 -0
  247. package/dist/promote-command-PCWT5N6S.js +140 -0
  248. package/dist/prompt-II3F3LND.js +27 -0
  249. package/dist/publish-command-TTDUUJI5.js +414 -0
  250. package/dist/pull-command-VBO7C4S3.js +161 -0
  251. package/dist/pull-superseded-GJWLG7XO.js +20 -0
  252. package/dist/release-command-N4ZPKMHR.js +146 -0
  253. package/dist/release-ns-command-3KFDMZ6G.js +1745 -0
  254. package/dist/response-HlXahv4K.d.ts +925 -0
  255. package/dist/retry-command-AS5EVREX.js +34 -0
  256. package/dist/routes-manifest-SNWUVBT6.js +43 -0
  257. package/dist/runtime-XETHVF33.js +14 -0
  258. package/dist/scaffold.d.ts +1911 -0
  259. package/dist/scaffold.js +107 -0
  260. package/dist/secrets-file-LVZD6IIM.js +56 -0
  261. package/dist/secrets-fill-command-TTCPSVXN.js +218 -0
  262. package/dist/seed-VU7C3QYS.js +46 -0
  263. package/dist/sent-writes-N7X4OVXT.js +22 -0
  264. package/dist/source-resolve-S2XA3XZF.js +83 -0
  265. package/dist/static-host-B2Y6AG3W.js +352 -0
  266. package/dist/status-command-RUDXTF7I.js +554 -0
  267. package/dist/store-6VNCD4D7.js +20 -0
  268. package/dist/store-ARM6VMO5.js +98 -0
  269. package/dist/store-DuYfzKlW.d.ts +3144 -0
  270. package/dist/suggest-6FOOYKHG.js +12 -0
  271. package/dist/sveltekit.d.ts +154 -0
  272. package/dist/sveltekit.js +109 -0
  273. package/dist/sync-contributions-UCEROO26.js +415 -0
  274. package/dist/table-ENAVMITR.js +42 -0
  275. package/dist/tables-command-GUPXXSB5.js +156 -0
  276. package/dist/tenant-IIHPOHGP.js +42 -0
  277. package/dist/tenant-command-D5HGI2X4.js +965 -0
  278. package/dist/test-command-TIKZMDPZ.js +476 -0
  279. package/dist/tests-BGGIOK3L.js +26 -0
  280. package/dist/token-NICJUTMT.js +72 -0
  281. package/dist/toolchain-hooks-GHKLUJOH.js +96 -0
  282. package/dist/toolchain-modules-5EAZUONB.js +24 -0
  283. package/dist/tracked-backend-EIBUMDZA.js +80 -0
  284. package/dist/update-check-2W2NLDTC.js +136 -0
  285. package/dist/upgrade-command-QHNFWM7O.js +531 -0
  286. package/dist/verify-rollout-DRCK5TDD.js +61 -0
  287. package/dist/whoami-command-STGINTXH.js +51 -0
  288. package/dist/workspace-2CLHU2LK.js +93 -0
  289. package/dist/workspace-binding-56PIIPCP.js +54 -0
  290. package/dist/workspace-command-JEXQETJD.js +535 -0
  291. package/dist/workspace-env-F2RFMSC5.js +70 -0
  292. package/dist/workspace-export-OJSH2HIW.js +21 -0
  293. package/dist/writable-VA7OISSK.js +25 -0
  294. package/dist/xano-ICFUSPFR.js +42 -0
  295. package/dist/xanosdk-import-GN42TO2B.js +56 -0
  296. package/dist/xanosdk-project-S6DXJONQ.js +41 -0
  297. package/dist/xdo-CxDr2Q1C.d.ts +1371 -0
  298. package/guides/README.md +33 -0
  299. package/guides/authoring.md +921 -0
  300. package/guides/cli.md +401 -0
  301. package/guides/codegen.md +177 -0
  302. package/guides/codes.md +404 -0
  303. package/guides/coverage.md +74 -0
  304. package/guides/deploying.md +1525 -0
  305. package/guides/environment.md +400 -0
  306. package/guides/marketplace.md +415 -0
  307. package/guides/module-contract.md +558 -0
  308. package/guides/object-kinds.md +433 -0
  309. package/guides/project-structure.md +43 -0
  310. package/guides/scaffold.md +351 -0
  311. package/guides/typed-frontend.md +242 -0
  312. package/llms/client.md +63 -0
  313. package/llms/errors.md +56 -0
  314. package/llms/fields.md +176 -0
  315. package/llms/filters.md +183 -0
  316. package/llms/kinds-agent-mcp.md +30 -0
  317. package/llms/kinds-core.md +100 -0
  318. package/llms/kinds-knowledge.md +20 -0
  319. package/llms/kinds-realtime.md +76 -0
  320. package/llms/lambda.md +94 -0
  321. package/llms/legacy.md +44 -0
  322. package/llms/lock.md +40 -0
  323. package/llms/object-kinds.md +34 -0
  324. package/llms/statements-calls.md +62 -0
  325. package/llms/statements-catalog.md +320 -0
  326. package/llms/statements-data.md +66 -0
  327. package/llms/statements-runtime.md +68 -0
  328. package/llms/tests.md +59 -0
  329. package/llms/toolchain.md +16 -0
  330. package/llms/triggers.md +36 -0
  331. package/llms/values.md +29 -0
  332. package/llms-full.txt +2085 -0
  333. package/llms.txt +493 -0
  334. package/manifest.json +11224 -0
  335. package/package.json +162 -0
  336. package/types/lambda-globals.d.ts +129 -0
@@ -0,0 +1,923 @@
1
+ import {
2
+ keptDuplicates,
3
+ replacedRegistrations,
4
+ reportSuperseded
5
+ } from "./chunk-D53J55C5.js";
6
+ import {
7
+ rerenderEnvExample
8
+ } from "./chunk-W3HBUKFO.js";
9
+ import {
10
+ carriedSeedRows,
11
+ decodeBundle,
12
+ fetchWorkspaceBundle,
13
+ placeGeneratedFiles,
14
+ refuseDuplicateSourceGuids,
15
+ reportSeedRows,
16
+ seedRowsLanding,
17
+ verifyPulledTree,
18
+ withSourceIdentities,
19
+ writeDocumentationTokens
20
+ } from "./chunk-X677DMZM.js";
21
+ import {
22
+ confirm
23
+ } from "./chunk-65HWOMGV.js";
24
+ import {
25
+ fetchSourceArchive
26
+ } from "./chunk-AOSYVMUS.js";
27
+ import {
28
+ decodeWorkspaceArchive,
29
+ encodeWorkspaceArchive
30
+ } from "./chunk-3DRXWLJ5.js";
31
+ import {
32
+ ensureSecretPathGitignored
33
+ } from "./chunk-YHEFQUQB.js";
34
+ import {
35
+ readVersion,
36
+ refreshAgentGuidance
37
+ } from "./chunk-ETO6LGLD.js";
38
+ import {
39
+ WORKSPACE_ENV_BASENAME,
40
+ WORKSPACE_ENV_EXAMPLE_BASENAME,
41
+ namesInEnvExample,
42
+ readWorkspaceEnvFile
43
+ } from "./chunk-DAD3ONIS.js";
44
+ import {
45
+ memoCredential,
46
+ refuseProfileForLocal,
47
+ selectBackend
48
+ } from "./chunk-HHN734BU.js";
49
+ import {
50
+ getAccessToken
51
+ } from "./chunk-ET4Y4XCB.js";
52
+ import {
53
+ requireBackendSlot
54
+ } from "./chunk-STSFNCY4.js";
55
+ import {
56
+ contextFlags
57
+ } from "./chunk-NAQDMEHV.js";
58
+ import {
59
+ backendDirIn,
60
+ resolveBackendDir
61
+ } from "./chunk-5A2PLKZB.js";
62
+ import {
63
+ CODEGEN_MARKER,
64
+ DECODE_MARKER,
65
+ PRESERVED_ON_REFRESH,
66
+ SHELL_FILES_IN_BACKEND,
67
+ XANO_DIR,
68
+ containedWrites,
69
+ describeDecodeReplace,
70
+ filesUnder,
71
+ planDecodeReplace,
72
+ planTouchesExisting,
73
+ readDecodeRecord,
74
+ removeEmptiedDirs,
75
+ removeFiles
76
+ } from "./chunk-AHJWCYQO.js";
77
+ import {
78
+ readLockFile,
79
+ writeLockFile
80
+ } from "./chunk-P2HAGF6H.js";
81
+ import {
82
+ decodeMarkerHead,
83
+ decodeMarkerWith
84
+ } from "./chunk-UCQ2VUTG.js";
85
+ import {
86
+ CliError,
87
+ UsageError,
88
+ detail,
89
+ info,
90
+ isMachineOutput,
91
+ pastePath,
92
+ step,
93
+ success,
94
+ terminalText,
95
+ warn,
96
+ writeJson
97
+ } from "./chunk-PTHVMXZI.js";
98
+ import {
99
+ WORKSPACE_SECRETS_BASENAME
100
+ } from "./chunk-3JDU4VRL.js";
101
+ import {
102
+ WORKSPACE_KEY,
103
+ identityNamesByGuid,
104
+ lockKey,
105
+ lockNameForObject,
106
+ withObjects
107
+ } from "./chunk-6MR5TI5V.js";
108
+ import {
109
+ shellQuote
110
+ } from "./chunk-5ZSO4T2G.js";
111
+
112
+ // src/emit/pull-command.ts
113
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
114
+ import { basename, join, dirname, isAbsolute, relative, resolve, sep } from "path";
115
+ import { execFileSync } from "child_process";
116
+ import { createRequire } from "module";
117
+ import { pathToFileURL } from "url";
118
+ var PRESERVED = /* @__PURE__ */ new Set([...PRESERVED_ON_REFRESH, ...SHELL_FILES_IN_BACKEND, basename(CODEGEN_MARKER)]);
119
+ function backendDirCleanliness(cwd, backendDir) {
120
+ try {
121
+ const out = execFileSync("git", ["status", "--porcelain", "--", backendDir], {
122
+ cwd,
123
+ encoding: "utf8",
124
+ stdio: ["ignore", "pipe", "ignore"]
125
+ });
126
+ return out.trim() === "" ? "clean" : "dirty";
127
+ } catch {
128
+ return "unknown";
129
+ }
130
+ }
131
+ function gitChangedUnder(cwd, backendDir) {
132
+ try {
133
+ const out = execFileSync("git", ["diff", "--name-only", "--relative", "HEAD", "--", backendDir], {
134
+ cwd,
135
+ encoding: "utf8",
136
+ stdio: ["ignore", "pipe", "ignore"]
137
+ });
138
+ const prefix = `${backendDir.replace(/\/+$/, "")}/`;
139
+ return new Set(
140
+ out.split("\n").map((line) => line.trim()).filter((line) => line.startsWith(prefix)).map((line) => line.slice(prefix.length))
141
+ );
142
+ } catch {
143
+ return /* @__PURE__ */ new Set();
144
+ }
145
+ }
146
+ function withGitEdits(plan, changed) {
147
+ if (changed.size === 0) return plan;
148
+ const moved = plan.rewrittenUnknown.filter((p) => changed.has(p));
149
+ if (moved.length === 0) return plan;
150
+ return {
151
+ ...plan,
152
+ edited: [...plan.edited, ...moved],
153
+ rewrittenUnknown: plan.rewrittenUnknown.filter((p) => !changed.has(p))
154
+ };
155
+ }
156
+ function lockReportOf(reconciliation) {
157
+ if (reconciliation === void 0) return { dropped: [], repinned: [], renamed: [] };
158
+ const renamed = reconciliation.renamed ?? [];
159
+ const moved = /* @__PURE__ */ new Set([...reconciliation.repinned.map((r) => r.key), ...renamed.map((r) => r.from)]);
160
+ return { dropped: reconciliation.dropped.filter((k) => !moved.has(k)), repinned: reconciliation.repinned, renamed };
161
+ }
162
+ function pulledIdentities(payload) {
163
+ const out = /* @__PURE__ */ new Map();
164
+ const appNames = identityNamesByGuid(payload);
165
+ for (const [payloadKey, value] of Object.entries(payload)) {
166
+ if (!Array.isArray(value)) continue;
167
+ for (const row of value) {
168
+ if (row === null || typeof row !== "object") continue;
169
+ const rec = row;
170
+ if (typeof rec.name !== "string") continue;
171
+ const name = lockNameForObject(payloadKey, rec, appNames);
172
+ out.set(lockKey(payloadKey, name), typeof rec.guid === "string" ? rec.guid : void 0);
173
+ }
174
+ }
175
+ return out;
176
+ }
177
+ function noneOfTheIdentities(count, lock) {
178
+ return count === 1 ? `The one identity in ${lock} does not appear in` : `None of the ${count} identities in ${lock} appear in`;
179
+ }
180
+ function reconcileLock(lock, pulled) {
181
+ const kept = [];
182
+ const dropped = [];
183
+ const repinned = [];
184
+ const renamed = [];
185
+ const keyByGuid = /* @__PURE__ */ new Map();
186
+ for (const [key, guid] of pulled) if (guid !== void 0) keyByGuid.set(guid, key);
187
+ for (const [key, entry] of Object.entries(lock.objects)) {
188
+ if (key === WORKSPACE_KEY) continue;
189
+ const identity = pulled.get(key);
190
+ const present = pulled.has(key);
191
+ if (present && (entry.guid === void 0 || identity === void 0 || entry.guid === identity)) {
192
+ kept.push(key);
193
+ } else {
194
+ dropped.push(key);
195
+ if (present && identity !== void 0 && entry.guid !== void 0) {
196
+ repinned.push({ key, from: entry.guid, to: identity });
197
+ } else if (!present && entry.guid !== void 0) {
198
+ const to = keyByGuid.get(entry.guid);
199
+ if (to !== void 0 && to !== key && to.slice(0, to.indexOf(":")) === key.slice(0, key.indexOf(":")) && !(to in lock.objects)) {
200
+ renamed.push({ from: key, to, guid: entry.guid });
201
+ }
202
+ }
203
+ }
204
+ }
205
+ return {
206
+ kept,
207
+ dropped,
208
+ repinned,
209
+ ...renamed.length > 0 ? { renamed } : {},
210
+ disjoint: kept.length === 0 && renamed.length === 0 && dropped.length > 0
211
+ };
212
+ }
213
+ function reconciledLock(lock, reconciliation, payload) {
214
+ const next = withObjects(lock, {});
215
+ for (const key of reconciliation.kept) next.objects[key] = lock.objects[key];
216
+ const ws = payload[WORKSPACE_KEY];
217
+ const pulled = ws !== null && typeof ws === "object" && typeof ws.canonical === "string" ? ws.canonical : "";
218
+ const recorded = lock.objects[WORKSPACE_KEY];
219
+ if (pulled !== "") next.objects[WORKSPACE_KEY] = { ...recorded, canonical: pulled };
220
+ else if (recorded !== void 0) next.objects[WORKSPACE_KEY] = recorded;
221
+ return next;
222
+ }
223
+ function pulledLock(lock, reconciliation, payload) {
224
+ const reconciled = reconciledLock(lock, reconciliation, payload);
225
+ try {
226
+ return withSourceIdentities(reconciled, payload);
227
+ } catch (err) {
228
+ warn(
229
+ `Could not record the source's identities in xano.lock (${err instanceof Error ? err.message : String(err)}). The first \`xanosdk export\` records them.`,
230
+ "lock.write-failed"
231
+ );
232
+ return reconciled;
233
+ }
234
+ }
235
+ function projectBackendAbove(cwd) {
236
+ let dir = resolve(cwd);
237
+ for (; ; ) {
238
+ const parent = dirname(dir);
239
+ if (parent === dir) return void 0;
240
+ dir = parent;
241
+ const backend = existsSync(join(dir, "package.json")) ? backendDirIn(dir) : join(dir, XANO_DIR);
242
+ if (existsSync(join(backend, "index.ts"))) return relative(cwd, backend).split(sep).join("/");
243
+ }
244
+ }
245
+ function decodeHint(cwd, file, out) {
246
+ const backend = resolve(cwd, out);
247
+ if (existsSync(join(backend, basename(CODEGEN_MARKER)))) {
248
+ return `To decode a bundle file into this project's backend use \`${generateHint(cwd, file, out)}\`.`;
249
+ }
250
+ const base = basename(backend);
251
+ let fresh = join(dirname(backend), `${base}-decoded`);
252
+ for (let n = 2; existsSync(fresh); n++) fresh = join(dirname(backend), `${base}-decoded-${n}`);
253
+ const shown = relative(cwd, backend).split(sep).join("/") || ".";
254
+ const target = relative(cwd, fresh).split(sep).join("/");
255
+ return `${shown}/ was not written by a decode (it holds no ${basename(CODEGEN_MARKER)}), so a decode will not replace it. To decode the bundle into a new directory beside it use \`xanosdk generate ${shellQuote(file)} --out ${shellQuote(target)}\`.`;
256
+ }
257
+ function generateHint(cwd, file, out) {
258
+ const yes = process.stdin.isTTY === true ? "" : " --yes";
259
+ const backend = resolve(cwd, out);
260
+ const here = resolve(cwd);
261
+ if (here !== backend && !here.startsWith(`${backend}${sep}`)) {
262
+ return `xanosdk generate ${shellQuote(file)} --out ${shellQuote(out)} --force${yes}`;
263
+ }
264
+ const root = dirname(backend);
265
+ const fromRoot = (p) => relative(root, p).split(sep).join("/") || ".";
266
+ const target = isAbsolute(file) ? file : fromRoot(resolve(cwd, file));
267
+ return `cd ${shellQuote(relative(here, root).split(sep).join("/"))} && xanosdk generate ${shellQuote(target)} --out ${shellQuote(fromRoot(backend))} --force${yes}`;
268
+ }
269
+ async function runPullCommand(args) {
270
+ const cwd = process.cwd();
271
+ const backendDir = resolveBackendDir(cwd, args.backendDir, (m) => new UsageError(
272
+ `${m} A pull replaces the directory it is given.`,
273
+ { hintFor: { command: "pull" } }
274
+ ));
275
+ const first = args.positionals[0];
276
+ if (first !== void 0 && !/^[a-z][a-z-]+:/i.test(first) && (/\.json$/i.test(first) || /[\\/]/.test(first))) {
277
+ const out = args.backendDir !== void 0 || existsSync(join(cwd, backendDir, "index.ts")) ? backendDir : projectBackendAbove(cwd);
278
+ throw new UsageError(
279
+ `\`xanosdk pull\` refreshes from a live backend, and "${first}" names a file. ` + (out !== void 0 ? decodeHint(cwd, first, out) : `There is no project here to decode it into: \`xanosdk init <dir> --from ${shellQuote(first)}\` writes a whole project around it.`),
280
+ { hintFor: { command: "pull" } }
281
+ );
282
+ }
283
+ if (!existsSync(join(cwd, backendDir, "index.ts"))) {
284
+ throw new UsageError(
285
+ `\`xanosdk pull\` refreshes the backend of a project that already exists, and there is no ${backendDir}/index.ts here. \`xanosdk init <dir> --from <source>\` writes a whole project around a decoded backend` + (args.backendDir === void 0 ? `, and \`--backend-dir <path>\` names the directory when this project keeps its backend somewhere discovery cannot find it.` : `.`)
286
+ );
287
+ }
288
+ const slot = requireBackendSlot("pull", void 0, "subject");
289
+ const credential = memoCredential(() => getAccessToken(args));
290
+ const source = await selectBackend(slot, args.positionals[0], { credential, deps: { cwd } });
291
+ refuseProfileForLocal(args.profile, [source.kind], slot);
292
+ const raw = args.positionals[0] ?? source.kind;
293
+ if (args.branch !== void 0 && source.kind !== "workspace") {
294
+ throw new UsageError(
295
+ `\`--branch\` applies to \`workspace\` only. ${args.positionals[0] === void 0 ? `This project's ${source.kind}` : `"${raw}"`} carries the logic it was built from, not a branch to choose between.`,
296
+ { hintFor: { command: "pull" } }
297
+ );
298
+ }
299
+ step(`Reading ${raw}`);
300
+ const fetched = args.branch !== void 0 ? { archive: encodeWorkspaceArchive(JSON.stringify(await fetchWorkspaceBundle(await credential(), args.branch))), provenance: "workspace", label: `workspace branch "${args.branch.trim()}"` } : await fetchSourceArchive(credential, raw, cwd);
301
+ const bundle = decodeWorkspaceArchive(fetched.archive);
302
+ const keptName = source.kind === "workspace" || source.kind === "local-engine" ? void 0 : projectWorkspaceName(join(cwd, backendDir, "index.ts"));
303
+ const project = decodeBundle(bundle, {
304
+ secretsFile: `${backendDir}/${WORKSPACE_SECRETS_BASENAME}`,
305
+ writesSecrets: args.noSecrets !== true,
306
+ ...keptName !== void 0 ? { workspaceName: keptName } : {}
307
+ });
308
+ refuseDuplicateSourceGuids(project);
309
+ const seedRows = carriedSeedRows(fetched.archive, bundle.payload);
310
+ const placed = placeGeneratedFiles(project, backendDir);
311
+ const settings = source.kind === "release" ? keepProjectSettings(placed, backendDir, join(cwd, backendDir)) : { files: placed, kept: false, lost: [], from: WORKSPACE_SETTINGS_FILE };
312
+ const files = settings.files;
313
+ const dirAbs = join(cwd, backendDir);
314
+ const prefix = `${backendDir}/`;
315
+ const decoded = files.map((f) => ({ path: f.path.slice(prefix.length), content: f.content }));
316
+ const incoming = new Map(decoded.map((f) => [f.path, f.content]));
317
+ const existing = filesUnder(dirAbs).filter((p) => !PRESERVED.has(p));
318
+ let plan = planDecodeReplace(dirAbs, incoming, existing, readDecodeRecord(dirAbs, existing));
319
+ const deletions = plan.removals;
320
+ const lockPath = join(cwd, backendDir, "xano.lock");
321
+ const lock = existsSync(lockPath) ? readLockFile(lockPath) : void 0;
322
+ const reconciliation = lock === void 0 ? void 0 : reconcileLock(lock, pulledIdentities(bundle.payload));
323
+ if (reconciliation?.disjoint === true && args.yes !== true) {
324
+ throw await needsYes(
325
+ args,
326
+ `${noneOfTheIdentities(reconciliation.dropped.length, "xano.lock")} ${fetched.label}. That is what pointing a project at an unrelated backend looks like, and carrying the lock across would arm a wrong prune later.`,
327
+ "if you meant to repoint this project",
328
+ { refused: "unrelated-lock" }
329
+ );
330
+ }
331
+ const existingSet = new Set(existing);
332
+ const upToDate = !planTouchesExisting(plan) && [...incoming.keys()].every((p) => existingSet.has(p)) && (reconciliation?.dropped.length ?? 0) === 0;
333
+ const duplicates = keptDuplicates(dirAbs, incoming, plan.kept, backendDir);
334
+ if (upToDate) {
335
+ await refreshAgentGuidance({ ...args, file: join(cwd, backendDir, "index.ts") });
336
+ finishUpToDate(cwd, backendDir, project, args, fetched, lock, lockPath, reconciliation, bundle.payload, files.length, plan.kept, settingsReport(settings, backendDir), seedRows, duplicates);
337
+ return;
338
+ }
339
+ const cleanliness = backendDirCleanliness(cwd, backendDir);
340
+ if (cleanliness === "dirty" && args.yes !== true) {
341
+ throw await needsYes(
342
+ args,
343
+ `${backendDir}/ has uncommitted changes, and a pull rewrites the files it decodes. Commit or stash them first.`,
344
+ "to go ahead \u2014 it overwrites your edits to decoded files and keeps files you added",
345
+ { refused: "uncommitted-changes" }
346
+ );
347
+ }
348
+ if (cleanliness === "unknown") {
349
+ warn(`Not a git repository \u2014 nothing here holds the version of ${backendDir}/ about to be replaced.`, "pull.no-git");
350
+ }
351
+ if (cleanliness === "dirty") plan = withGitEdits(plan, gitChangedUnder(cwd, backendDir));
352
+ describeDecodeReplace(plan, backendDir, fetched.label, (line, files2) => warn(line, "pull.replace", files2));
353
+ const newFiles = [...incoming.keys()].filter((p) => !existingSet.has(p)).sort();
354
+ if (newFiles.length > 0) {
355
+ info(`${newFiles.length} new file${newFiles.length === 1 ? "" : "s"} will be written:`);
356
+ for (const p of newFiles.slice(0, 20)) detail(`${backendDir}/${p}`);
357
+ if (newFiles.length > 20) detail(`\u2026 and ${newFiles.length - 20} more`);
358
+ }
359
+ const droppedSeeds = codeSeedsDropped(dirAbs, incoming, plan, backendDir);
360
+ const rowsOnly = seedRows.filter((s) => !droppedSeeds.some((d) => d.table === s.table));
361
+ reportDroppedSeeds(
362
+ droppedSeeds,
363
+ seedRows,
364
+ fetched,
365
+ contextFlags(args),
366
+ cleanliness !== "unknown",
367
+ rowsOnly.length === 0,
368
+ source.kind === "release"
369
+ );
370
+ const modulesReplaced = replacedRegistrations(
371
+ dirAbs,
372
+ incoming,
373
+ existing.filter((p) => !plan.kept.includes(p)),
374
+ backendDir
375
+ );
376
+ reportSuperseded(duplicates, modulesReplaced, backendDir, cleanliness === "clean");
377
+ if (keptName !== void 0) {
378
+ detail(`Kept this project's workspace name "${keptName}" \u2014 ${fetched.label} does not carry it.`);
379
+ }
380
+ reportSeedRows(rowsOnly, fetched.label, fetched.provenance, backendDir, contextFlags(args));
381
+ if (settings.kept) {
382
+ detail(
383
+ `Kept this project's ${backendDir}/${WORKSPACE_SETTINGS_FILE} \u2014 ${fetched.label} carries no workspace settings.`
384
+ );
385
+ } else if (settings.lost.length > 0) {
386
+ warn(
387
+ `${fetched.label} carries no workspace settings, so the workspaceConfig in ${backendDir}/${settings.from} is rewritten without its ${settings.lost.join(", ")}. ${cleanliness === "unknown" ? "Add them back by hand" : "Restore them from git"} to keep them` + (settings.from === WORKSPACE_SETTINGS_FILE ? ` (a release pull keeps ${backendDir}/${WORKSPACE_SETTINGS_FILE} when ${backendDir}/index.ts imports its export and passes it to \`.registerWorkspace()\`)` : ` (declared in ${backendDir}/${WORKSPACE_SETTINGS_FILE} as \`export const workspaceSettings\`, a release pull keeps them)`) + `, or pull from the workspace that holds them.`,
388
+ "pull.settings-lost"
389
+ );
390
+ }
391
+ if (plan.removals.includes(WORKSPACE_SETTINGS_FILE)) {
392
+ warn(
393
+ `${fetched.label} carries no workspace settings, so ${backendDir}/${WORKSPACE_SETTINGS_FILE} (the previous decode's) is removed and index.ts registers none. Restore it from git to keep them, or pull from the workspace that holds them.`,
394
+ "pull.settings-lost"
395
+ );
396
+ }
397
+ const lockReport = lockReportOf(reconciliation);
398
+ if (lockReport.dropped.length > 0) {
399
+ const dropped = lockReport.dropped;
400
+ warn(
401
+ `${dropped.length} ${backendDir}/xano.lock entr${dropped.length === 1 ? "y has" : "ies have"} no counterpart in ${fetched.label} and will be dropped:`,
402
+ "pull.lock-dropped",
403
+ // The lock's own key spelling (`dbo:users`), so it can be found in the file.
404
+ capped(dropped)
405
+ );
406
+ }
407
+ if (lockReport.renamed.length > 0) {
408
+ const renamed = lockReport.renamed;
409
+ info(
410
+ `${renamed.length} ${backendDir}/xano.lock entr${renamed.length === 1 ? "y keeps its" : "ies keep their"} identity under the name ${fetched.label} carries ${renamed.length === 1 ? "it" : "them"} by (renamed there):`
411
+ );
412
+ for (const line of capped(renamed.map((r) => `${r.from} \u2192 ${r.to} (guid ${r.guid})`))) detail(line);
413
+ }
414
+ if (lockReport.repinned.length > 0) {
415
+ const repinned = lockReport.repinned;
416
+ warn(
417
+ `${repinned.length} ${backendDir}/xano.lock entr${repinned.length === 1 ? "y" : "ies"} will be re-pinned to the object ${fetched.label} holds under the same name:`,
418
+ "pull.lock-repinned",
419
+ capped(repinned.map((r) => `${r.key}: ${r.from} \u2192 ${r.to}`))
420
+ );
421
+ }
422
+ if (args.yes !== true) {
423
+ const { yesRerun } = await import("./retry-command-AS5EVREX.js");
424
+ const { rerun, note } = yesRerun(args, "pull");
425
+ const ok = await confirm(`Replace ${backendDir}/ from ${fetched.label}?`, {
426
+ flag: "--yes",
427
+ refusal: { details: { written: false }, rerun, note }
428
+ });
429
+ if (!ok) {
430
+ info("Pull cancelled. Nothing was written.");
431
+ return;
432
+ }
433
+ }
434
+ const planned = containedWrites(
435
+ join(cwd, backendDir),
436
+ files,
437
+ (path) => new UsageError(
438
+ `${fetched.label} carries a file that would be written outside ${backendDir}/ ("${path}"). Nothing was written. A source cannot place files anywhere else in this project, so this one is refused rather than trusted.`
439
+ ),
440
+ cwd
441
+ );
442
+ const previousNames = [
443
+ .../* @__PURE__ */ new Set([
444
+ ...namesInEnvExample(join(cwd, backendDir, WORKSPACE_ENV_EXAMPLE_BASENAME)),
445
+ ...declaredEnvNames(dirAbs)
446
+ ])
447
+ ];
448
+ step(`Writing ${backendDir}/ from ${fetched.label}`);
449
+ removeFiles(dirAbs, plan.removals);
450
+ removeEmptiedDirs(dirAbs, plan.removals);
451
+ for (const file of planned) {
452
+ mkdirSync(dirname(file.full), { recursive: true });
453
+ writeFileSync(file.full, file.content, "utf8");
454
+ }
455
+ const head = decodeMarkerHead(previousMarker(dirAbs), "pull", fetched.provenance, readVersion(), project.report.toJson());
456
+ writeFileSync(join(dirAbs, DECODE_MARKER), `${JSON.stringify(decodeMarkerWith(head, decoded), null, 2)}
457
+ `, "utf8");
458
+ reportKept(backendDir, plan.kept);
459
+ reportFindings(project, backendDir);
460
+ ensureSecretPathGitignored(join(cwd, backendDir, WORKSPACE_ENV_BASENAME));
461
+ writeDocumentationTokens(
462
+ cwd,
463
+ project.documentationTokens,
464
+ args,
465
+ fetched.label,
466
+ join(cwd, backendDir, WORKSPACE_SECRETS_BASENAME)
467
+ );
468
+ if (lock !== void 0 && reconciliation !== void 0) {
469
+ writeLockFile(lockPath, pulledLock(lock, reconciliation, bundle.payload));
470
+ }
471
+ try {
472
+ const keptNames = settings.kept ? settings.envNames ?? previousNames : void 0;
473
+ reportEnvNameChanges(
474
+ cwd,
475
+ backendDir,
476
+ keptNames ?? previousNames,
477
+ keptNames ?? Object.keys(project.env),
478
+ (one) => envFillRemedy(source.kind, args, one)
479
+ );
480
+ } catch (err) {
481
+ warn(
482
+ `Could not check ${backendDir}/${WORKSPACE_ENV_BASENAME} for missing values (${err instanceof Error ? err.message : String(err)}). The pull itself is complete.`,
483
+ "pull.env-check-failed"
484
+ );
485
+ }
486
+ warnTsxNeeded(join(cwd, backendDir, "index.ts"), planned.map((f) => f.full), backendDir);
487
+ await refreshAgentGuidance({ ...args, file: join(cwd, backendDir, "index.ts") });
488
+ let verified = null;
489
+ if (args.skipRoundtrip !== true) {
490
+ step(`Verifying ${backendDir}/ round-trips`);
491
+ verified = await verifyPulledTree(cwd, backendDir, project, source.kind, settings.kept);
492
+ if (verified === false) {
493
+ process.stderr.write(`${terminalText(project.report.renderCli({ fileBase: `${backendDir}/` }))}
494
+ `);
495
+ warn(
496
+ `${backendDir}/ is NOT verified \u2014 the objects listed above do not re-export as ${fetched.label} holds them. Do not deploy it; reconcile the objects the report names, or re-run the pull once the source is fixed.`,
497
+ "pull.unverified"
498
+ );
499
+ }
500
+ }
501
+ if (isMachineOutput(args)) {
502
+ writeJson({
503
+ source: fetched.provenance,
504
+ upToDate: false,
505
+ files: files.length,
506
+ deleted: deletions.length,
507
+ removedEdited: plan.removedEdited.map((p) => `${backendDir}/${p}`),
508
+ rewrittenEdited: plan.edited.map((p) => `${backendDir}/${p}`),
509
+ kept: plan.kept.map((p) => `${backendDir}/${p}`),
510
+ lockKept: reconciliation?.kept.length ?? 0,
511
+ lockDropped: lockReport.dropped.length,
512
+ lockRepinned: lockReport.repinned.length,
513
+ lockRenamed: lockReport.renamed.length,
514
+ workspaceSettings: settingsReport(settings, backendDir),
515
+ seedRows,
516
+ newFiles: newFiles.map((p) => `${backendDir}/${p}`),
517
+ droppedSeeds,
518
+ keptDuplicates: duplicates,
519
+ modulesReplaced,
520
+ verified
521
+ });
522
+ if (verified === false) throw pullVerifyFailed(cwd, backendDir);
523
+ success(`Pulled ${fetched.label}`);
524
+ detail(`${files.length} files written, ${deletions.length} removed`);
525
+ return;
526
+ }
527
+ if (verified === false) throw pullVerifyFailed(cwd, backendDir);
528
+ success(`Pulled ${fetched.label}`);
529
+ detail(`${files.length} files written, ${deletions.length} removed`);
530
+ if (reconciliation !== void 0) {
531
+ detail(
532
+ // Every count `--json` carries, renamed included (E2E pass 29: it was not said).
533
+ `lock: ${reconciliation.kept.length} kept, ${lockReport.repinned.length} re-pinned, ${lockReport.renamed.length} renamed, ${lockReport.dropped.length} dropped`
534
+ );
535
+ }
536
+ }
537
+ function tsxResolvable(entry) {
538
+ for (const from of [pathToFileURL(resolve(entry)).href, import.meta.url]) {
539
+ try {
540
+ createRequire(from).resolve("tsx/esm/api");
541
+ return true;
542
+ } catch {
543
+ }
544
+ }
545
+ return false;
546
+ }
547
+ function warnTsxNeeded(entry, written, backendDir, resolvable = tsxResolvable) {
548
+ const modules = written.filter((f) => /\.[cm]?ts$/.test(f) && !/\.d\.[cm]?ts$/.test(f));
549
+ if (modules.length < 2 || resolvable(entry)) return;
550
+ warn(
551
+ `${backendDir}/ is now ${modules.length} TypeScript files, and an entry that imports its own modules loads only under tsx, which this project does not have \u2014 the next deploy fails until it does. Install it: \`npm i -D tsx\`.`,
552
+ "pull.tsx-needed"
553
+ );
554
+ }
555
+ function finishUpToDate(cwd, backendDir, project, args, fetched, lock, lockPath, reconciliation, payload, fileCount, kept, workspaceSettings, seedRows, duplicates) {
556
+ reportSeedRows(seedRows, fetched.label, fetched.provenance, backendDir, contextFlags(args));
557
+ ensureSecretPathGitignored(join(cwd, backendDir, WORKSPACE_ENV_BASENAME));
558
+ writeDocumentationTokens(cwd, project.documentationTokens, args, fetched.label, join(cwd, backendDir, WORKSPACE_SECRETS_BASENAME));
559
+ if (lock !== void 0 && reconciliation !== void 0) writeLockFile(lockPath, pulledLock(lock, reconciliation, payload));
560
+ if (isMachineOutput(args)) {
561
+ writeJson({
562
+ source: fetched.provenance,
563
+ upToDate: true,
564
+ files: fileCount,
565
+ deleted: 0,
566
+ removedEdited: [],
567
+ rewrittenEdited: [],
568
+ // The files no decode wrote are still there, and still the author's — the
569
+ // same list a replacing pull reports, so the field means one thing.
570
+ kept: kept.map((p) => `${backendDir}/${p}`),
571
+ lockKept: reconciliation?.kept.length ?? 0,
572
+ lockDropped: 0,
573
+ lockRepinned: 0,
574
+ lockRenamed: 0,
575
+ workspaceSettings,
576
+ seedRows,
577
+ newFiles: [],
578
+ droppedSeeds: [],
579
+ keptDuplicates: duplicates,
580
+ modulesReplaced: [],
581
+ // Nothing was written, so there is nothing new to check.
582
+ verified: null
583
+ });
584
+ }
585
+ success(`${backendDir}/ is already up to date with ${fetched.label} \u2014 nothing to replace.`);
586
+ if (!isMachineOutput(args)) {
587
+ reportKept(backendDir, kept);
588
+ reportSuperseded(duplicates, [], backendDir, false);
589
+ }
590
+ }
591
+ function codeSeedsDropped(dirAbs, incoming, plan, backendDir) {
592
+ const pulled = /* @__PURE__ */ new Map();
593
+ for (const text of incoming.values()) {
594
+ for (const t of declaredTables(text)) {
595
+ if (t.name !== null) pulled.set(t.name, (pulled.get(t.name) ?? false) || t.seeded);
596
+ }
597
+ }
598
+ const out = [];
599
+ const into = (table, own) => {
600
+ if (table === null) return incoming.has(own) ? `${backendDir}/${own}` : null;
601
+ for (const [p, text] of incoming) if (declaredTables(text).some((t) => t.name === table)) return `${backendDir}/${p}`;
602
+ return null;
603
+ };
604
+ const read = (p) => {
605
+ try {
606
+ return readFileSync(join(dirAbs, p), "utf8");
607
+ } catch {
608
+ return void 0;
609
+ }
610
+ };
611
+ for (const p of [...plan.edited, ...plan.rewrittenUnknown, ...plan.changedBySource, ...plan.removals]) {
612
+ const current = read(p);
613
+ if (current === void 0) continue;
614
+ for (const t of declaredTables(current)) {
615
+ if (!t.seeded) continue;
616
+ const kept = t.name === null ? SEED.test(incoming.get(p) ?? "") : pulled.get(t.name) === true;
617
+ if (!kept) out.push({ table: t.name, file: `${backendDir}/${p}`, kept: false, into: into(t.name, p) });
618
+ }
619
+ }
620
+ for (const p of plan.kept) {
621
+ const current = read(p);
622
+ if (current === void 0) continue;
623
+ for (const t of declaredTables(current)) {
624
+ if (t.seeded && t.name !== null && pulled.get(t.name) === false) {
625
+ out.push({ table: t.name, file: `${backendDir}/${p}`, kept: true, into: into(t.name, p) });
626
+ }
627
+ }
628
+ }
629
+ return out;
630
+ }
631
+ var SEED = /\bseed\s*:/;
632
+ function declaredTables(text) {
633
+ const starts = [...text.matchAll(/\btable\s*\(\s*\{/g)].map((m) => m.index);
634
+ return starts.map((start, i) => {
635
+ const chunk = text.slice(start, starts[i + 1] ?? text.length);
636
+ const name = /\bname\s*:\s*(["'`])([^"'`]+)\1/.exec(chunk)?.[2];
637
+ return { name: name ?? null, seeded: SEED.test(chunk) };
638
+ });
639
+ }
640
+ function reportDroppedSeeds(dropped, seedRows, fetched, flags, inGit, saysLanding, fromRelease) {
641
+ if (dropped.length === 0) return;
642
+ const { label } = fetched;
643
+ const one = dropped.length === 1;
644
+ const rowsFor = (table) => seedRows.find((s) => s.table === table)?.rows;
645
+ const lines = dropped.map((d) => {
646
+ const rows = rowsFor(d.table);
647
+ const carried = rows !== void 0 ? `${label} carries ${rows} seed ${rows === 1 ? "row" : "rows"} for it, which a decoded tree does not hold either` : fromRelease ? `${label} carries no seed rows for it` : `a pull doesn't carry live rows, so none come from ${label}`;
648
+ const file = pastePath(d.file);
649
+ const target = pastePath(d.into ?? d.file);
650
+ const gitPath = file.startsWith("../") || file.startsWith("/") ? file : `./${file}`;
651
+ const keep = d.kept ? `${file} stays on disk but is no longer part of the project \u2014 copy its \`seed:\` array into ${target} after the pull` : inGit ? `after the pull, copy its \`seed:\` array from \`git show HEAD:${gitPath}\` into ${target}` : `nothing here holds the current version \u2014 copy its \`seed:\` array out of ${file} before pulling, then into ${target}`;
652
+ const from = dirname(d.file);
653
+ const to = dirname(d.into ?? d.file);
654
+ const rebase = from === to ? "" : ` \u2014 its \`seedFile(\u2026)\`/\`hostedFile(\u2026)\` paths are relative to ${file}, so in ${target} prefix each relative one with \`${relative(to, from).split(sep).join("/")}/\` (\`./seed/x.json\` \u2192 \`${relative(to, join(from, "seed", "x.json")).split(sep).join("/").replace(/^(?!\.)/, "./")}\`)`;
655
+ return `${d.table === null ? file : `${d.table} (${file})`}: ${carried}. To keep the code seed, ${keep}${rebase}.`;
656
+ });
657
+ warn(
658
+ `${dropped.length} table${one ? " is" : "s are"} seeded in code, and the pulled tree drops ${one ? "that" : "each"} \`seed:\`:`,
659
+ "pull.seeds-dropped",
660
+ saysLanding && dropped.some((d) => rowsFor(d.table) !== void 0) ? [...lines, seedRowsLanding(fetched.provenance, flags)] : lines
661
+ );
662
+ }
663
+ function settingsReport(settings, backendDir) {
664
+ return { kept: settings.kept, dropped: settings.lost, file: `${backendDir}/${settings.from}` };
665
+ }
666
+ var WORKSPACE_SETTINGS_FILE = "workspace.ts";
667
+ var WORKSPACE_SETTINGS_BINDING = "workspaceSettings";
668
+ function registeredSettingsExport(index, settings) {
669
+ const local = /\.registerWorkspace\(\s*([A-Za-z_$][\w$]*)\s*\)/.exec(index)?.[1];
670
+ if (local === void 0) return void 0;
671
+ const imports = /\bimport\s+(?:type\s+)?([A-Za-z_$][\w$]*)?\s*,?\s*(?:\{([^}]*)\})?\s*from\s*["']\.\/workspace(?:\.js|\.ts)?["']/g;
672
+ for (const m of index.matchAll(imports)) {
673
+ if (m[1] === local) return /\bexport\s+default\b/.test(settings) ? "default" : void 0;
674
+ for (const spec of (m[2] ?? "").split(",")) {
675
+ const [imported = "", as] = spec.trim().split(/\s+as\s+/);
676
+ const name = imported.trim();
677
+ if (name === "" || (as?.trim() ?? name) !== local) continue;
678
+ const word = name.replace(/\$/g, "\\$");
679
+ const exported = new RegExp(`\\bexport\\s+(?:const|let|var)\\s+${word}\\b|\\bexport\\s*\\{[^}]*\\b${word}\\b[^}]*\\}`);
680
+ return exported.test(settings) ? { name } : void 0;
681
+ }
682
+ }
683
+ return void 0;
684
+ }
685
+ function importingKeptSettings(index, binding) {
686
+ if (binding !== "default" && binding.name === WORKSPACE_SETTINGS_BINDING) return index;
687
+ const spec = binding === "default" ? WORKSPACE_SETTINGS_BINDING : `{ ${binding.name} as ${WORKSPACE_SETTINGS_BINDING} }`;
688
+ return index.replace(
689
+ /\bimport\s*\{\s*workspaceSettings\s*\}\s*from\s*(["']\.\/workspace\.js["'])/,
690
+ (_m, from) => `import ${spec} from ${from}`
691
+ );
692
+ }
693
+ function literalEntries(text, open) {
694
+ const entries = [];
695
+ let depth = 0;
696
+ let key = true;
697
+ for (let i = open; i < text.length; i++) {
698
+ const c = text[i];
699
+ if (c === '"' || c === "'" || c === "`") {
700
+ let j = i + 1;
701
+ while (j < text.length && text[j] !== c) j += text[j] === "\\" ? 2 : 1;
702
+ if (depth === 1 && key) entries.push({ key: text.slice(i + 1, j), value: j + 1 });
703
+ i = j;
704
+ key = false;
705
+ } else if (depth === 1 && key && text.startsWith("...", i)) {
706
+ entries.push({ key: void 0, value: i + 3 });
707
+ i += 2;
708
+ key = false;
709
+ } else if ("{[(".includes(c)) {
710
+ if (depth === 1 && key && c === "[") entries.push({ key: void 0, value: i });
711
+ key = ++depth === 1;
712
+ } else if ("}])".includes(c)) {
713
+ if (--depth === 0) break;
714
+ } else if (depth === 1 && c === ",") {
715
+ key = true;
716
+ } else if (depth === 1 && key && /[A-Za-z_$]/.test(c)) {
717
+ const word = /^[\w$]+/.exec(text.slice(i))[0];
718
+ entries.push({ key: word, value: i + word.length });
719
+ i += word.length - 1;
720
+ key = false;
721
+ }
722
+ }
723
+ return entries;
724
+ }
725
+ function settingsLiteral(text) {
726
+ const at = /\bworkspaceConfig\s*\(\s*\{/.exec(text);
727
+ return at === null ? -1 : at.index + at[0].length - 1;
728
+ }
729
+ function settingsKeys(text) {
730
+ const open = settingsLiteral(text);
731
+ if (open < 0) return [];
732
+ return literalEntries(text, open).flatMap((e) => e.key === void 0 ? [] : [e.key]);
733
+ }
734
+ function settingsEnvNames(text) {
735
+ const open = settingsLiteral(text);
736
+ if (open < 0) return void 0;
737
+ const entries = literalEntries(text, open);
738
+ const env = entries.find((e) => e.key === "env");
739
+ if (env === void 0) return entries.some((e) => e.key === void 0) ? void 0 : [];
740
+ const value = /^\s*:\s*\{/.exec(text.slice(env.value));
741
+ if (value === null) return void 0;
742
+ const names = literalEntries(text, env.value + value[0].length - 1);
743
+ return names.some((e) => e.key === void 0) ? void 0 : names.map((e) => e.key);
744
+ }
745
+ function readableDeclaredEnvNames(dirAbs) {
746
+ let found = false;
747
+ const names = [];
748
+ for (const name of [WORKSPACE_SETTINGS_FILE, "index.ts"]) {
749
+ let text;
750
+ try {
751
+ text = readFileSync(join(dirAbs, name), "utf8");
752
+ } catch {
753
+ continue;
754
+ }
755
+ if (settingsLiteral(text) < 0) continue;
756
+ const read = settingsEnvNames(text);
757
+ if (read === void 0) return void 0;
758
+ found = true;
759
+ names.push(...read);
760
+ }
761
+ return found ? [...new Set(names)] : void 0;
762
+ }
763
+ function declaredEnvNames(dirAbs) {
764
+ return [WORKSPACE_SETTINGS_FILE, "index.ts"].flatMap((name) => {
765
+ try {
766
+ return settingsEnvNames(readFileSync(join(dirAbs, name), "utf8")) ?? [];
767
+ } catch {
768
+ return [];
769
+ }
770
+ });
771
+ }
772
+ function keepProjectSettings(files, backendDir, dirAbs) {
773
+ const incoming = files.find((f) => f.path === `${backendDir}/${WORKSPACE_SETTINGS_FILE}`);
774
+ const read = (name) => {
775
+ try {
776
+ return readFileSync(join(dirAbs, name), "utf8");
777
+ } catch {
778
+ return void 0;
779
+ }
780
+ };
781
+ const ours = read(WORKSPACE_SETTINGS_FILE);
782
+ const index = read("index.ts") ?? "";
783
+ const binding = ours === void 0 ? void 0 : registeredSettingsExport(index, ours);
784
+ if (incoming !== void 0 && ours !== void 0 && binding !== void 0) {
785
+ const example = `${backendDir}/${WORKSPACE_ENV_EXAMPLE_BASENAME}`;
786
+ const entry = `${backendDir}/index.ts`;
787
+ const ourExample = read(WORKSPACE_ENV_EXAMPLE_BASENAME);
788
+ const envNames = settingsEnvNames(ours);
789
+ const exampleContent = (decoded) => ourExample ?? (envNames === void 0 ? void 0 : rerenderEnvExample(decoded, envNames));
790
+ const out = files.flatMap((f) => {
791
+ if (f === incoming) return [{ ...f, content: ours }];
792
+ if (f.path === entry) return [{ ...f, content: importingKeptSettings(f.content, binding) }];
793
+ if (f.path !== example) return [f];
794
+ const content = exampleContent(f.content);
795
+ return content === void 0 ? [] : [{ ...f, content }];
796
+ });
797
+ return { files: out, kept: true, lost: [], from: WORKSPACE_SETTINGS_FILE, ...envNames === void 0 ? {} : { envNames } };
798
+ }
799
+ const inline = binding === void 0 && settingsLiteral(index) >= 0;
800
+ const from = ours !== void 0 && !inline ? WORKSPACE_SETTINGS_FILE : "index.ts";
801
+ const theirs = new Set(incoming === void 0 ? [] : settingsKeys(incoming.content));
802
+ const lost = settingsKeys(from === "index.ts" ? index : ours ?? "").filter((k) => k === "env" || !theirs.has(k));
803
+ return { files, kept: false, lost, from };
804
+ }
805
+ function projectWorkspaceName(entry) {
806
+ let text;
807
+ try {
808
+ text = readFileSync(entry, "utf8");
809
+ } catch {
810
+ return void 0;
811
+ }
812
+ const m = /\bworkspace\(\s*("(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*')\s*[,)]/.exec(text);
813
+ if (m === null) return void 0;
814
+ const lit = m[1];
815
+ try {
816
+ const name = lit.startsWith('"') ? JSON.parse(lit) : lit.slice(1, -1);
817
+ return name.trim() === "" ? void 0 : name;
818
+ } catch {
819
+ return void 0;
820
+ }
821
+ }
822
+ function reportFindings(project, backendDir) {
823
+ const rendered = project.report.renderCli({ fileBase: `${backendDir}/` });
824
+ if (rendered === "") return;
825
+ const summary = project.report.summarize();
826
+ if (summary.bySeverity.error + summary.bySeverity.warning > 0) {
827
+ warn(`Not everything was carried into the tree \u2014 ${project.report.headline()} (listed below).`, "decode.findings");
828
+ } else {
829
+ info("Some values are deliberately not carried into the tree:");
830
+ }
831
+ process.stderr.write(`${terminalText(rendered)}
832
+ `);
833
+ }
834
+ function pullVerifyFailed(cwd, backendDir) {
835
+ return Object.assign(
836
+ new Error(
837
+ `Round-trip verification failed for ${join(cwd, backendDir)} \u2014 see the mismatches above. The files were written so you can inspect them; do not deploy them.`
838
+ ),
839
+ { exitCode: 2 }
840
+ );
841
+ }
842
+ function reportKept(backendDir, kept) {
843
+ if (kept.length === 0) return;
844
+ warn(
845
+ `Kept ${kept.length} file${kept.length === 1 ? "" : "s"} in ${backendDir}/ no decode wrote \u2014 ${kept.length === 1 ? "it is" : "they are"} yours, and not part of the decoded tree:`,
846
+ "pull.kept-files",
847
+ capped(kept.map((p) => `${backendDir}/${p}`))
848
+ );
849
+ }
850
+ function capped(lines) {
851
+ return [...lines.slice(0, 20), ...lines.length > 20 ? [`\u2026 and ${lines.length - 20} more`] : []];
852
+ }
853
+ function previousMarker(dir) {
854
+ try {
855
+ const parsed = JSON.parse(readFileSync(join(dir, DECODE_MARKER), "utf8"));
856
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
857
+ } catch {
858
+ }
859
+ return {};
860
+ }
861
+ function reportEnvNameChanges(cwd, backendDir, before, after, remedy) {
862
+ const envFile = `${backendDir}/${WORKSPACE_ENV_BASENAME}`;
863
+ const exampleFile = `${backendDir}/${WORKSPACE_ENV_EXAMPLE_BASENAME}`;
864
+ const had = new Set(before);
865
+ const has = new Set(after);
866
+ const added = after.filter((n) => !had.has(n));
867
+ const removed = before.filter((n) => !has.has(n));
868
+ if (added.length > 0) {
869
+ info(`Env vars added by this pull: ${added.join(", ")} (declared in ${exampleFile}).`);
870
+ }
871
+ if (removed.length > 0) {
872
+ info(`Env vars no longer declared: ${removed.join(", ")}.`);
873
+ }
874
+ if (after.length === 0) return;
875
+ const values = readWorkspaceEnvFile(join(cwd, envFile)) ?? {};
876
+ const missing = after.filter((n) => !Object.hasOwn(values, n));
877
+ if (missing.length === 0) return;
878
+ warn(
879
+ `${missing.length} declared env var${missing.length === 1 ? " has" : "s have"} no value in ${envFile}: ${missing.join(", ")}. A deploy will refuse until ${missing.length === 1 ? "it does" : "they do"} \u2014 ${remedy(missing.length === 1)}`,
880
+ "workspace-env.missing-values"
881
+ );
882
+ }
883
+ function envFillRemedy(kind, args, one = false) {
884
+ const them = one ? "it" : "them";
885
+ const raw = args.positionals[0];
886
+ if (kind === "release") {
887
+ return `a release carries no env values, so fill ${them} in by hand, or read ${them} from a running backend with \`xanosdk env pull --from <backend>\`.`;
888
+ }
889
+ const from = raw === void 0 ? "" : ` --from ${shellQuote(raw)}`;
890
+ const flags = kind === "local-engine" ? "" : contextFlags(args);
891
+ return `fill ${them} in, or run \`xanosdk env pull${from}${flags}\`.`;
892
+ }
893
+ async function needsYes(args, head, why, details) {
894
+ const { yesRerun } = await import("./retry-command-AS5EVREX.js");
895
+ const { rerun, note } = yesRerun(args, "pull");
896
+ return new CliError("SDK_USAGE", `${head} Re-run as \`${rerun}\` ${why}.${note}`, {
897
+ exitCode: 1,
898
+ details: { reason: "needs-confirmation", written: false, ...details }
899
+ });
900
+ }
901
+
902
+ export {
903
+ backendDirCleanliness,
904
+ gitChangedUnder,
905
+ withGitEdits,
906
+ lockReportOf,
907
+ pulledIdentities,
908
+ noneOfTheIdentities,
909
+ reconcileLock,
910
+ reconciledLock,
911
+ pulledLock,
912
+ runPullCommand,
913
+ tsxResolvable,
914
+ warnTsxNeeded,
915
+ codeSeedsDropped,
916
+ registeredSettingsExport,
917
+ settingsEnvNames,
918
+ readableDeclaredEnvNames,
919
+ declaredEnvNames,
920
+ projectWorkspaceName,
921
+ envFillRemedy
922
+ };
923
+ //# sourceMappingURL=chunk-K4WX6UUU.js.map