d1s 0.2.8 → 0.2.9

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 (310) hide show
  1. package/dist/.next/.next/BUILD_ID +1 -1
  2. package/dist/.next/.next/app-build-manifest.json +33 -26
  3. package/dist/.next/.next/app-path-routes-manifest.json +1 -1
  4. package/dist/.next/.next/build-manifest.json +2 -2
  5. package/dist/.next/.next/cache/.rscinfo +1 -1
  6. package/dist/.next/.next/cache/.tsbuildinfo +1 -1
  7. package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
  8. package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
  9. package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
  10. package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
  11. package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
  12. package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
  13. package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
  14. package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
  15. package/dist/.next/.next/next-minimal-server.js.nft.json +1 -1
  16. package/dist/.next/.next/next-server.js.nft.json +1 -1
  17. package/dist/.next/.next/prerender-manifest.json +1 -1
  18. package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  19. package/dist/.next/.next/server/app/_not-found.html +1 -1
  20. package/dist/.next/.next/server/app/_not-found.rsc +4 -4
  21. package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
  22. package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  23. package/dist/.next/.next/server/app/api/databases/route.js +1 -1
  24. package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  25. package/dist/.next/.next/server/app/api/migrations/sync/route.js +28 -3
  26. package/dist/.next/.next/server/app/api/migrations/sync/route.js.nft.json +1 -1
  27. package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  28. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +26 -1
  29. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -1
  30. package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  31. package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -0
  32. package/dist/.next/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -0
  33. package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -0
  34. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +26 -1
  35. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -1
  36. package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  37. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +26 -1
  38. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -1
  39. package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  40. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +28 -3
  41. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -1
  42. package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  43. package/dist/.next/.next/server/app/api/push-remote/preview/route.js +28 -3
  44. package/dist/.next/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -1
  45. package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  46. package/dist/.next/.next/server/app/api/query/route.js +27 -2
  47. package/dist/.next/.next/server/app/api/query/route.js.nft.json +1 -1
  48. package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  49. package/dist/.next/.next/server/app/api/tables/[name]/route.js +4 -4
  50. package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  51. package/dist/.next/.next/server/app/api/tables/route.js +2 -2
  52. package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  53. package/dist/.next/.next/server/app/api/update/route.js +2 -2
  54. package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  55. package/dist/.next/.next/server/app/index.html +3 -3
  56. package/dist/.next/.next/server/app/index.rsc +5 -5
  57. package/dist/.next/.next/server/app/page.js +11 -11
  58. package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
  59. package/dist/.next/.next/server/app-paths-manifest.json +2 -1
  60. package/dist/.next/.next/server/chunks/226.js +30 -0
  61. package/dist/.next/.next/server/chunks/336.js +1 -1
  62. package/dist/.next/.next/server/pages/404.html +1 -1
  63. package/dist/.next/.next/server/pages/500.html +1 -1
  64. package/dist/.next/.next/server/pages-manifest.json +1 -1
  65. package/dist/.next/.next/server/server-reference-manifest.json +1 -1
  66. package/dist/.next/.next/static/7XBqETNmhSxMXhw8iUpEa/_buildManifest.js +1 -0
  67. package/dist/.next/.next/static/chunks/{958-98887928efebfdf7.js → 176-9146975ef8699719.js} +1 -1
  68. package/dist/.next/.next/static/chunks/{735-c9144179c6bd7d06.js → 735-b885dfec6353171d.js} +1 -1
  69. package/dist/.next/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +1 -0
  70. package/dist/.next/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +1 -0
  71. package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +1 -0
  72. package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +1 -0
  73. package/dist/.next/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +1 -0
  74. package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +1 -0
  75. package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +1 -0
  76. package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +1 -0
  77. package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +1 -0
  78. package/dist/.next/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +1 -0
  79. package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +1 -0
  80. package/dist/.next/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +1 -0
  81. package/dist/.next/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +1 -0
  82. package/dist/.next/.next/static/chunks/app/page-5990cb23b8bd27c4.js +1 -0
  83. package/dist/.next/.next/static/css/674bee6608c638e4.css +3 -0
  84. package/dist/.next/.next/trace +3 -3
  85. package/dist/.next/.next/types/app/api/pull-data/confirm/route.ts +347 -0
  86. package/dist/.next/BUILD_ID +1 -1
  87. package/dist/.next/app-build-manifest.json +35 -21
  88. package/dist/.next/app-path-routes-manifest.json +1 -1
  89. package/dist/.next/build-manifest.json +2 -2
  90. package/dist/.next/cache/.rscinfo +1 -1
  91. package/dist/.next/cache/.tsbuildinfo +1 -1
  92. package/dist/.next/cache/webpack/client-production/0.pack +0 -0
  93. package/dist/.next/cache/webpack/client-production/index.pack +0 -0
  94. package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
  95. package/dist/.next/cache/webpack/server-production/0.pack +0 -0
  96. package/dist/.next/cache/webpack/server-production/index.pack +0 -0
  97. package/dist/.next/next-minimal-server.js.nft.json +1 -1
  98. package/dist/.next/next-server.js.nft.json +1 -1
  99. package/dist/.next/prerender-manifest.json +1 -1
  100. package/dist/.next/server/app/_not-found/page.js +1 -1
  101. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  102. package/dist/.next/server/app/_not-found.html +1 -1
  103. package/dist/.next/server/app/_not-found.rsc +4 -4
  104. package/dist/.next/server/app/api/cloudflare/route.js +1 -1
  105. package/dist/.next/server/app/api/cloudflare/route.js.nft.json +1 -1
  106. package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  107. package/dist/.next/server/app/api/databases/route.js +1 -1
  108. package/dist/.next/server/app/api/databases/route.js.nft.json +1 -1
  109. package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  110. package/dist/.next/server/app/api/migrations/sync/route.js +28 -3
  111. package/dist/.next/server/app/api/migrations/sync/route.js.nft.json +1 -1
  112. package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  113. package/dist/.next/server/app/api/migrations/sync-files/route.js +26 -1
  114. package/dist/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -1
  115. package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  116. package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -0
  117. package/dist/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -0
  118. package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -0
  119. package/dist/.next/server/app/api/pull-remote/confirm/route.js +26 -1
  120. package/dist/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -1
  121. package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  122. package/dist/.next/server/app/api/pull-remote/preview/route.js +26 -1
  123. package/dist/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -1
  124. package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  125. package/dist/.next/server/app/api/push-remote/confirm/route.js +28 -3
  126. package/dist/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -1
  127. package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  128. package/dist/.next/server/app/api/push-remote/preview/route.js +28 -3
  129. package/dist/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -1
  130. package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  131. package/dist/.next/server/app/api/query/route.js +27 -2
  132. package/dist/.next/server/app/api/query/route.js.nft.json +1 -1
  133. package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  134. package/dist/.next/server/app/api/tables/[name]/route.js +3 -3
  135. package/dist/.next/server/app/api/tables/[name]/route.js.nft.json +1 -1
  136. package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  137. package/dist/.next/server/app/api/tables/route.js +2 -2
  138. package/dist/.next/server/app/api/tables/route.js.nft.json +1 -1
  139. package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  140. package/dist/.next/server/app/api/update/route.js +5 -0
  141. package/dist/.next/server/app/api/update/route.js.nft.json +1 -0
  142. package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -0
  143. package/dist/.next/server/app/index.html +3 -3
  144. package/dist/.next/server/app/index.rsc +5 -5
  145. package/dist/.next/server/app/page.js +13 -11
  146. package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
  147. package/dist/.next/server/app-paths-manifest.json +5 -3
  148. package/dist/.next/server/chunks/226.js +30 -0
  149. package/dist/.next/server/chunks/336.js +1 -1
  150. package/dist/.next/server/chunks/391.js +23 -0
  151. package/dist/.next/server/chunks/452.js +1 -0
  152. package/dist/.next/server/chunks/627.js +3 -3
  153. package/dist/.next/server/chunks/638.js +3 -3
  154. package/dist/.next/server/chunks/992.js +3 -3
  155. package/dist/.next/server/pages/404.html +1 -1
  156. package/dist/.next/server/pages/500.html +1 -1
  157. package/dist/.next/server/pages/_app.js +1 -1
  158. package/dist/.next/server/pages/_document.js +1 -1
  159. package/dist/.next/server/pages/_error.js +1 -1
  160. package/dist/.next/server/server-reference-manifest.json +1 -1
  161. package/dist/.next/static/MoZBULXFiTFzrY1JVK_Df/_buildManifest.js +1 -0
  162. package/dist/.next/static/chunks/176-9146975ef8699719.js +1 -0
  163. package/dist/.next/static/chunks/{735-c9144179c6bd7d06.js → 735-b885dfec6353171d.js} +1 -1
  164. package/dist/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +1 -0
  165. package/dist/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +1 -0
  166. package/dist/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +1 -0
  167. package/dist/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +1 -0
  168. package/dist/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +1 -0
  169. package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +1 -0
  170. package/dist/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +1 -0
  171. package/dist/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +1 -0
  172. package/dist/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +1 -0
  173. package/dist/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +1 -0
  174. package/dist/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +1 -0
  175. package/dist/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +1 -0
  176. package/dist/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +1 -0
  177. package/dist/.next/static/chunks/app/page-5990cb23b8bd27c4.js +1 -0
  178. package/dist/.next/static/css/674bee6608c638e4.css +3 -0
  179. package/dist/.next/trace +17 -14
  180. package/dist/.next/types/app/api/pull-data/confirm/route.ts +347 -0
  181. package/dist/.next/types/app/api/update/route.ts +347 -0
  182. package/dist/app/api/pull-data/confirm/route.js +230 -0
  183. package/dist/app/api/update/route.js +36 -0
  184. package/dist/app/app/api/pull-data/confirm/route.js +230 -0
  185. package/dist/app/app/api/update/route.js +30 -5
  186. package/dist/app/app/page.jsx +21 -17
  187. package/dist/app/page.jsx +24 -14
  188. package/dist/d1-studio.js +8 -1
  189. package/dist/lib/logger.js +35 -5
  190. package/dist/lib/sql-operations.js +77 -0
  191. package/package.json +1 -1
  192. package/scripts/studio.js +8 -1
  193. package/src/app/api/pull-data/confirm/route.js +230 -0
  194. package/src/app/api/update/route.js +30 -5
  195. package/src/app/page.jsx +21 -17
  196. package/src/components/environment-handler.jsx +70 -16
  197. package/src/components/environment-select.jsx +6 -3
  198. package/src/components/pull-preview-toast.jsx +90 -63
  199. package/src/components/sidebar.jsx +25 -24
  200. package/src/components/update-banner.jsx +29 -31
  201. package/src/context/database-context.js +4 -4
  202. package/src/lib/logger.js +35 -5
  203. package/src/lib/sql-operations.js +77 -0
  204. package/dist/.next/.next/cache/webpack/client-development/0.pack.gz +0 -0
  205. package/dist/.next/.next/cache/webpack/client-development/1.pack.gz +0 -0
  206. package/dist/.next/.next/cache/webpack/client-development/2.pack.gz +0 -0
  207. package/dist/.next/.next/cache/webpack/client-development/3.pack.gz +0 -0
  208. package/dist/.next/.next/cache/webpack/client-development/4.pack.gz +0 -0
  209. package/dist/.next/.next/cache/webpack/client-development/index.pack.gz +0 -0
  210. package/dist/.next/.next/cache/webpack/client-development/index.pack.gz.old +0 -0
  211. package/dist/.next/.next/cache/webpack/client-production/10.pack +0 -0
  212. package/dist/.next/.next/cache/webpack/client-production/11.pack +0 -0
  213. package/dist/.next/.next/cache/webpack/client-production/12.pack +0 -0
  214. package/dist/.next/.next/cache/webpack/client-production/13.pack +0 -0
  215. package/dist/.next/.next/cache/webpack/client-production/14.pack +0 -0
  216. package/dist/.next/.next/cache/webpack/client-production/3.pack +0 -0
  217. package/dist/.next/.next/cache/webpack/client-production/4.pack +0 -0
  218. package/dist/.next/.next/cache/webpack/client-production/5.pack +0 -0
  219. package/dist/.next/.next/cache/webpack/client-production/6.pack +0 -0
  220. package/dist/.next/.next/cache/webpack/client-production/7.pack +0 -0
  221. package/dist/.next/.next/cache/webpack/client-production/8.pack +0 -0
  222. package/dist/.next/.next/cache/webpack/client-production/9.pack +0 -0
  223. package/dist/.next/.next/cache/webpack/server-development/0.pack.gz +0 -0
  224. package/dist/.next/.next/cache/webpack/server-development/1.pack.gz +0 -0
  225. package/dist/.next/.next/cache/webpack/server-development/2.pack.gz +0 -0
  226. package/dist/.next/.next/cache/webpack/server-development/3.pack.gz +0 -0
  227. package/dist/.next/.next/cache/webpack/server-development/4.pack.gz +0 -0
  228. package/dist/.next/.next/cache/webpack/server-development/index.pack.gz +0 -0
  229. package/dist/.next/.next/cache/webpack/server-development/index.pack.gz.old +0 -0
  230. package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
  231. package/dist/.next/.next/cache/webpack/server-production/10.pack +0 -0
  232. package/dist/.next/.next/cache/webpack/server-production/11.pack +0 -0
  233. package/dist/.next/.next/cache/webpack/server-production/12.pack +0 -0
  234. package/dist/.next/.next/cache/webpack/server-production/13.pack +0 -0
  235. package/dist/.next/.next/cache/webpack/server-production/2.pack +0 -0
  236. package/dist/.next/.next/cache/webpack/server-production/3.pack +0 -0
  237. package/dist/.next/.next/cache/webpack/server-production/4.pack +0 -0
  238. package/dist/.next/.next/cache/webpack/server-production/5.pack +0 -0
  239. package/dist/.next/.next/cache/webpack/server-production/6.pack +0 -0
  240. package/dist/.next/.next/cache/webpack/server-production/7.pack +0 -0
  241. package/dist/.next/.next/cache/webpack/server-production/8.pack +0 -0
  242. package/dist/.next/.next/cache/webpack/server-production/9.pack +0 -0
  243. package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
  244. package/dist/.next/.next/server/chunks/686.js +0 -23
  245. package/dist/.next/.next/server/chunks/801.js +0 -55
  246. package/dist/.next/.next/static/IWRJZhjf8U8mjzz4h0VNE/_buildManifest.js +0 -1
  247. package/dist/.next/.next/static/JrwgdSDcipr0Zh7k19Cj_/_buildManifest.js +0 -1
  248. package/dist/.next/.next/static/chunks/422-6fa3c14fc64ad67b.js +0 -1
  249. package/dist/.next/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +0 -1
  250. package/dist/.next/.next/static/chunks/app/api/cloudflare/route-5133155a604f2719.js +0 -1
  251. package/dist/.next/.next/static/chunks/app/api/databases/route-63a31080b565794e.js +0 -1
  252. package/dist/.next/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +0 -1
  253. package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +0 -1
  254. package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-d97667565b4a59b6.js +0 -1
  255. package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +0 -1
  256. package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-7089bcbfeb6b5260.js +0 -1
  257. package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +0 -1
  258. package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-9143e6e4c3f05162.js +0 -1
  259. package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +0 -1
  260. package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-c963d143a51aed66.js +0 -1
  261. package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-072132c0a6cb3df3.js +0 -1
  262. package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +0 -1
  263. package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +0 -1
  264. package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-ca6bf35aa72661ee.js +0 -1
  265. package/dist/.next/.next/static/chunks/app/api/query/route-1466f6b7ffd8b6c0.js +0 -1
  266. package/dist/.next/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +0 -1
  267. package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +0 -1
  268. package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-898d3f85fc8544c4.js +0 -1
  269. package/dist/.next/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +0 -1
  270. package/dist/.next/.next/static/chunks/app/api/tables/route-91650359fc3735cb.js +0 -1
  271. package/dist/.next/.next/static/chunks/app/api/update/route-504d663df9124f97.js +0 -1
  272. package/dist/.next/.next/static/chunks/app/page-2c28a255a4ecd8d4.js +0 -1
  273. package/dist/.next/.next/static/chunks/app/page-3db7feef57019055.js +0 -1
  274. package/dist/.next/.next/static/chunks/app/page-79049bfa6cc07e11.js +0 -1
  275. package/dist/.next/.next/static/css/4957328384ed5c42.css +0 -3
  276. package/dist/.next/.next/static/css/cf41da7a0d47f779.css +0 -3
  277. package/dist/.next/.next/static/gc8l1G6KXOeLLOM7VJip6/_buildManifest.js +0 -1
  278. package/dist/.next/.next/static/gc8l1G6KXOeLLOM7VJip6/_ssgManifest.js +0 -1
  279. package/dist/.next/.next/static/kYsJoni86CJWDuTkc1xU6/_buildManifest.js +0 -1
  280. package/dist/.next/.next/static/kYsJoni86CJWDuTkc1xU6/_ssgManifest.js +0 -1
  281. package/dist/.next/.next/static/scC5qwQC9H7rR1groM0Q-/_buildManifest.js +0 -1
  282. package/dist/.next/.next/static/scC5qwQC9H7rR1groM0Q-/_ssgManifest.js +0 -1
  283. package/dist/.next/.next/static/tEHOI_-t-iqfJClNzuo9m/_buildManifest.js +0 -1
  284. package/dist/.next/.next/static/tEHOI_-t-iqfJClNzuo9m/_ssgManifest.js +0 -1
  285. package/dist/.next/.next/static/vin2VQs5pM_dH2e2_I7AN/_buildManifest.js +0 -1
  286. package/dist/.next/.next/static/vin2VQs5pM_dH2e2_I7AN/_ssgManifest.js +0 -1
  287. package/dist/.next/.next/static/wHKwQhaxin5_i06GFVDHb/_buildManifest.js +0 -1
  288. package/dist/.next/.next/static/wHKwQhaxin5_i06GFVDHb/_ssgManifest.js +0 -1
  289. package/dist/.next/.next/static/xW4MspD8XibrhXDi_q2IO/_buildManifest.js +0 -1
  290. package/dist/.next/.next/static/xW4MspD8XibrhXDi_q2IO/_ssgManifest.js +0 -1
  291. package/dist/.next/server/chunks/686.js +0 -23
  292. package/dist/.next/server/chunks/801.js +0 -55
  293. package/dist/.next/static/ZwNOdZJ0LOtE0AJMNWwzY/_buildManifest.js +0 -1
  294. package/dist/.next/static/ZwNOdZJ0LOtE0AJMNWwzY/_ssgManifest.js +0 -1
  295. package/dist/.next/static/chunks/422-6fa3c14fc64ad67b.js +0 -1
  296. package/dist/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +0 -1
  297. package/dist/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +0 -1
  298. package/dist/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +0 -1
  299. package/dist/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +0 -1
  300. package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +0 -1
  301. package/dist/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +0 -1
  302. package/dist/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +0 -1
  303. package/dist/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +0 -1
  304. package/dist/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +0 -1
  305. package/dist/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +0 -1
  306. package/dist/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +0 -1
  307. package/dist/.next/static/chunks/app/page-79049bfa6cc07e11.js +0 -1
  308. package/dist/.next/static/css/cf41da7a0d47f779.css +0 -3
  309. /package/dist/.next/.next/static/{IWRJZhjf8U8mjzz4h0VNE → 7XBqETNmhSxMXhw8iUpEa}/_ssgManifest.js +0 -0
  310. /package/dist/.next/{.next/static/JrwgdSDcipr0Zh7k19Cj_ → static/MoZBULXFiTFzrY1JVK_Df}/_ssgManifest.js +0 -0
