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,72 @@
|
|
|
1
|
+
// api/databases/route.js
|
|
2
|
+
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
try {
|
|
8
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
9
|
+
|
|
10
|
+
if (!projectDir) {
|
|
11
|
+
console.error('D1_PROJECT_DIR environment variable is not set');
|
|
12
|
+
return NextResponse.json(
|
|
13
|
+
{ error: 'Project directory not configured' },
|
|
14
|
+
{ status: 500 }
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log('Looking for Wrangler configuration in:', projectDir);
|
|
19
|
+
|
|
20
|
+
// Use findWranglerConfig helper
|
|
21
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
22
|
+
if (!wranglerResult || !wranglerResult.config) {
|
|
23
|
+
return NextResponse.json(
|
|
24
|
+
{ error: 'No Wrangler configuration file found in project directory' },
|
|
25
|
+
{ status: 404 }
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const config = wranglerResult.config;
|
|
29
|
+
|
|
30
|
+
if (!config.d1_databases?.length) {
|
|
31
|
+
return NextResponse.json(
|
|
32
|
+
{ error: 'No D1 databases configured in Wrangler configuration' },
|
|
33
|
+
{ status: 404 }
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return NextResponse.json({
|
|
38
|
+
databases: config.d1_databases,
|
|
39
|
+
debug: {
|
|
40
|
+
projectDir,
|
|
41
|
+
// Exposing the path from the helper for debugging consistency
|
|
42
|
+
configPath: wranglerResult.configPath || 'N/A',
|
|
43
|
+
databaseCount: config.d1_databases.length
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error('Error reading database configuration:', error);
|
|
48
|
+
|
|
49
|
+
return NextResponse.json(
|
|
50
|
+
{
|
|
51
|
+
error: 'Failed to read database configuration',
|
|
52
|
+
details: error.message,
|
|
53
|
+
debug: {
|
|
54
|
+
errorCode: error.code,
|
|
55
|
+
errorStack: error.stack
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{ status: 500 }
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function OPTIONS() {
|
|
64
|
+
return new NextResponse(null, {
|
|
65
|
+
status: 204,
|
|
66
|
+
headers: {
|
|
67
|
+
'Access-Control-Allow-Origin': '*',
|
|
68
|
+
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
|
69
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// app/api/migrations/sync/route.js
|
|
2
|
+
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
5
|
+
import { readFile } from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import {
|
|
8
|
+
initMigrationsTable,
|
|
9
|
+
compareMigrations,
|
|
10
|
+
trackMigration,
|
|
11
|
+
updateMigrationStatus,
|
|
12
|
+
createChecksum
|
|
13
|
+
} from '@/lib/migrations';
|
|
14
|
+
import { promisify } from 'util';
|
|
15
|
+
import { exec } from 'child_process';
|
|
16
|
+
|
|
17
|
+
const execAsync = promisify(exec);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* POST handler for syncing migrations.
|
|
21
|
+
* Uses the centralized Wrangler configuration helper to determine the D1 database.
|
|
22
|
+
*/
|
|
23
|
+
export async function POST(req) {
|
|
24
|
+
try {
|
|
25
|
+
const { accountId, apiToken } = await req.json();
|
|
26
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
27
|
+
|
|
28
|
+
if (!projectDir) {
|
|
29
|
+
return NextResponse.json(
|
|
30
|
+
{ error: 'Project directory not configured' },
|
|
31
|
+
{ status: 500 }
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Use the helper to load the Wrangler configuration
|
|
36
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
37
|
+
if (!wranglerResult || !wranglerResult.config) {
|
|
38
|
+
return NextResponse.json(
|
|
39
|
+
{ error: 'No Wrangler configuration file found in project directory' },
|
|
40
|
+
{ status: 404 }
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const config = wranglerResult.config;
|
|
44
|
+
if (!config.d1_databases?.length) {
|
|
45
|
+
return NextResponse.json(
|
|
46
|
+
{ error: 'No D1 databases configured' },
|
|
47
|
+
{ status: 404 }
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
const databaseName = config.d1_databases[0].database_name;
|
|
51
|
+
|
|
52
|
+
// Initialize remote first (simpler schema)
|
|
53
|
+
await execAsync(
|
|
54
|
+
`wrangler d1 execute ${databaseName} --remote --command="
|
|
55
|
+
CREATE TABLE IF NOT EXISTS d1_migrations (
|
|
56
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
57
|
+
name TEXT NOT NULL UNIQUE,
|
|
58
|
+
applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
59
|
+
);"`,
|
|
60
|
+
{
|
|
61
|
+
env: {
|
|
62
|
+
...process.env,
|
|
63
|
+
CLOUDFLARE_ACCOUNT_ID: accountId,
|
|
64
|
+
CLOUDFLARE_API_TOKEN: apiToken
|
|
65
|
+
},
|
|
66
|
+
cwd: projectDir
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// For local, explicitly create with nullable checksum
|
|
71
|
+
await execAsync(
|
|
72
|
+
`wrangler d1 execute ${databaseName} --local --command="
|
|
73
|
+
CREATE TABLE IF NOT EXISTS d1_migrations (
|
|
74
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
75
|
+
name TEXT NOT NULL UNIQUE,
|
|
76
|
+
checksum TEXT DEFAULT NULL,
|
|
77
|
+
applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
78
|
+
);"`,
|
|
79
|
+
{ cwd: projectDir }
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Compare migrations between environments
|
|
83
|
+
const comparison = await compareMigrations(projectDir, databaseName);
|
|
84
|
+
|
|
85
|
+
// Handle pending migrations
|
|
86
|
+
const results = {
|
|
87
|
+
applied: [],
|
|
88
|
+
failed: [],
|
|
89
|
+
skipped: []
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
for (const migration of comparison.pending) {
|
|
93
|
+
try {
|
|
94
|
+
// Read migration file content
|
|
95
|
+
const migrationPath = path.join(projectDir, 'migrations', migration.name);
|
|
96
|
+
const migrationContent = await readFile(migrationPath, 'utf8');
|
|
97
|
+
|
|
98
|
+
// Execute migration in remote environment using Wrangler
|
|
99
|
+
const process = await execAsync(
|
|
100
|
+
`wrangler d1 execute ${databaseName} --remote --command='${migrationContent.replace(/'/g, "''")}'`,
|
|
101
|
+
{
|
|
102
|
+
env: {
|
|
103
|
+
...process.env,
|
|
104
|
+
CLOUDFLARE_ACCOUNT_ID: accountId,
|
|
105
|
+
CLOUDFLARE_API_TOKEN: apiToken
|
|
106
|
+
},
|
|
107
|
+
cwd: projectDir
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Track successful migration in the remote environment
|
|
112
|
+
await trackMigration(projectDir, databaseName, {
|
|
113
|
+
name: migration.name,
|
|
114
|
+
environment: 'remote',
|
|
115
|
+
status: 'applied',
|
|
116
|
+
checksum: createChecksum(migrationContent),
|
|
117
|
+
version: migration.version
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
results.applied.push(migration.name);
|
|
121
|
+
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error(`Failed to apply migration ${migration.name}:`, error);
|
|
124
|
+
|
|
125
|
+
// Track failed migration
|
|
126
|
+
await trackMigration(projectDir, databaseName, {
|
|
127
|
+
name: migration.name,
|
|
128
|
+
environment: 'remote',
|
|
129
|
+
status: 'failed',
|
|
130
|
+
checksum: migration.checksum,
|
|
131
|
+
version: migration.version,
|
|
132
|
+
errorMessage: error.message
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
results.failed.push({
|
|
136
|
+
name: migration.name,
|
|
137
|
+
error: error.message
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Handle migration conflicts (e.g., checksum mismatches)
|
|
143
|
+
for (const conflict of comparison.conflicts) {
|
|
144
|
+
results.skipped.push({
|
|
145
|
+
name: conflict.name,
|
|
146
|
+
reason: 'Checksum mismatch between environments'
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return NextResponse.json({
|
|
151
|
+
success: true,
|
|
152
|
+
results: {
|
|
153
|
+
...results,
|
|
154
|
+
synced: comparison.synced
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error('Migration sync error:', error);
|
|
160
|
+
return NextResponse.json({
|
|
161
|
+
success: false,
|
|
162
|
+
error: {
|
|
163
|
+
message: 'Failed to sync migrations',
|
|
164
|
+
details: error.message
|
|
165
|
+
}
|
|
166
|
+
}, { status: 500 });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function OPTIONS() {
|
|
171
|
+
return new NextResponse(null, { status: 204 });
|
|
172
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// app/api/migrations/sync-files/route.js
|
|
2
|
+
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
5
|
+
import { readFile, readdir } from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import { exec } from 'child_process';
|
|
9
|
+
import { createChecksum } from '@/lib/migrations';
|
|
10
|
+
|
|
11
|
+
const execAsync = promisify(exec);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves the list of migrations recorded in the D1 migrations table.
|
|
15
|
+
*/
|
|
16
|
+
async function getDatabaseMigrations(projectDir, databaseName) {
|
|
17
|
+
try {
|
|
18
|
+
const { stdout } = await execAsync(
|
|
19
|
+
`wrangler d1 execute ${databaseName} --local --command="SELECT name, checksum FROM d1_migrations;" --json`,
|
|
20
|
+
{ cwd: projectDir }
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const result = JSON.parse(stdout);
|
|
24
|
+
return result.results?.[0]?.results || [];
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('Error getting database migrations:', error);
|
|
27
|
+
throw new Error('Failed to get database migrations');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Reads migration files from the local migrations directory.
|
|
33
|
+
*/
|
|
34
|
+
async function getMigrationFiles(projectDir) {
|
|
35
|
+
try {
|
|
36
|
+
const migrationsDir = path.join(projectDir, 'migrations');
|
|
37
|
+
const files = await readdir(migrationsDir);
|
|
38
|
+
|
|
39
|
+
const migrations = await Promise.all(
|
|
40
|
+
files
|
|
41
|
+
.filter(f => f.endsWith('.sql'))
|
|
42
|
+
.map(async name => {
|
|
43
|
+
const filePath = path.join(migrationsDir, name);
|
|
44
|
+
const content = await readFile(filePath, 'utf8');
|
|
45
|
+
return {
|
|
46
|
+
name,
|
|
47
|
+
path: filePath,
|
|
48
|
+
content,
|
|
49
|
+
checksum: createChecksum(content)
|
|
50
|
+
};
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return migrations.sort((a, b) => a.name.localeCompare(b.name));
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error.code === 'ENOENT') {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
throw new Error('Failed to read migration files');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Executes a database query via Wrangler.
|
|
65
|
+
*/
|
|
66
|
+
async function executeQuery(projectDir, databaseName, query) {
|
|
67
|
+
try {
|
|
68
|
+
await execAsync(
|
|
69
|
+
`wrangler d1 execute ${databaseName} --local --command="${query.replace(/"/g, '\\"')}"`,
|
|
70
|
+
{ cwd: projectDir }
|
|
71
|
+
);
|
|
72
|
+
return true;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error('Query execution error:', error);
|
|
75
|
+
throw new Error('Failed to execute database query');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* POST handler to sync migration files with the D1 migrations table.
|
|
81
|
+
* Uses the centralized helper to load the Wrangler configuration.
|
|
82
|
+
*/
|
|
83
|
+
export async function POST(req) {
|
|
84
|
+
try {
|
|
85
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
86
|
+
if (!projectDir) {
|
|
87
|
+
return NextResponse.json({ error: 'Project directory not configured' }, { status: 500 });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Use the helper to get the Wrangler configuration
|
|
91
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
92
|
+
if (!wranglerResult || !wranglerResult.config) {
|
|
93
|
+
return NextResponse.json({ error: 'Could not find Wrangler configuration' }, { status: 404 });
|
|
94
|
+
}
|
|
95
|
+
const config = wranglerResult.config;
|
|
96
|
+
if (!config.d1_databases?.length) {
|
|
97
|
+
return NextResponse.json({ error: 'No D1 databases configured' }, { status: 404 });
|
|
98
|
+
}
|
|
99
|
+
// Get the first D1 database name from the configuration
|
|
100
|
+
const databaseName = config.d1_databases[0].database_name;
|
|
101
|
+
|
|
102
|
+
// Get migrations from the database and from the local file system
|
|
103
|
+
const [dbMigrations, fileMigrations] = await Promise.all([
|
|
104
|
+
getDatabaseMigrations(projectDir, databaseName),
|
|
105
|
+
getMigrationFiles(projectDir)
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
const dbMigrationsMap = new Map(dbMigrations.map(m => [m.name, m]));
|
|
109
|
+
const fileMigrationsMap = new Map(fileMigrations.map(m => [m.name, m]));
|
|
110
|
+
|
|
111
|
+
const changes = {
|
|
112
|
+
added: [], // New files to add to d1_migrations
|
|
113
|
+
removed: [], // Records to remove from d1_migrations
|
|
114
|
+
unchanged: [] // Files that match with records
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Identify migrations to remove (record exists in DB but file is missing)
|
|
118
|
+
for (const [name] of dbMigrationsMap) {
|
|
119
|
+
if (!fileMigrationsMap.has(name)) {
|
|
120
|
+
changes.removed.push(name);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Remove records for missing files
|
|
125
|
+
if (changes.removed.length > 0) {
|
|
126
|
+
const names = changes.removed.map(name => `'${name}'`).join(',');
|
|
127
|
+
await executeQuery(
|
|
128
|
+
projectDir,
|
|
129
|
+
databaseName,
|
|
130
|
+
`DELETE FROM d1_migrations WHERE name IN (${names});`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Process each migration file: add new records and mark unchanged
|
|
135
|
+
for (const [name, fileMigration] of fileMigrationsMap) {
|
|
136
|
+
const dbMigration = dbMigrationsMap.get(name);
|
|
137
|
+
|
|
138
|
+
if (!dbMigration) {
|
|
139
|
+
// Add new record for file
|
|
140
|
+
changes.added.push(name);
|
|
141
|
+
await executeQuery(
|
|
142
|
+
projectDir,
|
|
143
|
+
databaseName,
|
|
144
|
+
`INSERT OR REPLACE INTO d1_migrations (name, checksum) VALUES ('${name}', '${fileMigration.checksum}');`
|
|
145
|
+
);
|
|
146
|
+
} else {
|
|
147
|
+
changes.unchanged.push(name);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return NextResponse.json({
|
|
152
|
+
success: true,
|
|
153
|
+
details: {
|
|
154
|
+
added: changes.added,
|
|
155
|
+
removed: changes.removed,
|
|
156
|
+
unchanged: changes.unchanged
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('Migration file sync error:', error);
|
|
162
|
+
return NextResponse.json({
|
|
163
|
+
error: error.message || 'Failed to sync migrations'
|
|
164
|
+
}, {
|
|
165
|
+
status: 500
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function OPTIONS() {
|
|
171
|
+
return new NextResponse(null, { status: 204 });
|
|
172
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// api/pull-remote/confirm/route.js
|
|
2
|
+
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { writeFile, mkdir, readdir, unlink } from 'fs/promises';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
7
|
+
import {
|
|
8
|
+
executeSQL,
|
|
9
|
+
ErrorTypes,
|
|
10
|
+
formatSQLStatement,
|
|
11
|
+
getMigrationFileContent
|
|
12
|
+
} from '@/lib/sql-operations';
|
|
13
|
+
import { getCurrentSchema, analyzeDependencies } from '@/lib/schema-operations';
|
|
14
|
+
import { initMigrationsTable, recordMigration, getRemoteMigrations } from '@/lib/migrations.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Applies the pull migrations by:
|
|
18
|
+
* 1. Fetching remote migration metadata.
|
|
19
|
+
* 2. For each remote migration, fetching the migration file content from remote.
|
|
20
|
+
* 3. Staging the migration files.
|
|
21
|
+
* 4. Performing a destructive update on local objects.
|
|
22
|
+
* 5. Resetting the local migrations table.
|
|
23
|
+
* 6. Applying staged migrations sequentially (writing files, recording and executing them).
|
|
24
|
+
* 7. Replacing the local migrations folder with the staged files.
|
|
25
|
+
*
|
|
26
|
+
* This completely replaces the local state with the remote state.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} projectDir - The project directory.
|
|
29
|
+
* @param {string} accountId - Cloudflare account ID.
|
|
30
|
+
* @param {string} apiToken - Cloudflare API token.
|
|
31
|
+
* @param {string} databaseName - The target D1 database name.
|
|
32
|
+
* @returns {object} Details of applied migrations.
|
|
33
|
+
*/
|
|
34
|
+
async function applyPullMigrations(projectDir, accountId, apiToken, databaseName) {
|
|
35
|
+
const env = {
|
|
36
|
+
...process.env,
|
|
37
|
+
CLOUDFLARE_API_TOKEN: apiToken,
|
|
38
|
+
CLOUDFLARE_ACCOUNT_ID: accountId
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// Define paths for the main migrations folder and a temporary staging folder.
|
|
43
|
+
const migrationsDir = path.join(projectDir, 'migrations');
|
|
44
|
+
const stagingDir = path.join(projectDir, 'migrations-temp');
|
|
45
|
+
|
|
46
|
+
// Ensure both directories exist.
|
|
47
|
+
await mkdir(migrationsDir, { recursive: true });
|
|
48
|
+
await mkdir(stagingDir, { recursive: true });
|
|
49
|
+
|
|
50
|
+
// Clear out any existing files in the staging folder.
|
|
51
|
+
const stagedFilesList = await readdir(stagingDir).catch(() => []);
|
|
52
|
+
await Promise.all(stagedFilesList.map(file => unlink(path.join(stagingDir, file))));
|
|
53
|
+
|
|
54
|
+
// --- STEP 1: Fetch remote migration metadata ---
|
|
55
|
+
console.log('Fetching remote migration metadata...');
|
|
56
|
+
const remoteMigrations = await getRemoteMigrations(projectDir, databaseName, env);
|
|
57
|
+
console.log('Remote migration metadata:', remoteMigrations);
|
|
58
|
+
|
|
59
|
+
// --- STEP 2: For each remote migration, fetch its file content ---
|
|
60
|
+
console.log('Fetching migration file content from remote...');
|
|
61
|
+
const stagedFiles = new Map();
|
|
62
|
+
for (const migration of remoteMigrations) {
|
|
63
|
+
try {
|
|
64
|
+
const migrationFileName = migration.name; // Use the remote migration's name.
|
|
65
|
+
const content = await getMigrationFileContent(projectDir, databaseName, migrationFileName, env);
|
|
66
|
+
stagedFiles.set(migrationFileName, content);
|
|
67
|
+
console.log(`Staged migration file: ${migrationFileName}`);
|
|
68
|
+
await writeFile(path.join(stagingDir, migrationFileName), content, 'utf8');
|
|
69
|
+
} catch (fileError) {
|
|
70
|
+
console.error(`Error fetching content for migration ${migration.name}:`, fileError);
|
|
71
|
+
throw new Error(`Failed to fetch migration file content for ${migration.name}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// --- STEP 3: Fetch local schema for destructive update ---
|
|
76
|
+
console.log('Fetching local schema for destructive update...');
|
|
77
|
+
const currentSchema = await getCurrentSchema(projectDir, databaseName, env, false);
|
|
78
|
+
const tableSchema = currentSchema.filter(obj =>
|
|
79
|
+
obj.type === 'table' && obj.name && obj.name.toLowerCase() !== 'if'
|
|
80
|
+
);
|
|
81
|
+
console.log('Local table schema:', tableSchema);
|
|
82
|
+
const dropOrder = tableSchema.length > 0
|
|
83
|
+
? analyzeDependencies(
|
|
84
|
+
tableSchema.map(obj => ({
|
|
85
|
+
tableName: obj.name,
|
|
86
|
+
sql: obj.sql,
|
|
87
|
+
type: obj.type
|
|
88
|
+
}))
|
|
89
|
+
)
|
|
90
|
+
: [];
|
|
91
|
+
console.log('Computed drop order:', dropOrder);
|
|
92
|
+
|
|
93
|
+
// --- STEP 4: Destructive update (all-or-nothing) ---
|
|
94
|
+
console.log('Beginning destructive update...');
|
|
95
|
+
try {
|
|
96
|
+
console.log('Disabling foreign keys...');
|
|
97
|
+
await executeSQL(projectDir, databaseName, 'PRAGMA foreign_keys=OFF;', env, false);
|
|
98
|
+
|
|
99
|
+
// Drop triggers.
|
|
100
|
+
const triggers = currentSchema.filter(obj => obj.type === 'trigger');
|
|
101
|
+
for (const trigger of triggers) {
|
|
102
|
+
console.log(`Dropping trigger: ${trigger.name}`);
|
|
103
|
+
await executeSQL(
|
|
104
|
+
projectDir,
|
|
105
|
+
databaseName,
|
|
106
|
+
formatSQLStatement(`DROP TRIGGER IF EXISTS ${trigger.name}`),
|
|
107
|
+
env,
|
|
108
|
+
false
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
// Drop indexes.
|
|
112
|
+
const indexes = currentSchema.filter(obj => obj.type === 'index');
|
|
113
|
+
for (const index of indexes) {
|
|
114
|
+
console.log(`Dropping index: ${index.name}`);
|
|
115
|
+
await executeSQL(
|
|
116
|
+
projectDir,
|
|
117
|
+
databaseName,
|
|
118
|
+
formatSQLStatement(`DROP INDEX IF EXISTS ${index.name}`),
|
|
119
|
+
env,
|
|
120
|
+
false
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
// Drop tables in reverse dependency order.
|
|
124
|
+
for (const tableName of dropOrder.reverse()) {
|
|
125
|
+
console.log(`Dropping table: ${tableName}`);
|
|
126
|
+
await executeSQL(
|
|
127
|
+
projectDir,
|
|
128
|
+
databaseName,
|
|
129
|
+
formatSQLStatement(`DROP TABLE IF EXISTS ${tableName}`),
|
|
130
|
+
env,
|
|
131
|
+
false
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
console.log('Re-enabling foreign keys...');
|
|
135
|
+
await executeSQL(projectDir, databaseName, 'PRAGMA foreign_keys=ON;', env, false);
|
|
136
|
+
} catch (dropError) {
|
|
137
|
+
throw new Error(`Error dropping existing objects: ${dropError.message}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// --- STEP 5: Reset the local migrations table ---
|
|
141
|
+
try {
|
|
142
|
+
console.log('Resetting local migrations table...');
|
|
143
|
+
await initMigrationsTable(projectDir, databaseName, 'local', true);
|
|
144
|
+
} catch (initError) {
|
|
145
|
+
throw new Error(`Error resetting migrations table: ${initError.message}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- STEP 6: Apply staged migrations ---
|
|
149
|
+
// (Transactions removed because D1 operates in auto-commit mode)
|
|
150
|
+
const appliedPreview = { preview: [] };
|
|
151
|
+
let currentFilename = '';
|
|
152
|
+
try {
|
|
153
|
+
for (const [filename, content] of stagedFiles.entries()) {
|
|
154
|
+
currentFilename = filename;
|
|
155
|
+
console.log(`Applying migration: ${filename}`);
|
|
156
|
+
// Write the migration file to the main migrations folder.
|
|
157
|
+
await writeFile(path.join(migrationsDir, filename), content, 'utf8');
|
|
158
|
+
|
|
159
|
+
// Compute a checksum from the content.
|
|
160
|
+
const checksum = require('crypto')
|
|
161
|
+
.createHash('sha256')
|
|
162
|
+
.update(content)
|
|
163
|
+
.digest('hex');
|
|
164
|
+
|
|
165
|
+
console.log(`Recording migration: ${filename} with checksum ${checksum}`);
|
|
166
|
+
await recordMigration(
|
|
167
|
+
projectDir,
|
|
168
|
+
databaseName,
|
|
169
|
+
{ name: filename, checksum },
|
|
170
|
+
env,
|
|
171
|
+
false
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Execute the migration SQL on the local database.
|
|
175
|
+
await executeSQL(projectDir, databaseName, content, env, false);
|
|
176
|
+
|
|
177
|
+
appliedPreview.preview.push({ migration: filename, action: 'applied' });
|
|
178
|
+
}
|
|
179
|
+
} catch (applyError) {
|
|
180
|
+
throw new Error(`Error applying migration ${currentFilename}: ${applyError.message}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// --- STEP 7: Replace main migrations folder with staged files ---
|
|
184
|
+
console.log('Replacing main migrations folder with staged files...');
|
|
185
|
+
const mainFiles = await readdir(migrationsDir).catch(() => []);
|
|
186
|
+
if (mainFiles.length) {
|
|
187
|
+
for (const file of mainFiles) {
|
|
188
|
+
console.log(`Deleting local migration file: ${file}`);
|
|
189
|
+
await unlink(path.join(migrationsDir, file));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
for (const [filename, content] of stagedFiles.entries()) {
|
|
193
|
+
console.log(`Copying staged file ${filename} to main migrations folder`);
|
|
194
|
+
await writeFile(path.join(migrationsDir, filename), content, 'utf8');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log('Pull migration applied successfully.');
|
|
198
|
+
return {
|
|
199
|
+
appliedMigrations: Array.from(stagedFiles.keys()),
|
|
200
|
+
details: appliedPreview
|
|
201
|
+
};
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error('Pull migration error:', error);
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* POST handler for pull-remote confirm.
|
|
210
|
+
* Reads the Wrangler configuration (via findWranglerConfig) to obtain the D1 database name,
|
|
211
|
+
* then applies the pull migrations.
|
|
212
|
+
*/
|
|
213
|
+
export async function POST(req) {
|
|
214
|
+
try {
|
|
215
|
+
const { accountId, apiToken } = await req.json();
|
|
216
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
217
|
+
if (!projectDir) {
|
|
218
|
+
return NextResponse.json({
|
|
219
|
+
success: false,
|
|
220
|
+
error: {
|
|
221
|
+
type: ErrorTypes.VALIDATION_ERROR,
|
|
222
|
+
message: 'Project directory not configured'
|
|
223
|
+
}
|
|
224
|
+
}, { status: 500 });
|
|
225
|
+
}
|
|
226
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
227
|
+
if (!wranglerResult || !wranglerResult.config) {
|
|
228
|
+
return NextResponse.json({
|
|
229
|
+
success: false,
|
|
230
|
+
error: {
|
|
231
|
+
type: ErrorTypes.VALIDATION_ERROR,
|
|
232
|
+
message: 'Could not find Wrangler configuration'
|
|
233
|
+
}
|
|
234
|
+
}, { status: 400 });
|
|
235
|
+
}
|
|
236
|
+
const config = wranglerResult.config;
|
|
237
|
+
if (!config.d1_databases?.length) {
|
|
238
|
+
return NextResponse.json({
|
|
239
|
+
success: false,
|
|
240
|
+
error: {
|
|
241
|
+
type: ErrorTypes.VALIDATION_ERROR,
|
|
242
|
+
message: 'No D1 databases configured'
|
|
243
|
+
}
|
|
244
|
+
}, { status: 400 });
|
|
245
|
+
}
|
|
246
|
+
const databaseName = config.d1_databases[0].database_name;
|
|
247
|
+
const result = await applyPullMigrations(projectDir, accountId, apiToken, databaseName);
|
|
248
|
+
return NextResponse.json({
|
|
249
|
+
success: true,
|
|
250
|
+
message: 'Pull migrations applied successfully',
|
|
251
|
+
details: result
|
|
252
|
+
});
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.error('Pull remote confirm error:', error);
|
|
255
|
+
return NextResponse.json({
|
|
256
|
+
success: false,
|
|
257
|
+
error: {
|
|
258
|
+
type: error.type || ErrorTypes.EXECUTION_ERROR,
|
|
259
|
+
message: error.message || 'Failed to apply pull migrations',
|
|
260
|
+
details: error.details || {
|
|
261
|
+
suggestions: [
|
|
262
|
+
'Check your Cloudflare credentials',
|
|
263
|
+
'Verify database permissions',
|
|
264
|
+
'Ensure all migration files are accessible'
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}, { status: 500 });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* OPTIONS handler for pre-flight requests.
|
|
274
|
+
*/
|
|
275
|
+
export async function OPTIONS() {
|
|
276
|
+
return new NextResponse(null, { status: 204 });
|
|
277
|
+
}
|