d1s 0.2.13 → 0.3.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 +18 -1
- package/dist/.next/.next/BUILD_ID +1 -1
- package/dist/.next/.next/app-build-manifest.json +119 -77
- package/dist/.next/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/.next/build-manifest.json +7 -7
- package/dist/.next/.next/cache/.rscinfo +1 -1
- package/dist/.next/.next/cache/.tsbuildinfo +1 -1
- 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/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/0.pack +0 -0
- package/dist/.next/.next/cache/webpack/client-production/1.pack +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/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/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/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-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/index.pack.gz +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/3.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/react-loadable-manifest.json +11 -1
- package/dist/.next/.next/required-server-files.json +1 -1
- package/dist/.next/.next/routes-manifest.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 +5 -5
- package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
- package/dist/.next/.next/server/app/api/cloudflare/route.js.nft.json +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.js.nft.json +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/list/route.js +26 -0
- package/dist/.next/.next/server/app/api/migrations/list/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/migrations/list/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/migrations/sync/route.js +5 -5
- 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 +4 -4
- 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/pro/route.js +1 -0
- package/dist/.next/.next/server/app/api/pro/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/pro/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -1
- package/dist/.next/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +4 -4
- 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 +4 -4
- 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 +6 -6
- 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 +6 -6
- 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 +9 -9
- 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/schema/route.js +1 -0
- package/dist/.next/.next/server/app/api/schema/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/schema/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/import/route.js +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/import/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/import/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -5
- package/dist/.next/.next/server/app/api/tables/[name]/route.js.nft.json +1 -1
- 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.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/api/time-travel/preview/route.js +1 -0
- package/dist/.next/.next/server/app/api/time-travel/preview/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/time-travel/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/time-travel/restore/route.js +1 -0
- package/dist/.next/.next/server/app/api/time-travel/restore/route.js.nft.json +1 -0
- package/dist/.next/.next/server/app/api/time-travel/restore/route_client-reference-manifest.js +1 -0
- package/dist/.next/.next/server/app/api/update/route.js +1 -1
- package/dist/.next/.next/server/app/api/update/route.js.nft.json +1 -1
- package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app/index.html +5 -3
- package/dist/.next/.next/server/app/index.rsc +6 -6
- package/dist/.next/.next/server/app/page.js +15 -15
- 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 +8 -2
- package/dist/.next/.next/server/chunks/226.js +12 -12
- package/dist/.next/.next/server/chunks/452.js +1 -1
- package/dist/.next/.next/server/chunks/487.js +1 -0
- package/dist/.next/.next/server/chunks/572.js +1 -1
- package/dist/.next/.next/server/chunks/992.js +2 -2
- package/dist/.next/.next/server/chunks/{638.js → 994.js} +3 -3
- package/dist/.next/.next/server/middleware-build-manifest.js +1 -1
- package/dist/.next/.next/server/middleware-react-loadable-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/server-reference-manifest.json +1 -1
- package/dist/.next/.next/static/-OO4tE7EKr8o62Bne-ODo/_buildManifest.js +1 -0
- package/dist/.next/.next/static/3kAeIJC56X7aw1Fk5_OXO/_buildManifest.js +1 -0
- package/dist/.next/.next/static/J8r9W6xxmYYvuKehItNuW/_buildManifest.js +1 -0
- package/dist/.next/.next/static/ZmKZbpam0G_d3SphfZPJ7/_buildManifest.js +1 -0
- package/dist/.next/.next/static/arc9h7hbaQzL1Dl0iuVrT/_buildManifest.js +1 -0
- package/dist/.next/.next/static/chunks/1a258343.3b3e7ba5ba0bd0d2.js +1 -0
- package/dist/.next/.next/static/chunks/345.8fc37569d5708622.js +1 -0
- package/dist/.next/.next/static/chunks/480-85b6c8ae3f51b156.js +1 -0
- package/dist/.next/.next/static/chunks/52.2cdc9bdb75e1fc2e.js +1 -0
- package/dist/.next/.next/static/chunks/803-a2fcfbd00e6b3b38.js +1 -0
- package/dist/.next/.next/static/chunks/{92-5f7522943fcb72a8.js → 92-a84bdac2be7c8d7a.js} +1 -1
- package/dist/.next/.next/static/chunks/app/api/cloudflare/route-d0c1dc2a9e7dce36.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/databases/route-cd322321212797cf.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/list/route-cd710ff75b6bcd02.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-ee522f232b9f0a9c.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-79ee2c26f87d3bc7.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pro/route-c90c1f901fc00d38.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-data/confirm/route-118764086af798f8.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-2b0ade4ebfcea0bc.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-342db7ea13e6f447.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-b778c053bd515abd.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-ab090482f299f57f.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/query/route-4d21a8b1d34491f1.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/schema/route-cb17a387d6b557ad.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/import/route-510472de7a5c29bd.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-6a1fa95c303ce0de.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/tables/route-daa975df4ea8e8f8.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/time-travel/preview/route-5787d7e8f17bd539.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/time-travel/restore/route-84b64a27e831e21c.js +1 -0
- package/dist/.next/.next/static/chunks/app/api/update/route-54ee900537982652.js +1 -0
- package/dist/.next/.next/static/chunks/app/{layout-40ec07d04681ba81.js → layout-f0ec4d636ee0f763.js} +1 -1
- package/dist/.next/.next/static/chunks/app/page-358bf2112802ff85.js +1 -0
- package/dist/.next/.next/static/chunks/app/page-3ec9d72ecb052d39.js +1 -0
- package/dist/.next/.next/static/chunks/webpack-024900a94af4f0a7.js +1 -0
- package/dist/.next/.next/static/css/2c165a0ede9b2442.css +3 -0
- package/dist/.next/.next/static/css/32df9a4d493f8b0f.css +31 -0
- package/dist/.next/.next/static/f_PVCmmSeM5SwW3M1tw7Q/_buildManifest.js +1 -0
- package/dist/.next/.next/static/fiesjBWbrmSSyLf4biwrX/_buildManifest.js +1 -0
- package/dist/.next/.next/static/ft39e6W6vSgUL7peRo7pE/_buildManifest.js +1 -0
- package/dist/.next/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/.next/.next/static/u7ssdTycF4iQ-w-pQZhxg/_buildManifest.js +1 -0
- package/dist/.next/.next/static/v-i2YsOGT890zutOSiqqK/_buildManifest.js +1 -0
- package/dist/.next/.next/trace +3 -3
- package/dist/.next/.next/types/app/api/migrations/list/route.ts +347 -0
- package/dist/.next/.next/types/app/api/pro/route.ts +347 -0
- package/dist/.next/.next/types/app/api/schema/route.ts +347 -0
- package/dist/.next/.next/types/app/api/tables/[name]/import/route.ts +347 -0
- package/dist/.next/.next/types/app/api/time-travel/preview/route.ts +347 -0
- package/dist/.next/.next/types/app/api/time-travel/restore/route.ts +347 -0
- package/dist/.next/BUILD_ID +1 -1
- package/dist/.next/app-build-manifest.json +122 -80
- package/dist/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/build-manifest.json +7 -7
- 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/react-loadable-manifest.json +11 -1
- package/dist/.next/required-server-files.json +1 -1
- package/dist/.next/routes-manifest.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 +5 -5
- 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/list/route.js +26 -0
- package/dist/.next/server/app/api/migrations/list/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/migrations/list/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/migrations/sync/route.js +5 -5
- 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 +4 -4
- 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/pro/route.js +1 -0
- package/dist/.next/server/app/api/pro/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/pro/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -1
- package/dist/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/api/pull-remote/confirm/route.js +4 -4
- 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 +4 -4
- 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 +6 -6
- 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 +6 -6
- 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 +9 -9
- 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/schema/route.js +1 -0
- package/dist/.next/server/app/api/schema/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/schema/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/tables/[name]/import/route.js +1 -0
- package/dist/.next/server/app/api/tables/[name]/import/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/tables/[name]/import/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/tables/[name]/route.js +5 -5
- 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/time-travel/preview/route.js +1 -0
- package/dist/.next/server/app/api/time-travel/preview/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/time-travel/preview/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/time-travel/restore/route.js +1 -0
- package/dist/.next/server/app/api/time-travel/restore/route.js.nft.json +1 -0
- package/dist/.next/server/app/api/time-travel/restore/route_client-reference-manifest.js +1 -0
- package/dist/.next/server/app/api/update/route.js +1 -1
- package/dist/.next/server/app/api/update/route.js.nft.json +1 -1
- package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/index.html +5 -3
- package/dist/.next/server/app/index.rsc +6 -6
- package/dist/.next/server/app/page.js +15 -15
- 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 +11 -5
- package/dist/.next/server/chunks/226.js +12 -12
- package/dist/.next/server/chunks/391.js +1 -1
- package/dist/.next/server/chunks/452.js +1 -1
- package/dist/.next/server/chunks/487.js +1 -0
- package/dist/.next/server/chunks/572.js +1 -1
- package/dist/.next/server/chunks/992.js +3 -3
- package/dist/.next/server/chunks/{638.js → 994.js} +3 -3
- package/dist/.next/server/middleware-build-manifest.js +1 -1
- package/dist/.next/server/middleware-react-loadable-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-manifest.json +1 -1
- package/dist/.next/server/server-reference-manifest.json +1 -1
- package/dist/.next/static/chunks/1a258343.3b3e7ba5ba0bd0d2.js +1 -0
- package/dist/.next/static/chunks/345.8fc37569d5708622.js +1 -0
- package/dist/.next/static/chunks/480-85b6c8ae3f51b156.js +1 -0
- package/dist/.next/static/chunks/52.2cdc9bdb75e1fc2e.js +1 -0
- package/dist/.next/static/chunks/803-a2fcfbd00e6b3b38.js +1 -0
- package/dist/.next/static/chunks/{92-5f7522943fcb72a8.js → 92-a84bdac2be7c8d7a.js} +1 -1
- package/dist/.next/static/chunks/app/api/cloudflare/route-d0c1dc2a9e7dce36.js +1 -0
- package/dist/.next/static/chunks/app/api/databases/route-cd322321212797cf.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/list/route-cd710ff75b6bcd02.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync/route-ee522f232b9f0a9c.js +1 -0
- package/dist/.next/static/chunks/app/api/migrations/sync-files/route-79ee2c26f87d3bc7.js +1 -0
- package/dist/.next/static/chunks/app/api/pro/route-c90c1f901fc00d38.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-data/confirm/route-118764086af798f8.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-2b0ade4ebfcea0bc.js +1 -0
- package/dist/.next/static/chunks/app/api/pull-remote/preview/route-342db7ea13e6f447.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/confirm/route-b778c053bd515abd.js +1 -0
- package/dist/.next/static/chunks/app/api/push-remote/preview/route-ab090482f299f57f.js +1 -0
- package/dist/.next/static/chunks/app/api/query/route-4d21a8b1d34491f1.js +1 -0
- package/dist/.next/static/chunks/app/api/schema/route-cb17a387d6b557ad.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/[name]/import/route-510472de7a5c29bd.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/[name]/route-6a1fa95c303ce0de.js +1 -0
- package/dist/.next/static/chunks/app/api/tables/route-daa975df4ea8e8f8.js +1 -0
- package/dist/.next/static/chunks/app/api/time-travel/preview/route-5787d7e8f17bd539.js +1 -0
- package/dist/.next/static/chunks/app/api/time-travel/restore/route-84b64a27e831e21c.js +1 -0
- package/dist/.next/static/chunks/app/api/update/route-54ee900537982652.js +1 -0
- package/dist/.next/static/chunks/app/{layout-40ec07d04681ba81.js → layout-f0ec4d636ee0f763.js} +1 -1
- package/dist/.next/static/chunks/app/page-358bf2112802ff85.js +1 -0
- package/dist/.next/static/chunks/webpack-024900a94af4f0a7.js +1 -0
- package/dist/.next/static/css/2c165a0ede9b2442.css +3 -0
- package/dist/.next/static/css/32df9a4d493f8b0f.css +31 -0
- package/dist/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/.next/static/zh4Fz2tbm8GRka4woRrGp/_buildManifest.js +1 -0
- package/dist/.next/static/zh4Fz2tbm8GRka4woRrGp/_ssgManifest.js +1 -0
- package/dist/.next/trace +18 -3
- package/dist/.next/types/app/api/migrations/list/route.ts +347 -0
- package/dist/.next/types/app/api/pro/route.ts +347 -0
- package/dist/.next/types/app/api/schema/route.ts +347 -0
- package/dist/.next/types/app/api/tables/[name]/import/route.ts +347 -0
- package/dist/.next/types/app/api/time-travel/preview/route.ts +347 -0
- package/dist/.next/types/app/api/time-travel/restore/route.ts +347 -0
- package/dist/app/api/databases/route.js +2 -1
- package/dist/app/api/migrations/list/route.js +137 -0
- package/dist/app/api/migrations/sync-files/route.js +2 -1
- package/dist/app/api/pro/route.js +7 -0
- package/dist/app/api/pull-remote/confirm/route.js +138 -146
- package/dist/app/api/pull-remote/preview/route.js +49 -84
- package/dist/app/api/push-remote/confirm/route.js +31 -12
- package/dist/app/api/push-remote/preview/route.js +27 -12
- package/dist/app/api/query/route.js +24 -13
- package/dist/app/api/schema/route.js +63 -0
- package/dist/app/api/tables/[name]/import/route.js +112 -0
- package/dist/app/api/tables/[name]/route.js +38 -29
- package/dist/app/api/tables/route.js +29 -16
- package/dist/app/api/time-travel/preview/route.js +122 -0
- package/dist/app/api/time-travel/restore/route.js +106 -0
- package/dist/app/page.jsx +26 -8
- package/dist/d1-studio.js +129 -23
- package/dist/lib/license.js +99 -71
- package/dist/lib/local-db.js +223 -0
- package/dist/lib/migrations.js +40 -2
- package/dist/lib/parse-sql-error.js +99 -160
- package/dist/lib/sql-operations.js +28 -10
- package/dist/lib/telemetry.js +39 -0
- package/package.json +6 -2
- package/dist/.next/.next/static/FEsQ9jwPUQv5A3fwg6Opl/_buildManifest.js +0 -1
- package/dist/.next/.next/static/Y9mYu4WBghepP5oT_3OdR/_buildManifest.js +0 -1
- package/dist/.next/.next/static/ae3gNmoSGm-R5LJC4UagI/_buildManifest.js +0 -1
- package/dist/.next/.next/static/bKfUJeuvAQlBmR3TjrfkH/_buildManifest.js +0 -1
- package/dist/.next/.next/static/chunks/576-18a2209e1ed26aad.js +0 -1
- package/dist/.next/.next/static/chunks/735-b885dfec6353171d.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +0 -1
- package/dist/.next/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +0 -1
- package/dist/.next/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +0 -1
- package/dist/.next/.next/static/chunks/app/page-f2bc307c0d8acdaa.js +0 -1
- package/dist/.next/.next/static/chunks/webpack-c76ac1e586b2802a.js +0 -1
- package/dist/.next/.next/static/css/7c16f57d325d0d7d.css +0 -3
- package/dist/.next/.next/static/ejYPqJ2kVicVp5EFWOZIC/_buildManifest.js +0 -1
- package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_buildManifest.js +0 -1
- package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_buildManifest.js +0 -1
- package/dist/.next/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/dist/.next/.next/static/thaCy2qVeNqYYhdayr13C/_buildManifest.js +0 -1
- package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_buildManifest.js +0 -1
- package/dist/.next/cache/webpack/client-production/1.pack +0 -0
- package/dist/.next/cache/webpack/client-production/2.pack +0 -0
- package/dist/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_buildManifest.js +0 -1
- package/dist/.next/static/chunks/576-18a2209e1ed26aad.js +0 -1
- package/dist/.next/static/chunks/735-b885dfec6353171d.js +0 -1
- package/dist/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +0 -1
- package/dist/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +0 -1
- package/dist/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +0 -1
- package/dist/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +0 -1
- package/dist/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +0 -1
- package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +0 -1
- package/dist/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +0 -1
- package/dist/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +0 -1
- package/dist/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +0 -1
- package/dist/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +0 -1
- package/dist/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +0 -1
- package/dist/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +0 -1
- package/dist/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +0 -1
- package/dist/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +0 -1
- package/dist/.next/static/chunks/webpack-c76ac1e586b2802a.js +0 -1
- package/dist/.next/static/css/7c16f57d325d0d7d.css +0 -3
- package/dist/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- /package/dist/.next/.next/static/{FEsQ9jwPUQv5A3fwg6Opl → -OO4tE7EKr8o62Bne-ODo}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{Y9mYu4WBghepP5oT_3OdR → 3kAeIJC56X7aw1Fk5_OXO}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{ae3gNmoSGm-R5LJC4UagI → J8r9W6xxmYYvuKehItNuW}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{bKfUJeuvAQlBmR3TjrfkH → ZmKZbpam0G_d3SphfZPJ7}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{ejYPqJ2kVicVp5EFWOZIC → arc9h7hbaQzL1Dl0iuVrT}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/chunks/{4bd1b696-8c908eb707f85a27.js → 4bd1b696-124ea104c06f6cea.js} +0 -0
- /package/dist/.next/.next/static/chunks/{517-3b698a5d3da06ff7.js → 517-c876ce2f00030cd0.js} +0 -0
- /package/dist/.next/.next/static/chunks/{692-ede418e1d28a1394.js → 692-9e59d546afd11ec3.js} +0 -0
- /package/dist/.next/.next/static/chunks/app/_not-found/{page-b786c3dd79ad15a5.js → page-3e24b81707d98126.js} +0 -0
- /package/dist/.next/.next/static/{gABGrAoO8IPArDo_Ns_7g → f_PVCmmSeM5SwW3M1tw7Q}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{gh-QfIUVo4FTTduYCVKT6 → fiesjBWbrmSSyLf4biwrX}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{thaCy2qVeNqYYhdayr13C → ft39e6W6vSgUL7peRo7pE}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{ybCx6L6gHqtODbKmlhU-d → u7ssdTycF4iQ-w-pQZhxg}/_ssgManifest.js +0 -0
- /package/dist/.next/{static/IX-QLbm7scYnyqWeeimal → .next/static/v-i2YsOGT890zutOSiqqK}/_ssgManifest.js +0 -0
- /package/dist/.next/static/chunks/{4bd1b696-8c908eb707f85a27.js → 4bd1b696-124ea104c06f6cea.js} +0 -0
- /package/dist/.next/static/chunks/{517-3b698a5d3da06ff7.js → 517-c876ce2f00030cd0.js} +0 -0
- /package/dist/.next/static/chunks/{692-ede418e1d28a1394.js → 692-9e59d546afd11ec3.js} +0 -0
- /package/dist/.next/static/chunks/app/_not-found/{page-b786c3dd79ad15a5.js → page-3e24b81707d98126.js} +0 -0
|
@@ -5,7 +5,9 @@ import { promisify } from 'util';
|
|
|
5
5
|
import { exec } from 'child_process';
|
|
6
6
|
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
7
7
|
import { dbQueue } from '@/lib/database-queue';
|
|
8
|
+
import { executeLocalSQL } from '@/lib/local-db.js';
|
|
8
9
|
import logger from '@/lib/logger';
|
|
10
|
+
import { parseSQLError } from '@/lib/parse-sql-error';
|
|
9
11
|
import { sanitizeTableName, sanitizeColumnName } from '@/lib/sql-sanitizer.js';
|
|
10
12
|
|
|
11
13
|
const execAsync = promisify(exec);
|
|
@@ -17,27 +19,30 @@ export const dynamic = 'force-dynamic';
|
|
|
17
19
|
let isProcessing = false;
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
|
-
* Executes a D1 SQL query
|
|
21
|
-
* This function ensures that only one query is processed at a time.
|
|
22
|
+
* Executes a D1 SQL query, preferring direct SQLite access over the wrangler CLI.
|
|
22
23
|
*/
|
|
23
|
-
async function executeD1Query(
|
|
24
|
+
async function executeD1Query(sql, projectDir, dbConfig) {
|
|
25
|
+
// Try direct SQLite access first (fast path)
|
|
26
|
+
const localOutput = executeLocalSQL(projectDir, dbConfig, sql);
|
|
27
|
+
if (localOutput !== null) {
|
|
28
|
+
const parsed = JSON.parse(localOutput);
|
|
29
|
+
return parsed[0]?.results || [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Fall back to wrangler CLI
|
|
33
|
+
const databaseName = dbConfig.database_name;
|
|
24
34
|
try {
|
|
25
|
-
// Wait until any current query is finished.
|
|
26
35
|
while (isProcessing) {
|
|
27
36
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
28
37
|
}
|
|
29
38
|
isProcessing = true;
|
|
30
|
-
|
|
31
|
-
// Escape double quotes in the command and execute the query
|
|
32
39
|
const { stdout } = await execAsync(
|
|
33
|
-
`wrangler d1 execute ${databaseName} --local --command="${
|
|
40
|
+
`wrangler d1 execute ${databaseName} --local --command="${sql.replace(/"/g, '\\"')}" --json`,
|
|
34
41
|
{ cwd: projectDir }
|
|
35
42
|
);
|
|
36
|
-
|
|
37
43
|
const result = JSON.parse(stdout);
|
|
38
44
|
return result[0]?.results || [];
|
|
39
45
|
} catch (error) {
|
|
40
|
-
logger.error('Query execution error:', error);
|
|
41
46
|
throw error;
|
|
42
47
|
} finally {
|
|
43
48
|
isProcessing = false;
|
|
@@ -81,6 +86,8 @@ export async function GET(request, context) {
|
|
|
81
86
|
const page = parseInt(searchParams.get('page')) || 1;
|
|
82
87
|
const limit = parseInt(searchParams.get('limit')) || 50;
|
|
83
88
|
const offset = (page - 1) * limit;
|
|
89
|
+
const isExport = searchParams.get('export') === 'true';
|
|
90
|
+
const dbParam = searchParams.get('db');
|
|
84
91
|
|
|
85
92
|
const projectDir = process.env.D1_PROJECT_DIR;
|
|
86
93
|
if (!projectDir) {
|
|
@@ -96,21 +103,23 @@ export async function GET(request, context) {
|
|
|
96
103
|
if (!config.d1_databases?.length) {
|
|
97
104
|
throw new Error('No D1 databases configured');
|
|
98
105
|
}
|
|
99
|
-
//
|
|
100
|
-
const
|
|
106
|
+
// Resolve target database — use ?db param if provided, else fall back to first
|
|
107
|
+
const dbConfig = dbParam
|
|
108
|
+
? config.d1_databases.find(d => d.database_name === dbParam)
|
|
109
|
+
: config.d1_databases[0];
|
|
110
|
+
if (!dbConfig) throw new Error(`Database not found: ${dbParam}`);
|
|
111
|
+
const databaseName = dbConfig.database_name;
|
|
101
112
|
|
|
102
113
|
// Validate and sanitize table name to prevent SQL injection
|
|
103
114
|
const sanitizedTableName = sanitizeTableName(name);
|
|
104
115
|
|
|
105
116
|
// Get table schema using PRAGMA query (PRAGMA is safe from injection when table name is sanitized)
|
|
106
117
|
const schemaQuery = `PRAGMA table_info(${sanitizedTableName});`;
|
|
107
|
-
const schema = await executeD1Query(schemaQuery, projectDir,
|
|
118
|
+
const schema = await executeD1Query(schemaQuery, projectDir, dbConfig);
|
|
108
119
|
|
|
109
|
-
// Get the CREATE TABLE statement from sqlite_master
|
|
110
|
-
const createTableQuery = `SELECT sql FROM sqlite_master WHERE type='table' AND name = ?;`;
|
|
111
|
-
// Note: executeD1Query would need to support parameters, for now we sanitize the table name
|
|
120
|
+
// Get the CREATE TABLE statement from sqlite_master
|
|
112
121
|
const createTableQuerySafe = `SELECT sql FROM sqlite_master WHERE type='table' AND name='${name.replace(/'/g, "''")}';`;
|
|
113
|
-
const tableDefinition = await executeD1Query(createTableQuerySafe, projectDir,
|
|
122
|
+
const tableDefinition = await executeD1Query(createTableQuerySafe, projectDir, dbConfig);
|
|
114
123
|
const createTableSQL = tableDefinition[0]?.sql || '';
|
|
115
124
|
|
|
116
125
|
// Extract CHECK constraints from the CREATE TABLE statement
|
|
@@ -124,23 +133,25 @@ export async function GET(request, context) {
|
|
|
124
133
|
|
|
125
134
|
// Get total row count for the table (using sanitized table name)
|
|
126
135
|
const countQuery = `SELECT COUNT(*) as total FROM ${sanitizedTableName};`;
|
|
127
|
-
const countResult = await executeD1Query(countQuery, projectDir,
|
|
136
|
+
const countResult = await executeD1Query(countQuery, projectDir, dbConfig);
|
|
128
137
|
const totalRows = countResult[0]?.total || 0;
|
|
129
138
|
|
|
130
139
|
// Fetch paginated data using the primary key column for ordering
|
|
131
140
|
const primaryKeyColumn = schema.find(col => col.pk === 1)?.name || schema[0]?.name;
|
|
132
141
|
const sanitizedPrimaryKey = primaryKeyColumn ? sanitizeColumnName(primaryKeyColumn) : '*';
|
|
133
|
-
|
|
134
|
-
//
|
|
135
|
-
const safeLimitNum =
|
|
142
|
+
|
|
143
|
+
// For exports, skip the 1000-row cap; otherwise cap to prevent huge reads
|
|
144
|
+
const safeLimitNum = isExport
|
|
145
|
+
? Math.max(1, parseInt(limit) || 99999)
|
|
146
|
+
: Math.max(1, Math.min(parseInt(limit) || 50, 1000));
|
|
136
147
|
const safeOffsetNum = Math.max(0, parseInt(offset) || 0);
|
|
137
|
-
|
|
148
|
+
|
|
138
149
|
const dataQuery = `
|
|
139
|
-
SELECT * FROM ${sanitizedTableName}
|
|
140
|
-
ORDER BY ${sanitizedPrimaryKey} DESC
|
|
150
|
+
SELECT * FROM ${sanitizedTableName}
|
|
151
|
+
ORDER BY ${sanitizedPrimaryKey} DESC
|
|
141
152
|
LIMIT ${safeLimitNum} OFFSET ${safeOffsetNum};
|
|
142
153
|
`;
|
|
143
|
-
const data = await executeD1Query(dataQuery, projectDir,
|
|
154
|
+
const data = await executeD1Query(dataQuery, projectDir, dbConfig);
|
|
144
155
|
|
|
145
156
|
return NextResponse.json({
|
|
146
157
|
success: true,
|
|
@@ -158,13 +169,11 @@ export async function GET(request, context) {
|
|
|
158
169
|
});
|
|
159
170
|
|
|
160
171
|
} catch (error) {
|
|
161
|
-
|
|
172
|
+
const parsed = parseSQLError(error);
|
|
173
|
+
logger.error(`✗ ${parsed.message}`);
|
|
162
174
|
return NextResponse.json({
|
|
163
175
|
success: false,
|
|
164
|
-
error: {
|
|
165
|
-
message: error.message,
|
|
166
|
-
details: error.stack
|
|
167
|
-
}
|
|
176
|
+
error: { message: parsed.message }
|
|
168
177
|
}, {
|
|
169
178
|
status: error.message.includes('not configured') ? 500 :
|
|
170
179
|
error.message.includes('not found') ? 404 : 500
|
|
@@ -4,6 +4,7 @@ import { NextResponse } from 'next/server';
|
|
|
4
4
|
import { promisify } from 'util';
|
|
5
5
|
import { exec } from 'child_process';
|
|
6
6
|
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
7
|
+
import { executeLocalSQL } from '@/lib/local-db.js';
|
|
7
8
|
import logger from '@/lib/logger';
|
|
8
9
|
|
|
9
10
|
const execAsync = promisify(exec);
|
|
@@ -75,10 +76,13 @@ async function retryWithTimeout(fn, retries = 3, timeout = 1000) {
|
|
|
75
76
|
* GET handler for listing tables.
|
|
76
77
|
* It uses the Wrangler configuration (via findWranglerConfig) to determine the D1 database.
|
|
77
78
|
*/
|
|
78
|
-
export async function GET() {
|
|
79
|
+
export async function GET(request) {
|
|
79
80
|
logger.logRequest('GET', '/api/tables');
|
|
80
81
|
|
|
81
82
|
try {
|
|
83
|
+
const { searchParams } = new URL(request.url);
|
|
84
|
+
const dbParam = searchParams.get('db');
|
|
85
|
+
|
|
82
86
|
const projectDir = process.env.D1_PROJECT_DIR;
|
|
83
87
|
|
|
84
88
|
if (!projectDir) {
|
|
@@ -105,8 +109,14 @@ export async function GET() {
|
|
|
105
109
|
{ status: 404 }
|
|
106
110
|
);
|
|
107
111
|
}
|
|
108
|
-
//
|
|
109
|
-
const
|
|
112
|
+
// Resolve target database — use ?db param if provided, else fall back to first
|
|
113
|
+
const dbConfig = dbParam
|
|
114
|
+
? config.d1_databases.find(d => d.database_name === dbParam)
|
|
115
|
+
: config.d1_databases[0];
|
|
116
|
+
if (!dbConfig) {
|
|
117
|
+
return NextResponse.json({ error: `Database not found: ${dbParam}` }, { status: 404 });
|
|
118
|
+
}
|
|
119
|
+
const databaseName = dbConfig.database_name;
|
|
110
120
|
|
|
111
121
|
// SQL query to list non-system tables
|
|
112
122
|
const query = `
|
|
@@ -117,19 +127,22 @@ export async function GET() {
|
|
|
117
127
|
ORDER BY name;
|
|
118
128
|
`;
|
|
119
129
|
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
// Try direct SQLite access first (fast), fall back to wrangler CLI
|
|
131
|
+
let result;
|
|
132
|
+
const localOutput = executeLocalSQL(projectDir, dbConfig, query.trim());
|
|
133
|
+
if (localOutput !== null) {
|
|
134
|
+
result = JSON.parse(localOutput);
|
|
135
|
+
} else {
|
|
136
|
+
const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
137
|
+
const { stdout } = await retryWithTimeout(async () => {
|
|
138
|
+
return execAsync(
|
|
139
|
+
`${npxCmd} wrangler d1 execute ${databaseName} --local --json --command="${query.trim().replace(/\n\s*/g, ' ')}"`,
|
|
140
|
+
{ cwd: projectDir, timeout: 10000 }
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
result = extractJSONFromOutput(stdout);
|
|
144
|
+
}
|
|
145
|
+
|
|
133
146
|
const tables = extractTablesFromResult(result);
|
|
134
147
|
|
|
135
148
|
return NextResponse.json({
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// api/time-travel/preview/route.js
|
|
2
|
+
// GET → current bookmark + window info (no timestamp)
|
|
3
|
+
// POST → bookmark for a specific timestamp
|
|
4
|
+
|
|
5
|
+
import { NextResponse } from 'next/server';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
import { exec } from 'child_process';
|
|
8
|
+
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
9
|
+
import logger from '@/lib/logger';
|
|
10
|
+
|
|
11
|
+
const execAsync = promisify(exec);
|
|
12
|
+
|
|
13
|
+
async function resolveDb(req) {
|
|
14
|
+
const { searchParams } = new URL(req.url);
|
|
15
|
+
const db = searchParams.get('db');
|
|
16
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
17
|
+
if (!projectDir) throw Object.assign(new Error('Project directory not configured'), { status: 500 });
|
|
18
|
+
|
|
19
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
20
|
+
if (!wranglerResult?.config) throw Object.assign(new Error('No Wrangler configuration found'), { status: 400 });
|
|
21
|
+
|
|
22
|
+
const config = wranglerResult.config;
|
|
23
|
+
if (!config.d1_databases?.length) throw Object.assign(new Error('No D1 databases configured'), { status: 400 });
|
|
24
|
+
|
|
25
|
+
const dbConfig = db
|
|
26
|
+
? config.d1_databases.find(d => d.database_name === db)
|
|
27
|
+
: config.d1_databases[0];
|
|
28
|
+
if (!dbConfig) throw Object.assign(new Error(`Database not found: ${db}`), { status: 404 });
|
|
29
|
+
|
|
30
|
+
return { projectDir, databaseName: dbConfig.database_name };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseBookmark(raw) {
|
|
34
|
+
const clean = (raw || '').replace(/\x1B\[[0-9;]*m/g, '');
|
|
35
|
+
const jsonStart = clean.indexOf('{');
|
|
36
|
+
const jsonEnd = clean.lastIndexOf('}');
|
|
37
|
+
if (jsonStart !== -1 && jsonEnd !== -1) {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(clean.slice(jsonStart, jsonEnd + 1));
|
|
40
|
+
return parsed.bookmark ?? parsed.result?.bookmark ?? null;
|
|
41
|
+
} catch { /* fall through */ }
|
|
42
|
+
}
|
|
43
|
+
const match = clean.match(/bookmark[:\s]+([0-9a-f-]+)/i);
|
|
44
|
+
return match ? match[1] : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** GET /api/time-travel/preview?db=name — returns current (latest) bookmark */
|
|
48
|
+
export async function GET(req) {
|
|
49
|
+
if (process.env.D1_IS_PRO !== 'true') {
|
|
50
|
+
return NextResponse.json({ success: false, error: { type: 'PRO_REQUIRED', message: 'Pro license required. Run: d1s --license YOUR-KEY' } }, { status: 402 });
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const { projectDir, databaseName } = await resolveDb(req);
|
|
54
|
+
const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
55
|
+
const command = `${npxCmd} wrangler d1 time-travel info ${databaseName} --json`;
|
|
56
|
+
logger.debug(`Time travel GET: ${command}`);
|
|
57
|
+
|
|
58
|
+
const { stdout } = await execAsync(command, {
|
|
59
|
+
cwd: projectDir, env: process.env,
|
|
60
|
+
maxBuffer: 1024 * 1024 * 4, shell: true,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const bookmark = parseBookmark(stdout);
|
|
64
|
+
return NextResponse.json({ success: true, currentBookmark: bookmark, databaseName });
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const strip = s => (s || '').replace(/\x1B\[[0-9;]*m/g, '').trim();
|
|
67
|
+
const msg = strip(error.stderr) || strip(error.stdout) || strip(error.message) || 'Failed to get time travel info';
|
|
68
|
+
logger.error(`Time travel GET error: ${msg}`);
|
|
69
|
+
return NextResponse.json({ success: false, error: msg }, { status: error.status || 500 });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function POST(req) {
|
|
74
|
+
if (process.env.D1_IS_PRO !== 'true') {
|
|
75
|
+
return NextResponse.json({ success: false, error: { type: 'PRO_REQUIRED', message: 'Pro license required. Run: d1s --license YOUR-KEY' } }, { status: 402 });
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const body = await req.json();
|
|
79
|
+
const { timestamp } = body;
|
|
80
|
+
if (!timestamp) {
|
|
81
|
+
return NextResponse.json({ success: false, error: 'timestamp is required' }, { status: 400 });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Re-use resolveDb but from body.db
|
|
85
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
86
|
+
if (!projectDir) return NextResponse.json({ success: false, error: 'Project directory not configured' }, { status: 500 });
|
|
87
|
+
|
|
88
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
89
|
+
if (!wranglerResult?.config) return NextResponse.json({ success: false, error: 'No Wrangler configuration found' }, { status: 400 });
|
|
90
|
+
|
|
91
|
+
const config = wranglerResult.config;
|
|
92
|
+
if (!config.d1_databases?.length) return NextResponse.json({ success: false, error: 'No D1 databases configured' }, { status: 400 });
|
|
93
|
+
|
|
94
|
+
const dbConfig = body.db
|
|
95
|
+
? config.d1_databases.find(d => d.database_name === body.db)
|
|
96
|
+
: config.d1_databases[0];
|
|
97
|
+
if (!dbConfig) return NextResponse.json({ success: false, error: `Database not found: ${body.db}` }, { status: 404 });
|
|
98
|
+
|
|
99
|
+
const { database_name: databaseName } = dbConfig;
|
|
100
|
+
const unixTs = Math.floor(new Date(timestamp).getTime() / 1000);
|
|
101
|
+
const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
102
|
+
const command = `${npxCmd} wrangler d1 time-travel info ${databaseName} --timestamp=${unixTs} --json`;
|
|
103
|
+
logger.debug(`Time travel POST: ${command}`);
|
|
104
|
+
|
|
105
|
+
const { stdout } = await execAsync(command, {
|
|
106
|
+
cwd: projectDir, env: process.env,
|
|
107
|
+
maxBuffer: 1024 * 1024 * 4, shell: true,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const bookmark = parseBookmark(stdout);
|
|
111
|
+
return NextResponse.json({ success: true, bookmark, databaseName });
|
|
112
|
+
} catch (error) {
|
|
113
|
+
const strip = s => (s || '').replace(/\x1B\[[0-9;]*m/g, '').trim();
|
|
114
|
+
const msg = strip(error.stderr) || strip(error.stdout) || strip(error.message) || 'Failed to get time travel info';
|
|
115
|
+
logger.error(`Time travel preview error: ${msg}`);
|
|
116
|
+
return NextResponse.json({ success: false, error: msg }, { status: 500 });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function OPTIONS() {
|
|
121
|
+
return new NextResponse(null, { status: 204 });
|
|
122
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// api/time-travel/restore/route.js
|
|
2
|
+
// Calls `wrangler d1 time-travel restore` to roll back a remote D1 database.
|
|
3
|
+
|
|
4
|
+
import { NextResponse } from 'next/server';
|
|
5
|
+
import { promisify } from 'util';
|
|
6
|
+
import { exec } from 'child_process';
|
|
7
|
+
import { findWranglerConfig } from '@/lib/find-wrangler-config.js';
|
|
8
|
+
import logger from '@/lib/logger';
|
|
9
|
+
|
|
10
|
+
const execAsync = promisify(exec);
|
|
11
|
+
|
|
12
|
+
export async function POST(req) {
|
|
13
|
+
if (process.env.D1_IS_PRO !== 'true') {
|
|
14
|
+
return NextResponse.json({ success: false, error: { type: 'PRO_REQUIRED', message: 'Pro license required. Run: d1s --license YOUR-KEY' } }, { status: 402 });
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const { db, bookmark, timestamp } = await req.json();
|
|
18
|
+
|
|
19
|
+
if (!bookmark && !timestamp) {
|
|
20
|
+
return NextResponse.json(
|
|
21
|
+
{ success: false, error: 'bookmark or timestamp is required' },
|
|
22
|
+
{ status: 400 }
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const projectDir = process.env.D1_PROJECT_DIR;
|
|
27
|
+
if (!projectDir) {
|
|
28
|
+
return NextResponse.json({ success: false, error: 'Project directory not configured' }, { status: 500 });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const wranglerResult = await findWranglerConfig(projectDir);
|
|
32
|
+
if (!wranglerResult?.config) {
|
|
33
|
+
return NextResponse.json({ success: false, error: 'No Wrangler configuration found' }, { status: 400 });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const config = wranglerResult.config;
|
|
37
|
+
if (!config.d1_databases?.length) {
|
|
38
|
+
return NextResponse.json({ success: false, error: 'No D1 databases configured' }, { status: 400 });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const dbConfig = db
|
|
42
|
+
? config.d1_databases.find(d => d.database_name === db)
|
|
43
|
+
: config.d1_databases[0];
|
|
44
|
+
|
|
45
|
+
if (!dbConfig) {
|
|
46
|
+
return NextResponse.json({ success: false, error: `Database not found: ${db}` }, { status: 404 });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const databaseName = dbConfig.database_name;
|
|
50
|
+
const isWindows = process.platform === 'win32';
|
|
51
|
+
const npxCmd = isWindows ? 'npx.cmd' : 'npx';
|
|
52
|
+
|
|
53
|
+
// Prefer explicit bookmark; fall back to timestamp
|
|
54
|
+
let command;
|
|
55
|
+
if (bookmark) {
|
|
56
|
+
command = `${npxCmd} wrangler d1 time-travel restore ${databaseName} --bookmark=${bookmark} --json`;
|
|
57
|
+
} else {
|
|
58
|
+
const unixTs = Math.floor(new Date(timestamp).getTime() / 1000);
|
|
59
|
+
command = `${npxCmd} wrangler d1 time-travel restore ${databaseName} --timestamp=${unixTs} --json`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
logger.debug('Time travel restore command:', command);
|
|
63
|
+
|
|
64
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
65
|
+
cwd: projectDir,
|
|
66
|
+
env: process.env,
|
|
67
|
+
maxBuffer: 1024 * 1024 * 4,
|
|
68
|
+
shell: true,
|
|
69
|
+
timeout: 120000, // 2 min timeout for restore
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const clean = stdout.replace(/\x1B\[[0-9;]*m/g, '');
|
|
73
|
+
|
|
74
|
+
// Try to extract undo bookmark from output
|
|
75
|
+
let undoBookmark = null;
|
|
76
|
+
const undoMatch = clean.match(/undo[^:]*bookmark[:\s]+([0-9a-f-]+)/i) ||
|
|
77
|
+
clean.match(/pre.?restore[^:]*bookmark[:\s]+([0-9a-f-]+)/i) ||
|
|
78
|
+
clean.match(/saved[^:]*bookmark[:\s]+([0-9a-f-]+)/i);
|
|
79
|
+
if (undoMatch) undoBookmark = undoMatch[1];
|
|
80
|
+
|
|
81
|
+
// Also try JSON parse
|
|
82
|
+
const jsonStart = clean.indexOf('{');
|
|
83
|
+
const jsonEnd = clean.lastIndexOf('}');
|
|
84
|
+
if (jsonStart !== -1 && jsonEnd !== -1) {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(clean.slice(jsonStart, jsonEnd + 1));
|
|
87
|
+
if (!undoBookmark) {
|
|
88
|
+
undoBookmark = parsed.undoBookmark ?? parsed.undo_bookmark ?? parsed.result?.undoBookmark ?? null;
|
|
89
|
+
}
|
|
90
|
+
} catch { /* ignore */ }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return NextResponse.json({ success: true, undoBookmark, databaseName });
|
|
94
|
+
} catch (error) {
|
|
95
|
+
const strip = s => (s || '').replace(/\x1B\[[0-9;]*m/g, '').trim();
|
|
96
|
+
const stderr = strip(error.stderr);
|
|
97
|
+
const stdout = strip(error.stdout);
|
|
98
|
+
const msg = stderr || stdout || strip(error.message) || 'Restore failed';
|
|
99
|
+
logger.error(`Time travel restore error: ${msg}`);
|
|
100
|
+
return NextResponse.json({ success: false, error: msg }, { status: 500 });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function OPTIONS() {
|
|
105
|
+
return new NextResponse(null, { status: 204 });
|
|
106
|
+
}
|
package/dist/app/page.jsx
CHANGED
|
@@ -5,30 +5,48 @@ import { useState } from 'react';
|
|
|
5
5
|
import { AppSidebar } from '../components/sidebar';
|
|
6
6
|
import { SQLEditor } from '../components/sql-editor';
|
|
7
7
|
import { TableView } from '../components/table-view';
|
|
8
|
+
import { MigrationsView } from '../components/migrations-view';
|
|
9
|
+
import { SchemaView } from '../components/schema-view';
|
|
10
|
+
import { TimeTravelView } from '../components/time-travel-view';
|
|
11
|
+
import { RemoteSyncView } from '../components/remote-sync-view';
|
|
12
|
+
import { StatusBar } from '../components/status-bar';
|
|
8
13
|
|
|
9
14
|
export default function StudioPage() {
|
|
10
15
|
const [currentView, setCurrentView] = useState('sql-editor');
|
|
11
16
|
const [selectedTable, setSelectedTable] = useState(null);
|
|
17
|
+
const [initialSqlQuery, setInitialSqlQuery] = useState('');
|
|
12
18
|
|
|
13
19
|
const handleTableSelect = (tableName) => {
|
|
14
20
|
setSelectedTable(tableName);
|
|
15
21
|
setCurrentView('table-view');
|
|
16
22
|
};
|
|
17
23
|
|
|
24
|
+
const handleOpenInSQL = (sql) => {
|
|
25
|
+
setInitialSqlQuery(sql);
|
|
26
|
+
setCurrentView('sql-editor');
|
|
27
|
+
};
|
|
28
|
+
|
|
18
29
|
return (
|
|
19
30
|
<div className="flex h-screen bg-background">
|
|
20
|
-
<AppSidebar
|
|
21
|
-
className="w-64 border-r flex-shrink-0"
|
|
31
|
+
<AppSidebar
|
|
32
|
+
className="w-64 border-r flex-shrink-0"
|
|
22
33
|
currentView={currentView}
|
|
23
34
|
onNavigate={setCurrentView}
|
|
24
35
|
onTableSelect={handleTableSelect}
|
|
25
36
|
/>
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
<div className="flex-1 flex flex-col overflow-hidden">
|
|
38
|
+
<main className="flex-1 overflow-hidden">
|
|
39
|
+
{currentView === 'sql-editor' && <SQLEditor initialQuery={initialSqlQuery} />}
|
|
40
|
+
{currentView === 'schema' && <SchemaView />}
|
|
41
|
+
{currentView === 'migrations' && <MigrationsView />}
|
|
42
|
+
{currentView === 'time-travel' && <TimeTravelView />}
|
|
43
|
+
{currentView === 'remote-sync' && <RemoteSyncView />}
|
|
44
|
+
{currentView === 'table-view' && selectedTable && (
|
|
45
|
+
<TableView tableName={selectedTable} onOpenInSQL={handleOpenInSQL} />
|
|
46
|
+
)}
|
|
47
|
+
</main>
|
|
48
|
+
<StatusBar />
|
|
49
|
+
</div>
|
|
32
50
|
</div>
|
|
33
51
|
);
|
|
34
52
|
}
|