d1s 0.2.1

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 (408) hide show
  1. package/README.md +7 -0
  2. package/dist/.next/.next/BUILD_ID +1 -0
  3. package/dist/.next/.next/app-build-manifest.json +109 -0
  4. package/dist/.next/.next/app-path-routes-manifest.json +1 -0
  5. package/dist/.next/.next/build-manifest.json +33 -0
  6. package/dist/.next/.next/cache/.rscinfo +1 -0
  7. package/dist/.next/.next/cache/.tsbuildinfo +1 -0
  8. package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
  9. package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
  10. package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
  11. package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
  12. package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
  13. package/dist/.next/.next/cache/webpack/edge-server-production/0.pack +0 -0
  14. package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
  15. package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
  16. package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
  17. package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
  18. package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
  19. package/dist/.next/.next/diagnostics/build-diagnostics.json +6 -0
  20. package/dist/.next/.next/diagnostics/framework.json +1 -0
  21. package/dist/.next/.next/export-marker.json +1 -0
  22. package/dist/.next/.next/images-manifest.json +1 -0
  23. package/dist/.next/.next/next-minimal-server.js.nft.json +1 -0
  24. package/dist/.next/.next/next-server.js.nft.json +1 -0
  25. package/dist/.next/.next/package.json +1 -0
  26. package/dist/.next/.next/prerender-manifest.json +1 -0
  27. package/dist/.next/.next/react-loadable-manifest.json +1 -0
  28. package/dist/.next/.next/required-server-files.json +1 -0
  29. package/dist/.next/.next/routes-manifest.json +1 -0
  30. package/dist/.next/.next/server/app/_not-found/page.js +1 -0
  31. package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -0
  32. package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  33. package/dist/.next/.next/server/app/_not-found.html +1 -0
  34. package/dist/.next/.next/server/app/_not-found.meta +8 -0
  35. package/dist/.next/.next/server/app/_not-found.rsc +16 -0
  36. package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -0
  37. package/dist/.next/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
  38. package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
  39. package/dist/.next/.next/server/app/api/databases/route.js +1 -0
  40. package/dist/.next/.next/server/app/api/databases/route.js.nft.json +1 -0
  41. package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
  42. package/dist/.next/.next/server/app/api/migrations/sync/route.js +12 -0
  43. package/dist/.next/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
  44. package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
  45. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +1 -0
  46. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
  47. package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
  48. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +1 -0
  49. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
  50. package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
  51. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +1 -0
  52. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
  53. package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
  54. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +14 -0
  55. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
  56. package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
  57. package/dist/.next/.next/server/app/api/push-remote/preview/route.js +14 -0
  58. package/dist/.next/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
  59. package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
  60. package/dist/.next/.next/server/app/api/query/route.js +8 -0
  61. package/dist/.next/.next/server/app/api/query/route.js.nft.json +1 -0
  62. package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
  63. package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -0
  64. package/dist/.next/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
  65. package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
  66. package/dist/.next/.next/server/app/api/tables/route.js +7 -0
  67. package/dist/.next/.next/server/app/api/tables/route.js.nft.json +1 -0
  68. package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
  69. package/dist/.next/.next/server/app/index.html +3 -0
  70. package/dist/.next/.next/server/app/index.meta +7 -0
  71. package/dist/.next/.next/server/app/index.rsc +20 -0
  72. package/dist/.next/.next/server/app/page.js +58 -0
  73. package/dist/.next/.next/server/app/page.js.nft.json +1 -0
  74. package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -0
  75. package/dist/.next/.next/server/app-paths-manifest.json +15 -0
  76. package/dist/.next/.next/server/chunks/336.js +1 -0
  77. package/dist/.next/.next/server/chunks/627.js +6 -0
  78. package/dist/.next/.next/server/chunks/638.js +13 -0
  79. package/dist/.next/.next/server/chunks/801.js +55 -0
  80. package/dist/.next/.next/server/chunks/973.js +2 -0
  81. package/dist/.next/.next/server/chunks/992.js +3 -0
  82. package/dist/.next/.next/server/functions-config-manifest.json +1 -0
  83. package/dist/.next/.next/server/interception-route-rewrite-manifest.js +1 -0
  84. package/dist/.next/.next/server/middleware-build-manifest.js +1 -0
  85. package/dist/.next/.next/server/middleware-manifest.json +6 -0
  86. package/dist/.next/.next/server/middleware-react-loadable-manifest.js +1 -0
  87. package/dist/.next/.next/server/next-font-manifest.js +1 -0
  88. package/dist/.next/.next/server/next-font-manifest.json +1 -0
  89. package/dist/.next/.next/server/pages/404.html +1 -0
  90. package/dist/.next/.next/server/pages/500.html +1 -0
  91. package/dist/.next/.next/server/pages/_app.js +1 -0
  92. package/dist/.next/.next/server/pages/_app.js.nft.json +1 -0
  93. package/dist/.next/.next/server/pages/_document.js +1 -0
  94. package/dist/.next/.next/server/pages/_document.js.nft.json +1 -0
  95. package/dist/.next/.next/server/pages/_error.js +1 -0
  96. package/dist/.next/.next/server/pages/_error.js.nft.json +1 -0
  97. package/dist/.next/.next/server/pages-manifest.json +1 -0
  98. package/dist/.next/.next/server/server-reference-manifest.js +1 -0
  99. package/dist/.next/.next/server/server-reference-manifest.json +1 -0
  100. package/dist/.next/.next/server/webpack-runtime.js +1 -0
  101. package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_buildManifest.js +1 -0
  102. package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_ssgManifest.js +1 -0
  103. package/dist/.next/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
  104. package/dist/.next/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
  105. package/dist/.next/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
  106. package/dist/.next/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
  107. package/dist/.next/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
  108. package/dist/.next/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
  109. package/dist/.next/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
  110. package/dist/.next/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
  111. package/dist/.next/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
  112. package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
  113. package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
  114. package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
  115. package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
  116. package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
  117. package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
  118. package/dist/.next/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
  119. package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
  120. package/dist/.next/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
  121. package/dist/.next/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
  122. package/dist/.next/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
  123. package/dist/.next/.next/static/chunks/framework-d29117d969504448.js +1 -0
  124. package/dist/.next/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
  125. package/dist/.next/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
  126. package/dist/.next/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
  127. package/dist/.next/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
  128. package/dist/.next/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  129. package/dist/.next/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
  130. package/dist/.next/.next/static/css/c51a7ef325e30c16.css +3 -0
  131. package/dist/.next/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
  132. package/dist/.next/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  133. package/dist/.next/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  134. package/dist/.next/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  135. package/dist/.next/.next/trace +3 -0
  136. package/dist/.next/.next/types/app/api/cloudflare/route.ts +347 -0
  137. package/dist/.next/.next/types/app/api/databases/route.ts +347 -0
  138. package/dist/.next/.next/types/app/api/migrations/sync/route.ts +347 -0
  139. package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +347 -0
  140. package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
  141. package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +347 -0
  142. package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +347 -0
  143. package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +347 -0
  144. package/dist/.next/.next/types/app/api/query/route.ts +347 -0
  145. package/dist/.next/.next/types/app/api/tables/[name]/route.ts +347 -0
  146. package/dist/.next/.next/types/app/api/tables/route.ts +347 -0
  147. package/dist/.next/.next/types/app/page.ts +84 -0
  148. package/dist/.next/.next/types/cache-life.d.ts +141 -0
  149. package/dist/.next/.next/types/package.json +1 -0
  150. package/dist/.next/BUILD_ID +1 -0
  151. package/dist/.next/app-build-manifest.json +109 -0
  152. package/dist/.next/app-path-routes-manifest.json +1 -0
  153. package/dist/.next/build-manifest.json +33 -0
  154. package/dist/.next/cache/.rscinfo +1 -0
  155. package/dist/.next/cache/.tsbuildinfo +1 -0
  156. package/dist/.next/cache/webpack/client-production/0.pack +0 -0
  157. package/dist/.next/cache/webpack/client-production/index.pack +0 -0
  158. package/dist/.next/cache/webpack/edge-server-production/0.pack +0 -0
  159. package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
  160. package/dist/.next/cache/webpack/server-production/0.pack +0 -0
  161. package/dist/.next/cache/webpack/server-production/index.pack +0 -0
  162. package/dist/.next/diagnostics/build-diagnostics.json +6 -0
  163. package/dist/.next/diagnostics/framework.json +1 -0
  164. package/dist/.next/export-marker.json +1 -0
  165. package/dist/.next/images-manifest.json +1 -0
  166. package/dist/.next/next-minimal-server.js.nft.json +1 -0
  167. package/dist/.next/next-server.js.nft.json +1 -0
  168. package/dist/.next/package.json +1 -0
  169. package/dist/.next/prerender-manifest.json +1 -0
  170. package/dist/.next/react-loadable-manifest.json +1 -0
  171. package/dist/.next/required-server-files.json +1 -0
  172. package/dist/.next/routes-manifest.json +1 -0
  173. package/dist/.next/server/app/_not-found/page.js +1 -0
  174. package/dist/.next/server/app/_not-found/page.js.nft.json +1 -0
  175. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  176. package/dist/.next/server/app/_not-found.html +1 -0
  177. package/dist/.next/server/app/_not-found.meta +8 -0
  178. package/dist/.next/server/app/_not-found.rsc +16 -0
  179. package/dist/.next/server/app/api/cloudflare/route.js +1 -0
  180. package/dist/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
  181. package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
  182. package/dist/.next/server/app/api/databases/route.js +1 -0
  183. package/dist/.next/server/app/api/databases/route.js.nft.json +1 -0
  184. package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
  185. package/dist/.next/server/app/api/migrations/sync/route.js +12 -0
  186. package/dist/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
  187. package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
  188. package/dist/.next/server/app/api/migrations/sync-files/route.js +1 -0
  189. package/dist/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
  190. package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
  191. package/dist/.next/server/app/api/pull-remote/confirm/route.js +1 -0
  192. package/dist/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
  193. package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
  194. package/dist/.next/server/app/api/pull-remote/preview/route.js +1 -0
  195. package/dist/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
  196. package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
  197. package/dist/.next/server/app/api/push-remote/confirm/route.js +14 -0
  198. package/dist/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
  199. package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
  200. package/dist/.next/server/app/api/push-remote/preview/route.js +14 -0
  201. package/dist/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
  202. package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
  203. package/dist/.next/server/app/api/query/route.js +8 -0
  204. package/dist/.next/server/app/api/query/route.js.nft.json +1 -0
  205. package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
  206. package/dist/.next/server/app/api/tables/[name]/route.js +5 -0
  207. package/dist/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
  208. package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
  209. package/dist/.next/server/app/api/tables/route.js +7 -0
  210. package/dist/.next/server/app/api/tables/route.js.nft.json +1 -0
  211. package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
  212. package/dist/.next/server/app/index.html +3 -0
  213. package/dist/.next/server/app/index.meta +7 -0
  214. package/dist/.next/server/app/index.rsc +20 -0
  215. package/dist/.next/server/app/page.js +58 -0
  216. package/dist/.next/server/app/page.js.nft.json +1 -0
  217. package/dist/.next/server/app/page_client-reference-manifest.js +1 -0
  218. package/dist/.next/server/app-paths-manifest.json +15 -0
  219. package/dist/.next/server/chunks/336.js +1 -0
  220. package/dist/.next/server/chunks/627.js +6 -0
  221. package/dist/.next/server/chunks/638.js +13 -0
  222. package/dist/.next/server/chunks/801.js +55 -0
  223. package/dist/.next/server/chunks/973.js +2 -0
  224. package/dist/.next/server/chunks/992.js +3 -0
  225. package/dist/.next/server/functions-config-manifest.json +1 -0
  226. package/dist/.next/server/interception-route-rewrite-manifest.js +1 -0
  227. package/dist/.next/server/middleware-build-manifest.js +1 -0
  228. package/dist/.next/server/middleware-manifest.json +6 -0
  229. package/dist/.next/server/middleware-react-loadable-manifest.js +1 -0
  230. package/dist/.next/server/next-font-manifest.js +1 -0
  231. package/dist/.next/server/next-font-manifest.json +1 -0
  232. package/dist/.next/server/pages/404.html +1 -0
  233. package/dist/.next/server/pages/500.html +1 -0
  234. package/dist/.next/server/pages/_app.js +1 -0
  235. package/dist/.next/server/pages/_app.js.nft.json +1 -0
  236. package/dist/.next/server/pages/_document.js +1 -0
  237. package/dist/.next/server/pages/_document.js.nft.json +1 -0
  238. package/dist/.next/server/pages/_error.js +1 -0
  239. package/dist/.next/server/pages/_error.js.nft.json +1 -0
  240. package/dist/.next/server/pages-manifest.json +1 -0
  241. package/dist/.next/server/server-reference-manifest.js +1 -0
  242. package/dist/.next/server/server-reference-manifest.json +1 -0
  243. package/dist/.next/server/webpack-runtime.js +1 -0
  244. package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_buildManifest.js +1 -0
  245. package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_ssgManifest.js +1 -0
  246. package/dist/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
  247. package/dist/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
  248. package/dist/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
  249. package/dist/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
  250. package/dist/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
  251. package/dist/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
  252. package/dist/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
  253. package/dist/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
  254. package/dist/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
  255. package/dist/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
  256. package/dist/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
  257. package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
  258. package/dist/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
  259. package/dist/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
  260. package/dist/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
  261. package/dist/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
  262. package/dist/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
  263. package/dist/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
  264. package/dist/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
  265. package/dist/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
  266. package/dist/.next/static/chunks/framework-d29117d969504448.js +1 -0
  267. package/dist/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
  268. package/dist/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
  269. package/dist/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
  270. package/dist/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
  271. package/dist/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  272. package/dist/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
  273. package/dist/.next/static/css/c51a7ef325e30c16.css +3 -0
  274. package/dist/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
  275. package/dist/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  276. package/dist/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  277. package/dist/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  278. package/dist/.next/trace +13 -0
  279. package/dist/.next/types/app/api/cloudflare/route.ts +347 -0
  280. package/dist/.next/types/app/api/databases/route.ts +347 -0
  281. package/dist/.next/types/app/api/migrations/sync/route.ts +347 -0
  282. package/dist/.next/types/app/api/migrations/sync-files/route.ts +347 -0
  283. package/dist/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
  284. package/dist/.next/types/app/api/pull-remote/preview/route.ts +347 -0
  285. package/dist/.next/types/app/api/push-remote/confirm/route.ts +347 -0
  286. package/dist/.next/types/app/api/push-remote/preview/route.ts +347 -0
  287. package/dist/.next/types/app/api/query/route.ts +347 -0
  288. package/dist/.next/types/app/api/tables/[name]/route.ts +347 -0
  289. package/dist/.next/types/app/api/tables/route.ts +347 -0
  290. package/dist/.next/types/app/page.ts +84 -0
  291. package/dist/.next/types/cache-life.d.ts +141 -0
  292. package/dist/.next/types/package.json +1 -0
  293. package/dist/app/api/cloudflare/route.js +146 -0
  294. package/dist/app/api/databases/route.js +72 -0
  295. package/dist/app/api/migrations/sync/route.js +172 -0
  296. package/dist/app/api/migrations/sync-files/route.js +172 -0
  297. package/dist/app/api/pull-remote/confirm/route.js +277 -0
  298. package/dist/app/api/pull-remote/preview/route.js +143 -0
  299. package/dist/app/api/push-remote/confirm/route.js +196 -0
  300. package/dist/app/api/push-remote/preview/route.js +178 -0
  301. package/dist/app/api/query/route.js +160 -0
  302. package/dist/app/api/tables/[name]/route.js +173 -0
  303. package/dist/app/api/tables/route.js +174 -0
  304. package/dist/app/app/api/cloudflare/route.js +146 -0
  305. package/dist/app/app/api/databases/route.js +72 -0
  306. package/dist/app/app/api/migrations/sync/route.js +172 -0
  307. package/dist/app/app/api/migrations/sync-files/route.js +172 -0
  308. package/dist/app/app/api/pull-remote/confirm/route.js +277 -0
  309. package/dist/app/app/api/pull-remote/preview/route.js +143 -0
  310. package/dist/app/app/api/push-remote/confirm/route.js +196 -0
  311. package/dist/app/app/api/push-remote/preview/route.js +178 -0
  312. package/dist/app/app/api/query/route.js +160 -0
  313. package/dist/app/app/api/tables/[name]/route.js +173 -0
  314. package/dist/app/app/api/tables/route.js +174 -0
  315. package/dist/app/app/globals.css +93 -0
  316. package/dist/app/app/layout.jsx +35 -0
  317. package/dist/app/app/page.jsx +37 -0
  318. package/dist/app/globals.css +93 -0
  319. package/dist/app/layout.jsx +35 -0
  320. package/dist/app/page.jsx +37 -0
  321. package/dist/d1-studio.js +344 -0
  322. package/dist/lib/database-queue.js +33 -0
  323. package/dist/lib/error.js +20 -0
  324. package/dist/lib/find-wrangler-config.js +67 -0
  325. package/dist/lib/license.js +99 -0
  326. package/dist/lib/migrations.js +415 -0
  327. package/dist/lib/parse-sql-error.js +200 -0
  328. package/dist/lib/request-deduplication.js +24 -0
  329. package/dist/lib/schema-operations.js +103 -0
  330. package/dist/lib/sql-error-types.js +14 -0
  331. package/dist/lib/sql-operations.js +557 -0
  332. package/dist/lib/utils.js +6 -0
  333. package/next.config.mjs +18 -0
  334. package/package.json +97 -0
  335. package/postcss.config.mjs +8 -0
  336. package/scripts/studio.js +344 -0
  337. package/scripts/test.js +168 -0
  338. package/src/app/api/cloudflare/route.js +146 -0
  339. package/src/app/api/databases/route.js +72 -0
  340. package/src/app/api/migrations/sync/route.js +172 -0
  341. package/src/app/api/migrations/sync-files/route.js +172 -0
  342. package/src/app/api/pull-remote/confirm/route.js +277 -0
  343. package/src/app/api/pull-remote/preview/route.js +143 -0
  344. package/src/app/api/push-remote/confirm/route.js +196 -0
  345. package/src/app/api/push-remote/preview/route.js +178 -0
  346. package/src/app/api/query/route.js +160 -0
  347. package/src/app/api/tables/[name]/route.js +173 -0
  348. package/src/app/api/tables/route.js +174 -0
  349. package/src/app/globals.css +93 -0
  350. package/src/app/layout.jsx +35 -0
  351. package/src/app/page.jsx +37 -0
  352. package/src/components/cloudflare-credentials-modal.jsx +94 -0
  353. package/src/components/column-selector.jsx +133 -0
  354. package/src/components/column-sorting.jsx +65 -0
  355. package/src/components/delete-records-dialog.jsx +64 -0
  356. package/src/components/download-button.jsx +205 -0
  357. package/src/components/edit-error-alert.jsx +30 -0
  358. package/src/components/editable-cell.jsx +163 -0
  359. package/src/components/editable-row.jsx +169 -0
  360. package/src/components/environment-handler.jsx +278 -0
  361. package/src/components/environment-select.jsx +59 -0
  362. package/src/components/pull-preview-toast.jsx +188 -0
  363. package/src/components/push-error-alert.jsx +72 -0
  364. package/src/components/push-preview-toast.jsx +183 -0
  365. package/src/components/query-results.jsx +112 -0
  366. package/src/components/refresh-button.jsx +61 -0
  367. package/src/components/resize-columns.jsx +101 -0
  368. package/src/components/sidebar.jsx +236 -0
  369. package/src/components/sql-editor.jsx +411 -0
  370. package/src/components/sql-error-display.jsx +167 -0
  371. package/src/components/sync-migrations-button.jsx +87 -0
  372. package/src/components/table-error-dialog.jsx +65 -0
  373. package/src/components/table-toolbar.jsx +285 -0
  374. package/src/components/table-view.jsx +843 -0
  375. package/src/components/ui/alert.jsx +47 -0
  376. package/src/components/ui/button.jsx +48 -0
  377. package/src/components/ui/card.jsx +50 -0
  378. package/src/components/ui/checkbox.jsx +24 -0
  379. package/src/components/ui/collapsible.jsx +11 -0
  380. package/src/components/ui/dialog.jsx +96 -0
  381. package/src/components/ui/dropdown-menu.jsx +158 -0
  382. package/src/components/ui/input.jsx +19 -0
  383. package/src/components/ui/scroll-area.jsx +40 -0
  384. package/src/components/ui/select.jsx +121 -0
  385. package/src/components/ui/separator.jsx +25 -0
  386. package/src/components/ui/sheet.jsx +109 -0
  387. package/src/components/ui/sidebar.jsx +620 -0
  388. package/src/components/ui/skeleton.jsx +14 -0
  389. package/src/components/ui/table.jsx +86 -0
  390. package/src/components/ui/tabs.jsx +43 -0
  391. package/src/components/ui/toast.jsx +86 -0
  392. package/src/components/ui/toaster.jsx +35 -0
  393. package/src/components/ui/tooltip.jsx +28 -0
  394. package/src/context/database-context.js +510 -0
  395. package/src/hooks/use-mobile.jsx +19 -0
  396. package/src/hooks/use-sql-error.ts +23 -0
  397. package/src/hooks/use-toast.js +155 -0
  398. package/src/lib/database-queue.js +33 -0
  399. package/src/lib/error.js +20 -0
  400. package/src/lib/find-wrangler-config.js +67 -0
  401. package/src/lib/license.js +99 -0
  402. package/src/lib/migrations.js +415 -0
  403. package/src/lib/parse-sql-error.js +200 -0
  404. package/src/lib/request-deduplication.js +24 -0
  405. package/src/lib/schema-operations.js +103 -0
  406. package/src/lib/sql-error-types.js +14 -0
  407. package/src/lib/sql-operations.js +557 -0
  408. package/src/lib/utils.js +6 -0
