@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,680 @@
1
+ import {
2
+ diffAgainstLive,
3
+ payloadOf,
4
+ sectionKind,
5
+ tableAdditions,
6
+ vectorSize
7
+ } from "./chunk-45UIT5T2.js";
8
+ import {
9
+ ReleaseHttpError
10
+ } from "./chunk-2ZUEE4EK.js";
11
+ import {
12
+ TenantHttpError
13
+ } from "./chunk-A3UDOZB6.js";
14
+ import {
15
+ CliError,
16
+ detail,
17
+ warn,
18
+ withoutUrls
19
+ } from "./chunk-PTHVMXZI.js";
20
+ import {
21
+ suggest
22
+ } from "./chunk-UTI5G6OJ.js";
23
+ import {
24
+ authoredFieldType
25
+ } from "./chunk-TTEIYD5P.js";
26
+
27
+ // src/emit/plan-disclosure.ts
28
+ var NO_TABLE_EFFECTS = {
29
+ mode: "merge",
30
+ droppedTables: [],
31
+ createdTables: [],
32
+ addedColumns: [],
33
+ addedDefaults: {},
34
+ renamedTables: [],
35
+ droppedColumns: [],
36
+ retypedColumns: [],
37
+ narrowedEnums: [],
38
+ retargetedRefs: [],
39
+ indexChanges: [],
40
+ notNullKept: [],
41
+ notNullTightened: []
42
+ };
43
+ function tableEffects(outgoing, live, opts) {
44
+ const diff = diffAgainstLive(outgoing, live, {
45
+ mode: opts.mode === "rebuild" ? "replace" : "merge",
46
+ ...opts.stored === void 0 ? {} : { stored: opts.stored }
47
+ });
48
+ return tableEffectsOf(diff, tableAdditions(outgoing, live), opts);
49
+ }
50
+ function tableEffectsOf(diff, additions, opts) {
51
+ const skip = opts.skipTables ?? /* @__PURE__ */ new Set();
52
+ const kept = (list) => list.filter((c) => !skip.has(c.table));
53
+ const keptName = (list) => list.filter((c) => !skip.has(c.slice(0, c.indexOf("."))));
54
+ const dotted = (list) => kept(list).map((c) => `${c.table}.${c.column}`);
55
+ const rebuild = opts.mode === "rebuild";
56
+ const addedColumns = keptName(additions?.addedColumns ?? []);
57
+ return {
58
+ mode: opts.mode,
59
+ droppedTables: opts.mode === "replace" ? diff.uncarriedTables.map((table) => ({
60
+ table,
61
+ rows: null,
62
+ ...diff.replacedTables.includes(table) ? { replaced: true } : {}
63
+ })) : [],
64
+ createdTables: (additions?.createdTables ?? []).filter((t) => !skip.has(t)),
65
+ addedColumns,
66
+ addedDefaults: Object.fromEntries(
67
+ Object.entries(additions?.addedDefaults ?? {}).filter(([c]) => addedColumns.includes(c))
68
+ ),
69
+ renamedTables: (additions?.renamedTables ?? []).filter((r) => !skip.has(r.to)),
70
+ droppedColumns: dotted(diff.droppedColumns),
71
+ retypedColumns: rebuild ? [] : kept(diff.retypedColumns),
72
+ narrowedEnums: kept(diff.narrowedEnums),
73
+ retargetedRefs: kept(diff.retargetedRefs),
74
+ indexChanges: kept(diff.indexChanges),
75
+ // Measured: a replace relaxes NOT NULL, so only a merge can keep it.
76
+ notNullKept: opts.mode === "merge" ? dotted(diff.unrelaxedColumns) : [],
77
+ notNullTightened: kept(diff.tightenedColumns),
78
+ // A replace converts a reseeded table's storage like any other (measured),
79
+ // so the reseed does not take it out of the check.
80
+ storageChanges: rebuild ? [] : opts.mode === "replace" ? [...diff.storageChanges] : kept(diff.storageChanges)
81
+ };
82
+ }
83
+ async function assertStorageModesKept(changes, count, ctx) {
84
+ if (changes === void 0 || changes.length === 0) return;
85
+ const mode = (xdo) => xdo ? "JSON storage" : "column storage";
86
+ const Subject = ctx.subject.charAt(0).toUpperCase() + ctx.subject.slice(1);
87
+ const Target = ctx.target.charAt(0).toUpperCase() + ctx.target.slice(1);
88
+ const countOf = async (c) => await count({ name: c.liveName, ...c.guid === void 0 ? {} : { guid: c.guid } }) ?? null;
89
+ const rowsText = (rows) => rows === null ? "rows not counted" : `${rows} ${rows === 1 ? "row" : "rows"}`;
90
+ const refuse = (message, held2) => new CliError("SDK_IMPORT_REFUSED", message, {
91
+ exitCode: 2,
92
+ details: {
93
+ refused: "storageModeChange",
94
+ landed: false,
95
+ tables: held2.map((c) => ({ table: c.table, from: c.from, to: c.to, rows: c.rows }))
96
+ }
97
+ });
98
+ if (ctx.mode === "replace") {
99
+ for (const c of changes.filter((c2) => !c2.to)) {
100
+ detail(`${Subject} switches table ${c.table} to column storage (useXdo true \u2192 false); the instance converts it and keeps every value.`);
101
+ }
102
+ const toXdo = changes.filter((c) => c.to);
103
+ if (toXdo.length === 0) return;
104
+ const held2 = await Promise.all(toXdo.map(async (c) => ({ ...c, rows: await countOf(c) })));
105
+ throw refuse(
106
+ `${Target} was not changed: ${ctx.subject} switches ${held2.length === 1 ? "a table" : `${held2.length} tables`} to JSON storage, and the instance cannot convert a table from column storage back to JSON storage \u2014 it refuses the deploy whether or not the table holds rows:
107
+ ` + held2.map((c) => ` table ${c.table} (${rowsText(c.rows)}): useXdo false \u2192 true`).join("\n") + `
108
+ Nothing was sent. Keep each table's storage as it is: give the table \`useXdo: false\` \u2014 a table without its own \`useXdo\` follows the workspace's \`use_xdo\`. To switch one anyway, land a release that carries the JSON-storage table under a new name beside the old one, copy the rows across, then land one without the old table.`,
109
+ held2
110
+ );
111
+ }
112
+ const counted = await Promise.all(changes.map(async (c) => ({ ...c, rows: await countOf(c) })));
113
+ for (const c of counted.filter((c2) => c2.rows === 0)) {
114
+ detail(`${Subject} switches table ${c.table} to ${mode(c.to)} (useXdo ${c.from} \u2192 ${c.to}); it holds no rows, so nothing is lost.`);
115
+ }
116
+ const held = counted.filter((c) => c.rows !== 0);
117
+ if (held.length === 0) return;
118
+ const lines = held.map(
119
+ (c) => ` table ${c.table} (${rowsText(c.rows)}): useXdo ${c.from} \u2192 ${c.to} \u2014 ` + (c.from ? "every stored value would be erased (the rows stay, every field reads empty) and cannot be restored" : "the instance cannot convert a table that holds rows: the deploy fails partway on a NOT NULL violation")
120
+ );
121
+ throw refuse(
122
+ `${Target} was not changed: ${ctx.subject} switches ${held.length === 1 ? "a table" : `${held.length} tables`} holding rows to the other storage mode, which a merge cannot do without losing them:
123
+ ${lines.join("\n")}
124
+ Nothing was written. Keep each table's storage as it is: give the table \`useXdo: ${held[0].from}\`${held.some((c) => c.from !== held[0].from) ? " (or the mode it has now)" : ""} \u2014 a table without its own \`useXdo\` follows the workspace's \`use_xdo\`. To switch one anyway, declare the switched table as a new table, copy the rows across, then remove the old one${ctx.remedy === void 0 ? "." : `, or ${ctx.remedy}`}`,
125
+ held
126
+ );
127
+ }
128
+ function xdoConversionRefused(err) {
129
+ return (err instanceof TenantHttpError || err instanceof ReleaseHttpError) && /cannot be migrated from custom column names back to xdo/i.test(err.message);
130
+ }
131
+ function xdoConversionRefusal(target, err, cause) {
132
+ const table = /\bdatabase (\S+) cannot be migrated/i.exec(err.message)?.[1];
133
+ const Target = target.charAt(0).toUpperCase() + target.slice(1);
134
+ return new CliError(
135
+ "SDK_IMPORT_REFUSED",
136
+ `${Target} was not changed: the instance cannot convert ${table === void 0 ? "a table" : `table ${table}`} from column storage back to JSON storage (useXdo false \u2192 true), whether or not it holds rows, and refused the deploy. Nothing landed. Keep the table's storage as it is: give it \`useXdo: false\` \u2014 a table without its own \`useXdo\` follows the workspace's \`use_xdo\`.`,
137
+ {
138
+ exitCode: 2,
139
+ cause,
140
+ details: {
141
+ refused: "storageModeChange",
142
+ landed: false,
143
+ tables: table === void 0 ? [] : [{ table, from: false, to: true, rows: null }]
144
+ }
145
+ }
146
+ );
147
+ }
148
+ function replaceRetype(c) {
149
+ if (resizesVector(c)) return "stops";
150
+ const time = (t) => t === "epochms" || t === "timestamp";
151
+ if (c.from === "bool") return time(c.to) ? "stops" : c.to === "decimal" ? "converts" : "re-read";
152
+ if (time(c.from)) {
153
+ if (c.to === "int") return c.nullable === true ? "converts" : "stops";
154
+ return c.to === "decimal" ? "stops" : c.to === "bool" ? "converts" : "re-read";
155
+ }
156
+ return "converts";
157
+ }
158
+ function replaceConverts(c) {
159
+ return replaceRetype(c) === "converts";
160
+ }
161
+ function replaceCanStop(c) {
162
+ return replaceRetype(c) === "stops" || c.from === "text" && (c.to === "epochms" || c.to === "timestamp");
163
+ }
164
+ function stoppingRetypes(e) {
165
+ return e.mode === "replace" ? e.retypedColumns.filter(replaceCanStop).map((c) => `${c.table}.${c.column}`) : [];
166
+ }
167
+ function replaceRetypeNote(c) {
168
+ const outcome = replaceRetype(c);
169
+ if (outcome === "re-read") return ` \u2014 re-read, not converted: ${reReading(c)}`;
170
+ if (outcome === "stops") return ` \u2014 not converted: ${stopCondition(c)}`;
171
+ if (c.from === "bool") return " \u2014 converted for good: true \u2192 1, false \u2192 0";
172
+ if (c.from !== "epochms" && c.from !== "timestamp") return "";
173
+ return c.to === "int" ? " \u2014 converted for good: every timestamp \u2192 null" : " \u2014 converted for good: every value \u2192 false";
174
+ }
175
+ function reReading(c) {
176
+ const to = authoredFieldType(c.to);
177
+ if (c.from === "bool" && c.to === "text") return `true and false read "true" and "false"`;
178
+ if (c.from === "bool" && c.to === "int") return "true and false read 1 and 0";
179
+ if ((c.from === "epochms" || c.from === "timestamp") && c.to === "text") return `a timestamp reads as its epoch milliseconds ("1767225600000")`;
180
+ return `a value that does not read as ${to} reads null`;
181
+ }
182
+ function stopCondition(c) {
183
+ const from = authoredFieldType(c.from);
184
+ const to = authoredFieldType(c.to);
185
+ if (c.to === "int") {
186
+ return `a stored ${from} converts to null and ${c.column} is not nullable, so the deploy stops partway while a row holds a ${from} (a 0 lands as 0)`;
187
+ }
188
+ return `a stored ${from} does not convert to ${to}, so the deploy stops partway while the table holds rows`;
189
+ }
190
+ var READ_ONLY_SOURCES = /* @__PURE__ */ new Set(["bool", "epochms", "timestamp"]);
191
+ function omittedInsertsFail(retype, mode) {
192
+ if (mode === "rebuild") return false;
193
+ if (mode === "replace") return retype.to === "text" && READ_ONLY_SOURCES.has(retype.from);
194
+ if (retype.useXdo === true) return false;
195
+ const c = asStored(retype);
196
+ if (c.from === c.to) return false;
197
+ if (c.to === "uuid") return c.from !== "json";
198
+ if (TEXT_HELD.has(c.from)) return false;
199
+ const writes = TEXT_HELD.has(c.to) ? "text" : c.to === "json" ? "json" : NUMBER_WRITTEN.has(c.to) ? "number" : void 0;
200
+ if (writes === void 0) return false;
201
+ if (writes === "number" && !REFUSES_NUMBER.has(c.from) && !c.from.startsWith("geo_")) return false;
202
+ return !(writes === "text" && c.default !== void 0 && readsAs(c.from, c.default));
203
+ }
204
+ var TEXT_HELD = /* @__PURE__ */ new Set(["text", "email", "password", "enum"]);
205
+ var NUMBER_WRITTEN = /* @__PURE__ */ new Set(["int", "decimal", "epochms", "timestamp", "bool"]);
206
+ var REFUSES_NUMBER = /* @__PURE__ */ new Set(["date", "uuid"]);
207
+ function readsAs(type, value) {
208
+ const v = value.trim();
209
+ switch (type) {
210
+ case "int":
211
+ case "epochms":
212
+ case "timestamp":
213
+ return /^[+-]?\d+$/.test(v);
214
+ case "decimal":
215
+ return v !== "" && Number.isFinite(Number(v));
216
+ case "bool":
217
+ return /^(t|f|true|false|y|n|yes|no|on|off|1|0)$/i.test(v);
218
+ case "date":
219
+ return /^\d{4}-\d{2}-\d{2}$/.test(v);
220
+ case "uuid":
221
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v);
222
+ case "json":
223
+ try {
224
+ JSON.parse(v);
225
+ return true;
226
+ } catch {
227
+ return false;
228
+ }
229
+ default:
230
+ return false;
231
+ }
232
+ }
233
+ function setInsertsFail(retype, mode) {
234
+ const c = asStored(retype);
235
+ if (mode !== "merge") return false;
236
+ return resizesVector(c) || c.useXdo !== true && c.to === "uuid" && c.from !== "uuid" && !TEXT_HELD.has(c.from);
237
+ }
238
+ function resizesVector(c) {
239
+ const from = vectorSize(c.from);
240
+ const to = vectorSize(c.to);
241
+ return from !== void 0 && to !== void 0 && from !== to;
242
+ }
243
+ function newColumnRemedy(c) {
244
+ return `add the ${resizesVector(c) ? "new size" : "uuid"} as a new column (another name) instead`;
245
+ }
246
+ function asStored(c) {
247
+ return c.stored === void 0 || c.stored === c.from ? c : { ...c, from: c.stored };
248
+ }
249
+ function holding(c, mode, aside = "") {
250
+ const old = authoredFieldType(asStored(c).from);
251
+ if (mode !== "merge" || c.stored !== void 0) return `the column keeps holding ${old}${aside}, so`;
252
+ return `if the column still holds ${old} as created (no record here says an earlier merge retyped it)${aside},`;
253
+ }
254
+ function unknownStorageNote(c, mode) {
255
+ if (mode !== "merge" || c.stored !== void 0 || c.useXdo === true) return "";
256
+ return ` \u2014 what inserts do depends on the type the column holds, and no record here says it still holds ${authoredFieldType(c.from)} as created`;
257
+ }
258
+ function insertsFailNote(c, mode) {
259
+ if (setInsertsFail(c, mode)) {
260
+ return `${holding(c, mode, resizesVector(asStored(c)) ? ", which takes no other size" : ", which takes no uuid")} an insert that sets it fails with an SQL error` + (omittedInsertsFail(c, mode) ? " and so does one that leaves it unset" : "") + ` \u2014 ${newColumnRemedy(asStored(c))}`;
261
+ }
262
+ return `${holding(c, mode)} an insert that leaves it unset fails ${mode === "replace" ? "(SQL 22P02)" : "with an SQL error"} ${omittedInsertsRemedy(mode === "merge" ? asStored(c) : c)}`;
263
+ }
264
+ function omittedInsertsRemedy(c) {
265
+ if (c.to === "uuid") return "\u2014 a uuid column takes no default, so set it on every insert";
266
+ const example = TEXT_HELD.has(c.to) ? OLD_TYPE_DEFAULTS[c.from] : void 0;
267
+ if (example === void 0) return "whatever default it declares \u2014 set it on every insert";
268
+ const old = authoredFieldType(c.from);
269
+ return c.to === "enum" ? `until it declares a default ${old} also reads \u2014 an enum value such as ${JSON.stringify(example)}` : `until it declares a default ${old} also reads, such as ${JSON.stringify(example)}`;
270
+ }
271
+ var OLD_TYPE_DEFAULTS = {
272
+ int: "0",
273
+ decimal: "0",
274
+ epochms: "0",
275
+ timestamp: "0",
276
+ bool: "false",
277
+ date: "1970-01-01",
278
+ json: "{}",
279
+ uuid: "00000000-0000-0000-0000-000000000000"
280
+ };
281
+ function mergeReading(retype) {
282
+ const c = asStored(retype);
283
+ if (c.from === c.to) return "back to the type its values are stored as: every value reads as stored";
284
+ if (resizesVector(c)) {
285
+ return `every stored vector has ${vectorSize(c.from)} dimensions, so each reads null while the column has the new size, and reads again if it is changed back`;
286
+ }
287
+ if (c.from === "decimal" && c.to === "int") return "values read truncated (29.789 reads 29) and read whole again once retyped back";
288
+ if (c.useXdo === true) {
289
+ const dated = c.to === "epochms" || c.to === "timestamp" || c.to === "date";
290
+ if (c.from === "json" && c.to === "date") return "every read of the table fails (HTTP 500) while a row holds a json object there";
291
+ if ((c.from === "text" || c.from === "enum") && dated) {
292
+ return 'a stored value is not checked as a date: it can read as written ("12" reads 12) or as the time of the read ("x"), not null';
293
+ }
294
+ if (c.from === "bool" && c.to === "enum") return "true reads the enum's first value";
295
+ if (c.from === "decimal" && c.to === "text") return 'values read as stored (1.5 reads "1.5")';
296
+ }
297
+ if (c.from === "decimal" && c.to === "text") return `values read padded to the column's scale (29.789 reads "29.78900")`;
298
+ if (c.from === "bool" && c.to === "text") return 'true reads "1" and false reads ""';
299
+ if (c.from === "int" && c.to === "date") return 'values read as epoch milliseconds (5 reads "1970-01-01")';
300
+ if (c.from.startsWith("geo_") && c.to === "text") return "values read as hex-encoded geometry";
301
+ return void 0;
302
+ }
303
+ function typeChange(c) {
304
+ return `${authoredFieldType(c.from)} \u2192 ${authoredFieldType(c.to)}`;
305
+ }
306
+ function alteringChanges(e) {
307
+ const replace = e.mode === "replace";
308
+ return [
309
+ ...e.droppedTables.map((t) => `drop table ${t.table} \u2014 ${rowsGone(t.rows)}${t.replaced ? REPLACED_TABLE : ""}`),
310
+ ...e.renamedTables.map((r) => `rename table ${r.from} \u2192 ${r.to} (rows kept)`),
311
+ ...e.droppedColumns.map((c) => `drop column ${c} \u2014 every value it holds is destroyed`),
312
+ ...e.retypedColumns.map(
313
+ (c) => `retype ${c.table}.${c.column} (${typeChange(c)}) \u2014 ` + (!replace ? mergeReading(c) ?? `a stored value that does not read as ${authoredFieldType(c.to)} reads null` : replaceRetype(c) === "stops" ? stopCondition(c) : replaceConverts(c) ? `stored values are converted to ${authoredFieldType(c.to)} for good; one that does not convert becomes ${c.to === "int" && c.nullable === true ? "null" : emptyOf(c.to)}` : reReading(c)) + (setInsertsFail(c, e.mode) ? `; an insert that sets it fails${omittedInsertsFail(c, e.mode) ? ", and so does one that leaves it unset" : ""} \u2014 ${newColumnRemedy(asStored(c))}` : omittedInsertsFail(c, e.mode) ? `; an insert that leaves it unset fails ${omittedInsertsRemedy(e.mode === "merge" ? asStored(c) : c)}` : "")
314
+ ),
315
+ ...e.narrowedEnums.map(
316
+ (n) => `${n.table}.${n.column} loses ${n.removed.map((v) => `"${v}"`).join(", ")} \u2014 a row holding one reads null`
317
+ ),
318
+ ...e.retargetedRefs.map(
319
+ (r) => `${r.table}.${r.column} points at ${r.to} instead of ${r.from} \u2014 the ids rows hold now name ${r.to} rows`
320
+ ),
321
+ ...e.indexChanges.map(
322
+ (c) => `${c.action} index ${c.table}: ${c.index}` + (c.action === "add" && c.unique ? " \u2014 refused if the rows already hold duplicates for it" : "")
323
+ ),
324
+ ...e.notNullKept.map(
325
+ (c) => `${c} becomes nullable \u2014 if the table enforces NOT NULL there, it keeps refusing a row without a value`
326
+ ),
327
+ ...e.notNullTightened.map(
328
+ (c) => `${c.table}.${c.column} stops being nullable \u2014 a row holding null ` + (replace ? `is rewritten to ${emptyOf(c.type)} for good` : `reads ${emptyOf(c.type)}`)
329
+ )
330
+ ];
331
+ }
332
+ function additiveChanges(e) {
333
+ return [
334
+ ...e.createdTables.map((t) => `create table ${t}`),
335
+ ...e.addedColumns.map((c) => {
336
+ const value = e.addedDefaults[c];
337
+ return `add column ${c} \u2014 existing rows read ${value === void 0 ? "the type's empty value" : `its default ${JSON.stringify(value)}`}`;
338
+ })
339
+ ];
340
+ }
341
+ var REPLACED_TABLE = "; the release's table of that name is another table (another identity), created empty in its place";
342
+ function droppedTableLine(t) {
343
+ return `${t.table} (${t.rows === null ? "rows not counted" : `${t.rows} ${t.rows === 1 ? "row" : "rows"}`})` + (t.replaced ? REPLACED_TABLE : "");
344
+ }
345
+ function rowsGone(rows) {
346
+ return rows === null ? "every row it holds is deleted" : `its ${rows} ${rows === 1 ? "row is" : "rows are"} deleted`;
347
+ }
348
+ function emptyOf(type) {
349
+ if (type === "int" || type === "decimal" || type === "epochms" || type === "timestamp") return "0";
350
+ if (type === "text" || type === "email" || type === "password") return '""';
351
+ if (type === "bool") return "false";
352
+ return "the type's empty value";
353
+ }
354
+ function tableEffectFields(e) {
355
+ return {
356
+ droppedColumns: [...e.droppedColumns],
357
+ // `converted` under a replace only; `omittedInsertsFail` / `setInsertsFail` only where they hold.
358
+ // Types as authored (`timestamp`, never the stored `epochms`), matching the text output.
359
+ retypedColumns: e.retypedColumns.map((c) => ({
360
+ ...c,
361
+ from: authoredFieldType(c.from),
362
+ to: authoredFieldType(c.to),
363
+ ...c.stored !== void 0 ? { stored: authoredFieldType(c.stored) } : {},
364
+ ...e.mode === "replace" ? { converted: replaceConverts(c), ...replaceRetype(c) === "stops" ? { stops: true } : {} } : {},
365
+ ...omittedInsertsFail(c, e.mode) ? { omittedInsertsFail: true } : {},
366
+ ...setInsertsFail(c, e.mode) ? { setInsertsFail: true } : {}
367
+ })),
368
+ narrowedEnums: e.narrowedEnums.map((c) => ({ ...c, removed: [...c.removed] })),
369
+ retargetedRefs: e.retargetedRefs.map((c) => ({ ...c })),
370
+ indexChanges: e.indexChanges.map((c) => ({ ...c })),
371
+ notNullKept: [...e.notNullKept],
372
+ notNullTightened: e.notNullTightened.map((c) => ({ ...c, type: authoredFieldType(c.type) })),
373
+ storageChanges: storageChangesPayload(e.storageChanges ?? [])
374
+ };
375
+ }
376
+ function storageChangesPayload(changes) {
377
+ return changes.map((c) => ({ table: c.table, from: c.from, to: c.to }));
378
+ }
379
+ function tableEffectsPayload(e) {
380
+ return {
381
+ mode: e.mode,
382
+ droppedTables: e.droppedTables.map((t) => ({ ...t })),
383
+ createdTables: [...e.createdTables],
384
+ addedColumns: [...e.addedColumns],
385
+ addedDefaults: { ...e.addedDefaults },
386
+ renamedTables: e.renamedTables.map((r) => ({ ...r })),
387
+ ...tableEffectFields(e)
388
+ };
389
+ }
390
+ function discloseTableEffects(e, opts) {
391
+ const will = opts.will ?? "will";
392
+ const Subject = opts.subject.charAt(0).toUpperCase() + opts.subject.slice(1);
393
+ const say = (code, msg, items) => {
394
+ const remedy = opts.remedies?.[code];
395
+ warn(msg, code, remedy === void 0 ? items : [...items, remedy]);
396
+ };
397
+ const replace = e.mode === "replace";
398
+ if (opts.additiveWhere !== void 0) {
399
+ const added = additiveChanges(e);
400
+ if (added.length > 0) say("plan.schema-additive", `${Subject} ${will} add to ${opts.additiveWhere}:`, added);
401
+ }
402
+ if (e.droppedTables.length > 0) {
403
+ const one = e.droppedTables.length === 1;
404
+ say(
405
+ "plan.table-drop",
406
+ `${Subject} ${will} DROP ${plural(e.droppedTables.length, "table", "tables")} the release does not carry, with every row in ${one ? "it" : "them"}:`,
407
+ e.droppedTables.map(droppedTableLine)
408
+ );
409
+ }
410
+ if (e.renamedTables.length > 0) {
411
+ say(
412
+ "plan.table-rename",
413
+ `${Subject} ${will} rename ${plural(e.renamedTables.length, "table", "tables")}, keeping ${e.renamedTables.length === 1 ? "its" : "their"} rows:`,
414
+ e.renamedTables.map((r) => `${r.from} \u2192 ${r.to}`)
415
+ );
416
+ }
417
+ if (e.droppedColumns.length > 0) {
418
+ const one = e.droppedColumns.length === 1;
419
+ say(
420
+ "plan.column-drop",
421
+ `${Subject} ${will} DROP ${plural(e.droppedColumns.length, "column", "columns")}, with the values in ${one ? "it" : "them"}:`,
422
+ // A drop beside an add on one table reads as a rename, and is not one.
423
+ [...e.droppedColumns, ...droppedAndAdded(e).map((p) => renameHint(p, opts.stages))]
424
+ );
425
+ }
426
+ if (e.retypedColumns.length > 0) {
427
+ const n = plural(e.retypedColumns.length, "column changes", "columns change");
428
+ const lead = replace ? `${n} type \u2014 ${opts.subject} CONVERTS the stored values for good, and retyping back does not restore them: a value that converts does (int \u2192 text: 11 \u2192 "11"; text \u2192 int: "12" \u2192 12, "1.5" \u2192 2), one that does not becomes the type's empty value (text \u2192 int: "hello" \u2192 0; int or decimal \u2192 bool: every value \u2192 false), and one it cannot convert stops the deploy partway (text \u2192 timestamp: "hello"). A pair that differs says so:` : `${n} type \u2014 ${opts.subject} changes only the definition and leaves the stored values: one that reads as the new type does (int \u2192 text: 11 reads "11"), one that does not reads null while the column has the new type, and reads again if it is retyped back:`;
429
+ say(
430
+ "plan.column-retype",
431
+ lead,
432
+ e.retypedColumns.map(
433
+ (c) => `${c.table}.${c.column} (${typeChange(c)})` + (replace ? replaceRetypeNote(c) : "") + (!replace && mergeReading(c) !== void 0 ? ` \u2014 ${mergeReading(c)}` : "") + (omittedInsertsFail(c, e.mode) || setInsertsFail(c, e.mode) ? ` \u2014 ${insertsFailNote(c, e.mode)}` : unknownStorageNote(c, e.mode))
434
+ )
435
+ );
436
+ }
437
+ if (e.narrowedEnums.length > 0) {
438
+ say(
439
+ "plan.enum-values-removed",
440
+ `${plural(e.narrowedEnums.length, "enum column loses", "enum columns lose")} values \u2014 ${opts.subject} changes only the definition: a row holding a removed value reads null until the value is restored:`,
441
+ e.narrowedEnums.map((n) => `${n.table}.${n.column} (removes ${n.removed.map((v) => `"${v}"`).join(", ")})`)
442
+ );
443
+ }
444
+ if (e.retargetedRefs.length > 0) {
445
+ say(
446
+ "plan.tableref-retarget",
447
+ `${plural(e.retargetedRefs.length, "table reference points", "table references point")} at another table \u2014 ${opts.subject} keeps the ids the rows hold, which now name rows of the new table:`,
448
+ e.retargetedRefs.map((r) => `${r.table}.${r.column} (${r.from} \u2192 ${r.to})`)
449
+ );
450
+ }
451
+ if (e.indexChanges.length > 0) {
452
+ const uniqueAdd = e.indexChanges.some((c) => c.action === "add" && c.unique);
453
+ say(
454
+ "plan.index-change",
455
+ `${Subject} ${will} change ${plural(e.indexChanges.length, "index", "indexes")}` + (uniqueAdd ? " \u2014 a unique index it adds is refused if the rows already there hold duplicates for it:" : ":"),
456
+ e.indexChanges.map((c) => `${c.action} ${c.table}: ${c.index}`)
457
+ );
458
+ }
459
+ if (e.notNullKept.length > 0) {
460
+ say(
461
+ "plan.not-null-kept",
462
+ `${plural(e.notNullKept.length, "column becomes", "columns become")} nullable, and a merge does not relax a NOT NULL the table enforces: a column created required keeps refusing a row without a value (NOT NULL violation) while the export reads nullable \u2014 one made required by a merge was never enforced \u2014 and later deploys cannot see it:`,
463
+ e.notNullKept
464
+ );
465
+ }
466
+ if (e.notNullTightened.length > 0) {
467
+ say(
468
+ "plan.not-null-tightened",
469
+ replace ? `${plural(e.notNullTightened.length, "column stops", "columns stop")} being nullable \u2014 ${opts.subject} rewrites the rows that hold null there to the type's empty value (int 0, text "") for good: making it nullable again does not bring the nulls back:` : `${plural(e.notNullTightened.length, "column stops", "columns stop")} being nullable, and a merge does not rewrite the rows that hold null there: they read back as the type's empty value (int 0, text "", and a date column's key is left out of every row):`,
470
+ e.notNullTightened.map((c) => `${c.table}.${c.column} (${authoredFieldType(c.type)})`)
471
+ );
472
+ }
473
+ }
474
+ function droppedAndAdded(e) {
475
+ return droppedAndAddedAll(e).flatMap((p) => {
476
+ if (p.dropped.length === p.added.length) return [p];
477
+ const near = (a, b) => {
478
+ const [x, y] = [a.toLowerCase(), b.toLowerCase()];
479
+ const shorter = Math.min(x.length, y.length);
480
+ return shorter >= 4 && suggest(x, [y]) !== void 0 || shorter >= 3 && (x.includes(y) || y.includes(x));
481
+ };
482
+ const pairs = p.dropped.flatMap((d) => {
483
+ const a = p.added.find((c) => near(d, c));
484
+ return a === void 0 ? [] : [[d, a]];
485
+ });
486
+ if (pairs.length === 0) return [];
487
+ return [{ table: p.table, dropped: pairs.map(([d]) => d), added: [...new Set(pairs.map(([, a]) => a))] }];
488
+ });
489
+ }
490
+ function droppedAndAddedAll(e) {
491
+ const column = (dotted) => {
492
+ const at = dotted.indexOf(".");
493
+ return [dotted.slice(0, at), dotted.slice(at + 1)];
494
+ };
495
+ const out = /* @__PURE__ */ new Map();
496
+ for (const d of e.droppedColumns) {
497
+ const [table, name] = column(d);
498
+ const entry = out.get(table) ?? { dropped: [], added: [] };
499
+ entry.dropped.push(name);
500
+ out.set(table, entry);
501
+ }
502
+ for (const a of e.addedColumns) {
503
+ const [table, name] = column(a);
504
+ out.get(table)?.added.push(name);
505
+ }
506
+ return [...out].filter(([, v]) => v.added.length > 0).map(([table, v]) => ({ table, ...v }));
507
+ }
508
+ function renameHint(p, stages = "releases") {
509
+ const list = (names) => names.join(", ");
510
+ return `${p.table} drops ${list(p.dropped)} and adds ${list(p.added)}. A column has no identity of its own to rename by, so this does not move the values: those in ${list(p.dropped)} are destroyed and ${list(p.added)} start${p.added.length === 1 ? "s" : ""} empty. To keep them, land it as two ${stages}: one that adds ${list(p.added)} beside ${list(p.dropped)}, then backfill the rows, then one that drops ${list(p.dropped)}.`;
511
+ }
512
+ function releaseCanonicalMoves(archive, live) {
513
+ const out = [];
514
+ const held = payloadOf(live);
515
+ for (const [section, rows] of Object.entries(payloadOf(archive))) {
516
+ const there = held[section];
517
+ if (!Array.isArray(rows) || !Array.isArray(there)) continue;
518
+ for (const row of rows) {
519
+ if (row === null || typeof row !== "object") continue;
520
+ const r = row;
521
+ if (typeof r.guid !== "string" || r.guid === "" || typeof r.canonical !== "string" || r.canonical === "") continue;
522
+ const current = there.find(
523
+ (l) => l !== null && typeof l === "object" && l.guid === r.guid
524
+ );
525
+ const from = current?.canonical;
526
+ if (typeof from !== "string" || from === "" || from === r.canonical) continue;
527
+ out.push({ kind: sectionKind(section, r), name: typeof r.name === "string" ? r.name : "", from, to: r.canonical });
528
+ }
529
+ }
530
+ return out;
531
+ }
532
+ function discloseCanonicalMoves(moves, opts) {
533
+ if (moves.length === 0) return;
534
+ const Subject = opts.subject.charAt(0).toUpperCase() + opts.subject.slice(1);
535
+ warn(
536
+ `${Subject} ${opts.will ?? "will"} move ${plural(moves.length, "public URL", "public URLs")}${opts.when === void 0 ? "" : ` ${opts.when}`} \u2014 every endpoint under the slug served now stops answering:`,
537
+ "plan.canonical-change",
538
+ moves.map((m) => `${m.kind} "${m.name}": ${m.from} \u2192 ${m.to}`)
539
+ );
540
+ }
541
+ function movesClause(moves, lead = "It") {
542
+ if (moves.length === 0) return "";
543
+ return ` ${lead} MOVES ${moves.length === 1 ? "a public URL" : `${moves.length} public URLs`} (` + moves.map((m) => `${m.from} \u2192 ${m.to}`).join(", ") + `): the old ${moves.length === 1 ? "slug stops" : "slugs stop"} answering.`;
544
+ }
545
+ function plural(n, one, many) {
546
+ return `${n} ${n === 1 ? one : many}`;
547
+ }
548
+ async function releaseTableEffects(loadArchive, loadLive, opts = {}) {
549
+ let archive;
550
+ try {
551
+ archive = await loadArchive();
552
+ } catch (err) {
553
+ return { failure: "the release archive could not be read", read: "archive", cause: err };
554
+ }
555
+ if (archive === void 0) return { failure: "the release carries no id to read its archive from" };
556
+ let live;
557
+ try {
558
+ live = await loadLive();
559
+ } catch (err) {
560
+ const raw = err instanceof Error ? err.message : String(err);
561
+ const reason = withoutUrls(raw).replace(/\s+/g, " ").trim();
562
+ return { failure: reason.length > 200 ? `${reason.slice(0, 200)}\u2026` : reason, read: "destination", cause: err };
563
+ }
564
+ return { effects: tableEffects(archive, live, { ...opts, mode: opts.mode ?? "merge" }) };
565
+ }
566
+ function readOnce(read) {
567
+ let cached;
568
+ return () => {
569
+ cached ??= read().catch((err) => {
570
+ cached = void 0;
571
+ throw err;
572
+ });
573
+ return cached;
574
+ };
575
+ }
576
+ function uniqueIndexCandidates(e) {
577
+ return (e?.indexChanges ?? []).filter((c) => c.action === "add" && c.unique).map((c) => ({ table: c.table, index: c.index }));
578
+ }
579
+ function namedConstraint(stop, effects) {
580
+ const retyped = effects?.retypedColumns ?? [];
581
+ if (stop.kind === "not-null" && stop.column === void 0 && retyped.length > 0 && (effects?.notNullTightened ?? []).length === 0) {
582
+ return namedConstraint({ ...stop, kind: "conversion", notNull: true }, effects);
583
+ }
584
+ if (stop.kind === "conversion") {
585
+ if (stop.column !== void 0) return stop;
586
+ const stopping = effects?.mode === "replace" ? retyped.filter(replaceCanStop) : [];
587
+ const from = stopping.length > 0 ? stopping : retyped;
588
+ if (from.length === 1) {
589
+ const c = from[0];
590
+ return { ...stop, table: c.table, column: c.column, retypes: [{ ...c }] };
591
+ }
592
+ return from.length > 1 ? { ...stop, retypes: from.map((c) => ({ ...c })) } : stop;
593
+ }
594
+ if (stop.kind !== "unique" || stop.table !== void 0 || stop.index !== void 0) return stop;
595
+ const candidates = uniqueIndexCandidates(effects);
596
+ if (candidates.length === 1) return { ...stop, table: candidates[0].table, index: candidates[0].index };
597
+ return candidates.length > 1 ? { ...stop, candidates } : stop;
598
+ }
599
+ function constraintWhere(stop) {
600
+ const parts = [
601
+ stop.table === void 0 ? void 0 : `table "${stop.table}"`,
602
+ stop.index === void 0 ? void 0 : `index "${stop.index}"`,
603
+ stop.column === void 0 ? void 0 : `field "${stop.column}"`
604
+ ].filter((p) => p !== void 0);
605
+ const retype = stop.retypes?.length === 1 ? stop.retypes[0] : void 0;
606
+ if (parts.length > 0) return ` (${parts.join(", ")}${retype === void 0 ? "" : `: ${typeChange(retype)}`})`;
607
+ if (stop.retypes !== void 0 && stop.retypes.length > 1) {
608
+ return ` (one of: ${stop.retypes.map((c) => `${c.table}.${c.column} ${typeChange(c)}`).join("; ")})`;
609
+ }
610
+ if (stop.candidates !== void 0 && stop.candidates.length > 0) {
611
+ return ` (one of: ${stop.candidates.map((c) => `table "${c.table}" ${c.index}`).join("; ")})`;
612
+ }
613
+ return "";
614
+ }
615
+ function constraintStop(err) {
616
+ if (!(err instanceof TenantHttpError || err instanceof ReleaseHttpError)) return void 0;
617
+ const m = err.message;
618
+ const kind = /\b23505\b|unique[ _]violation|duplicate key/i.test(m) ? "unique" : /\b23502\b|not[ _-]null[ _]violation/i.test(m) ? "not-null" : /\b23503\b|foreign[ _]key[ _]violation/i.test(m) ? "foreign-key" : (
619
+ // Data exceptions: a value that does not read as the column's new
620
+ // type (22P02), is out of its range (22003), or is not a date (22007, 22008).
621
+ /\b22(?:P02|003|007|008|018)\b|invalid (?:text|input) (?:representation|syntax)|out of range/i.test(m) ? "conversion" : void 0
622
+ );
623
+ if (kind === void 0) return void 0;
624
+ const table = /\b(?:table|relation) "([^"]+)"/i.exec(m)?.[1];
625
+ const index = /\b(?:constraint|index) "([^"]+)"/i.exec(m)?.[1];
626
+ const column = /\bKey \(([^)]+)\)=/.exec(m)?.[1] ?? /\bcolumn "([^"]+)"/i.exec(m)?.[1];
627
+ return {
628
+ kind,
629
+ ...table === void 0 ? {} : { table },
630
+ ...index === void 0 ? {} : { index },
631
+ ...column === void 0 ? {} : { column }
632
+ };
633
+ }
634
+ var CONSTRAINT_PHRASE = {
635
+ unique: "a unique index",
636
+ "not-null": "a required column",
637
+ "foreign-key": "a reference",
638
+ conversion: "a column type (a stored value does not convert to it)"
639
+ };
640
+ var CONSTRAINT_FIX = {
641
+ unique: "Make the rows that share a value in the newly unique field distinct (or drop the unique index from the release)",
642
+ "not-null": "Fill the rows the newly required field is empty in (or give the field a default in the release)",
643
+ "foreign-key": "Remove or repoint the rows that reference a row that is not there",
644
+ conversion: "Change the stored values that do not read as the new type (or drop the retype from the release)"
645
+ };
646
+
647
+ export {
648
+ NO_TABLE_EFFECTS,
649
+ tableEffects,
650
+ tableEffectsOf,
651
+ assertStorageModesKept,
652
+ xdoConversionRefused,
653
+ xdoConversionRefusal,
654
+ replaceRetype,
655
+ replaceConverts,
656
+ stoppingRetypes,
657
+ omittedInsertsFail,
658
+ setInsertsFail,
659
+ alteringChanges,
660
+ additiveChanges,
661
+ droppedTableLine,
662
+ tableEffectFields,
663
+ storageChangesPayload,
664
+ tableEffectsPayload,
665
+ discloseTableEffects,
666
+ droppedAndAdded,
667
+ renameHint,
668
+ releaseCanonicalMoves,
669
+ discloseCanonicalMoves,
670
+ movesClause,
671
+ releaseTableEffects,
672
+ readOnce,
673
+ uniqueIndexCandidates,
674
+ namedConstraint,
675
+ constraintWhere,
676
+ constraintStop,
677
+ CONSTRAINT_PHRASE,
678
+ CONSTRAINT_FIX
679
+ };
680
+ //# sourceMappingURL=chunk-BWPNT55T.js.map