d1s 0.2.8 → 0.2.10
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/dist/.next/.next/BUILD_ID +1 -1
- package/dist/.next/.next/app-build-manifest.json +49 -42
- package/dist/.next/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/.next/build-manifest.json +3 -3
- package/dist/.next/.next/cache/.rscinfo +1 -1
- package/dist/.next/.next/cache/.tsbuildinfo +1 -1
- 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/3.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/4.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/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/2.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/next-minimal-server.js.nft.json +1 -1
- package/dist/.next/.next/next-server.js.nft.json +1 -1
- package/dist/.next/.next/prerender-manifest.json +1 -1
- package/dist/.next/.next/required-server-files.json +1 -1
- package/dist/.next/.next/server/app/_not-found/page.js +1 -1
- package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/_not-found.html +1 -1
- package/dist/.next/.next/server/app/_not-found.rsc +4 -4
- package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
- package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/databases/route.js +1 -1
- package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/migrations/sync/route.js +28 -3
- package/dist/.next/.next/server/app/api/migrations/sync/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +26 -1
- package/dist/.next/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -0
- package/dist/.next/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +26 -1
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +26 -1
- package/dist/.next/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +28 -3
- package/dist/.next/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/push-remote/preview/route.js +28 -3
- package/dist/.next/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/query/route.js +27 -2
- package/dist/.next/.next/server/app/api/query/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/tables/[name]/route.js +4 -4
- package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/tables/route.js +2 -2
- package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/update/route.js +1 -5
- package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/index.html +3 -3
- package/dist/.next/.next/server/app/index.rsc +5 -5
- package/dist/.next/.next/server/app/page.js +10 -10
- package/dist/.next/.next/server/app/page.js.nft.json +1 -1
- package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app-paths-manifest.json +5 -4
- package/dist/.next/.next/server/chunks/226.js +30 -0
- package/dist/.next/.next/server/chunks/90.js +1 -0
- package/dist/.next/.next/server/chunks/992.js +1 -1
- package/dist/.next/.next/server/middleware-build-manifest.js +1 -1
- package/dist/.next/.next/server/next-font-manifest.js +1 -1
- package/dist/.next/.next/server/next-font-manifest.json +1 -1
- package/dist/.next/.next/server/pages/404.html +1 -1
- package/dist/.next/.next/server/pages/500.html +1 -1
- package/dist/.next/.next/server/pages-manifest.json +1 -1
- package/dist/.next/.next/server/server-reference-manifest.json +1 -1
- package/dist/.next/.next/static/5dBGGUmK5q7of4h5Rahrg/_buildManifest.js +1 -0
- package/dist/.next/.next/static/PflNFnmFsNegSqhzjI6lA/_buildManifest.js +1 -0
- package/dist/.next/.next/static/chunks/{958-98887928efebfdf7.js → 700-dc8f9f08b166c5e6.js} +1 -1
- package/dist/.next/.next/static/chunks/{735-c9144179c6bd7d06.js → 735-b885dfec6353171d.js} +1 -1
- package/dist/.next/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +1 -0
- package/dist/.next/.next/static/chunks/app/layout-be6ee67cf0c92654.js +1 -0
- package/dist/.next/.next/static/chunks/app/page-16ec561fc8bebb5d.js +1 -0
- package/dist/.next/.next/static/chunks/{main-app-d36cdfb402b40f13.js → main-app-fa35024de9bd9284.js} +1 -1
- package/dist/.next/.next/static/css/0c512cea5f3d317a.css +3 -0
- package/dist/.next/.next/static/p8875OZM4iDNsPzmoyLe7/_buildManifest.js +1 -0
- package/dist/.next/.next/trace +3 -3
- package/dist/.next/.next/types/app/api/cloudflare/route.ts +1 -1
- package/dist/.next/.next/types/app/api/databases/route.ts +1 -1
- package/dist/.next/.next/types/app/api/migrations/sync/route.ts +1 -1
- package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +1 -1
- package/dist/.next/.next/types/app/api/pull-data/confirm/route.ts +347 -0
- package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
- package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +1 -1
- package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +1 -1
- package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +1 -1
- package/dist/.next/.next/types/app/api/query/route.ts +1 -1
- package/dist/.next/.next/types/app/api/tables/[name]/route.ts +1 -1
- package/dist/.next/.next/types/app/api/tables/route.ts +1 -1
- package/dist/.next/.next/types/app/api/update/route.ts +1 -1
- package/dist/.next/.next/types/app/page.ts +1 -1
- package/dist/.next/BUILD_ID +1 -1
- package/dist/.next/app-build-manifest.json +53 -39
- package/dist/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/build-manifest.json +3 -3
- package/dist/.next/cache/.rscinfo +1 -1
- package/dist/.next/cache/.tsbuildinfo +1 -1
- 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/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/next-minimal-server.js.nft.json +1 -1
- package/dist/.next/next-server.js.nft.json +1 -1
- package/dist/.next/prerender-manifest.json +1 -1
- package/dist/.next/required-server-files.json +1 -1
- package/dist/.next/server/app/_not-found/page.js +1 -1
- package/dist/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/_not-found.html +1 -1
- package/dist/.next/server/app/_not-found.rsc +4 -4
- package/dist/.next/server/app/api/cloudflare/route.js +1 -1
- package/dist/.next/server/app/api/cloudflare/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/databases/route.js +1 -1
- package/dist/.next/server/app/api/databases/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/migrations/sync/route.js +28 -3
- package/dist/.next/server/app/api/migrations/sync/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/migrations/sync-files/route.js +26 -1
- package/dist/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -0
- package/dist/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/pull-remote/confirm/route.js +26 -1
- package/dist/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/pull-remote/preview/route.js +26 -1
- package/dist/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/push-remote/confirm/route.js +28 -3
- package/dist/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/push-remote/preview/route.js +28 -3
- package/dist/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/query/route.js +27 -2
- package/dist/.next/server/app/api/query/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/tables/[name]/route.js +3 -3
- package/dist/.next/server/app/api/tables/[name]/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/tables/route.js +2 -2
- package/dist/.next/server/app/api/tables/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/update/route.js +1 -0
- package/dist/.next/server/app/api/update/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/index.html +3 -3
- package/dist/.next/server/app/index.rsc +5 -5
- package/dist/.next/server/app/page.js +13 -11
- package/dist/.next/server/app/page.js.nft.json +1 -1
- package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app-paths-manifest.json +6 -4
- package/dist/.next/server/chunks/226.js +30 -0
- package/dist/.next/server/chunks/391.js +23 -0
- package/dist/.next/server/chunks/452.js +1 -0
- package/dist/.next/server/chunks/627.js +3 -3
- package/dist/.next/server/chunks/638.js +3 -3
- package/dist/.next/server/chunks/90.js +1 -0
- package/dist/.next/server/chunks/992.js +3 -3
- package/dist/.next/server/middleware-build-manifest.js +1 -1
- package/dist/.next/server/next-font-manifest.js +1 -1
- package/dist/.next/server/next-font-manifest.json +1 -1
- package/dist/.next/server/pages/404.html +1 -1
- package/dist/.next/server/pages/500.html +1 -1
- package/dist/.next/server/pages/_app.js +1 -1
- package/dist/.next/server/pages/_document.js +1 -1
- package/dist/.next/server/pages/_error.js +1 -1
- package/dist/.next/server/server-reference-manifest.json +1 -1
- package/dist/.next/static/chunks/700-dc8f9f08b166c5e6.js +1 -0
- package/dist/.next/static/chunks/{735-c9144179c6bd7d06.js → 735-b885dfec6353171d.js} +1 -1
- package/dist/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +1 -0
- package/dist/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +1 -0
- package/dist/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +1 -0
- package/dist/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +1 -0
- package/dist/.next/static/chunks/app/layout-be6ee67cf0c92654.js +1 -0
- package/dist/.next/static/chunks/app/page-16ec561fc8bebb5d.js +1 -0
- package/dist/.next/static/chunks/{main-app-d36cdfb402b40f13.js → main-app-fa35024de9bd9284.js} +1 -1
- package/dist/.next/static/css/0c512cea5f3d317a.css +3 -0
- package/dist/.next/static 2/5dBGGUmK5q7of4h5Rahrg/_buildManifest.js +1 -0
- package/dist/.next/trace +16 -14
- package/dist/.next/types/app/api/cloudflare/route.ts +1 -1
- package/dist/.next/types/app/api/databases/route.ts +1 -1
- package/dist/.next/types/app/api/migrations/sync/route.ts +1 -1
- package/dist/.next/types/app/api/migrations/sync-files/route.ts +1 -1
- package/dist/.next/types/app/api/pull-data/confirm/route.ts +347 -0
- package/dist/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
- package/dist/.next/types/app/api/pull-remote/preview/route.ts +1 -1
- package/dist/.next/types/app/api/push-remote/confirm/route.ts +1 -1
- package/dist/.next/types/app/api/push-remote/preview/route.ts +1 -1
- package/dist/.next/types/app/api/query/route.ts +1 -1
- package/dist/.next/types/app/api/tables/[name]/route.ts +1 -1
- package/dist/.next/types/app/api/tables/route.ts +1 -1
- package/dist/.next/types/app/api/update/route.ts +347 -0
- package/dist/.next/types/app/page.ts +1 -1
- package/dist/app/api/pull-data/confirm/route.js +230 -0
- package/dist/app/api/update/route.js +45 -0
- package/dist/app/app/api/pull-data/confirm/route.js +230 -0
- package/dist/app/app/api/update/route.js +40 -6
- package/dist/app/app/page.jsx +21 -17
- package/dist/app/page.jsx +24 -14
- package/dist/d1-studio.js +8 -195
- package/dist/lib/logger.js +35 -5
- package/dist/lib/sql-operations.js +107 -24
- package/dist/lib/version-utils.js +34 -0
- package/package.json +2 -2
- package/scripts/studio.js +8 -195
- package/src/app/api/pull-data/confirm/route.js +230 -0
- package/src/app/api/update/route.js +40 -6
- package/src/app/page.jsx +21 -17
- package/src/components/environment-handler.jsx +70 -16
- package/src/components/environment-select.jsx +6 -3
- package/src/components/pull-preview-toast.jsx +90 -63
- package/src/components/sidebar.jsx +27 -25
- package/src/components/update-banner.jsx +70 -41
- package/src/context/database-context.js +4 -4
- package/src/lib/logger.js +35 -5
- package/src/lib/sql-operations.js +107 -24
- package/src/lib/version-utils.js +34 -0
- package/dist/.next/.next/cache/webpack/client-development/0.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/client-development/1.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/client-development/2.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/client-development/3.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/client-development/4.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/client-development/index.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/client-development/index.pack.gz.old +0 -0
- package/dist/.next/.next/cache/webpack/client-production/10.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/11.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/12.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/13.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/14.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/5.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/6.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/7.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/8.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/9.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-development/0.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/server-development/1.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/server-development/2.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/server-development/3.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/server-development/4.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/server-development/index.pack.gz +0 -0
- package/dist/.next/.next/cache/webpack/server-development/index.pack.gz.old +0 -0
- package/dist/.next/.next/cache/webpack/server-production/10.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/11.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/12.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/13.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/3.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/4.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/5.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/6.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/7.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/8.pack +0 -0
- package/dist/.next/.next/cache/webpack/server-production/9.pack +0 -0
- package/dist/.next/.next/server/chunks/336.js +0 -1
- package/dist/.next/.next/server/chunks/686.js +0 -23
- package/dist/.next/.next/server/chunks/801.js +0 -55
- package/dist/.next/.next/static/IWRJZhjf8U8mjzz4h0VNE/_buildManifest.js +0 -1
- package/dist/.next/.next/static/JrwgdSDcipr0Zh7k19Cj_/_buildManifest.js +0 -1
- package/dist/.next/.next/static/chunks/422-6fa3c14fc64ad67b.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/cloudflare/route-5133155a604f2719.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/databases/route-63a31080b565794e.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-d97667565b4a59b6.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-7089bcbfeb6b5260.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-9143e6e4c3f05162.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-c963d143a51aed66.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-072132c0a6cb3df3.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-ca6bf35aa72661ee.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/query/route-1466f6b7ffd8b6c0.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-898d3f85fc8544c4.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/tables/route-91650359fc3735cb.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/update/route-504d663df9124f97.js +0 -1
- package/dist/.next/.next/static/chunks/app/layout-8360fab69b848283.js +0 -1
- package/dist/.next/.next/static/chunks/app/page-2c28a255a4ecd8d4.js +0 -1
- package/dist/.next/.next/static/chunks/app/page-3db7feef57019055.js +0 -1
- package/dist/.next/.next/static/chunks/app/page-79049bfa6cc07e11.js +0 -1
- package/dist/.next/.next/static/css/4957328384ed5c42.css +0 -3
- package/dist/.next/.next/static/css/cf41da7a0d47f779.css +0 -3
- package/dist/.next/.next/static/gc8l1G6KXOeLLOM7VJip6/_buildManifest.js +0 -1
- package/dist/.next/.next/static/kYsJoni86CJWDuTkc1xU6/_buildManifest.js +0 -1
- package/dist/.next/.next/static/scC5qwQC9H7rR1groM0Q-/_buildManifest.js +0 -1
- package/dist/.next/.next/static/scC5qwQC9H7rR1groM0Q-/_ssgManifest.js +0 -1
- package/dist/.next/.next/static/tEHOI_-t-iqfJClNzuo9m/_buildManifest.js +0 -1
- package/dist/.next/.next/static/tEHOI_-t-iqfJClNzuo9m/_ssgManifest.js +0 -1
- package/dist/.next/.next/static/vin2VQs5pM_dH2e2_I7AN/_buildManifest.js +0 -1
- package/dist/.next/.next/static/vin2VQs5pM_dH2e2_I7AN/_ssgManifest.js +0 -1
- package/dist/.next/.next/static/wHKwQhaxin5_i06GFVDHb/_buildManifest.js +0 -1
- package/dist/.next/.next/static/wHKwQhaxin5_i06GFVDHb/_ssgManifest.js +0 -1
- package/dist/.next/.next/static/xW4MspD8XibrhXDi_q2IO/_buildManifest.js +0 -1
- package/dist/.next/.next/static/xW4MspD8XibrhXDi_q2IO/_ssgManifest.js +0 -1
- package/dist/.next/server/chunks/336.js +0 -1
- package/dist/.next/server/chunks/686.js +0 -23
- package/dist/.next/server/chunks/801.js +0 -55
- package/dist/.next/static/ZwNOdZJ0LOtE0AJMNWwzY/_buildManifest.js +0 -1
- package/dist/.next/static/ZwNOdZJ0LOtE0AJMNWwzY/_ssgManifest.js +0 -1
- package/dist/.next/static/chunks/422-6fa3c14fc64ad67b.js +0 -1
- package/dist/.next/static/chunks/app/api/cloudflare/route-3458d78022185d7f.js +0 -1
- package/dist/.next/static/chunks/app/api/databases/route-64255424877a9f72.js +0 -1
- package/dist/.next/static/chunks/app/api/migrations/sync/route-03766b3afcf043ba.js +0 -1
- package/dist/.next/static/chunks/app/api/migrations/sync-files/route-02fa291c8000dadf.js +0 -1
- package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-7e05bb8920127abe.js +0 -1
- package/dist/.next/static/chunks/app/api/pull-remote/preview/route-0fa15f783e8a306c.js +0 -1
- package/dist/.next/static/chunks/app/api/push-remote/confirm/route-96691f1880e4ed14.js +0 -1
- package/dist/.next/static/chunks/app/api/push-remote/preview/route-a798679c67374552.js +0 -1
- package/dist/.next/static/chunks/app/api/query/route-e90d0030a5083e20.js +0 -1
- package/dist/.next/static/chunks/app/api/tables/[name]/route-1efe63e73b480e58.js +0 -1
- package/dist/.next/static/chunks/app/api/tables/route-3772b4f480c4b4a4.js +0 -1
- package/dist/.next/static/chunks/app/layout-8360fab69b848283.js +0 -1
- package/dist/.next/static/chunks/app/page-79049bfa6cc07e11.js +0 -1
- package/dist/.next/static/css/cf41da7a0d47f779.css +0 -3
- /package/dist/.next/.next/static/{IWRJZhjf8U8mjzz4h0VNE → 5dBGGUmK5q7of4h5Rahrg}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{JrwgdSDcipr0Zh7k19Cj_ → PflNFnmFsNegSqhzjI6lA}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{gc8l1G6KXOeLLOM7VJip6 → p8875OZM4iDNsPzmoyLe7}/_ssgManifest.js +0 -0
- /package/dist/.next/{.next/static/kYsJoni86CJWDuTkc1xU6 → static 2/5dBGGUmK5q7of4h5Rahrg}/_ssgManifest.js +0 -0
|
@@ -112,26 +112,18 @@ export function parseStatement(sql) {
|
|
|
112
112
|
// Extract the index name.
|
|
113
113
|
const indexMatch = cleanSql.match(/INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?([\w$]+)/i);
|
|
114
114
|
const indexName = indexMatch ? indexMatch[1] : '';
|
|
115
|
-
// Extract the columns from the ON clause.
|
|
116
|
-
const onMatch = cleanSql.match(/ON\s+[\w$]+\s*\(([^)]+)\)/i);
|
|
117
|
-
const columns = onMatch ? onMatch[1].trim() : '';
|
|
118
|
-
// Remove spaces and replace commas with hyphens.
|
|
119
|
-
const formattedColumns = columns.replace(/\s+/g, '').replace(/,/g, '-').toLowerCase();
|
|
120
115
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
let description = indexName;
|
|
124
|
-
if (formattedColumns && !description.toLowerCase().includes(formattedColumns)) {
|
|
125
|
-
description += `-${formattedColumns}`;
|
|
126
|
-
}
|
|
116
|
+
// For index migrations, simply use the index name as the description.
|
|
117
|
+
const description = indexName;
|
|
127
118
|
|
|
128
119
|
return {
|
|
129
120
|
type: Operations.CREATE_INDEX,
|
|
130
121
|
tableName,
|
|
131
122
|
sql: cleanSql,
|
|
132
|
-
description // e.g. "
|
|
123
|
+
description // now simply the index name, e.g. "idx_technology_timestamp"
|
|
133
124
|
};
|
|
134
|
-
}
|
|
125
|
+
}
|
|
126
|
+
|
|
135
127
|
|
|
136
128
|
if (upperSql.startsWith('DROP INDEX')) {
|
|
137
129
|
const tableName = extractTableNameFromIndex(cleanSql);
|
|
@@ -342,6 +334,83 @@ export async function executeSQL(projectDir, databaseName, sql, env = {}, remote
|
|
|
342
334
|
}
|
|
343
335
|
}
|
|
344
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Fetches the latest `limit` records for a given table from the remote database.
|
|
339
|
+
*
|
|
340
|
+
* This implementation uses the executeSQL function with the remote flag enabled.
|
|
341
|
+
* It orders the results based on the provided ordering column. If no ordering column is provided,
|
|
342
|
+
* it falls back to the default "id" column.
|
|
343
|
+
*
|
|
344
|
+
* @param {string} projectDir - The project directory.
|
|
345
|
+
* @param {string} databaseName - The D1 database name.
|
|
346
|
+
* @param {string} tableName - The table to fetch records for.
|
|
347
|
+
* @param {object} env - Environment variables (including credentials).
|
|
348
|
+
* @param {number} limit - The number of records to fetch.
|
|
349
|
+
* @param {string} [orderingColumn="id"] - The column to order by.
|
|
350
|
+
* @returns {Promise<Array<object>>} Array of row objects.
|
|
351
|
+
*/
|
|
352
|
+
export async function fetchRemoteTableData(
|
|
353
|
+
projectDir,
|
|
354
|
+
databaseName,
|
|
355
|
+
tableName,
|
|
356
|
+
env,
|
|
357
|
+
limit,
|
|
358
|
+
orderingColumn = "id"
|
|
359
|
+
) {
|
|
360
|
+
// Use the provided ordering column; if not provided, default to "id".
|
|
361
|
+
const query = `SELECT * FROM "${tableName}" ORDER BY "${orderingColumn}" DESC LIMIT ${limit};`;
|
|
362
|
+
try {
|
|
363
|
+
// Execute the SQL command on the remote database.
|
|
364
|
+
const result = await executeSQL(projectDir, databaseName, query, env, true);
|
|
365
|
+
|
|
366
|
+
// ExecuteSQL returns stdout that should contain a JSON array starting from a '['.
|
|
367
|
+
const jsonStart = result.indexOf('[');
|
|
368
|
+
if (jsonStart === -1) {
|
|
369
|
+
throw new Error(`Unexpected result format: ${result}`);
|
|
370
|
+
}
|
|
371
|
+
const jsonStr = result.substring(jsonStart);
|
|
372
|
+
const parsed = JSON.parse(jsonStr);
|
|
373
|
+
// Assuming the structure: parsed[0].results contains the rows.
|
|
374
|
+
const rows = parsed[0]?.results || [];
|
|
375
|
+
return rows;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
logger.error(`Error fetching remote data for table ${tableName}:`, error);
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Generates a bulk insert SQL statement for the specified table and rows.
|
|
384
|
+
*
|
|
385
|
+
* This function constructs a single INSERT statement that inserts multiple rows.
|
|
386
|
+
* It escapes single quotes in string values. You may need to extend this for
|
|
387
|
+
* additional data types (e.g., numbers, dates, booleans) or more complex structures.
|
|
388
|
+
*
|
|
389
|
+
* @param {string} tableName - The table to insert into.
|
|
390
|
+
* @param {Array<object>} rows - An array of objects, each representing a row.
|
|
391
|
+
* @returns {string} The bulk insert SQL statement.
|
|
392
|
+
*/
|
|
393
|
+
export function generateBulkInsertSQL(tableName, rows) {
|
|
394
|
+
if (!rows || rows.length === 0) return '';
|
|
395
|
+
|
|
396
|
+
// Get the list of columns from the first row object.
|
|
397
|
+
const columns = Object.keys(rows[0]);
|
|
398
|
+
const columnList = columns.map(col => `"${col}"`).join(', ');
|
|
399
|
+
|
|
400
|
+
// Build the values list for each row.
|
|
401
|
+
const valuesList = rows.map(row => {
|
|
402
|
+
const values = columns.map(col => {
|
|
403
|
+
const value = row[col];
|
|
404
|
+
if (value === null || value === undefined) return 'NULL';
|
|
405
|
+
// For simplicity, treat the value as a string.
|
|
406
|
+
return `'${String(value).replace(/'/g, "''")}'`;
|
|
407
|
+
}).join(', ');
|
|
408
|
+
return `(${values})`;
|
|
409
|
+
}).join(', ');
|
|
410
|
+
|
|
411
|
+
return `INSERT INTO "${tableName}" (${columnList}) VALUES ${valuesList};`;
|
|
412
|
+
}
|
|
413
|
+
|
|
345
414
|
// ---------------------------------------------------------------------
|
|
346
415
|
// SQL Formatting and Helper Functions
|
|
347
416
|
// ---------------------------------------------------------------------
|
|
@@ -482,14 +551,14 @@ export function formatMigrationContent(sql) {
|
|
|
482
551
|
* @returns {Promise<string>} The migration file content.
|
|
483
552
|
*/
|
|
484
553
|
|
|
485
|
-
|
|
554
|
+
export async function getMigrationFileContent(projectDir, databaseName, migrationFile, env) {
|
|
486
555
|
try {
|
|
487
556
|
// Extract table name using improved helper
|
|
488
557
|
const tableName = await extractTableNameFromMigration(migrationFile);
|
|
489
558
|
let sql;
|
|
490
559
|
|
|
491
|
-
|
|
492
|
-
|
|
560
|
+
// For non-index migrations, try getting SQL from sqlite_master for table
|
|
561
|
+
if (tableName && !migrationFile.includes('create-index')) {
|
|
493
562
|
const result = await executeSQL(
|
|
494
563
|
projectDir,
|
|
495
564
|
databaseName,
|
|
@@ -506,24 +575,38 @@ export function formatMigrationContent(sql) {
|
|
|
506
575
|
}
|
|
507
576
|
}
|
|
508
577
|
|
|
509
|
-
// If we couldn't get the SQL from table, try index
|
|
578
|
+
// If we couldn't get the SQL from table and it's an index migration, try fetching via index name.
|
|
510
579
|
if (!sql && migrationFile.includes('create-index')) {
|
|
511
|
-
const indexMatch = migrationFile.match(/create-index[-
|
|
580
|
+
const indexMatch = migrationFile.match(/create-index[_-](.+)\.sql$/i);
|
|
512
581
|
if (indexMatch) {
|
|
513
|
-
|
|
582
|
+
let indexName = indexMatch[1]; // e.g. "idx_technology_timestamp-technology-timestamp"
|
|
583
|
+
let result = await executeSQL(
|
|
514
584
|
projectDir,
|
|
515
585
|
databaseName,
|
|
516
|
-
`SELECT sql FROM sqlite_master WHERE type='index' AND name='${
|
|
586
|
+
`SELECT sql FROM sqlite_master WHERE type='index' AND name='${indexName}' COLLATE NOCASE;`,
|
|
517
587
|
env,
|
|
518
588
|
true
|
|
519
589
|
);
|
|
520
|
-
|
|
590
|
+
let parsed = JSON.parse(result);
|
|
521
591
|
sql = parsed[0]?.results?.[0]?.sql;
|
|
592
|
+
// Fallback: if no result, try using only the part before the first hyphen.
|
|
593
|
+
if (!sql) {
|
|
594
|
+
const fallbackIndexName = indexName.split('-')[0]; // "idx_technology_timestamp"
|
|
595
|
+
result = await executeSQL(
|
|
596
|
+
projectDir,
|
|
597
|
+
databaseName,
|
|
598
|
+
`SELECT sql FROM sqlite_master WHERE type='index' AND name='${fallbackIndexName}' COLLATE NOCASE;`,
|
|
599
|
+
env,
|
|
600
|
+
true
|
|
601
|
+
);
|
|
602
|
+
parsed = JSON.parse(result);
|
|
603
|
+
sql = parsed[0]?.results?.[0]?.sql;
|
|
604
|
+
}
|
|
522
605
|
}
|
|
523
|
-
}
|
|
606
|
+
}
|
|
524
607
|
|
|
525
|
-
// If still no SQL
|
|
526
|
-
if (!sql && tableName) {
|
|
608
|
+
// If still no SQL and it's not an index migration, try a fallback query
|
|
609
|
+
if (!sql && tableName && !migrationFile.includes('create-index')) {
|
|
527
610
|
const result = await executeSQL(
|
|
528
611
|
projectDir,
|
|
529
612
|
databaseName,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// lib/version-utils.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compares semantic versions to determine if v2 is newer than v1
|
|
5
|
+
* @param {string} v1 - First version (e.g. "1.0.0")
|
|
6
|
+
* @param {string} v2 - Second version (e.g. "1.0.1")
|
|
7
|
+
* @returns {boolean} True if v2 is newer than v1
|
|
8
|
+
*/
|
|
9
|
+
export function isNewerVersion(v1, v2) {
|
|
10
|
+
if (!v1 || !v2) return false;
|
|
11
|
+
|
|
12
|
+
// Split versions by dots
|
|
13
|
+
const v1Parts = v1.split('.').map(Number);
|
|
14
|
+
const v2Parts = v2.split('.').map(Number);
|
|
15
|
+
|
|
16
|
+
// Compare major, minor, and patch versions
|
|
17
|
+
for (let i = 0; i < 3; i++) {
|
|
18
|
+
if (v2Parts[i] > v1Parts[i]) return true;
|
|
19
|
+
if (v2Parts[i] < v1Parts[i]) return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// If we reach here, versions are equal
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Formats version strings for display by removing leading 'v' if present
|
|
28
|
+
* @param {string} version - The version string (e.g. "v1.0.0" or "1.0.0")
|
|
29
|
+
* @returns {string} Formatted version (e.g. "1.0.0")
|
|
30
|
+
*/
|
|
31
|
+
export function formatVersion(version) {
|
|
32
|
+
if (!version) return '';
|
|
33
|
+
return version.startsWith('v') ? version.substring(1) : version;
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "d1s",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "D1 Studio – a native studio for managing Cloudflare D1 databases.",
|
|
6
6
|
"main": "./dist/d1-studio.js",
|
|
@@ -97,4 +97,4 @@
|
|
|
97
97
|
"tailwindcss": "^3.4.1",
|
|
98
98
|
"wrangler": "^3.107.3"
|
|
99
99
|
}
|
|
100
|
-
}
|
|
100
|
+
}
|
package/scripts/studio.js
CHANGED
|
@@ -3,17 +3,20 @@ import chalk from 'chalk';
|
|
|
3
3
|
import open from 'open';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { dirname, join } from 'path';
|
|
6
|
-
import { createHash } from 'crypto';
|
|
7
|
-
import { homedir } from 'os';
|
|
8
|
-
import os from 'os';
|
|
9
|
-
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
10
6
|
import express from 'express';
|
|
11
7
|
import { createServer } from 'http';
|
|
12
8
|
import next from 'next';
|
|
13
9
|
import { findWranglerConfig } from '../src/lib/find-wrangler-config.js';
|
|
14
10
|
import logger from '../src/lib/logger.js';
|
|
15
11
|
import updateNotifier from 'update-notifier';
|
|
16
|
-
import pkg from '../package.json'
|
|
12
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
13
|
+
|
|
14
|
+
// Check for debug flag
|
|
15
|
+
const hasDebugFlag = process.argv.includes('--debug');
|
|
16
|
+
if (hasDebugFlag) {
|
|
17
|
+
process.env.DEBUG = 'true';
|
|
18
|
+
logger.debug('Debug mode enabled');
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
const notifier = updateNotifier({ pkg, updateCheckInterval: 1000 * 60 * 60 * 24 });
|
|
19
22
|
notifier.notify({ defer: false });
|
|
@@ -22,133 +25,6 @@ notifier.notify({ defer: false });
|
|
|
22
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
23
26
|
const __dirname = dirname(__filename);
|
|
24
27
|
|
|
25
|
-
// License validation utilities
|
|
26
|
-
class LicenseError extends Error {
|
|
27
|
-
constructor(message, type = 'VALIDATION_ERROR') {
|
|
28
|
-
super(message);
|
|
29
|
-
this.name = 'LicenseError';
|
|
30
|
-
this.type = type;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
class StudioLicenseManager {
|
|
35
|
-
constructor() {
|
|
36
|
-
this.licenseDir = join(homedir(), '.d1studio');
|
|
37
|
-
this.licensePath = join(this.licenseDir, 'license.json');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async checkLicenseFile() {
|
|
41
|
-
try {
|
|
42
|
-
const licenseData = JSON.parse(await readFile(this.licensePath, 'utf8'));
|
|
43
|
-
|
|
44
|
-
// If no end_date or subscription_status, the license is valid (perpetual license)
|
|
45
|
-
if (!licenseData.end_date || !licenseData.subscription_status) {
|
|
46
|
-
return {
|
|
47
|
-
licenseData,
|
|
48
|
-
isValid: true,
|
|
49
|
-
isExpiringSoon: false
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Check subscription status first
|
|
54
|
-
if (licenseData.subscription_status !== 'active') {
|
|
55
|
-
return {
|
|
56
|
-
licenseData,
|
|
57
|
-
isValid: false,
|
|
58
|
-
isExpiringSoon: false
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const endDate = new Date(licenseData.end_date);
|
|
63
|
-
const now = new Date();
|
|
64
|
-
|
|
65
|
-
// Check if subscription has ended
|
|
66
|
-
if (endDate < now) {
|
|
67
|
-
return {
|
|
68
|
-
licenseData,
|
|
69
|
-
isValid: false,
|
|
70
|
-
isExpiringSoon: false
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Check if subscription ends in next 7 days
|
|
75
|
-
const sevenDaysFromNow = new Date(now.getTime() + (7 * 24 * 60 * 60 * 1000));
|
|
76
|
-
const isExpiringSoon = endDate <= sevenDaysFromNow;
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
licenseData,
|
|
80
|
-
isValid: true,
|
|
81
|
-
isExpiringSoon
|
|
82
|
-
};
|
|
83
|
-
} catch (error) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async saveLicenseFile(licenseData) {
|
|
89
|
-
try {
|
|
90
|
-
await mkdir(this.licenseDir, { recursive: true });
|
|
91
|
-
await writeFile(this.licensePath, JSON.stringify(licenseData, null, 2));
|
|
92
|
-
} catch (error) {
|
|
93
|
-
throw new LicenseError('Failed to save license information', 'SAVE_ERROR');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async function generateHardwareId() {
|
|
99
|
-
const osInfo = {
|
|
100
|
-
platform: process.platform,
|
|
101
|
-
arch: process.arch,
|
|
102
|
-
cpus: os.cpus().length,
|
|
103
|
-
hostname: os.hostname(),
|
|
104
|
-
username: os.userInfo().username,
|
|
105
|
-
};
|
|
106
|
-
const systemString = JSON.stringify(osInfo);
|
|
107
|
-
return createHash('sha256').update(systemString).digest('hex');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function validateLicenseRemote(licenseKey, email, hardwareId) {
|
|
111
|
-
const baseUrl =
|
|
112
|
-
process.env.NODE_ENV === 'development'
|
|
113
|
-
? 'http://localhost:4000'
|
|
114
|
-
: 'https://d1-studio.com';
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
const response = await fetch(`${baseUrl}/api/validate-license`, {
|
|
118
|
-
method: 'POST',
|
|
119
|
-
headers: { 'Content-Type': 'application/json' },
|
|
120
|
-
body: JSON.stringify({ licenseKey, email, hardwareId }),
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const result = await response.json();
|
|
124
|
-
|
|
125
|
-
if (!response.ok) {
|
|
126
|
-
throw new LicenseError(
|
|
127
|
-
result.message || 'License validation failed',
|
|
128
|
-
result.type || 'VALIDATION_ERROR'
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return result;
|
|
133
|
-
} catch (error) {
|
|
134
|
-
if (error instanceof LicenseError) {
|
|
135
|
-
throw error;
|
|
136
|
-
}
|
|
137
|
-
if (error.name === 'TypeError' && error.message.includes('fetch')) {
|
|
138
|
-
throw new LicenseError(
|
|
139
|
-
process.env.NODE_ENV === 'development'
|
|
140
|
-
? 'Unable to connect to local license validation service. Make sure the development server is running.'
|
|
141
|
-
: 'Unable to connect to license server. Please check your internet connection.',
|
|
142
|
-
'CONNECTION_ERROR'
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
throw new LicenseError(
|
|
146
|
-
'An unexpected error occurred during license validation',
|
|
147
|
-
'VALIDATION_ERROR'
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
28
|
async function startServer(port, projectDirectory) {
|
|
153
29
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
154
30
|
// Determine Next.js app directory based on environment:
|
|
@@ -203,69 +79,6 @@ async function startStudio() {
|
|
|
203
79
|
try {
|
|
204
80
|
logger.info(chalk.green('Initializing D1 Studio...'));
|
|
205
81
|
|
|
206
|
-
const licenseManager = new StudioLicenseManager();
|
|
207
|
-
|
|
208
|
-
// Check existing license
|
|
209
|
-
const licenseCheck = await licenseManager.checkLicenseFile();
|
|
210
|
-
|
|
211
|
-
// Handle license validation
|
|
212
|
-
if (!licenseCheck || !licenseCheck.isValid) {
|
|
213
|
-
// Prompt for license information if needed
|
|
214
|
-
const { default: inquirer } = await import('inquirer');
|
|
215
|
-
logger.info(chalk.yellow('\nPlease enter your D1 Studio license information:'));
|
|
216
|
-
|
|
217
|
-
const answers = await inquirer.prompt([
|
|
218
|
-
{
|
|
219
|
-
type: 'input',
|
|
220
|
-
name: 'licenseKey',
|
|
221
|
-
message: 'License Key:',
|
|
222
|
-
validate: (input) => input.length > 0 || 'License key is required',
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
type: 'input',
|
|
226
|
-
name: 'email',
|
|
227
|
-
message: 'Email:',
|
|
228
|
-
validate: (input) => {
|
|
229
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
230
|
-
return emailRegex.test(input) || 'Please enter a valid email';
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
]);
|
|
234
|
-
|
|
235
|
-
const hardwareId = await generateHardwareId();
|
|
236
|
-
|
|
237
|
-
try {
|
|
238
|
-
const validation = await validateLicenseRemote(
|
|
239
|
-
answers.licenseKey,
|
|
240
|
-
answers.email,
|
|
241
|
-
hardwareId
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// Save the complete validation response
|
|
245
|
-
await licenseManager.saveLicenseFile({
|
|
246
|
-
licenseKey: answers.licenseKey,
|
|
247
|
-
email: answers.email,
|
|
248
|
-
hardwareId,
|
|
249
|
-
end_date: validation.end_date,
|
|
250
|
-
subscription_status: validation.subscription_status,
|
|
251
|
-
type: validation.licenseType,
|
|
252
|
-
activatedAt: new Date().toISOString()
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
logger.info(chalk.green('\nLicense activated successfully!'));
|
|
256
|
-
} catch (error) {
|
|
257
|
-
logger.error(chalk.red(`\nLicense validation failed: ${error.message}`));
|
|
258
|
-
process.exit(1);
|
|
259
|
-
}
|
|
260
|
-
} else if (licenseCheck.isExpiringSoon) {
|
|
261
|
-
// Show warning about expiring subscription
|
|
262
|
-
const endDate = new Date(licenseCheck.licenseData.end_date).toLocaleDateString();
|
|
263
|
-
logger.warn(chalk.yellow(`
|
|
264
|
-
⚠️ Your subscription will expire on ${endDate}
|
|
265
|
-
Please renew your subscription at https://d1-studio.com to continue using D1 Studio.
|
|
266
|
-
`));
|
|
267
|
-
}
|
|
268
|
-
|
|
269
82
|
// Get wrangler configuration
|
|
270
83
|
try {
|
|
271
84
|
const userProjectPath = process.cwd();
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// api/pull-data/confirm/route.js
|
|
2
|
+
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { executeSQL } from '@/lib/sql-operations';
|
|
5
|
+
import { getCurrentSchema } from '@/lib/schema-operations';
|
|
6
|
+
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
7
|
+
import logger from '@/lib/logger';
|
|
8
|
+
import {
|
|
9
|
+
fetchRemoteTableData as fetchRemoteDataHelper,
|
|
10
|
+
generateBulkInsertSQL
|
|
11
|
+
} from '@/lib/sql-operations';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Helper to extract the ordering column (primary key) from a table's schema.
|
|
15
|
+
* Assumes that each table’s schema object contains a "columns" array with an "isPrimaryKey" flag.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} tableSchema - Schema info for the table.
|
|
18
|
+
* @returns {string} The column name to use for ordering.
|
|
19
|
+
*/
|
|
20
|
+
function getOrderingColumn(tableSchema) {
|
|
21
|
+
const pkColumn = tableSchema.columns?.find(col => col.isPrimaryKey);
|
|
22
|
+
const orderingCol = pkColumn ? pkColumn.name : 'rowid';
|
|
23
|
+
logger.debug(`Determined ordering column for table ${tableSchema.name || 'unknown'}: ${orderingCol}`);
|
|
24
|
+
return orderingCol;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Computes an insertion order for tables based on their foreign key dependencies.
|
|
29
|
+
* The returned array is sorted so that if table A is referenced by table B,
|
|
30
|
+
* then A appears earlier in the list.
|
|
31
|
+
*
|
|
32
|
+
* @param {Array<object>} tableSchemas - Array of table schema objects.
|
|
33
|
+
* @returns {Array<string>} Ordered array of table names.
|
|
34
|
+
*/
|
|
35
|
+
function computeInsertionOrder(tableSchemas) {
|
|
36
|
+
// Build a dependency graph: key = table name, value = set of tables that this table depends on.
|
|
37
|
+
const graph = {};
|
|
38
|
+
tableSchemas.forEach(table => {
|
|
39
|
+
// Initialize graph for this table.
|
|
40
|
+
graph[table.name] = new Set();
|
|
41
|
+
// Use a regex to find FOREIGN KEY references in the table's SQL.
|
|
42
|
+
// This regex assumes the foreign key clause looks like:
|
|
43
|
+
// FOREIGN KEY (...) REFERENCES referencedTable(...)
|
|
44
|
+
const fkRegex = /FOREIGN KEY\s*\([^)]*\)\s+REFERENCES\s+(\w+)/gi;
|
|
45
|
+
let match;
|
|
46
|
+
while ((match = fkRegex.exec(table.sql)) !== null) {
|
|
47
|
+
const referencedTable = match[1];
|
|
48
|
+
graph[table.name].add(referencedTable);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
logger.debug('Computed dependency graph:', graph);
|
|
52
|
+
|
|
53
|
+
// Topological sort (depth-first search) to compute insertion order.
|
|
54
|
+
const sorted = [];
|
|
55
|
+
const visited = {}; // 'temp' = visiting, 'perm' = done
|
|
56
|
+
|
|
57
|
+
function visit(tableName) {
|
|
58
|
+
if (visited[tableName] === 'temp') {
|
|
59
|
+
throw new Error(`Cycle detected in dependencies at table ${tableName}`);
|
|
60
|
+
}
|
|
61
|
+
if (!visited[tableName]) {
|
|
62
|
+
visited[tableName] = 'temp';
|
|
63
|
+
// Visit all tables that this table depends on.
|
|
64
|
+
graph[tableName].forEach(dep => {
|
|
65
|
+
// Only visit if the dependency is in our graph (i.e. among our tables)
|
|
66
|
+
if (graph[dep]) {
|
|
67
|
+
visit(dep);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
visited[tableName] = 'perm';
|
|
71
|
+
sorted.push(tableName);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Object.keys(graph).forEach(tableName => {
|
|
76
|
+
if (!visited[tableName]) {
|
|
77
|
+
visit(tableName);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
logger.debug('Computed insertion order (parent tables first):', sorted);
|
|
82
|
+
return sorted;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Applies the data pull by:
|
|
87
|
+
* 1. Fetching the local schema to determine table names and primary keys.
|
|
88
|
+
* 2. Computing the insertion order so that parent tables are inserted before child tables.
|
|
89
|
+
* 3. For each table (in insertion order), fetching the latest 100 records from the remote database.
|
|
90
|
+
* 4. Generating a bulk insert statement and executing it.
|
|
91
|
+
*
|
|
92
|
+
* This function aborts the entire process if any insert fails.
|
|
93
|
+
*
|
|
94
|
+
* @param {string} projectDir
|
|
95
|
+
* @param {string} accountId
|
|
96
|
+
* @param {string} apiToken
|
|
97
|
+
* @param {string} databaseName
|
|
98
|
+
* @returns {object} Details of data pulled.
|
|
99
|
+
*/
|
|
100
|
+
async function applyDataPull(projectDir, accountId, apiToken, databaseName) {
|
|
101
|
+
logger.debug('Starting data pull process...');
|
|
102
|
+
const env = {
|
|
103
|
+
...process.env,
|
|
104
|
+
CLOUDFLARE_API_TOKEN: apiToken,
|
|
105
|
+
CLOUDFLARE_ACCOUNT_ID: accountId
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
logger.debug('Fetching current schema for data pull...');
|
|
109
|
+
const currentSchema = await getCurrentSchema(projectDir, databaseName, env, false);
|
|
110
|
+
// Filter for table objects that have a name.
|
|
111
|
+
const tableSchemas = currentSchema.filter(obj => obj.type === 'table' && obj.name);
|
|
112
|
+
logger.debug('Local table schema for data pull:', tableSchemas.map(t => t.name));
|
|
113
|
+
|
|
114
|
+
// Compute insertion order based on foreign key dependencies.
|
|
115
|
+
const insertionOrder = computeInsertionOrder(tableSchemas);
|
|
116
|
+
logger.debug('Final computed insertion order:', insertionOrder);
|
|
117
|
+
|
|
118
|
+
// Process each table in the computed insertion order.
|
|
119
|
+
for (const tableName of insertionOrder) {
|
|
120
|
+
const table = tableSchemas.find(t => t.name === tableName);
|
|
121
|
+
if (!table) {
|
|
122
|
+
logger.debug(`Skipping table ${tableName} as it is not in the current schema list.`);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
logger.debug(`Processing table: ${tableName}`);
|
|
126
|
+
const orderingColumn = getOrderingColumn(table);
|
|
127
|
+
logger.debug(`Fetching data for table: ${tableName} ordered by ${orderingColumn}`);
|
|
128
|
+
|
|
129
|
+
// Fetch remote data.
|
|
130
|
+
const rows = await fetchRemoteDataHelper(
|
|
131
|
+
projectDir,
|
|
132
|
+
databaseName,
|
|
133
|
+
tableName,
|
|
134
|
+
env,
|
|
135
|
+
75,
|
|
136
|
+
orderingColumn
|
|
137
|
+
);
|
|
138
|
+
logger.debug(`Fetched ${rows.length} records for table: ${tableName}`);
|
|
139
|
+
|
|
140
|
+
if (rows.length > 0) {
|
|
141
|
+
const insertSQL = generateBulkInsertSQL(tableName, rows);
|
|
142
|
+
logger.debug(`Generated bulk insert SQL for ${tableName}: ${insertSQL}`);
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
// Execute the insert SQL directly.
|
|
146
|
+
await executeSQL(projectDir, databaseName, insertSQL, env, false);
|
|
147
|
+
logger.debug(`Bulk inserted ${rows.length} records into table: ${tableName}`);
|
|
148
|
+
} catch (insertError) {
|
|
149
|
+
logger.error(`Error inserting data into table ${tableName}:`, insertError);
|
|
150
|
+
// Abort the entire process to preserve data integrity.
|
|
151
|
+
throw new Error(`Data pull failed for table ${tableName}: ${insertError.message}`);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
logger.debug(`No data fetched for table: ${tableName}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
logger.debug('Data pull process completed successfully.');
|
|
158
|
+
return { message: 'All data pulled successfully.' };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function POST(req) {
|
|
162
|
+
try {
|
|
163
|
+
logger.debug('Received request for data pull.');
|
|
164
|
+
const { accountId, apiToken } = await req.json();
|
|
165
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
166
|
+
if (!projectDir) {
|
|
167
|
+
return NextResponse.json(
|
|
168
|
+
{
|
|
169
|
+
success: false,
|
|
170
|
+
error: {
|
|
171
|
+
type: 'VALIDATION_ERROR',
|
|
172
|
+
message: 'Project directory not configured'
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{ status: 500 }
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
179
|
+
if (!wranglerResult || !wranglerResult.config) {
|
|
180
|
+
return NextResponse.json(
|
|
181
|
+
{
|
|
182
|
+
success: false,
|
|
183
|
+
error: {
|
|
184
|
+
type: 'VALIDATION_ERROR',
|
|
185
|
+
message: 'Could not find Wrangler configuration'
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{ status: 400 }
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
const config = wranglerResult.config;
|
|
192
|
+
if (!config.d1_databases?.length) {
|
|
193
|
+
return NextResponse.json(
|
|
194
|
+
{
|
|
195
|
+
success: false,
|
|
196
|
+
error: {
|
|
197
|
+
type: 'VALIDATION_ERROR',
|
|
198
|
+
message: 'No D1 databases configured'
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
{ status: 400 }
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
const databaseName = config.d1_databases[0].database_name;
|
|
205
|
+
logger.debug(`Initiating data pull for database: ${databaseName}`);
|
|
206
|
+
const result = await applyDataPull(projectDir, accountId, apiToken, databaseName);
|
|
207
|
+
logger.debug('Data pull result:', result);
|
|
208
|
+
return NextResponse.json({
|
|
209
|
+
success: true,
|
|
210
|
+
message: result.message,
|
|
211
|
+
details: result
|
|
212
|
+
});
|
|
213
|
+
} catch (error) {
|
|
214
|
+
logger.error('Pull data confirm error:', error);
|
|
215
|
+
return NextResponse.json(
|
|
216
|
+
{
|
|
217
|
+
success: false,
|
|
218
|
+
error: {
|
|
219
|
+
type: error.type || 'EXECUTION_ERROR',
|
|
220
|
+
message: error.message || 'Failed to apply data pull'
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{ status: 500 }
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export async function OPTIONS() {
|
|
229
|
+
return new NextResponse(null, { status: 204 });
|
|
230
|
+
}
|