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.
- package/README.md +7 -0
- package/dist/.next/.next/BUILD_ID +1 -0
- package/dist/.next/.next/app-build-manifest.json +109 -0
- package/dist/.next/.next/app-path-routes-manifest.json +1 -0
- package/dist/.next/.next/build-manifest.json +33 -0
- package/dist/.next/.next/cache/.rscinfo +1 -0
- package/dist/.next/.next/cache/.tsbuildinfo +1 -0
- package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/dist/.next/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/dist/.next/.next/diagnostics/build-diagnostics.json +6 -0
- package/dist/.next/.next/diagnostics/framework.json +1 -0
- package/dist/.next/.next/export-marker.json +1 -0
- package/dist/.next/.next/images-manifest.json +1 -0
- package/dist/.next/.next/next-minimal-server.js.nft.json +1 -0
- package/dist/.next/.next/next-server.js.nft.json +1 -0
- package/dist/.next/.next/package.json +1 -0
- package/dist/.next/.next/prerender-manifest.json +1 -0
- package/dist/.next/.next/react-loadable-manifest.json +1 -0
- package/dist/.next/.next/required-server-files.json +1 -0
- package/dist/.next/.next/routes-manifest.json +1 -0
- package/dist/.next/.next/server/app/_not-found/page.js +1 -0
- package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/_not-found.html +1 -0
- package/dist/.next/.next/server/app/_not-found.meta +8 -0
- package/dist/.next/.next/server/app/_not-found.rsc +16 -0
- package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -0
- package/dist/.next/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/databases/route.js +1 -0
- package/dist/.next/.next/server/app/api/databases/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync/route.js +12 -0
- package/dist/.next/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +14 -0
- package/dist/.next/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/push-remote/preview/route.js +14 -0
- package/dist/.next/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/query/route.js +8 -0
- package/dist/.next/.next/server/app/api/query/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -0
- package/dist/.next/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/tables/route.js +7 -0
- package/dist/.next/.next/server/app/api/tables/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/index.html +3 -0
- package/dist/.next/.next/server/app/index.meta +7 -0
- package/dist/.next/.next/server/app/index.rsc +20 -0
- package/dist/.next/.next/server/app/page.js +58 -0
- package/dist/.next/.next/server/app/page.js.nft.json +1 -0
- package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app-paths-manifest.json +15 -0
- package/dist/.next/.next/server/chunks/336.js +1 -0
- package/dist/.next/.next/server/chunks/627.js +6 -0
- package/dist/.next/.next/server/chunks/638.js +13 -0
- package/dist/.next/.next/server/chunks/801.js +55 -0
- package/dist/.next/.next/server/chunks/973.js +2 -0
- package/dist/.next/.next/server/chunks/992.js +3 -0
- package/dist/.next/.next/server/functions-config-manifest.json +1 -0
- package/dist/.next/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/dist/.next/.next/server/middleware-build-manifest.js +1 -0
- package/dist/.next/.next/server/middleware-manifest.json +6 -0
- package/dist/.next/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/.next/.next/server/next-font-manifest.js +1 -0
- package/dist/.next/.next/server/next-font-manifest.json +1 -0
- package/dist/.next/.next/server/pages/404.html +1 -0
- package/dist/.next/.next/server/pages/500.html +1 -0
- package/dist/.next/.next/server/pages/_app.js +1 -0
- package/dist/.next/.next/server/pages/_app.js.nft.json +1 -0
- package/dist/.next/.next/server/pages/_document.js +1 -0
- package/dist/.next/.next/server/pages/_document.js.nft.json +1 -0
- package/dist/.next/.next/server/pages/_error.js +1 -0
- package/dist/.next/.next/server/pages/_error.js.nft.json +1 -0
- package/dist/.next/.next/server/pages-manifest.json +1 -0
- package/dist/.next/.next/server/server-reference-manifest.js +1 -0
- package/dist/.next/.next/server/server-reference-manifest.json +1 -0
- package/dist/.next/.next/server/webpack-runtime.js +1 -0
- package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_buildManifest.js +1 -0
- package/dist/.next/.next/static/ODMSSwVqLoDcBgbFHUjr8/_ssgManifest.js +1 -0
- package/dist/.next/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
- package/dist/.next/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
- package/dist/.next/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
- package/dist/.next/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
- package/dist/.next/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
- package/dist/.next/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
- package/dist/.next/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
- package/dist/.next/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
- package/dist/.next/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
- package/dist/.next/.next/static/chunks/framework-d29117d969504448.js +1 -0
- package/dist/.next/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
- package/dist/.next/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
- package/dist/.next/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
- package/dist/.next/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
- package/dist/.next/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/.next/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
- package/dist/.next/.next/static/css/c51a7ef325e30c16.css +3 -0
- package/dist/.next/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/dist/.next/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/.next/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/.next/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/dist/.next/.next/trace +3 -0
- package/dist/.next/.next/types/app/api/cloudflare/route.ts +347 -0
- package/dist/.next/.next/types/app/api/databases/route.ts +347 -0
- package/dist/.next/.next/types/app/api/migrations/sync/route.ts +347 -0
- package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +347 -0
- package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
- package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +347 -0
- package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +347 -0
- package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +347 -0
- package/dist/.next/.next/types/app/api/query/route.ts +347 -0
- package/dist/.next/.next/types/app/api/tables/[name]/route.ts +347 -0
- package/dist/.next/.next/types/app/api/tables/route.ts +347 -0
- package/dist/.next/.next/types/app/page.ts +84 -0
- package/dist/.next/.next/types/cache-life.d.ts +141 -0
- package/dist/.next/.next/types/package.json +1 -0
- package/dist/.next/BUILD_ID +1 -0
- package/dist/.next/app-build-manifest.json +109 -0
- package/dist/.next/app-path-routes-manifest.json +1 -0
- package/dist/.next/build-manifest.json +33 -0
- package/dist/.next/cache/.rscinfo +1 -0
- package/dist/.next/cache/.tsbuildinfo +1 -0
- package/dist/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/.next/diagnostics/build-diagnostics.json +6 -0
- package/dist/.next/diagnostics/framework.json +1 -0
- package/dist/.next/export-marker.json +1 -0
- package/dist/.next/images-manifest.json +1 -0
- package/dist/.next/next-minimal-server.js.nft.json +1 -0
- package/dist/.next/next-server.js.nft.json +1 -0
- package/dist/.next/package.json +1 -0
- package/dist/.next/prerender-manifest.json +1 -0
- package/dist/.next/react-loadable-manifest.json +1 -0
- package/dist/.next/required-server-files.json +1 -0
- package/dist/.next/routes-manifest.json +1 -0
- package/dist/.next/server/app/_not-found/page.js +1 -0
- package/dist/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/_not-found.html +1 -0
- package/dist/.next/server/app/_not-found.meta +8 -0
- package/dist/.next/server/app/_not-found.rsc +16 -0
- package/dist/.next/server/app/api/cloudflare/route.js +1 -0
- package/dist/.next/server/app/api/cloudflare/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/databases/route.js +1 -0
- package/dist/.next/server/app/api/databases/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/migrations/sync/route.js +12 -0
- package/dist/.next/server/app/api/migrations/sync/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/migrations/sync-files/route.js +1 -0
- package/dist/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/pull-remote/confirm/route.js +1 -0
- package/dist/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/pull-remote/preview/route.js +1 -0
- package/dist/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/push-remote/confirm/route.js +14 -0
- package/dist/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/push-remote/preview/route.js +14 -0
- package/dist/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/query/route.js +8 -0
- package/dist/.next/server/app/api/query/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/tables/[name]/route.js +5 -0
- package/dist/.next/server/app/api/tables/[name]/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/tables/route.js +7 -0
- package/dist/.next/server/app/api/tables/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/index.html +3 -0
- package/dist/.next/server/app/index.meta +7 -0
- package/dist/.next/server/app/index.rsc +20 -0
- package/dist/.next/server/app/page.js +58 -0
- package/dist/.next/server/app/page.js.nft.json +1 -0
- package/dist/.next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/.next/server/app-paths-manifest.json +15 -0
- package/dist/.next/server/chunks/336.js +1 -0
- package/dist/.next/server/chunks/627.js +6 -0
- package/dist/.next/server/chunks/638.js +13 -0
- package/dist/.next/server/chunks/801.js +55 -0
- package/dist/.next/server/chunks/973.js +2 -0
- package/dist/.next/server/chunks/992.js +3 -0
- package/dist/.next/server/functions-config-manifest.json +1 -0
- package/dist/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/dist/.next/server/middleware-build-manifest.js +1 -0
- package/dist/.next/server/middleware-manifest.json +6 -0
- package/dist/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/.next/server/next-font-manifest.js +1 -0
- package/dist/.next/server/next-font-manifest.json +1 -0
- package/dist/.next/server/pages/404.html +1 -0
- package/dist/.next/server/pages/500.html +1 -0
- package/dist/.next/server/pages/_app.js +1 -0
- package/dist/.next/server/pages/_app.js.nft.json +1 -0
- package/dist/.next/server/pages/_document.js +1 -0
- package/dist/.next/server/pages/_document.js.nft.json +1 -0
- package/dist/.next/server/pages/_error.js +1 -0
- package/dist/.next/server/pages/_error.js.nft.json +1 -0
- package/dist/.next/server/pages-manifest.json +1 -0
- package/dist/.next/server/server-reference-manifest.js +1 -0
- package/dist/.next/server/server-reference-manifest.json +1 -0
- package/dist/.next/server/webpack-runtime.js +1 -0
- package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_buildManifest.js +1 -0
- package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_ssgManifest.js +1 -0
- package/dist/.next/static/chunks/422-6fa3c14fc64ad67b.js +1 -0
- package/dist/.next/static/chunks/4bd1b696-8c908eb707f85a27.js +1 -0
- package/dist/.next/static/chunks/517-3b698a5d3da06ff7.js +2 -0
- package/dist/.next/static/chunks/692-ede418e1d28a1394.js +1 -0
- package/dist/.next/static/chunks/735-c9144179c6bd7d06.js +1 -0
- package/dist/.next/static/chunks/92-c4466e0f1ca8a3a8.js +1 -0
- package/dist/.next/static/chunks/app/_not-found/page-b786c3dd79ad15a5.js +1 -0
- package/dist/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +1 -0
- package/dist/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +1 -0
- package/dist/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +1 -0
- package/dist/.next/static/chunks/app/layout-8360fab69b848283.js +1 -0
- package/dist/.next/static/chunks/app/page-75081ac7a88cb706.js +1 -0
- package/dist/.next/static/chunks/framework-d29117d969504448.js +1 -0
- package/dist/.next/static/chunks/main-8d0ab17774ffa031.js +1 -0
- package/dist/.next/static/chunks/main-app-d36cdfb402b40f13.js +1 -0
- package/dist/.next/static/chunks/pages/_app-d23763e3e6c904ff.js +1 -0
- package/dist/.next/static/chunks/pages/_error-9b7125ad1a1e68fa.js +1 -0
- package/dist/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/.next/static/chunks/webpack-c76ac1e586b2802a.js +1 -0
- package/dist/.next/static/css/c51a7ef325e30c16.css +3 -0
- package/dist/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/dist/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/dist/.next/trace +13 -0
- package/dist/.next/types/app/api/cloudflare/route.ts +347 -0
- package/dist/.next/types/app/api/databases/route.ts +347 -0
- package/dist/.next/types/app/api/migrations/sync/route.ts +347 -0
- package/dist/.next/types/app/api/migrations/sync-files/route.ts +347 -0
- package/dist/.next/types/app/api/pull-remote/confirm/route.ts +347 -0
- package/dist/.next/types/app/api/pull-remote/preview/route.ts +347 -0
- package/dist/.next/types/app/api/push-remote/confirm/route.ts +347 -0
- package/dist/.next/types/app/api/push-remote/preview/route.ts +347 -0
- package/dist/.next/types/app/api/query/route.ts +347 -0
- package/dist/.next/types/app/api/tables/[name]/route.ts +347 -0
- package/dist/.next/types/app/api/tables/route.ts +347 -0
- package/dist/.next/types/app/page.ts +84 -0
- package/dist/.next/types/cache-life.d.ts +141 -0
- package/dist/.next/types/package.json +1 -0
- package/dist/app/api/cloudflare/route.js +146 -0
- package/dist/app/api/databases/route.js +72 -0
- package/dist/app/api/migrations/sync/route.js +172 -0
- package/dist/app/api/migrations/sync-files/route.js +172 -0
- package/dist/app/api/pull-remote/confirm/route.js +277 -0
- package/dist/app/api/pull-remote/preview/route.js +143 -0
- package/dist/app/api/push-remote/confirm/route.js +196 -0
- package/dist/app/api/push-remote/preview/route.js +178 -0
- package/dist/app/api/query/route.js +160 -0
- package/dist/app/api/tables/[name]/route.js +173 -0
- package/dist/app/api/tables/route.js +174 -0
- package/dist/app/app/api/cloudflare/route.js +146 -0
- package/dist/app/app/api/databases/route.js +72 -0
- package/dist/app/app/api/migrations/sync/route.js +172 -0
- package/dist/app/app/api/migrations/sync-files/route.js +172 -0
- package/dist/app/app/api/pull-remote/confirm/route.js +277 -0
- package/dist/app/app/api/pull-remote/preview/route.js +143 -0
- package/dist/app/app/api/push-remote/confirm/route.js +196 -0
- package/dist/app/app/api/push-remote/preview/route.js +178 -0
- package/dist/app/app/api/query/route.js +160 -0
- package/dist/app/app/api/tables/[name]/route.js +173 -0
- package/dist/app/app/api/tables/route.js +174 -0
- package/dist/app/app/globals.css +93 -0
- package/dist/app/app/layout.jsx +35 -0
- package/dist/app/app/page.jsx +37 -0
- package/dist/app/globals.css +93 -0
- package/dist/app/layout.jsx +35 -0
- package/dist/app/page.jsx +37 -0
- package/dist/d1-studio.js +344 -0
- package/dist/lib/database-queue.js +33 -0
- package/dist/lib/error.js +20 -0
- package/dist/lib/find-wrangler-config.js +67 -0
- package/dist/lib/license.js +99 -0
- package/dist/lib/migrations.js +415 -0
- package/dist/lib/parse-sql-error.js +200 -0
- package/dist/lib/request-deduplication.js +24 -0
- package/dist/lib/schema-operations.js +103 -0
- package/dist/lib/sql-error-types.js +14 -0
- package/dist/lib/sql-operations.js +557 -0
- package/dist/lib/utils.js +6 -0
- package/next.config.mjs +18 -0
- package/package.json +97 -0
- package/postcss.config.mjs +8 -0
- package/scripts/studio.js +344 -0
- package/scripts/test.js +168 -0
- package/src/app/api/cloudflare/route.js +146 -0
- package/src/app/api/databases/route.js +72 -0
- package/src/app/api/migrations/sync/route.js +172 -0
- package/src/app/api/migrations/sync-files/route.js +172 -0
- package/src/app/api/pull-remote/confirm/route.js +277 -0
- package/src/app/api/pull-remote/preview/route.js +143 -0
- package/src/app/api/push-remote/confirm/route.js +196 -0
- package/src/app/api/push-remote/preview/route.js +178 -0
- package/src/app/api/query/route.js +160 -0
- package/src/app/api/tables/[name]/route.js +173 -0
- package/src/app/api/tables/route.js +174 -0
- package/src/app/globals.css +93 -0
- package/src/app/layout.jsx +35 -0
- package/src/app/page.jsx +37 -0
- package/src/components/cloudflare-credentials-modal.jsx +94 -0
- package/src/components/column-selector.jsx +133 -0
- package/src/components/column-sorting.jsx +65 -0
- package/src/components/delete-records-dialog.jsx +64 -0
- package/src/components/download-button.jsx +205 -0
- package/src/components/edit-error-alert.jsx +30 -0
- package/src/components/editable-cell.jsx +163 -0
- package/src/components/editable-row.jsx +169 -0
- package/src/components/environment-handler.jsx +278 -0
- package/src/components/environment-select.jsx +59 -0
- package/src/components/pull-preview-toast.jsx +188 -0
- package/src/components/push-error-alert.jsx +72 -0
- package/src/components/push-preview-toast.jsx +183 -0
- package/src/components/query-results.jsx +112 -0
- package/src/components/refresh-button.jsx +61 -0
- package/src/components/resize-columns.jsx +101 -0
- package/src/components/sidebar.jsx +236 -0
- package/src/components/sql-editor.jsx +411 -0
- package/src/components/sql-error-display.jsx +167 -0
- package/src/components/sync-migrations-button.jsx +87 -0
- package/src/components/table-error-dialog.jsx +65 -0
- package/src/components/table-toolbar.jsx +285 -0
- package/src/components/table-view.jsx +843 -0
- package/src/components/ui/alert.jsx +47 -0
- package/src/components/ui/button.jsx +48 -0
- package/src/components/ui/card.jsx +50 -0
- package/src/components/ui/checkbox.jsx +24 -0
- package/src/components/ui/collapsible.jsx +11 -0
- package/src/components/ui/dialog.jsx +96 -0
- package/src/components/ui/dropdown-menu.jsx +158 -0
- package/src/components/ui/input.jsx +19 -0
- package/src/components/ui/scroll-area.jsx +40 -0
- package/src/components/ui/select.jsx +121 -0
- package/src/components/ui/separator.jsx +25 -0
- package/src/components/ui/sheet.jsx +109 -0
- package/src/components/ui/sidebar.jsx +620 -0
- package/src/components/ui/skeleton.jsx +14 -0
- package/src/components/ui/table.jsx +86 -0
- package/src/components/ui/tabs.jsx +43 -0
- package/src/components/ui/toast.jsx +86 -0
- package/src/components/ui/toaster.jsx +35 -0
- package/src/components/ui/tooltip.jsx +28 -0
- package/src/context/database-context.js +510 -0
- package/src/hooks/use-mobile.jsx +19 -0
- package/src/hooks/use-sql-error.ts +23 -0
- package/src/hooks/use-toast.js +155 -0
- package/src/lib/database-queue.js +33 -0
- package/src/lib/error.js +20 -0
- package/src/lib/find-wrangler-config.js +67 -0
- package/src/lib/license.js +99 -0
- package/src/lib/migrations.js +415 -0
- package/src/lib/parse-sql-error.js +200 -0
- package/src/lib/request-deduplication.js +24 -0
- package/src/lib/schema-operations.js +103 -0
- package/src/lib/sql-error-types.js +14 -0
- package/src/lib/sql-operations.js +557 -0
- package/src/lib/utils.js +6 -0
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
// sql-operations.js
|
|
2
|
+
|
|
3
|
+
import { promisify } from 'util';
|
|
4
|
+
import { exec } from 'child_process';
|
|
5
|
+
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
|
|
8
|
+
// ---------------------------------------------------------------------
|
|
9
|
+
// Operation & Error Types (for schema changes and SQL execution)
|
|
10
|
+
// ---------------------------------------------------------------------
|
|
11
|
+
export const Operations = {
|
|
12
|
+
CREATE_TABLE: 'CREATE_TABLE',
|
|
13
|
+
ALTER_TABLE: 'ALTER_TABLE',
|
|
14
|
+
DROP_TABLE: 'DROP_TABLE',
|
|
15
|
+
CREATE_INDEX: 'CREATE_INDEX',
|
|
16
|
+
DROP_INDEX: 'DROP_INDEX',
|
|
17
|
+
DATA_MODIFICATION: 'DATA_MODIFICATION'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const ErrorTypes = {
|
|
21
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
22
|
+
SYNTAX_ERROR: 'SYNTAX_ERROR',
|
|
23
|
+
EXECUTION_ERROR: 'EXECUTION_ERROR',
|
|
24
|
+
DEPENDENCY_ERROR: 'DEPENDENCY_ERROR'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------
|
|
28
|
+
// SQL Parsing and Validation
|
|
29
|
+
// ---------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
export function isSchemaChange(statement) {
|
|
32
|
+
return statement.type !== Operations.DATA_MODIFICATION;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Enhanced parseStatement:
|
|
37
|
+
* Detects the type of SQL statement and, for ALTER TABLE, captures rename details.
|
|
38
|
+
*/
|
|
39
|
+
export function parseStatement(sql) {
|
|
40
|
+
const cleanSql = sql.trim().replace(/\s+/g, ' ');
|
|
41
|
+
const upperSql = cleanSql.toUpperCase();
|
|
42
|
+
|
|
43
|
+
if (upperSql.startsWith('CREATE TABLE')) {
|
|
44
|
+
// Optionally, you might want to capture column definitions here
|
|
45
|
+
return {
|
|
46
|
+
type: Operations.CREATE_TABLE,
|
|
47
|
+
tableName: extractTableName(cleanSql, 'CREATE TABLE'),
|
|
48
|
+
sql: cleanSql,
|
|
49
|
+
description: 'create-table'
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (upperSql.startsWith('ALTER TABLE')) {
|
|
54
|
+
const tableName = extractTableName(cleanSql, 'ALTER TABLE');
|
|
55
|
+
let description = '';
|
|
56
|
+
|
|
57
|
+
// Check for RENAME COLUMN operations first.
|
|
58
|
+
if (upperSql.includes('RENAME')) {
|
|
59
|
+
const renameMatch = cleanSql.match(/RENAME\s+(?:COLUMN\s+)?([\w$]+)\s+TO\s+([\w$]+)/i);
|
|
60
|
+
if (renameMatch) {
|
|
61
|
+
description = `rename-${renameMatch[1]}-to-${renameMatch[2]}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Check for ADD COLUMN operations.
|
|
65
|
+
else if (upperSql.includes('ADD COLUMN')) {
|
|
66
|
+
const addMatch = cleanSql.match(/ADD\s+COLUMN\s+([\w$]+)(\s+[\w()]+)?/i);
|
|
67
|
+
if (addMatch) {
|
|
68
|
+
// Capture column name and optionally the data type
|
|
69
|
+
const column = addMatch[1];
|
|
70
|
+
const dataType = addMatch[2] ? addMatch[2].trim().replace(/\s+/g, '-') : '';
|
|
71
|
+
description = dataType ? `add-${column}-${dataType}` : `add-${column}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Check for DROP COLUMN operations.
|
|
75
|
+
else if (upperSql.includes('DROP COLUMN')) {
|
|
76
|
+
const dropMatch = cleanSql.match(/DROP\s+COLUMN\s+([\w$]+)/i);
|
|
77
|
+
if (dropMatch) {
|
|
78
|
+
description = `drop-${dropMatch[1]}`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Check for MODIFY COLUMN or CHANGE COLUMN operations.
|
|
82
|
+
else if (upperSql.includes('MODIFY COLUMN') || upperSql.includes('CHANGE COLUMN')) {
|
|
83
|
+
const modifyMatch = cleanSql.match(/(?:MODIFY|CHANGE)\s+COLUMN\s+([\w$]+)(\s+[\w()]+)?/i);
|
|
84
|
+
if (modifyMatch) {
|
|
85
|
+
const column = modifyMatch[1];
|
|
86
|
+
const newDefinition = modifyMatch[2] ? modifyMatch[2].trim().replace(/\s+/g, '-') : '';
|
|
87
|
+
description = newDefinition ? `modify-${column}-to-${newDefinition}` : `modify-${column}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
type: Operations.ALTER_TABLE,
|
|
93
|
+
tableName,
|
|
94
|
+
sql: cleanSql,
|
|
95
|
+
description // will be an empty string if none of the above matches
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (upperSql.startsWith('DROP TABLE')) {
|
|
100
|
+
return {
|
|
101
|
+
type: Operations.DROP_TABLE,
|
|
102
|
+
tableName: extractTableName(cleanSql, 'DROP TABLE'),
|
|
103
|
+
sql: cleanSql,
|
|
104
|
+
description: 'drop-table'
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (upperSql.startsWith('CREATE INDEX') || upperSql.startsWith('CREATE UNIQUE INDEX')) {
|
|
109
|
+
// Extract table name via the existing helper (if needed elsewhere)
|
|
110
|
+
const tableName = extractTableNameFromIndex(cleanSql);
|
|
111
|
+
// Extract the index name.
|
|
112
|
+
const indexMatch = cleanSql.match(/INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?([\w$]+)/i);
|
|
113
|
+
const indexName = indexMatch ? indexMatch[1] : '';
|
|
114
|
+
// Extract the columns from the ON clause.
|
|
115
|
+
const onMatch = cleanSql.match(/ON\s+[\w$]+\s*\(([^)]+)\)/i);
|
|
116
|
+
const columns = onMatch ? onMatch[1].trim() : '';
|
|
117
|
+
// Remove spaces and replace commas with hyphens.
|
|
118
|
+
const formattedColumns = columns.replace(/\s+/g, '').replace(/,/g, '-').toLowerCase();
|
|
119
|
+
|
|
120
|
+
// Build a description that uses the index name,
|
|
121
|
+
// and appends the columns if they are not already included.
|
|
122
|
+
let description = indexName;
|
|
123
|
+
if (formattedColumns && !description.toLowerCase().includes(formattedColumns)) {
|
|
124
|
+
description += `-${formattedColumns}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
type: Operations.CREATE_INDEX,
|
|
129
|
+
tableName,
|
|
130
|
+
sql: cleanSql,
|
|
131
|
+
description // e.g. "idx_movies_name" or "idx_movies_name-name"
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (upperSql.startsWith('DROP INDEX')) {
|
|
136
|
+
const tableName = extractTableNameFromIndex(cleanSql);
|
|
137
|
+
const indexMatch = cleanSql.match(/DROP\s+INDEX\s+(?:IF\s+EXISTS\s+)?([\w$]+)/i);
|
|
138
|
+
const indexName = indexMatch ? indexMatch[1] : '';
|
|
139
|
+
return {
|
|
140
|
+
type: Operations.DROP_INDEX,
|
|
141
|
+
tableName,
|
|
142
|
+
sql: cleanSql,
|
|
143
|
+
description: indexName ? `drop-index-${indexName}` : 'drop-index'
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Default case: treat as data modification.
|
|
148
|
+
return {
|
|
149
|
+
type: Operations.DATA_MODIFICATION,
|
|
150
|
+
sql: cleanSql,
|
|
151
|
+
description: 'data-modification'
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function validateStatement(statement) {
|
|
156
|
+
if (statement.type !== Operations.DATA_MODIFICATION && !statement.tableName) {
|
|
157
|
+
throw {
|
|
158
|
+
type: ErrorTypes.VALIDATION_ERROR,
|
|
159
|
+
message: `Invalid SQL statement: unable to determine table name for "${statement.type}".`,
|
|
160
|
+
details: { sql: statement.sql }
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return statement;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Helpers for extracting table names.
|
|
167
|
+
export function extractTableName(sql, prefix) {
|
|
168
|
+
const match = sql.match(new RegExp(`${prefix}\\s+(?:IF\\s+(?:NOT\\s+)?EXISTS\\s+)?([\\w_]+)`, 'i'));
|
|
169
|
+
return match ? match[1] : null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function extractTableNameFromIndex(sql) {
|
|
173
|
+
const match = sql.match(/ON\s+([\w_]+)/i);
|
|
174
|
+
return match ? match[1] : null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Improved helper to extract table name from migration filename.
|
|
179
|
+
* Handles patterns such as:
|
|
180
|
+
* - 0001_create-users-table.sql => table name: users
|
|
181
|
+
* - 0002_alter-orders-table.sql => table name: orders
|
|
182
|
+
* - 0003_create-index_orders.sql => table name: orders (for indexes)
|
|
183
|
+
*/
|
|
184
|
+
export async function extractTableNameFromMigration(filename) {
|
|
185
|
+
// Pattern 1: Matches filenames like "20250218072608_create-table_new_table.sql"
|
|
186
|
+
const createRegex1 = /^\d+_create[-_]table[_-](.+)\.sql$/i;
|
|
187
|
+
// Pattern 2: Matches filenames like "0001_create-books-table.sql"
|
|
188
|
+
const createRegex2 = /^\d+_create[-](.+)-table\.sql$/i;
|
|
189
|
+
|
|
190
|
+
// For alter migrations:
|
|
191
|
+
// Pattern 1: e.g., "20250218072608_alter-table_new_table_add-column_notes.sql"
|
|
192
|
+
const alterRegex1 = /^\d+_alter[-_]table[_-](.+?)(?:[_-].+)?\.sql$/i;
|
|
193
|
+
// Pattern 2: In case a similar alternate format exists.
|
|
194
|
+
const alterRegex2 = /^\d+_alter[-](.+?)-table(?:[_-].+)?\.sql$/i;
|
|
195
|
+
|
|
196
|
+
// Index migrations:
|
|
197
|
+
const indexRegex = /^\d+_create[-_]index[-_](.+)\.sql$/i;
|
|
198
|
+
|
|
199
|
+
let match = filename.match(createRegex1);
|
|
200
|
+
if (match) return match[1];
|
|
201
|
+
|
|
202
|
+
match = filename.match(createRegex2);
|
|
203
|
+
if (match) return match[1];
|
|
204
|
+
|
|
205
|
+
match = filename.match(alterRegex1);
|
|
206
|
+
if (match) return match[1];
|
|
207
|
+
|
|
208
|
+
match = filename.match(alterRegex2);
|
|
209
|
+
if (match) return match[1];
|
|
210
|
+
|
|
211
|
+
match = filename.match(indexRegex);
|
|
212
|
+
if (match) return match[1];
|
|
213
|
+
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function removeSQLComments(sql) {
|
|
218
|
+
return sql
|
|
219
|
+
.split('\n')
|
|
220
|
+
.filter(line => !line.trim().startsWith('--'))
|
|
221
|
+
.join('\n')
|
|
222
|
+
.trim();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Checks if a table already exists in the given database.
|
|
227
|
+
*
|
|
228
|
+
* @param {string} projectDir - The project directory.
|
|
229
|
+
* @param {string} databaseName - The D1 database name.
|
|
230
|
+
* @param {object} env - Environment variables.
|
|
231
|
+
* @param {string} tableName - The table name to check.
|
|
232
|
+
* @param {boolean} [remote=false] - Whether to check the remote database.
|
|
233
|
+
* @returns {Promise<boolean>} True if the table exists; otherwise, false.
|
|
234
|
+
*/
|
|
235
|
+
export async function tableExists(projectDir, databaseName, env, tableName, remote = false) {
|
|
236
|
+
// Query the sqlite_master table for the given table name.
|
|
237
|
+
const query = `SELECT name FROM sqlite_master WHERE type='table' AND name = '${tableName}' COLLATE NOCASE;`;
|
|
238
|
+
|
|
239
|
+
const result = await executeSQL(projectDir, databaseName, query, env, remote);
|
|
240
|
+
try {
|
|
241
|
+
const jsonStart = result.indexOf('[');
|
|
242
|
+
if (jsonStart !== -1) {
|
|
243
|
+
const jsonStr = result.substring(jsonStart);
|
|
244
|
+
const parsed = JSON.parse(jsonStr);
|
|
245
|
+
const results = parsed[0]?.results || [];
|
|
246
|
+
return results.length > 0;
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
} catch (e) {
|
|
250
|
+
console.error("Error parsing tableExists result:", e);
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Parse a full SQL query (multiple statements) into an array of parsed statement objects.
|
|
256
|
+
export function parseQuery(query) {
|
|
257
|
+
const noComments = query
|
|
258
|
+
.replace(/--.*$/gm, '')
|
|
259
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
260
|
+
.trim();
|
|
261
|
+
return noComments
|
|
262
|
+
.split(';')
|
|
263
|
+
.map(stmt => stmt.trim())
|
|
264
|
+
.filter(stmt => stmt.length > 0)
|
|
265
|
+
.map(stmt => parseStatement(stmt + ';'));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ---------------------------------------------------------------------
|
|
269
|
+
// SQL Execution
|
|
270
|
+
// ---------------------------------------------------------------------
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Executes a SQL command via Wrangler.
|
|
274
|
+
* Supports both local and remote execution.
|
|
275
|
+
*/
|
|
276
|
+
export async function executeSQL(projectDir, databaseName, sql, env = {}, remote = false) {
|
|
277
|
+
try {
|
|
278
|
+
// Use let so we can modify the SQL if needed.
|
|
279
|
+
let cleanSQL = sql.trim().replace(/\s+/g, ' ');
|
|
280
|
+
const upperSQL = cleanSQL.toUpperCase();
|
|
281
|
+
|
|
282
|
+
// If it's an index creation and doesn't already have IF NOT EXISTS, add it.
|
|
283
|
+
if ((upperSQL.startsWith("CREATE INDEX") || upperSQL.startsWith("CREATE UNIQUE INDEX")) &&
|
|
284
|
+
!upperSQL.includes("IF NOT EXISTS")) {
|
|
285
|
+
if (upperSQL.startsWith("CREATE UNIQUE INDEX")) {
|
|
286
|
+
cleanSQL = cleanSQL.replace(/CREATE\s+UNIQUE\s+INDEX/i, "CREATE UNIQUE INDEX IF NOT EXISTS");
|
|
287
|
+
} else {
|
|
288
|
+
cleanSQL = cleanSQL.replace(/CREATE\s+INDEX/i, "CREATE INDEX IF NOT EXISTS");
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const isWindows = process.platform === 'win32';
|
|
293
|
+
const npxCommand = isWindows ? 'npx.cmd' : 'npx';
|
|
294
|
+
const executionFlag = remote ? '--remote' : '--local';
|
|
295
|
+
const command = `${npxCommand} wrangler d1 execute ${databaseName} ${executionFlag} --command="${cleanSQL.replace(/"/g, '\\"')}"`;
|
|
296
|
+
const execOptions = {
|
|
297
|
+
cwd: projectDir,
|
|
298
|
+
env: { ...process.env, ...env },
|
|
299
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
300
|
+
shell: true
|
|
301
|
+
};
|
|
302
|
+
console.log('Executing command:', command);
|
|
303
|
+
const { stdout, stderr } = await execAsync(command, execOptions);
|
|
304
|
+
if (stderr && !stderr.includes('🌀')) {
|
|
305
|
+
throw new Error(stderr);
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
const jsonStart = stdout.indexOf('[');
|
|
309
|
+
if (jsonStart !== -1) {
|
|
310
|
+
return stdout.substring(jsonStart);
|
|
311
|
+
}
|
|
312
|
+
} catch (parseError) {
|
|
313
|
+
console.warn('JSON parse warning:', parseError);
|
|
314
|
+
}
|
|
315
|
+
return stdout;
|
|
316
|
+
} catch (error) {
|
|
317
|
+
console.error('SQL Execution error:', error);
|
|
318
|
+
// Instead of creating a new error object, preserve the original error details
|
|
319
|
+
throw {
|
|
320
|
+
type: ErrorTypes.EXECUTION_ERROR,
|
|
321
|
+
message: 'Failed to execute SQL command',
|
|
322
|
+
details: {
|
|
323
|
+
command: error.cmd,
|
|
324
|
+
stderr: error.stderr,
|
|
325
|
+
stdout: error.stdout,
|
|
326
|
+
originalError: error.message,
|
|
327
|
+
suggestions: [
|
|
328
|
+
'Ensure Node.js and Wrangler are installed',
|
|
329
|
+
'Check npx in PATH',
|
|
330
|
+
'Verify the D1 database exists and is configured',
|
|
331
|
+
'Check wrangler.toml configuration'
|
|
332
|
+
]
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// ---------------------------------------------------------------------
|
|
339
|
+
// SQL Formatting and Helper Functions
|
|
340
|
+
// ---------------------------------------------------------------------
|
|
341
|
+
|
|
342
|
+
export function formatSQLStatement(sql) {
|
|
343
|
+
const cleanSql = sql.trim();
|
|
344
|
+
const upperSql = cleanSql.toUpperCase();
|
|
345
|
+
if (upperSql.startsWith('CREATE TABLE')) return formatCreateTable(cleanSql);
|
|
346
|
+
if (upperSql.startsWith('CREATE INDEX') || upperSql.startsWith('CREATE UNIQUE INDEX'))
|
|
347
|
+
return formatCreateIndex(cleanSql);
|
|
348
|
+
if (upperSql.startsWith('ALTER TABLE')) return formatAlterTable(cleanSql);
|
|
349
|
+
if (upperSql.startsWith('DROP TABLE') || upperSql.startsWith('DROP INDEX'))
|
|
350
|
+
return formatDropStatement(cleanSql);
|
|
351
|
+
if (upperSql.startsWith('INSERT INTO')) return formatInsert(cleanSql);
|
|
352
|
+
if (upperSql.startsWith('UPDATE')) return formatUpdate(cleanSql);
|
|
353
|
+
if (upperSql.startsWith('DELETE FROM')) return formatDelete(cleanSql);
|
|
354
|
+
if (upperSql.startsWith('SELECT')) return formatSelect(cleanSql);
|
|
355
|
+
return cleanSql + ';';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function formatCreateTable(sql) {
|
|
359
|
+
const match = sql.match(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)\s*\(([\s\S]*)\)/i);
|
|
360
|
+
if (!match) return sql;
|
|
361
|
+
const [ , tableName, columnDefs ] = match;
|
|
362
|
+
const parts = splitSQLParts(columnDefs);
|
|
363
|
+
const definitions = parts.map(part => part.trim()).filter(Boolean);
|
|
364
|
+
return `CREATE TABLE ${tableName} (\n ${definitions.join(',\n ')}\n);`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function formatDropStatement(sql) {
|
|
368
|
+
const match = sql.match(/DROP\s+(TABLE|INDEX)\s+(?:IF\s+EXISTS\s+)?(\w+)/i);
|
|
369
|
+
if (!match) return sql;
|
|
370
|
+
const [ , type, name ] = match;
|
|
371
|
+
return `DROP ${type} IF EXISTS ${name};`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function formatCreateIndex(sql) {
|
|
375
|
+
const match = sql.match(/CREATE\s+(UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)\s+ON\s+(\w+)\s*\((.*)\)/i);
|
|
376
|
+
if (!match) return sql;
|
|
377
|
+
const [ , unique, indexName, tableName, columns ] = match;
|
|
378
|
+
const formattedColumns = columns.split(',').map(col => col.trim()).join(', ');
|
|
379
|
+
return `CREATE ${unique || ''}INDEX ${indexName} ON ${tableName} (${formattedColumns});`;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export function formatAlterTable(sql) {
|
|
383
|
+
const match = sql.match(/ALTER\s+TABLE\s+(\w+)\s+(.*)/i);
|
|
384
|
+
if (!match) return sql;
|
|
385
|
+
const [ , tableName, alterations ] = match;
|
|
386
|
+
const parts = splitSQLParts(alterations);
|
|
387
|
+
if (parts.length === 1) return `ALTER TABLE ${tableName} ${parts[0]};`;
|
|
388
|
+
return `ALTER TABLE ${tableName}\n${parts.map((part, i) => ` ${part}${i < parts.length - 1 ? ',' : ';'}`).join('\n')}`;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function formatInsert(sql) {
|
|
392
|
+
const match = sql.match(/INSERT\s+INTO\s+(\w+)\s*(\([^)]+\))?\s*VALUES\s*(.+)/i);
|
|
393
|
+
if (!match) return sql;
|
|
394
|
+
const [ , table, columns, values ] = match;
|
|
395
|
+
const valueSets = splitSQLParts(values);
|
|
396
|
+
let formatted = `INSERT INTO ${table}${columns ? ` ${columns}` : ''}\nVALUES\n`;
|
|
397
|
+
formatted += valueSets.map((set, i) => ` ${set}${i < valueSets.length - 1 ? ',' : ';'}`).join('\n');
|
|
398
|
+
return formatted;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function formatUpdate(sql) {
|
|
402
|
+
const match = sql.match(/UPDATE\s+(\w+)\s+SET\s+(.+?)(?:\s+WHERE\s+(.+))?$/i);
|
|
403
|
+
if (!match) return sql;
|
|
404
|
+
const [ , table, sets, where ] = match;
|
|
405
|
+
const setClauses = splitSQLParts(sets);
|
|
406
|
+
let formatted = `UPDATE ${table}\nSET\n${setClauses.map(clause => ` ${clause.trim()}`).join(',\n')}`;
|
|
407
|
+
if (where) formatted += `\nWHERE\n ${where.trim()}`;
|
|
408
|
+
return formatted + ';';
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export function formatDelete(sql) {
|
|
412
|
+
const match = sql.match(/DELETE\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+))?$/i);
|
|
413
|
+
if (!match) return sql;
|
|
414
|
+
const [ , table, where ] = match;
|
|
415
|
+
let formatted = `DELETE FROM ${table}`;
|
|
416
|
+
if (where) formatted += `\nWHERE\n ${where.trim()}`;
|
|
417
|
+
return formatted + ';';
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export function formatSelect(sql) {
|
|
421
|
+
const parts = sql.match(/SELECT\s+(.+?)\s+FROM\s+(.+?)(?:\s+WHERE\s+(.+?))?(?:\s+GROUP\s+BY\s+(.+?))?(?:\s+HAVING\s+(.+?))?(?:\s+ORDER\s+BY\s+(.+?))?(?:\s+LIMIT\s+(.+?))?$/i);
|
|
422
|
+
if (!parts) return sql;
|
|
423
|
+
const [ , columns, tables, where, groupBy, having, orderBy, limit ] = parts;
|
|
424
|
+
let formatted = `SELECT\n ${columns.split(',').map(c => c.trim()).join(',\n ')}\nFROM\n ${tables.trim()}`;
|
|
425
|
+
if (where) formatted += `\nWHERE\n ${where.trim()}`;
|
|
426
|
+
if (groupBy) formatted += `\nGROUP BY\n ${groupBy.trim()}`;
|
|
427
|
+
if (having) formatted += `\nHAVING\n ${having.trim()}`;
|
|
428
|
+
if (orderBy) formatted += `\nORDER BY\n ${orderBy.trim()}`;
|
|
429
|
+
if (limit) formatted += `\nLIMIT ${limit.trim()}`;
|
|
430
|
+
return formatted + ';';
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export function splitSQLParts(sql) {
|
|
434
|
+
const parts = [];
|
|
435
|
+
let currentPart = '';
|
|
436
|
+
let parenCount = 0;
|
|
437
|
+
let inQuote = false;
|
|
438
|
+
let prevChar = '';
|
|
439
|
+
for (let char of sql) {
|
|
440
|
+
if (char === '"' && prevChar !== '\\') inQuote = !inQuote;
|
|
441
|
+
if (!inQuote) {
|
|
442
|
+
if (char === '(') parenCount++;
|
|
443
|
+
if (char === ')') parenCount--;
|
|
444
|
+
}
|
|
445
|
+
if (char === ',' && parenCount === 0 && !inQuote) {
|
|
446
|
+
parts.push(currentPart.trim());
|
|
447
|
+
currentPart = '';
|
|
448
|
+
} else {
|
|
449
|
+
currentPart += char;
|
|
450
|
+
}
|
|
451
|
+
prevChar = char;
|
|
452
|
+
}
|
|
453
|
+
if (currentPart.trim()) parts.push(currentPart.trim());
|
|
454
|
+
return parts;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Formats a full migration content by splitting statements and formatting each.
|
|
459
|
+
*/
|
|
460
|
+
export function formatMigrationContent(sql) {
|
|
461
|
+
const statements = sql.split(';').map(stmt => stmt.trim()).filter(stmt => stmt.length > 0);
|
|
462
|
+
return statements.map(stmt => formatSQLStatement(stmt)).join('\n\n') + '\n';
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Fetches the SQL content of a migration file from remote.
|
|
467
|
+
* This version does not use an extra dummy SELECT.
|
|
468
|
+
* It issues a harmless valid SQL statement (SELECT '' AS content;)
|
|
469
|
+
* alongside the migration directive, so that Wrangler executes the command.
|
|
470
|
+
*
|
|
471
|
+
* @param {string} projectDir - The project directory.
|
|
472
|
+
* @param {string} databaseName - The D1 database name.
|
|
473
|
+
* @param {string} filename - The migration filename.
|
|
474
|
+
* @param {object} env - Environment variables.
|
|
475
|
+
* @returns {Promise<string>} The migration file content.
|
|
476
|
+
*/
|
|
477
|
+
|
|
478
|
+
export async function getMigrationFileContent(projectDir, databaseName, migrationFile, env) {
|
|
479
|
+
try {
|
|
480
|
+
// Extract table name using improved helper
|
|
481
|
+
const tableName = await extractTableNameFromMigration(migrationFile);
|
|
482
|
+
let sql;
|
|
483
|
+
|
|
484
|
+
if (tableName) {
|
|
485
|
+
// Try getting SQL from sqlite_master for table
|
|
486
|
+
const result = await executeSQL(
|
|
487
|
+
projectDir,
|
|
488
|
+
databaseName,
|
|
489
|
+
`SELECT sql FROM sqlite_master WHERE type='table' AND name='${tableName}';`,
|
|
490
|
+
env,
|
|
491
|
+
true
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
try {
|
|
495
|
+
const parsed = JSON.parse(result);
|
|
496
|
+
sql = parsed[0]?.results?.[0]?.sql;
|
|
497
|
+
} catch (e) {
|
|
498
|
+
console.error('Error parsing sqlite_master result:', e);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// If we couldn't get the SQL from table, try index
|
|
503
|
+
if (!sql && migrationFile.includes('create-index')) {
|
|
504
|
+
const indexMatch = migrationFile.match(/create-index[-_]([^_.]+)/);
|
|
505
|
+
if (indexMatch) {
|
|
506
|
+
const result = await executeSQL(
|
|
507
|
+
projectDir,
|
|
508
|
+
databaseName,
|
|
509
|
+
`SELECT sql FROM sqlite_master WHERE type='index' AND name='${indexMatch[1]}';`,
|
|
510
|
+
env,
|
|
511
|
+
true
|
|
512
|
+
);
|
|
513
|
+
const parsed = JSON.parse(result);
|
|
514
|
+
sql = parsed[0]?.results?.[0]?.sql;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// If still no SQL, try fetching any object matching the name pattern
|
|
519
|
+
if (!sql && tableName) {
|
|
520
|
+
const result = await executeSQL(
|
|
521
|
+
projectDir,
|
|
522
|
+
databaseName,
|
|
523
|
+
`SELECT sql FROM sqlite_master WHERE name LIKE '%${tableName}%' LIMIT 1;`,
|
|
524
|
+
env,
|
|
525
|
+
true
|
|
526
|
+
);
|
|
527
|
+
try {
|
|
528
|
+
const parsed = JSON.parse(result);
|
|
529
|
+
sql = parsed[0]?.results?.[0]?.sql;
|
|
530
|
+
} catch (e) {
|
|
531
|
+
console.error('Error parsing fallback result:', e);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (!sql) {
|
|
536
|
+
throw new Error(`Could not retrieve SQL content for migration: ${migrationFile}`);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Format and return the SQL
|
|
540
|
+
return sql + ';';
|
|
541
|
+
|
|
542
|
+
} catch (error) {
|
|
543
|
+
throw {
|
|
544
|
+
type: ErrorTypes.EXECUTION_ERROR,
|
|
545
|
+
message: `Failed to get migration file content: ${error.message}`,
|
|
546
|
+
details: {
|
|
547
|
+
file: migrationFile,
|
|
548
|
+
error: error.message,
|
|
549
|
+
suggestions: [
|
|
550
|
+
'Check if the table exists in the remote database',
|
|
551
|
+
'Verify the migration filename follows the expected pattern',
|
|
552
|
+
'Ensure you have permissions to access the remote database'
|
|
553
|
+
]
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
}
|