@@ -4,14 +4,21 @@ const { combine, timestamp, printf, colorize } = winston.format;
4
4
 
5
5
  const isDevelopment = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === undefined;
6
6
  const isProduction = process.env.NODE_ENV === 'production';
7
+ // Check for DEBUG env var which is set by --debug flag
7
8
  const isDebug = process.env.DEBUG === 'true';
8
9
 
9
- const logFormat = printf(({ level, message, timestamp }) => {
10
- return `${timestamp} ${level}: ${message}`;
10
+ const logFormat = printf(({ level, message, timestamp, ...metadata }) => {
11
+ let msg = `${timestamp} ${level}: ${message}`;
12
+ // Add metadata if present
13
+ if (Object.keys(metadata).length > 0) {
14
+ msg += ` ${JSON.stringify(metadata)}`;
15
+ }
16
+ return msg;
11
17
  });
12
18
 
13
19
  const logger = winston.createLogger({
14
- level: isProduction ? 'warn' : (isDebug ? 'debug' : 'info'),
20
+ // Set log level based on environment and debug flag
21
+ level: isDebug ? 'debug' : (isProduction ? 'warn' : 'info'),
15
22
  format: combine(
16
23
  timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
17
24
  colorize(),
@@ -19,10 +26,33 @@ const logger = winston.createLogger({
19
26
  ),
20
27
  transports: [
21
28
  new winston.transports.Console({
22
- level: isProduction ? 'warn' : (isDebug ? 'debug' : 'info'),
29
+ level: isDebug ? 'debug' : (isProduction ? 'warn' : 'info'),
23
30
  silent: process.env.NODE_ENV === 'test'
24
31
  })
25
32
  ]
26
33
  });
27
34
 
28
- export default logger;
35
+ // Add helper methods
36
+ logger.logRequest = (method, path, params = {}) => {
37
+ logger.debug(`Request: ${method} ${path}`, params);
38
+ };
39
+
40
+ logger.logError = (error, source = 'unknown') => {
41
+ logger.error(`Error in ${source}: ${error.message}`, {
42
+ error: error.stack || error.message,
43
+ source
44
+ });
45
+ };
46
+
47
+ logger.shouldLog = (level) => {
48
+ const currentLevel = logger.level;
49
+ const levels = {
50
+ error: 0,
51
+ warn: 1,
52
+ info: 2,
53
+ debug: 3
54
+ };
55
+ return levels[level] <= levels[currentLevel];
56
+ };
57
+
58
+ export default logger;
@@ -342,6 +342,83 @@ export async function executeSQL(projectDir, databaseName, sql, env = {}, remote
342
342
  }
343
343
  }
344
344
 
345
+ /**
346
+ * Fetches the latest `limit` records for a given table from the remote database.
347
+ *
348
+ * This implementation uses the executeSQL function with the remote flag enabled.
349
+ * It orders the results based on the provided ordering column. If no ordering column is provided,
350
+ * it falls back to the default "id" column.
351
+ *
352
+ * @param {string} projectDir - The project directory.
353
+ * @param {string} databaseName - The D1 database name.
354
+ * @param {string} tableName - The table to fetch records for.
355
+ * @param {object} env - Environment variables (including credentials).
356
+ * @param {number} limit - The number of records to fetch.
357
+ * @param {string} [orderingColumn="id"] - The column to order by.
358
+ * @returns {Promise<Array<object>>} Array of row objects.
359
+ */
360
+ export async function fetchRemoteTableData(
361
+ projectDir,
362
+ databaseName,
363
+ tableName,
364
+ env,
365
+ limit,
366
+ orderingColumn = "id"
367
+ ) {
368
+ // Use the provided ordering column; if not provided, default to "id".
369
+ const query = `SELECT * FROM "${tableName}" ORDER BY "${orderingColumn}" DESC LIMIT ${limit};`;
370
+ try {
371
+ // Execute the SQL command on the remote database.
372
+ const result = await executeSQL(projectDir, databaseName, query, env, true);
373
+
374
+ // ExecuteSQL returns stdout that should contain a JSON array starting from a '['.
375
+ const jsonStart = result.indexOf('[');
376
+ if (jsonStart === -1) {
377
+ throw new Error(`Unexpected result format: ${result}`);
378
+ }
379
+ const jsonStr = result.substring(jsonStart);
380
+ const parsed = JSON.parse(jsonStr);
381
+ // Assuming the structure: parsed[0].results contains the rows.
382
+ const rows = parsed[0]?.results || [];
383
+ return rows;
384
+ } catch (error) {
385
+ logger.error(`Error fetching remote data for table ${tableName}:`, error);
386
+ throw error;
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Generates a bulk insert SQL statement for the specified table and rows.
392
+ *
393
+ * This function constructs a single INSERT statement that inserts multiple rows.
394
+ * It escapes single quotes in string values. You may need to extend this for
395
+ * additional data types (e.g., numbers, dates, booleans) or more complex structures.
396
+ *
397
+ * @param {string} tableName - The table to insert into.
398
+ * @param {Array<object>} rows - An array of objects, each representing a row.
399
+ * @returns {string} The bulk insert SQL statement.
400
+ */
401
+ export function generateBulkInsertSQL(tableName, rows) {
402
+ if (!rows || rows.length === 0) return '';
403
+
404
+ // Get the list of columns from the first row object.
405
+ const columns = Object.keys(rows[0]);
406
+ const columnList = columns.map(col => `"${col}"`).join(', ');
407
+
408
+ // Build the values list for each row.
409
+ const valuesList = rows.map(row => {
410
+ const values = columns.map(col => {
411
+ const value = row[col];
412
+ if (value === null || value === undefined) return 'NULL';
413
+ // For simplicity, treat the value as a string.
414
+ return `'${String(value).replace(/'/g, "''")}'`;
415
+ }).join(', ');
416
+ return `(${values})`;
417
+ }).join(', ');
418
+
419
+ return `INSERT INTO "${tableName}" (${columnList}) VALUES ${valuesList};`;
420
+ }
421
+
345
422
  // ---------------------------------------------------------------------
346
423
  // SQL Formatting and Helper Functions
347
424
  // ---------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "d1s",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "type": "module",
5
5
  "description": "D1 Studio – a native studio for managing Cloudflare D1 databases.",
6
6
  "main": "./dist/d1-studio.js",
package/scripts/studio.js CHANGED
@@ -13,7 +13,14 @@ import next from 'next';
13
13
  import { findWranglerConfig } from '../src/lib/find-wrangler-config.js';
14
14
  import logger from '../src/lib/logger.js';
15
15
  import updateNotifier from 'update-notifier';
16
- import pkg from '../package.json' assert { type: 'json' };
16
+ import pkg from '../package.json' with { type: 'json' };
17
+
18
+ // Check for debug flag
19
+ const hasDebugFlag = process.argv.includes('--debug');
20
+ if (hasDebugFlag) {
21
+ process.env.DEBUG = 'true';
22
+ logger.debug('Debug mode enabled');
23
+ }
17
24
 
18
25
  const notifier = updateNotifier({ pkg, updateCheckInterval: 1000 * 60 * 60 * 24 });
19
26
  notifier.notify({ defer: false });
@@ -0,0 +1,230 @@
1
+ // api/pull-data/confirm/route.js
2
+
3
+ import { NextResponse } from 'next/server';
4
+ import { executeSQL } from '@/lib/sql-operations';
5
+ import { getCurrentSchema } from '@/lib/schema-operations';
6
+ import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
7
+ import logger from '@/lib/logger';
8
+ import {
9
+ fetchRemoteTableData as fetchRemoteDataHelper,
10
+ generateBulkInsertSQL
11
+ } from '@/lib/sql-operations';
12
+
13
+ /**
14
+ * Helper to extract the ordering column (primary key) from a table's schema.
15
+ * Assumes that each table’s schema object contains a "columns" array with an "isPrimaryKey" flag.
16
+ *
17
+ * @param {object} tableSchema - Schema info for the table.
18
+ * @returns {string} The column name to use for ordering.
19
+ */
20
+ function getOrderingColumn(tableSchema) {
21
+ const pkColumn = tableSchema.columns?.find(col => col.isPrimaryKey);
22
+ const orderingCol = pkColumn ? pkColumn.name : 'rowid';
23
+ logger.debug(`Determined ordering column for table ${tableSchema.name || 'unknown'}: ${orderingCol}`);
24
+ return orderingCol;
25
+ }
26
+
27
+ /**
28
+ * Computes an insertion order for tables based on their foreign key dependencies.
29
+ * The returned array is sorted so that if table A is referenced by table B,
30
+ * then A appears earlier in the list.
31
+ *
32
+ * @param {Array<object>} tableSchemas - Array of table schema objects.
33
+ * @returns {Array<string>} Ordered array of table names.
34
+ */
35
+ function computeInsertionOrder(tableSchemas) {
36
+ // Build a dependency graph: key = table name, value = set of tables that this table depends on.
37
+ const graph = {};
38
+ tableSchemas.forEach(table => {
39
+ // Initialize graph for this table.
40
+ graph[table.name] = new Set();
41
+ // Use a regex to find FOREIGN KEY references in the table's SQL.
42
+ // This regex assumes the foreign key clause looks like:
43
+ // FOREIGN KEY (...) REFERENCES referencedTable(...)
44
+ const fkRegex = /FOREIGN KEY\s*\([^)]*\)\s+REFERENCES\s+(\w+)/gi;
45
+ let match;
46
+ while ((match = fkRegex.exec(table.sql)) !== null) {
47
+ const referencedTable = match[1];
48
+ graph[table.name].add(referencedTable);
49
+ }
50
+ });
51
+ logger.debug('Computed dependency graph:', graph);
52
+
53
+ // Topological sort (depth-first search) to compute insertion order.
54
+ const sorted = [];
55
+ const visited = {}; // 'temp' = visiting, 'perm' = done
56
+
57
+ function visit(tableName) {
58
+ if (visited[tableName] === 'temp') {
59
+ throw new Error(`Cycle detected in dependencies at table ${tableName}`);
60
+ }
61
+ if (!visited[tableName]) {
62
+ visited[tableName] = 'temp';
63
+ // Visit all tables that this table depends on.
64
+ graph[tableName].forEach(dep => {
65
+ // Only visit if the dependency is in our graph (i.e. among our tables)
66
+ if (graph[dep]) {
67
+ visit(dep);
68
+ }
69
+ });
70
+ visited[tableName] = 'perm';
71
+ sorted.push(tableName);
72
+ }
73
+ }
74
+
75
+ Object.keys(graph).forEach(tableName => {
76
+ if (!visited[tableName]) {
77
+ visit(tableName);
78
+ }
79
+ });
80
+
81
+ logger.debug('Computed insertion order (parent tables first):', sorted);
82
+ return sorted;
83
+ }
84
+
85
+ /**
86
+ * Applies the data pull by:
87
+ * 1. Fetching the local schema to determine table names and primary keys.
88
+ * 2. Computing the insertion order so that parent tables are inserted before child tables.
89
+ * 3. For each table (in insertion order), fetching the latest 100 records from the remote database.
90
+ * 4. Generating a bulk insert statement and executing it.
91
+ *
92
+ * This function aborts the entire process if any insert fails.
93
+ *
94
+ * @param {string} projectDir
95
+ * @param {string} accountId
96
+ * @param {string} apiToken
97
+ * @param {string} databaseName
98
+ * @returns {object} Details of data pulled.
99
+ */
100
+ async function applyDataPull(projectDir, accountId, apiToken, databaseName) {
101
+ logger.debug('Starting data pull process...');
102
+ const env = {
103
+ ...process.env,
104
+ CLOUDFLARE_API_TOKEN: apiToken,
105
+ CLOUDFLARE_ACCOUNT_ID: accountId
106
+ };
107
+
108
+ logger.debug('Fetching current schema for data pull...');
109
+ const currentSchema = await getCurrentSchema(projectDir, databaseName, env, false);
110
+ // Filter for table objects that have a name.
111
+ const tableSchemas = currentSchema.filter(obj => obj.type === 'table' && obj.name);
112
+ logger.debug('Local table schema for data pull:', tableSchemas.map(t => t.name));
113
+
114
+ // Compute insertion order based on foreign key dependencies.
115
+ const insertionOrder = computeInsertionOrder(tableSchemas);
116
+ logger.debug('Final computed insertion order:', insertionOrder);
117
+
118
+ // Process each table in the computed insertion order.
119
+ for (const tableName of insertionOrder) {
120
+ const table = tableSchemas.find(t => t.name === tableName);
121
+ if (!table) {
122
+ logger.debug(`Skipping table ${tableName} as it is not in the current schema list.`);
123
+ continue;
124
+ }
125
+ logger.debug(`Processing table: ${tableName}`);
126
+ const orderingColumn = getOrderingColumn(table);
127
+ logger.debug(`Fetching data for table: ${tableName} ordered by ${orderingColumn}`);
128
+
129
+ // Fetch remote data.
130
+ const rows = await fetchRemoteDataHelper(
131
+ projectDir,
132
+ databaseName,
133
+ tableName,
134
+ env,
135
+ 75,
136
+ orderingColumn
137
+ );
138
+ logger.debug(`Fetched ${rows.length} records for table: ${tableName}`);
139
+
140
+ if (rows.length > 0) {
141
+ const insertSQL = generateBulkInsertSQL(tableName, rows);
142
+ logger.debug(`Generated bulk insert SQL for ${tableName}: ${insertSQL}`);
143
+
144
+ try {
145
+ // Execute the insert SQL directly.
146
+ await executeSQL(projectDir, databaseName, insertSQL, env, false);
147
+ logger.debug(`Bulk inserted ${rows.length} records into table: ${tableName}`);
148
+ } catch (insertError) {
149
+ logger.error(`Error inserting data into table ${tableName}:`, insertError);
150
+ // Abort the entire process to preserve data integrity.
151
+ throw new Error(`Data pull failed for table ${tableName}: ${insertError.message}`);
152
+ }
153
+ } else {
154
+ logger.debug(`No data fetched for table: ${tableName}`);
155
+ }
156
+ }
157
+ logger.debug('Data pull process completed successfully.');
158
+ return { message: 'All data pulled successfully.' };
159
+ }
160
+
161
+ export async function POST(req) {
162
+ try {
163
+ logger.debug('Received request for data pull.');
164
+ const { accountId, apiToken } = await req.json();
165
+ const projectDir = process.env.D1_PROJECT_DIR;
166
+ if (!projectDir) {
167
+ return NextResponse.json(
168
+ {
169
+ success: false,
170
+ error: {
171
+ type: 'VALIDATION_ERROR',
172
+ message: 'Project directory not configured'
173
+ }
174
+ },
175
+ { status: 500 }
176
+ );
177
+ }
178
+ const wranglerResult = await findWranglerConfig(projectDir);
179
+ if (!wranglerResult || !wranglerResult.config) {
180
+ return NextResponse.json(
181
+ {
182
+ success: false,
183
+ error: {
184
+ type: 'VALIDATION_ERROR',
185
+ message: 'Could not find Wrangler configuration'
186
+ }
187
+ },
188
+ { status: 400 }
189
+ );
190
+ }
191
+ const config = wranglerResult.config;
192
+ if (!config.d1_databases?.length) {
193
+ return NextResponse.json(
194
+ {
195
+ success: false,
196
+ error: {
197
+ type: 'VALIDATION_ERROR',
198
+ message: 'No D1 databases configured'
199
+ }
200
+ },
201
+ { status: 400 }
202
+ );
203
+ }
204
+ const databaseName = config.d1_databases[0].database_name;
205
+ logger.debug(`Initiating data pull for database: ${databaseName}`);
206
+ const result = await applyDataPull(projectDir, accountId, apiToken, databaseName);
207
+ logger.debug('Data pull result:', result);
208
+ return NextResponse.json({
209
+ success: true,
210
+ message: result.message,
211
+ details: result
212
+ });
213
+ } catch (error) {
214
+ logger.error('Pull data confirm error:', error);
215
+ return NextResponse.json(
216
+ {
217
+ success: false,
218
+ error: {
219
+ type: error.type || 'EXECUTION_ERROR',
220
+ message: error.message || 'Failed to apply data pull'
221
+ }
222
+ },
223
+ { status: 500 }
224
+ );
225
+ }
226
+ }
227
+
228
+ export async function OPTIONS() {
229
+ return new NextResponse(null, { status: 204 });
230
+ }
@@ -4,8 +4,33 @@ import updateNotifier from 'update-notifier';
4
4
  import pkg from '../../../../package.json' assert { type: 'json' };
5
5
 
6
6
  export async function GET() {
7
- // Check for updates (you might want to cache this result to avoid too many requests)
8
- const notifier = updateNotifier({ pkg, updateCheckInterval: 1000 * 60 * 60 * 24 });
9
- const update = notifier.update;
10
- return NextResponse.json({ update });
11
- }
7
+ try {
8
+ // Create notifier instance with package info
9
+ const notifier = updateNotifier({
10
+ pkg,
11
+ updateCheckInterval: 1000 * 60 * 60 * 24 // Check once per day
12
+ });
13
+
14
+ // If there's an update, notifier.update will contain the update info
15
+ if (notifier.update) {
16
+ const { latest, current } = notifier.update;
17
+
18
+ // Only return update info if versions are different
19
+ if (latest !== current) {
20
+ return NextResponse.json({
21
+ update: {
22
+ latest,
23
+ current
24
+ }
25
+ });
26
+ }
27
+ }
28
+
29
+ // No update available
30
+ return NextResponse.json({ update: null });
31
+ } catch (error) {
32
+ console.error('Error checking for updates:', error);
33
+ // Return null on error to prevent banner from showing
34
+ return NextResponse.json({ update: null });
35
+ }
36
+ }
package/src/app/page.jsx CHANGED
@@ -7,7 +7,6 @@ import { SQLEditor } from '../components/sql-editor';
7
7
  import { TableView } from '../components/table-view';
8
8
  import UpdateBanner from '@/components/update-banner';
9
9
 
10
-
11
10
  export default function StudioPage() {
12
11
  const [currentView, setCurrentView] = useState('sql-editor');
13
12
  const [selectedTable, setSelectedTable] = useState(null);
@@ -18,23 +17,28 @@ export default function StudioPage() {
18
17
  };
19
18
 
20
19
  return (
21
- <div className="min-h-screen bg-background">
22
- {/* notification banner at the top of the page */}
20
+ <div className="flex flex-col min-h-screen bg-background">
21
+ {/* Banner */}
23
22
  <UpdateBanner />
24
- {/* sidebar */}
25
- <AppSidebar
26
- className="w-64 border-r"
27
- currentView={currentView}
28
- onNavigate={setCurrentView}
29
- onTableSelect={handleTableSelect}
30
- />
31
- {/* main content */}
32
- <main className="ml-64 h-screen">
33
- {currentView === 'sql-editor' && <SQLEditor />}
34
- {currentView === 'table-view' && selectedTable && (
35
- <TableView tableName={selectedTable} />
36
- )}
37
- </main>
23
+
24
+ {/* Main layout */}
25
+ <div className="flex flex-1">
26
+ {/* Sidebar */}
27
+ <AppSidebar
28
+ className="w-64 border-r fixed h-[calc(100vh-var(--banner-height,0px))]"
29
+ currentView={currentView}
30
+ onNavigate={setCurrentView}
31
+ onTableSelect={handleTableSelect}
32
+ />
33
+
34
+ {/* Main content */}
35
+ <main className="ml-64 flex-1 h-[calc(100vh-var(--banner-height,0px))]">
36
+ {currentView === 'sql-editor' && <SQLEditor />}
37
+ {currentView === 'table-view' && selectedTable && (
38
+ <TableView tableName={selectedTable} />
39
+ )}
40
+ </main>
41
+ </div>
38
42
  </div>
39
43
  );
40
44
  }
@@ -18,11 +18,14 @@ const ErrorTypes = {
18
18
  export function useEnvironmentController() {
19
19
  const [isConnecting, setIsConnecting] = useState(false);
20
20
  const [isPushing, setIsPushing] = useState(false);
21
+ // New state for data pull status
22
+ const [isDataPulling, setIsDataPulling] = useState(false);
21
23
  const [showPreview, setShowPreview] = useState(false);
22
24
  const [previewData, setPreviewData] = useState(null);
23
25
  const [previewError, setPreviewError] = useState(null);
24
- const [previewType, setPreviewType] = useState(null); // "push" or "pull"
26
+ const [previewType, setPreviewType] = useState(null);
25
27
  const [previewSuccess, setPreviewSuccess] = useState(null);
28
+ const [environment, setEnvironment] = useState('local');
26
29
  const { toast } = useToast();
27
30
  const { refreshTables } = useDatabase();
28
31
 
@@ -93,7 +96,7 @@ export function useEnvironmentController() {
93
96
  }
94
97
  };
95
98
 
96
- // Confirm push
99
+ // Update the confirmPush function:
97
100
  const confirmPush = async () => {
98
101
  try {
99
102
  setIsPushing(true);
@@ -113,7 +116,7 @@ export function useEnvironmentController() {
113
116
  if (!data.success) {
114
117
  throw new Error(data.error?.message || 'Failed to confirm push');
115
118
  }
116
-
119
+
117
120
  // Update the preview data to show applied status
118
121
  setPreviewData(prev => ({
119
122
  ...prev,
@@ -122,12 +125,16 @@ export function useEnvironmentController() {
122
125
  action: item.action === 'will be applied' ? 'applied' : item.action
123
126
  }))
124
127
  }));
125
-
126
- // Set success message instead of showing toast
128
+
127
129
  setPreviewSuccess(`Applied ${data.details.applied} migration(s), skipped ${data.details.skipped}.`);
130
+
131
+ // Reset environment after success
132
+ setEnvironment('local');
128
133
  } catch (error) {
129
134
  console.error("Push to remote confirm failed:", error);
130
135
  setPreviewError(error);
136
+ // Reset environment after error
137
+ setEnvironment('local');
131
138
  } finally {
132
139
  setIsPushing(false);
133
140
  }
@@ -169,11 +176,13 @@ export function useEnvironmentController() {
169
176
  }
170
177
  };
171
178
 
172
- // Confirm pull
179
+ // In confirmPull function, add environment reset:
173
180
  const confirmPull = async () => {
174
181
  try {
175
182
  setIsPushing(true);
183
+ setEnvironment('pull'); // Ensure correct state during pull
176
184
  setPreviewError(null);
185
+ setPreviewSuccess(null);
177
186
 
178
187
  const credentials = await validateStoredCredentials();
179
188
  if (!credentials) throw new Error("No valid credentials found");
@@ -189,25 +198,61 @@ export function useEnvironmentController() {
189
198
  throw new Error(data.error?.message || 'Failed to confirm pull');
190
199
  }
191
200
 
192
- clearPreviewState();
193
- toast({
194
- title: "Migration Success",
195
- description: `Pull migrations applied successfully.`,
196
- });
201
+ setPreviewSuccess(`Pull migrations applied successfully.`);
202
+
203
+ setPreviewData(prev => ({
204
+ ...prev,
205
+ preview: prev.preview.map(item => ({
206
+ ...item,
207
+ action: item.action === 'will be applied' ? 'applied' : item.action
208
+ }))
209
+ }));
210
+
197
211
  await refreshTables();
212
+
198
213
  } catch (error) {
199
214
  console.error("Pull to remote confirm failed:", error);
200
215
  setPreviewError(error);
201
- toast({
202
- title: "Migration Failed",
203
- description: error.message || "Failed to pull migrations from remote",
204
- variant: "destructive",
205
- });
206
216
  } finally {
207
217
  setIsPushing(false);
218
+ setEnvironment('local'); // Reset to local regardless of success/failure
208
219
  }
209
220
  };
210
221
 
222
+ // In confirmDataPull function, add syncing state:
223
+ const confirmDataPull = async () => {
224
+ try {
225
+ setIsDataPulling(true);
226
+ setEnvironment('syncing'); // Set environment to syncing during data pull
227
+ setPreviewError(null);
228
+ setPreviewSuccess(null);
229
+
230
+ const credentials = await validateStoredCredentials();
231
+ if (!credentials) throw new Error("No valid credentials found");
232
+
233
+ const response = await fetch("/api/pull-data/confirm", {
234
+ method: "POST",
235
+ headers: { "Content-Type": "application/json" },
236
+ body: JSON.stringify(credentials)
237
+ });
238
+
239
+ const data = await response.json();
240
+ if (!data.success) {
241
+ throw new Error(data.error?.message || 'Failed to confirm data pull');
242
+ }
243
+
244
+ setPreviewSuccess("Remote data synced successfully.");
245
+ await refreshTables();
246
+
247
+ } catch (error) {
248
+ console.error("Data pull confirm failed:", error);
249
+ setPreviewError(error);
250
+ } finally {
251
+ setIsDataPulling(false);
252
+ setEnvironment('local'); // Reset to local regardless of success/failure
253
+ }
254
+ };
255
+
211
256
  // Connect to Cloudflare
212
257
  async function connectToCloudflare(credentials) {
213
258
  try {
@@ -240,14 +285,18 @@ export function useEnvironmentController() {
240
285
  }
241
286
  }
242
287
 
288
+ // Update PreviewUI to pass onDataPull and isDataPulling for pull previews.
243
289
  const PreviewUI = showPreview && (
244
290
  previewType === "pull" ? (
245
291
  <PullPreviewToast
246
292
  preview={previewData?.preview || []}
247
293
  onConfirm={confirmPull}
294
+ onDataPull={confirmDataPull} // pass the new data pull handler
248
295
  onCancel={clearPreviewState}
249
296
  isConfirming={isPushing}
297
+ isDataPulling={isDataPulling}
250
298
  error={previewError}
299
+ success={previewSuccess}
251
300
  isLoading={isPushing && !previewData?.preview?.length}
252
301
  />
253
302
  ) : (
@@ -266,13 +315,18 @@ export function useEnvironmentController() {
266
315
  return {
267
316
  isConnecting,
268
317
  isPushing,
318
+ isDataPulling,
269
319
  showPreview,
270
320
  previewError,
321
+ environment, // Add this
322
+ setEnvironment, // Add this if needed
271
323
  pushToRemote,
272
324
  pullToRemotePreview,
273
325
  confirmPull,
326
+ confirmDataPull, // export the new function
274
327
  connectToCloudflare,
275
328
  validateStoredCredentials,
276
329
  PreviewUI
277
330
  };
278
331
  }
332
+