@@ -0,0 +1,33 @@
1
+ // utils/database-queue.js
2
+ class DatabaseQueue {
3
+ constructor() {
4
+ this.queue = [];
5
+ this.isProcessing = false;
6
+ }
7
+
8
+ async add(operation) {
9
+ return new Promise((resolve, reject) => {
10
+ this.queue.push({ operation, resolve, reject });
11
+ this.processNext();
12
+ });
13
+ }
14
+
15
+ async processNext() {
16
+ if (this.isProcessing || this.queue.length === 0) return;
17
+
18
+ this.isProcessing = true;
19
+ const { operation, resolve, reject } = this.queue.shift();
20
+
21
+ try {
22
+ const result = await operation();
23
+ resolve(result);
24
+ } catch (error) {
25
+ reject(error);
26
+ } finally {
27
+ this.isProcessing = false;
28
+ this.processNext();
29
+ }
30
+ }
31
+ }
32
+
33
+ export const dbQueue = new DatabaseQueue();
@@ -0,0 +1,20 @@
1
+ // lib/errors.js
2
+ export class LicenseError extends Error {
3
+ constructor(message, type = 'VALIDATION_ERROR') {
4
+ super(message);
5
+ this.name = 'LicenseError';
6
+ this.type = type;
7
+ }
8
+ }
9
+
10
+ export const ErrorTypes = {
11
+ LICENSE_NOT_FOUND: 'LICENSE_NOT_FOUND',
12
+ EMAIL_MISMATCH: 'EMAIL_MISMATCH',
13
+ INACTIVE_LICENSE: 'INACTIVE_LICENSE',
14
+ INACTIVE_SUBSCRIPTION: 'INACTIVE_SUBSCRIPTION',
15
+ EXPIRED_SUBSCRIPTION: 'EXPIRED_SUBSCRIPTION',
16
+ MAX_ACTIVATIONS: 'MAX_ACTIVATIONS',
17
+ CONNECTION_ERROR: 'CONNECTION_ERROR',
18
+ VALIDATION_ERROR: 'VALIDATION_ERROR',
19
+ SAVE_ERROR: 'SAVE_ERROR'
20
+ };
@@ -0,0 +1,67 @@
1
+ // lib/find-wrangler-config.js
2
+ import { readFile } from 'fs/promises';
3
+ import { findUp } from 'find-up';
4
+ import { parse as parseToml } from '@iarna/toml';
5
+ import stripJsonComments from 'strip-json-comments';
6
+ import chalk from 'chalk';
7
+
8
+ /**
9
+ * Finds and parses the Wrangler configuration file.
10
+ *
11
+ * @param {string} userProjectPath - The path where to look for the config file
12
+ * @returns {Promise<{config: object, projectPath: string}|null>}
13
+ */
14
+ export async function findWranglerConfig(userProjectPath) {
15
+ try {
16
+ if (!userProjectPath || typeof userProjectPath !== 'string') {
17
+ throw new Error('Project path is required and must be a string');
18
+ }
19
+
20
+ console.log(chalk.blue('Looking for wrangler configuration in:'), userProjectPath);
21
+
22
+ // Define the possible configuration file names in priority order.
23
+ const possibleFiles = ['wrangler.toml', 'wrangler.json', 'wrangler.jsonc'];
24
+ let configPath = null;
25
+ let configFileUsed = null;
26
+
27
+ // Search for any of the possible config files
28
+ for (const file of possibleFiles) {
29
+ configPath = await findUp(file, { cwd: userProjectPath });
30
+ if (configPath) {
31
+ configFileUsed = file;
32
+ break;
33
+ }
34
+ }
35
+
36
+ if (!configPath) {
37
+ console.log(chalk.yellow('No Wrangler configuration file found in:'), userProjectPath);
38
+ return null;
39
+ }
40
+
41
+ console.log(chalk.green(`Found ${configFileUsed} at:`), configPath);
42
+
43
+ // Read the configuration file
44
+ let configContent = await readFile(configPath, 'utf-8');
45
+ let config;
46
+
47
+ // Parse based on file type
48
+ if (configFileUsed.endsWith('.toml')) {
49
+ config = parseToml(configContent);
50
+ } else {
51
+ // If it's JSONC, strip comments before parsing
52
+ if (configFileUsed.endsWith('.jsonc')) {
53
+ configContent = stripJsonComments(configContent);
54
+ }
55
+ config = JSON.parse(configContent);
56
+ }
57
+
58
+ return {
59
+ config,
60
+ projectPath: userProjectPath
61
+ };
62
+
63
+ } catch (error) {
64
+ console.error(chalk.red('Error reading Wrangler configuration:'), error.message);
65
+ throw error;
66
+ }
67
+ }
@@ -0,0 +1,99 @@
1
+ // lib/license.js
2
+ import os from 'os';
3
+ import { join } from 'path';
4
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
5
+ import { createHash } from 'crypto';
6
+ import { LicenseError } from './errors.js';
7
+
8
+ export async function generateHardwareId() {
9
+ const osInfo = {
10
+ platform: process.platform,
11
+ arch: process.arch,
12
+ cpus: os.cpus().length,
13
+ hostname: os.hostname(),
14
+ username: os.userInfo().username
15
+ };
16
+
17
+ const systemString = JSON.stringify(osInfo);
18
+ return createHash('sha256').update(systemString).digest('hex');
19
+ }
20
+
21
+ export async function checkLicenseFile() {
22
+ const licenseDir = join(os.homedir(), '.d1studio');
23
+ const licensePath = join(licenseDir, 'license.json');
24
+
25
+ try {
26
+ const licenseData = JSON.parse(await readFile(licensePath, 'utf8'));
27
+ const hardwareId = await generateHardwareId();
28
+
29
+ if (licenseData.hardwareId !== hardwareId) {
30
+ return null;
31
+ }
32
+
33
+ return licenseData;
34
+ } catch (error) {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ export async function saveLicenseFile(licenseData) {
40
+ const licenseDir = join(os.homedir(), '.d1studio');
41
+ const licensePath = join(licenseDir, 'license.json');
42
+
43
+ try {
44
+ await mkdir(licenseDir, { recursive: true });
45
+ await writeFile(licensePath, JSON.stringify(licenseData, null, 2));
46
+ } catch (error) {
47
+ throw new LicenseError('Failed to save license information', 'SAVE_ERROR');
48
+ }
49
+ }
50
+
51
+ export async function validateLicenseRemote(licenseKey, email, hardwareId) {
52
+ const baseUrl = process.env.NODE_ENV === 'development'
53
+ ? 'http://localhost:4000'
54
+ : 'https://d1-studio.com';
55
+
56
+ try {
57
+ const response = await fetch(`${baseUrl}/api/validate-license`, {
58
+ method: 'POST',
59
+ headers: {
60
+ 'Content-Type': 'application/json',
61
+ },
62
+ body: JSON.stringify({
63
+ licenseKey,
64
+ email,
65
+ hardwareId
66
+ })
67
+ });
68
+
69
+ const result = await response.json();
70
+
71
+ if (!response.ok) {
72
+ throw new LicenseError(
73
+ result.message || 'License validation failed',
74
+ result.type || 'VALIDATION_ERROR'
75
+ );
76
+ }
77
+
78
+ return result;
79
+
80
+ } catch (error) {
81
+ if (error instanceof LicenseError) {
82
+ throw error;
83
+ }
84
+
85
+ if (error.name === 'TypeError' && error.message.includes('fetch')) {
86
+ throw new LicenseError(
87
+ process.env.NODE_ENV === 'development'
88
+ ? 'Unable to connect to local license validation service. Make sure the development server is running.'
89
+ : 'Unable to connect to license server. Please check your internet connection.',
90
+ 'CONNECTION_ERROR'
91
+ );
92
+ }
93
+
94
+ throw new LicenseError(
95
+ 'An unexpected error occurred during license validation',
96
+ 'VALIDATION_ERROR'
97
+ );
98
+ }
99
+ }
@@ -0,0 +1,415 @@
1
+ // /lib/migrations.js
2
+
3
+ import { readFile } from 'fs/promises';
4
+ import { promisify } from 'util';
5
+ import { exec } from 'child_process';
6
+ import { createHash } from 'crypto';
7
+ import { mkdir, writeFile } from 'fs/promises';
8
+ import path from 'path';
9
+ import {
10
+ executeSQL,
11
+ ErrorTypes,
12
+ formatMigrationContent,
13
+ parseStatement,
14
+ validateStatement,
15
+ Operations,
16
+ tableExists
17
+ } from './sql-operations.js';
18
+ import { analyzeDependencies } from '@/lib/schema-operations';
19
+
20
+ const execAsync = promisify(exec);
21
+
22
+ /**
23
+ * Initializes the migrations table.
24
+ * For remote environments: table with (id, name, applied_at).
25
+ * For local environments: table with (id, name, checksum, applied_at),
26
+ * where checksum is optional.
27
+ *
28
+ * If reset is true (e.g. during a pull operation), the table is cleared.
29
+ *
30
+ * @param {string} projectDir
31
+ * @param {string} databaseName
32
+ * @param {('local'|'remote')} environment
33
+ * @param {boolean} [reset=false] - If true, clear existing records.
34
+ */
35
+ export async function initMigrationsTable(projectDir, databaseName, environment = 'local', reset = false) {
36
+ const flag = environment === 'remote' ? '--remote' : '--local';
37
+ // For remote, keep original D1 schema
38
+ const createTableSQL = environment === 'remote'
39
+ ? `
40
+ CREATE TABLE IF NOT EXISTS d1_migrations (
41
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
42
+ name TEXT NOT NULL UNIQUE,
43
+ applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
44
+ );
45
+ `
46
+ : `
47
+ CREATE TABLE IF NOT EXISTS d1_migrations (
48
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
49
+ name TEXT NOT NULL UNIQUE,
50
+ checksum TEXT NULL,
51
+ applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
52
+ );
53
+ `;
54
+
55
+ try {
56
+ // Create the table if it doesn't exist
57
+ await execAsync(
58
+ `wrangler d1 execute ${databaseName} ${flag} --command="${createTableSQL.replace(/"/g, '\\"')}"`,
59
+ { cwd: projectDir }
60
+ );
61
+
62
+ if (reset) {
63
+ const deleteSQL = `DELETE FROM d1_migrations;`;
64
+ await execAsync(
65
+ `wrangler d1 execute ${databaseName} ${flag} --command="${deleteSQL.replace(/"/g, '\\"')}"`,
66
+ { cwd: projectDir }
67
+ );
68
+ }
69
+ } catch (error) {
70
+ console.error(`Failed to initialize migrations table in ${environment}:`, error);
71
+ throw error;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Generate a migration file name using a stable naming convention.
77
+ * Format: YYYYMMDDHHMMSS_operation_tablename[optional-description].sql
78
+ *
79
+ * @param {Object} stmt - The SQL statement object containing type, tableName and optional description
80
+ * @returns {string} The formatted migration filename
81
+ */
82
+ function getMigrationFileName(stmt) {
83
+ const timestamp = new Date().toISOString().replace(/[^0-9]/g, '').slice(0, -3);
84
+ const operation = stmt.type.toLowerCase().replace(/_/g, '-');
85
+
86
+ // Map for non-index operations.
87
+ const operationMap = {
88
+ 'create-table': 'create-table',
89
+ 'alter-table': 'alter-table',
90
+ 'drop-table': 'drop-table',
91
+ 'drop-index': 'drop-index',
92
+ 'create-view': 'create-view',
93
+ 'drop-view': 'drop-view',
94
+ 'add-foreign-key': 'add-foreign-key',
95
+ 'drop-foreign-key': 'drop-foreign-key',
96
+ 'add-constraint': 'add-constraint',
97
+ 'drop-constraint': 'drop-constraint'
98
+ };
99
+
100
+ if (stmt.type === 'CREATE_INDEX') {
101
+ // For index migrations, simply include the operation and the description.
102
+ const desc = stmt.description.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-_]/g, '');
103
+ return `${timestamp}_create-index_${desc}.sql`;
104
+ } else {
105
+ let fileName = `${timestamp}_${operationMap[operation] || operation}_${stmt.tableName}`;
106
+ // Append description for alter migrations if available.
107
+ if (stmt.type === 'ALTER_TABLE' && stmt.description) {
108
+ fileName += `_${stmt.description}`;
109
+ }
110
+ fileName = fileName.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-_]/g, '');
111
+ return fileName + '.sql';
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Validates a migration file by reading, parsing, and validating its SQL.
117
+ *
118
+ * @param {string} filePath - Full path to the migration file.
119
+ * @returns {object} Object with `isValid` flag and either the parsed statement or errors.
120
+ */
121
+ export async function validateMigrationFile(filePath) {
122
+ const content = await readFile(filePath, 'utf8');
123
+ try {
124
+ const statement = parseStatement(content);
125
+ validateStatement(statement);
126
+ return { isValid: true, statement };
127
+ } catch (error) {
128
+ return { isValid: false, errors: error };
129
+ }
130
+ }
131
+
132
+ // Get remote migrations
133
+ export async function getRemoteMigrations(projectDir, databaseName, env) {
134
+ try {
135
+ const result = await executeSQL(
136
+ projectDir,
137
+ databaseName,
138
+ 'SELECT name, applied_at FROM d1_migrations ORDER BY applied_at;',
139
+ env,
140
+ true
141
+ );
142
+
143
+ if (typeof result === 'string') {
144
+ const jsonStart = result.indexOf('[');
145
+ if (jsonStart !== -1) {
146
+ const jsonStr = result.substring(jsonStart);
147
+ const parsed = JSON.parse(jsonStr);
148
+ return parsed[0]?.results || [];
149
+ }
150
+ }
151
+ return [];
152
+ } catch (error) {
153
+ throw {
154
+ type: ErrorTypes.EXECUTION_ERROR,
155
+ message: 'Failed to get remote migrations',
156
+ details: {
157
+ error: error.message,
158
+ suggestions: [
159
+ 'Check remote database permissions',
160
+ 'Verify credentials and connection'
161
+ ]
162
+ }
163
+ };
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Records (or tracks) a migration.
169
+ * For remote, skips checksum.
170
+ *
171
+ * @param {string} projectDir
172
+ * @param {string} databaseName
173
+ * @param {Object} migrationData { name, checksum }
174
+ * @param {('local'|'remote')} environment
175
+ */
176
+ // Update tracking function to handle both cases
177
+ export async function trackMigration(projectDir, databaseName, { name, checksum }, environment = 'local') {
178
+ const flag = environment === 'remote' ? '--remote' : '--local';
179
+
180
+ // For Studio-originated migrations (with checksum), check if we need to add the column
181
+ if (environment === 'local' && checksum) {
182
+ try {
183
+ // Check if checksum column exists
184
+ const hasChecksumColumn = await execAsync(
185
+ `wrangler d1 execute ${databaseName} ${flag} --command="SELECT checksum FROM d1_migrations LIMIT 1;"`,
186
+ { cwd: projectDir }
187
+ ).catch(() => false);
188
+
189
+ // If column doesn't exist, alter table to add it
190
+ if (!hasChecksumColumn) {
191
+ await execAsync(
192
+ `wrangler d1 execute ${databaseName} ${flag} --command="ALTER TABLE d1_migrations ADD COLUMN checksum TEXT;"`,
193
+ { cwd: projectDir }
194
+ );
195
+ }
196
+ } catch (error) {
197
+ // Ignore errors - the column might already exist
198
+ }
199
+ }
200
+
201
+ // For Studio migrations (with checksum)
202
+ const insertSQL = environment === 'remote' || !checksum
203
+ ? `
204
+ INSERT OR REPLACE INTO d1_migrations (name, applied_at)
205
+ VALUES ('${name}', CURRENT_TIMESTAMP);
206
+ `
207
+ : `
208
+ INSERT OR REPLACE INTO d1_migrations (name, checksum, applied_at)
209
+ VALUES ('${name}', '${checksum}', CURRENT_TIMESTAMP);
210
+ `;
211
+
212
+ try {
213
+ await execAsync(
214
+ `wrangler d1 execute ${databaseName} ${flag} --command="${insertSQL.replace(/"/g, '\\"')}"`,
215
+ { cwd: projectDir }
216
+ );
217
+ } catch (error) {
218
+ console.error('Failed to track migration:', error);
219
+ throw error;
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Records a migration (used during push).
225
+ * For remote, checksum is omitted.
226
+ *
227
+ * @param {string} projectDir
228
+ * @param {string} databaseName
229
+ * @param {Object} migrationData { name, checksum }
230
+ * @param {object} env
231
+ * @param {boolean} remote
232
+ */
233
+ export async function recordMigration(projectDir, databaseName, { name, checksum }, env = {}, remote = false) {
234
+ // For CLI migrations or remote, don't include checksum
235
+ const sql = remote || !checksum
236
+ ? `
237
+ INSERT OR REPLACE INTO d1_migrations (name, applied_at)
238
+ VALUES ('${name}', CURRENT_TIMESTAMP);
239
+ `
240
+ : `
241
+ INSERT OR REPLACE INTO d1_migrations (name, checksum, applied_at)
242
+ VALUES ('${name}', '${checksum}', CURRENT_TIMESTAMP);
243
+ `;
244
+
245
+ try {
246
+ await executeSQL(projectDir, databaseName, sql, env, remote);
247
+ } catch (error) {
248
+ throw {
249
+ type: ErrorTypes.EXECUTION_ERROR,
250
+ message: `Failed to record migration ${name}`,
251
+ details: {
252
+ file: name,
253
+ error: error.message,
254
+ suggestions: ['Check if migration is already recorded']
255
+ }
256
+ };
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Compares local and remote migrations.
262
+ *
263
+ * @param {string} projectDir
264
+ * @param {string} databaseName
265
+ * @returns {Promise<Object>} { applied: Array, count: Number }
266
+ */
267
+ export async function compareMigrations(projectDir, databaseName) {
268
+ try {
269
+ const migrations = await getRemoteMigrations(projectDir, databaseName, {});
270
+ const migrationMap = new Map(migrations.map(m => [m.name, m]));
271
+ return {
272
+ applied: Array.from(migrationMap.keys()),
273
+ count: migrationMap.size
274
+ };
275
+ } catch (error) {
276
+ console.error('Failed to compare migrations:', error);
277
+ throw error;
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Generates a SHA256 checksum for migration content.
283
+ *
284
+ * @param {string} content
285
+ * @returns {string}
286
+ */
287
+ export function createChecksum(content) {
288
+ return createHash('sha256').update(content).digest('hex');
289
+ }
290
+
291
+ /**
292
+ * Processes schema changes (DDL) and creates migration files.
293
+ * Uses a stable naming convention:
294
+ * YYYYMMDDHHMMSS_operation_tablename[optional-description].sql
295
+ *
296
+ * Executes the SQL, writes the migration file, and tracks it.
297
+ * If any part fails, the process aborts (all-or-nothing).
298
+ *
299
+ * This updated version uses analyzeDependencies to order the changes.
300
+ *
301
+ * @param {string} projectDir
302
+ * @param {string} databaseName
303
+ * @param {Array<Object>} statements - Parsed schema change statements.
304
+ * Each statement is expected to have at least a `tableName` (if applicable) and `sql` property.
305
+ * @returns {Promise<Array>} Array of migration records.
306
+ */
307
+ export async function handleSchemaChange(projectDir, databaseName, statements) {
308
+ try {
309
+ const migrationsDir = path.join(projectDir, 'migrations');
310
+ await mkdir(migrationsDir, { recursive: true });
311
+ const results = [];
312
+
313
+ // Partition statements into schema changes and data modifications.
314
+ const schemaChanges = [];
315
+ const dataModifications = [];
316
+ for (const stmt of statements) {
317
+ if (stmt.type === Operations.DATA_MODIFICATION) {
318
+ dataModifications.push(stmt);
319
+ } else {
320
+ schemaChanges.push(stmt);
321
+ }
322
+ }
323
+
324
+ // Group schema change statements by table name.
325
+ const groupedStatements = new Map();
326
+ const NO_TABLE_KEY = '__no_table__';
327
+ for (const stmt of schemaChanges) {
328
+ const key = stmt.tableName ? stmt.tableName.toLowerCase() : NO_TABLE_KEY;
329
+ if (!groupedStatements.has(key)) {
330
+ groupedStatements.set(key, []);
331
+ }
332
+ groupedStatements.get(key).push(stmt);
333
+ }
334
+
335
+ // For those with a table name, get an ordered list using analyzeDependencies.
336
+ const tableKeys = [...groupedStatements.keys()].filter(key => key !== NO_TABLE_KEY);
337
+ let orderedTables = [];
338
+ if (tableKeys.length > 0) {
339
+ const sampleStatements = tableKeys.map(key => groupedStatements.get(key)[0]);
340
+ orderedTables = analyzeDependencies(sampleStatements);
341
+ }
342
+
343
+ // Process schema changes (create migration files).
344
+ for (const tableName of orderedTables) {
345
+ const stmts = groupedStatements.get(tableName) || [];
346
+ for (const stmt of stmts) {
347
+ try {
348
+ // For DROP TABLE statements, check if the table exists.
349
+ if (stmt.type === Operations.DROP_TABLE) {
350
+ const exists = await tableExists(projectDir, databaseName, {}, stmt.tableName, false);
351
+ if (!exists) {
352
+ throw new Error(`no such table: ${stmt.tableName}`);
353
+ }
354
+ }
355
+ // Execute the schema change SQL.
356
+ const result = await executeSQL(projectDir, databaseName, stmt.sql);
357
+ // Check the output for syntax error messages.
358
+ if (
359
+ result &&
360
+ (result.toLowerCase().includes('syntax error') ||
361
+ result.toLowerCase().includes('sqlite_error'))
362
+ ) {
363
+ throw new Error(result);
364
+ }
365
+ // Generate a migration file.
366
+ const migrationFileName = getMigrationFileName(stmt);
367
+ const migrationPath = path.join(migrationsDir, migrationFileName);
368
+ const formattedSQL = formatMigrationContent(stmt.sql);
369
+ await writeFile(migrationPath, formattedSQL, 'utf8');
370
+ // Compute checksum and track the migration.
371
+ const checksum = createChecksum(stmt.sql);
372
+ await trackMigration(projectDir, databaseName, { name: migrationFileName, checksum }, 'local');
373
+ results.push({ type: stmt.type, table: stmt.tableName, migration: migrationFileName, checksum });
374
+ } catch (error) {
375
+ throw error;
376
+ }
377
+ }
378
+ groupedStatements.delete(tableName);
379
+ }
380
+
381
+ // Process any remaining schema changes with no table name.
382
+ if (groupedStatements.has(NO_TABLE_KEY)) {
383
+ for (const stmt of groupedStatements.get(NO_TABLE_KEY)) {
384
+ try {
385
+ await executeSQL(projectDir, databaseName, stmt.sql);
386
+ const migrationFileName = getMigrationFileName(stmt);
387
+ const migrationPath = path.join(migrationsDir, migrationFileName);
388
+ const formattedSQL = formatMigrationContent(stmt.sql);
389
+ await writeFile(migrationPath, formattedSQL, 'utf8');
390
+ const checksum = createChecksum(stmt.sql);
391
+ await trackMigration(projectDir, databaseName, { name: migrationFileName, checksum }, 'local');
392
+ results.push({ type: stmt.type, table: stmt.tableName || null, migration: migrationFileName, checksum });
393
+ } catch (error) {
394
+ throw error;
395
+ }
396
+ }
397
+ }
398
+
399
+ // Now process data modification statements (execute them, but don't create migration files).
400
+ for (const stmt of dataModifications) {
401
+ try {
402
+ await executeSQL(projectDir, databaseName, stmt.sql);
403
+ // Record the success of the data modification execution.
404
+ results.push({ type: stmt.type, table: stmt.tableName || null, executed: true });
405
+ } catch (error) {
406
+ throw error;
407
+ }
408
+ }
409
+
410
+ return results;
411
+ } catch (error) {
412
+ throw error;
413
+ }
414
+ }
415
+