d1s 0.2.4 → 0.2.6
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 +12 -12
- package/dist/.next/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/.next/build-manifest.json +2 -2
- 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/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/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 +2 -2
- 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/sync/route.js +3 -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 +1 -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-remote/confirm/route.js +1 -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 +1 -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 +2 -2
- 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 +2 -2
- 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 +2 -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.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/index.html +3 -3
- package/dist/.next/.next/server/app/index.rsc +3 -3
- package/dist/.next/.next/server/app/page.js +8 -8
- package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/.next/server/app-paths-manifest.json +3 -3
- package/dist/.next/.next/server/chunks/{801.js → 603.js} +1 -1
- package/dist/.next/.next/server/chunks/686.js +23 -0
- 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/server/webpack-runtime.js +1 -1
- package/dist/.next/.next/static/chunks/app/page-79049bfa6cc07e11.js +1 -0
- package/dist/.next/.next/static/css/cf41da7a0d47f779.css +3 -0
- package/dist/.next/.next/trace +3 -3
- package/dist/.next/BUILD_ID +1 -1
- package/dist/.next/app-build-manifest.json +18 -18
- package/dist/.next/app-path-routes-manifest.json +1 -1
- package/dist/.next/build-manifest.json +2 -2
- 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/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 +2 -2
- 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 +3 -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 +1 -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-remote/confirm/route.js +1 -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 +1 -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 +2 -2
- 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 +2 -2
- 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 +2 -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 +4 -4
- 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/index.html +3 -3
- package/dist/.next/server/app/index.rsc +3 -3
- package/dist/.next/server/app/page.js +8 -8
- package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app-paths-manifest.json +7 -7
- package/dist/.next/server/chunks/{801.js → 603.js} +11 -11
- package/dist/.next/server/chunks/686.js +23 -0
- package/dist/.next/server/pages/404.html +1 -1
- package/dist/.next/server/pages/500.html +1 -1
- package/dist/.next/server/server-reference-manifest.json +1 -1
- package/dist/.next/server/webpack-runtime.js +1 -1
- package/dist/.next/static/chunks/app/page-79049bfa6cc07e11.js +1 -0
- package/dist/.next/static/css/cf41da7a0d47f779.css +3 -0
- package/dist/.next/trace +14 -13
- package/dist/app/api/databases/route.js +1 -1
- package/dist/app/api/pull-remote/confirm/route.js +20 -20
- package/dist/app/api/push-remote/confirm/route.js +1 -1
- package/dist/app/api/push-remote/preview/route.js +1 -1
- package/dist/app/api/query/route.js +7 -7
- package/dist/app/app/page.jsx +3 -6
- package/dist/app/page.jsx +3 -6
- package/dist/d1-studio.js +42 -87
- package/dist/lib/find-wrangler-config.js +10 -9
- package/dist/lib/logger.js +19 -0
- package/package.json +3 -2
- package/scripts/studio.js +42 -87
- package/src/app/page.jsx +3 -6
- package/src/components/sidebar.jsx +108 -92
- package/src/lib/find-wrangler-config.js +10 -9
- package/src/lib/logger.js +19 -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/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/server/chunks/973.js +0 -2
- package/dist/.next/.next/static/chunks/app/page-75081ac7a88cb706.js +0 -1
- package/dist/.next/.next/static/css/c51a7ef325e30c16.css +0 -3
- package/dist/.next/.next/static/fSVNB2iNhKcZdXXgESWZk/_buildManifest.js +0 -1
- package/dist/.next/.next/static/fSVNB2iNhKcZdXXgESWZk/_ssgManifest.js +0 -1
- package/dist/.next/.next/static/xzPddcyKcodbwNX_sKljr/_buildManifest.js +0 -1
- package/dist/.next/.next/static/xzPddcyKcodbwNX_sKljr/_ssgManifest.js +0 -1
- package/dist/.next/server/chunks/973.js +0 -2
- package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_buildManifest.js +0 -1
- package/dist/.next/static/OmPVuV0d1lrcjSBQzxkdH/_ssgManifest.js +0 -1
- package/dist/.next/static/chunks/app/page-75081ac7a88cb706.js +0 -1
- package/dist/.next/static/css/c51a7ef325e30c16.css +0 -3
- /package/dist/.next/.next/static/{ODMSSwVqLoDcBgbFHUjr8 → HsZ8OanS5v86DqC9rErO-}/_buildManifest.js +0 -0
- /package/dist/.next/.next/static/{ODMSSwVqLoDcBgbFHUjr8 → HsZ8OanS5v86DqC9rErO-}/_ssgManifest.js +0 -0
- /package/dist/.next/.next/static/{YIuXI2CxMwg2fuuUEBsXL → q6WmQmyONe88bMN0_jrC2}/_buildManifest.js +0 -0
- /package/dist/.next/.next/static/{YIuXI2CxMwg2fuuUEBsXL → q6WmQmyONe88bMN0_jrC2}/_ssgManifest.js +0 -0
- /package/dist/.next/{.next/static/_t0S4u4KzUwKctaxLKvx4 → static/Tk1fnz_CXLavm23ZEeChG}/_buildManifest.js +0 -0
- /package/dist/.next/{.next/static/_t0S4u4KzUwKctaxLKvx4 → static/Tk1fnz_CXLavm23ZEeChG}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
|
|
3
|
+
const { combine, timestamp, printf, colorize } = winston.format;
|
|
4
|
+
|
|
5
|
+
const logFormat = printf(({ level, message, timestamp }) => {
|
|
6
|
+
return `${timestamp} ${level}: ${message}`;
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const logger = winston.createLogger({
|
|
10
|
+
level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
|
|
11
|
+
format: combine(
|
|
12
|
+
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
|
13
|
+
colorize(),
|
|
14
|
+
logFormat
|
|
15
|
+
),
|
|
16
|
+
transports: [new winston.transports.Console()]
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export default logger;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "d1s",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "D1 Studio – a native studio for managing Cloudflare D1 databases.",
|
|
6
6
|
"main": "./dist/d1-studio.js",
|
|
@@ -81,7 +81,8 @@
|
|
|
81
81
|
"react-dom": "^18.2.0",
|
|
82
82
|
"strip-json-comments": "^5.0.1",
|
|
83
83
|
"tailwind-merge": "^2.6.0",
|
|
84
|
-
"tailwindcss-animate": "^1.0.7"
|
|
84
|
+
"tailwindcss-animate": "^1.0.7",
|
|
85
|
+
"winston": "^3.17.0"
|
|
85
86
|
},
|
|
86
87
|
"devDependencies": {
|
|
87
88
|
"@eslint/eslintrc": "^3",
|
package/scripts/studio.js
CHANGED
|
@@ -11,6 +11,7 @@ import express from 'express';
|
|
|
11
11
|
import { createServer } from 'http';
|
|
12
12
|
import next from 'next';
|
|
13
13
|
import { findWranglerConfig } from '../src/lib/find-wrangler-config.js';
|
|
14
|
+
import logger from '../src/lib/logger.js';
|
|
14
15
|
|
|
15
16
|
// Compute the absolute path of this file and its directory.
|
|
16
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -46,14 +47,8 @@ async function validateLicenseRemote(licenseKey, email, hardwareId) {
|
|
|
46
47
|
try {
|
|
47
48
|
const response = await fetch(`${baseUrl}/api/validate-license`, {
|
|
48
49
|
method: 'POST',
|
|
49
|
-
headers: {
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
body: JSON.stringify({
|
|
53
|
-
licenseKey,
|
|
54
|
-
email,
|
|
55
|
-
hardwareId,
|
|
56
|
-
}),
|
|
50
|
+
headers: { 'Content-Type': 'application/json' },
|
|
51
|
+
body: JSON.stringify({ licenseKey, email, hardwareId }),
|
|
57
52
|
});
|
|
58
53
|
|
|
59
54
|
const result = await response.json();
|
|
@@ -65,7 +60,6 @@ async function validateLicenseRemote(licenseKey, email, hardwareId) {
|
|
|
65
60
|
);
|
|
66
61
|
}
|
|
67
62
|
|
|
68
|
-
// Check for subscription expiration if end_date is provided.
|
|
69
63
|
if (result.end_date && new Date(result.end_date) < new Date()) {
|
|
70
64
|
throw new LicenseError(
|
|
71
65
|
'Your subscription has expired. Please renew your license to continue using D1 Studio.',
|
|
@@ -78,7 +72,6 @@ async function validateLicenseRemote(licenseKey, email, hardwareId) {
|
|
|
78
72
|
if (error instanceof LicenseError) {
|
|
79
73
|
throw error;
|
|
80
74
|
}
|
|
81
|
-
|
|
82
75
|
if (error.name === 'TypeError' && error.message.includes('fetch')) {
|
|
83
76
|
throw new LicenseError(
|
|
84
77
|
process.env.NODE_ENV === 'development'
|
|
@@ -87,7 +80,6 @@ async function validateLicenseRemote(licenseKey, email, hardwareId) {
|
|
|
87
80
|
'CONNECTION_ERROR'
|
|
88
81
|
);
|
|
89
82
|
}
|
|
90
|
-
|
|
91
83
|
throw new LicenseError(
|
|
92
84
|
'An unexpected error occurred during license validation',
|
|
93
85
|
'VALIDATION_ERROR'
|
|
@@ -106,7 +98,6 @@ async function checkLicenseFile() {
|
|
|
106
98
|
if (licenseData.hardwareId !== hardwareId) {
|
|
107
99
|
return null;
|
|
108
100
|
}
|
|
109
|
-
|
|
110
101
|
return licenseData;
|
|
111
102
|
} catch (error) {
|
|
112
103
|
return null;
|
|
@@ -127,22 +118,19 @@ async function saveLicenseFile(licenseData) {
|
|
|
127
118
|
|
|
128
119
|
async function startServer(port, projectDirectory) {
|
|
129
120
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
//
|
|
133
|
-
// In production (published package), __dirname is in the 'dist' folder so we use it directly.
|
|
134
|
-
// In development, we assume the structure is different and go one level up.
|
|
121
|
+
// Determine Next.js app directory based on environment:
|
|
122
|
+
// In production (published package) __dirname is used.
|
|
123
|
+
// In development (npm link), assume the build is in the parent folder.
|
|
135
124
|
const isProduction = process.env.NODE_ENV !== 'development';
|
|
136
125
|
const nextAppDir = isProduction ? __dirname : join(__dirname, '..');
|
|
137
126
|
|
|
127
|
+
const dev = process.env.NODE_ENV === 'development';
|
|
138
128
|
const app = next({
|
|
139
129
|
dev,
|
|
140
130
|
dir: nextAppDir,
|
|
141
131
|
conf: {
|
|
142
132
|
distDir: '.next',
|
|
143
|
-
experimental: {
|
|
144
|
-
appDir: true
|
|
145
|
-
}
|
|
133
|
+
experimental: { appDir: true }
|
|
146
134
|
}
|
|
147
135
|
});
|
|
148
136
|
const handle = app.getRequestHandler();
|
|
@@ -150,41 +138,29 @@ async function startServer(port, projectDirectory) {
|
|
|
150
138
|
app.prepare()
|
|
151
139
|
.then(() => {
|
|
152
140
|
const server = express();
|
|
153
|
-
|
|
154
|
-
// Set environment variables
|
|
155
141
|
process.env.PORT = port.toString();
|
|
156
142
|
process.env.D1_PROJECT_DIR = projectDirectory;
|
|
143
|
+
const httpServer = createServer((req, res) => handle(req, res));
|
|
157
144
|
|
|
158
|
-
|
|
159
|
-
const httpServer = createServer((req, res) => {
|
|
160
|
-
handle(req, res);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Handle all requests through Next.js
|
|
164
|
-
server.all('*', (req, res) => {
|
|
165
|
-
return handle(req, res);
|
|
166
|
-
});
|
|
145
|
+
server.all('*', (req, res) => handle(req, res));
|
|
167
146
|
|
|
168
|
-
// Start listening
|
|
169
147
|
httpServer.listen(port, (err) => {
|
|
170
148
|
if (err) {
|
|
171
|
-
|
|
149
|
+
logger.error(chalk.red(`Failed to start server: ${err}`));
|
|
172
150
|
rejectPromise(err);
|
|
173
151
|
return;
|
|
174
152
|
}
|
|
175
|
-
|
|
176
|
-
console.log(chalk.green(`Server started on port ${port}`));
|
|
153
|
+
logger.info(chalk.green(`Server started on port ${port}`));
|
|
177
154
|
resolvePromise(httpServer);
|
|
178
155
|
});
|
|
179
156
|
|
|
180
|
-
// Handle server errors
|
|
181
157
|
httpServer.on('error', (err) => {
|
|
182
|
-
|
|
158
|
+
logger.error(chalk.red(`Server error: ${err}`));
|
|
183
159
|
rejectPromise(err);
|
|
184
160
|
});
|
|
185
161
|
})
|
|
186
162
|
.catch((err) => {
|
|
187
|
-
|
|
163
|
+
logger.error(chalk.red(`Failed to prepare Next.js app: ${err}`));
|
|
188
164
|
rejectPromise(err);
|
|
189
165
|
});
|
|
190
166
|
});
|
|
@@ -192,17 +168,15 @@ async function startServer(port, projectDirectory) {
|
|
|
192
168
|
|
|
193
169
|
async function startStudio() {
|
|
194
170
|
try {
|
|
195
|
-
|
|
171
|
+
logger.info(chalk.green('Initializing D1 Studio...'));
|
|
196
172
|
|
|
197
173
|
// Validate license
|
|
198
174
|
let licenseData = await checkLicenseFile();
|
|
199
|
-
|
|
175
|
+
logger.debug(chalk.blue(`License data found: ${JSON.stringify(licenseData)}`));
|
|
200
176
|
|
|
201
177
|
const TWELVE_HOURS_MS = 43200000; // 12 hours
|
|
202
178
|
let shouldRevalidate = true;
|
|
203
|
-
|
|
204
179
|
if (licenseData) {
|
|
205
|
-
// Use lastValidatedAt if available; otherwise, fall back to activatedAt.
|
|
206
180
|
const lastCheck = new Date(licenseData.lastValidatedAt || licenseData.activatedAt);
|
|
207
181
|
if (Date.now() - lastCheck.getTime() < TWELVE_HOURS_MS) {
|
|
208
182
|
shouldRevalidate = false;
|
|
@@ -211,7 +185,7 @@ async function startStudio() {
|
|
|
211
185
|
|
|
212
186
|
if (!licenseData || shouldRevalidate) {
|
|
213
187
|
const { default: inquirer } = await import('inquirer');
|
|
214
|
-
|
|
188
|
+
logger.info(chalk.yellow('\nPlease enter your D1 Studio license information:'));
|
|
215
189
|
|
|
216
190
|
const answers = await inquirer.prompt([
|
|
217
191
|
{
|
|
@@ -231,10 +205,9 @@ async function startStudio() {
|
|
|
231
205
|
},
|
|
232
206
|
]);
|
|
233
207
|
|
|
234
|
-
|
|
208
|
+
logger.debug(chalk.blue(`Entered license information: ${JSON.stringify(answers)}`));
|
|
235
209
|
|
|
236
210
|
const hardwareId = await generateHardwareId();
|
|
237
|
-
|
|
238
211
|
try {
|
|
239
212
|
const validation = await validateLicenseRemote(
|
|
240
213
|
answers.licenseKey,
|
|
@@ -242,51 +215,42 @@ async function startStudio() {
|
|
|
242
215
|
hardwareId
|
|
243
216
|
);
|
|
244
217
|
|
|
245
|
-
// Optionally, you can store the returned end_date for future checks.
|
|
246
218
|
licenseData = {
|
|
247
219
|
licenseKey: answers.licenseKey,
|
|
248
220
|
email: answers.email,
|
|
249
|
-
hardwareId,
|
|
250
|
-
licenseType: validation.licenseType,
|
|
251
221
|
activatedAt: new Date().toISOString(),
|
|
252
|
-
lastValidatedAt: new Date().toISOString(),
|
|
253
222
|
endDate: validation.end_date || null
|
|
254
223
|
};
|
|
255
224
|
|
|
256
225
|
await saveLicenseFile(licenseData);
|
|
257
|
-
|
|
226
|
+
logger.info(chalk.green('\nLicense activated successfully!'));
|
|
258
227
|
} catch (error) {
|
|
259
|
-
|
|
228
|
+
logger.error(chalk.red(`\nLicense validation failed: ${error.message}`));
|
|
260
229
|
process.exit(1);
|
|
261
230
|
}
|
|
262
|
-
} else {
|
|
263
|
-
// console.log(chalk.blue('Using cached license data.'));
|
|
264
231
|
}
|
|
265
232
|
|
|
266
233
|
// Get wrangler configuration
|
|
267
234
|
try {
|
|
268
235
|
const userProjectPath = process.cwd();
|
|
269
|
-
|
|
270
236
|
if (!userProjectPath) {
|
|
271
|
-
|
|
237
|
+
logger.error(chalk.red('Error: Could not determine project directory'));
|
|
272
238
|
process.exit(1);
|
|
273
239
|
}
|
|
274
|
-
|
|
240
|
+
|
|
275
241
|
const wranglerResult = await findWranglerConfig(userProjectPath);
|
|
276
|
-
|
|
277
242
|
if (!wranglerResult || !wranglerResult.config) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
243
|
+
logger.error(chalk.red('\nError: No wrangler.toml found in current directory'));
|
|
244
|
+
logger.info(chalk.yellow('Make sure you are in a Cloudflare Workers project directory'));
|
|
245
|
+
logger.info(chalk.yellow('with a valid wrangler.toml file.'));
|
|
281
246
|
process.exit(1);
|
|
282
247
|
}
|
|
283
|
-
|
|
248
|
+
|
|
284
249
|
const { config, projectPath } = wranglerResult;
|
|
285
|
-
|
|
286
250
|
if (!config.d1_databases?.length) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
251
|
+
logger.error(chalk.red('\nError: No D1 databases configured in wrangler.toml'));
|
|
252
|
+
logger.info(chalk.yellow('\nAdd D1 configuration to your wrangler.toml:'));
|
|
253
|
+
logger.info(chalk.gray(`
|
|
290
254
|
[[d1_databases]]
|
|
291
255
|
binding = "DB"
|
|
292
256
|
database_name = "my-database"
|
|
@@ -294,11 +258,10 @@ async function startStudio() {
|
|
|
294
258
|
`));
|
|
295
259
|
process.exit(1);
|
|
296
260
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
console.log(chalk.green('\nFound D1 databases:'));
|
|
261
|
+
|
|
262
|
+
logger.info(chalk.green('\nFound D1 databases:'));
|
|
300
263
|
config.d1_databases.forEach((db) => {
|
|
301
|
-
|
|
264
|
+
logger.info(chalk.blue(` - ${db.database_name} (${db.binding})`));
|
|
302
265
|
});
|
|
303
266
|
|
|
304
267
|
const port = 4000;
|
|
@@ -306,7 +269,7 @@ async function startStudio() {
|
|
|
306
269
|
|
|
307
270
|
await startServer(port, projectPath);
|
|
308
271
|
|
|
309
|
-
|
|
272
|
+
logger.info(chalk.green(`
|
|
310
273
|
┌─────────────────────────────────────────┐
|
|
311
274
|
│ │
|
|
312
275
|
│ D1 Studio is running on port ${port} │
|
|
@@ -316,50 +279,42 @@ async function startStudio() {
|
|
|
316
279
|
└─────────────────────────────────────────┘
|
|
317
280
|
`));
|
|
318
281
|
|
|
319
|
-
// Add delay before opening browser
|
|
320
282
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
321
283
|
|
|
322
284
|
try {
|
|
323
285
|
await open(url, {
|
|
324
286
|
wait: false,
|
|
325
287
|
url: true,
|
|
326
|
-
app: {
|
|
327
|
-
name: open.apps.chrome
|
|
328
|
-
}
|
|
288
|
+
app: { name: open.apps.chrome }
|
|
329
289
|
}).catch(() => {
|
|
330
|
-
return open(url, {
|
|
331
|
-
wait: false,
|
|
332
|
-
url: true
|
|
333
|
-
});
|
|
290
|
+
return open(url, { wait: false, url: true });
|
|
334
291
|
});
|
|
335
292
|
} catch (browserError) {
|
|
336
|
-
|
|
337
|
-
|
|
293
|
+
logger.info(chalk.yellow('\nCould not automatically open browser.'));
|
|
294
|
+
logger.info(chalk.blue(`Please open your browser and navigate to: ${url}`));
|
|
338
295
|
}
|
|
339
|
-
|
|
340
296
|
} catch (configError) {
|
|
341
|
-
|
|
297
|
+
logger.error(chalk.red(`\nConfiguration error: ${configError.message}`));
|
|
342
298
|
process.exit(1);
|
|
343
299
|
}
|
|
344
|
-
|
|
345
300
|
} catch (error) {
|
|
346
|
-
|
|
301
|
+
logger.error(chalk.red(`\nFailed to start D1 Studio: ${error}`));
|
|
347
302
|
process.exit(1);
|
|
348
303
|
}
|
|
349
304
|
}
|
|
350
305
|
|
|
351
306
|
// Handle termination
|
|
352
307
|
process.on('SIGINT', () => {
|
|
353
|
-
|
|
308
|
+
logger.info(chalk.yellow('\nShutting down D1 Studio...'));
|
|
354
309
|
process.exit(0);
|
|
355
310
|
});
|
|
356
311
|
|
|
357
312
|
process.on('SIGTERM', () => {
|
|
358
|
-
|
|
313
|
+
logger.info(chalk.yellow('\nShutting down D1 Studio...'));
|
|
359
314
|
process.exit(0);
|
|
360
315
|
});
|
|
361
316
|
|
|
362
317
|
startStudio().catch((error) => {
|
|
363
|
-
|
|
318
|
+
logger.error(chalk.red(`\nFailed to start D1 Studio: ${error}`));
|
|
364
319
|
process.exit(1);
|
|
365
320
|
});
|
package/src/app/page.jsx
CHANGED
|
@@ -10,23 +10,20 @@ export default function StudioPage() {
|
|
|
10
10
|
const [currentView, setCurrentView] = useState('sql-editor');
|
|
11
11
|
const [selectedTable, setSelectedTable] = useState(null);
|
|
12
12
|
|
|
13
|
-
// We don't need to handle push errors here anymore since we're using toasts
|
|
14
|
-
// The error handling is now managed by the useEnvironmentController hook
|
|
15
|
-
|
|
16
13
|
const handleTableSelect = (tableName) => {
|
|
17
14
|
setSelectedTable(tableName);
|
|
18
15
|
setCurrentView('table-view');
|
|
19
16
|
};
|
|
20
17
|
|
|
21
18
|
return (
|
|
22
|
-
<div className="
|
|
19
|
+
<div className="min-h-screen bg-background">
|
|
23
20
|
<AppSidebar
|
|
24
|
-
className="w-64 border-r
|
|
21
|
+
className="w-64 border-r"
|
|
25
22
|
currentView={currentView}
|
|
26
23
|
onNavigate={setCurrentView}
|
|
27
24
|
onTableSelect={handleTableSelect}
|
|
28
25
|
/>
|
|
29
|
-
<main className="
|
|
26
|
+
<main className="ml-64 h-screen">
|
|
30
27
|
{currentView === 'sql-editor' && <SQLEditor />}
|
|
31
28
|
{currentView === 'table-view' && selectedTable && (
|
|
32
29
|
<TableView tableName={selectedTable} />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// components/sidebar.jsx
|
|
2
2
|
'use client';
|
|
3
3
|
|
|
4
|
-
import React, { useEffect, useState } from 'react';
|
|
4
|
+
import React, { useEffect, useState, useMemo } from 'react';
|
|
5
5
|
import {
|
|
6
6
|
Table2,
|
|
7
7
|
Search,
|
|
@@ -42,12 +42,25 @@ export function AppSidebar({
|
|
|
42
42
|
PreviewUI,
|
|
43
43
|
} = useEnvironmentController();
|
|
44
44
|
|
|
45
|
-
//
|
|
46
|
-
const filteredTables =
|
|
47
|
-
tables?.filter((table) =>
|
|
45
|
+
// Updated filtering logic with d1_migrations priority
|
|
46
|
+
const filteredTables = useMemo(() => {
|
|
47
|
+
const filtered = tables?.filter((table) =>
|
|
48
48
|
table.toLowerCase().includes(searchTerm.toLowerCase())
|
|
49
49
|
) || [];
|
|
50
50
|
|
|
51
|
+
// Sort all tables alphabetically first
|
|
52
|
+
const sortedTables = [...filtered].sort((a, b) => a.localeCompare(b));
|
|
53
|
+
|
|
54
|
+
// If d1_migrations exists in the filtered list, move it to the top
|
|
55
|
+
const d1MigrationsIndex = sortedTables.indexOf('d1_migrations');
|
|
56
|
+
if (d1MigrationsIndex !== -1) {
|
|
57
|
+
sortedTables.splice(d1MigrationsIndex, 1);
|
|
58
|
+
sortedTables.unshift('d1_migrations');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return sortedTables;
|
|
62
|
+
}, [tables, searchTerm]);
|
|
63
|
+
|
|
51
64
|
const handleTableClick = async (table) => {
|
|
52
65
|
try {
|
|
53
66
|
setIsTableLoading(true);
|
|
@@ -120,23 +133,36 @@ export function AppSidebar({
|
|
|
120
133
|
|
|
121
134
|
return (
|
|
122
135
|
<>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
136
|
+
<aside className={`${className} w-64 fixed top-0 left-0 h-full bg-neutral-50 p-4`}>
|
|
137
|
+
<div className="flex flex-col h-full font-sans">
|
|
138
|
+
{/* Header */}
|
|
139
|
+
<div className="flex items-center gap-2 mb-6">
|
|
140
|
+
<Table2 className="h-5 w-5" />
|
|
141
|
+
<span className="font-mono font-bold text-sm">d1-studio</span>
|
|
142
|
+
</div>
|
|
130
143
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
144
|
+
{/* SQL Editor Section */}
|
|
145
|
+
<div className="mb-6">
|
|
146
|
+
<button
|
|
147
|
+
className={`w-full flex items-center gap-x-1 border rounded-md text-sm font-medium transition-colors px-2 py-2
|
|
148
|
+
${currentView === 'sql-editor' ? 'bg-neutral-900 text-white' : 'bg-white hover:bg-neutral-100'}`}
|
|
149
|
+
onClick={() => onNavigate('sql-editor')}
|
|
150
|
+
disabled={isTableLoading}
|
|
151
|
+
>
|
|
152
|
+
<TerminalSquare className="h-[16px] w-[16px]" />
|
|
153
|
+
SQL editor
|
|
154
|
+
</button>
|
|
155
|
+
</div>
|
|
138
156
|
|
|
139
|
-
|
|
157
|
+
{/* Error Message */}
|
|
158
|
+
{error && (
|
|
159
|
+
<Alert variant="destructive" className="mb-4">
|
|
160
|
+
<AlertCircle className="h-4 w-4" />
|
|
161
|
+
<AlertDescription className="text-sm ml-2">{error}</AlertDescription>
|
|
162
|
+
</Alert>
|
|
163
|
+
)}
|
|
164
|
+
|
|
165
|
+
{/* Database Section */}
|
|
140
166
|
<div className="flex items-center justify-between mb-6">
|
|
141
167
|
<div>
|
|
142
168
|
<div className="text-xs text-muted-foreground mb-1">Database name</div>
|
|
@@ -144,7 +170,7 @@ export function AppSidebar({
|
|
|
144
170
|
{databases[0]?.database_name || 'No database found'}
|
|
145
171
|
</div>
|
|
146
172
|
</div>
|
|
147
|
-
|
|
173
|
+
|
|
148
174
|
<EnvironmentSelect
|
|
149
175
|
value={environment}
|
|
150
176
|
onValueChange={handleEnvironmentChange}
|
|
@@ -153,84 +179,74 @@ export function AppSidebar({
|
|
|
153
179
|
showPreview={showPreview}
|
|
154
180
|
/>
|
|
155
181
|
</div>
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
SQL editor
|
|
167
|
-
</button>
|
|
168
|
-
</div>
|
|
169
|
-
|
|
170
|
-
{/* Search Section */}
|
|
171
|
-
<div className="relative mb-6 bg-white">
|
|
172
|
-
<Search className="absolute left-2 top-2.5 h-4 w-4 text-neutral-500" />
|
|
173
|
-
<Input
|
|
174
|
-
placeholder="Search tables"
|
|
175
|
-
value={searchTerm}
|
|
176
|
-
onChange={(e) => setSearchTerm(e.target.value)}
|
|
177
|
-
className="pl-7"
|
|
178
|
-
/>
|
|
179
|
-
</div>
|
|
180
|
-
|
|
181
|
-
{/* Tables Section */}
|
|
182
|
-
<div>
|
|
183
|
-
<div className="flex items-center justify-between mb-1">
|
|
184
|
-
<h3 className="text-sm font-medium text-muted-foreground">
|
|
185
|
-
Tables {tables?.length ? `(${tables.length})` : ''}
|
|
186
|
-
</h3>
|
|
187
|
-
{isTablesLoading && <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />}
|
|
182
|
+
|
|
183
|
+
{/* Search Section */}
|
|
184
|
+
<div className="relative mb-6 bg-white">
|
|
185
|
+
<Search className="absolute left-2 top-2.5 h-4 w-4 text-neutral-500" />
|
|
186
|
+
<Input
|
|
187
|
+
placeholder="Search tables"
|
|
188
|
+
value={searchTerm}
|
|
189
|
+
onChange={(e) => setSearchTerm(e.target.value)}
|
|
190
|
+
className="pl-7"
|
|
191
|
+
/>
|
|
188
192
|
</div>
|
|
193
|
+
|
|
194
|
+
{/* Scrollable Tables Section - Updated */}
|
|
195
|
+
<div className="flex-1 min-h-0 flex flex-col">
|
|
196
|
+
{/* Tables Header */}
|
|
197
|
+
<div className="flex items-center justify-between mb-1 flex-none">
|
|
198
|
+
<h3 className="text-sm font-medium text-muted-foreground">
|
|
199
|
+
Tables {tables?.length ? `(${tables.length})` : ''}
|
|
200
|
+
</h3>
|
|
201
|
+
{isTablesLoading && <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />}
|
|
202
|
+
</div>
|
|
189
203
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
204
|
+
{/* Tables List - Scrollable - Updated with padding bottom */}
|
|
205
|
+
<div className="overflow-y-auto flex-1">
|
|
206
|
+
<div className="pr-2 pb-4"> {/* Added pb-4 for bottom padding */}
|
|
207
|
+
{!isTablesLoading && filteredTables.length === 0 && (
|
|
208
|
+
<div className="text-sm font-medium text-muted-foreground px-2 py-2">
|
|
209
|
+
{searchTerm
|
|
210
|
+
? 'No matching tables found'
|
|
211
|
+
: error
|
|
212
|
+
? 'Error loading tables'
|
|
213
|
+
: 'No tables available'
|
|
214
|
+
}
|
|
215
|
+
</div>
|
|
216
|
+
)}
|
|
217
|
+
|
|
218
|
+
{filteredTables.map((table) => (
|
|
219
|
+
<button
|
|
220
|
+
key={table}
|
|
221
|
+
className={`w-full text-left text-sm font-medium rounded-md transition-colors px-2 py-2
|
|
222
|
+
${currentView === 'table-view' && selectedTable === table
|
|
223
|
+
? 'bg-[#F0F0F0] text-neutral-900 font-semibold'
|
|
224
|
+
: 'text-neutral-700 hover:bg-[#F2F2F2]'}
|
|
225
|
+
${isTableLoading && 'opacity-50 cursor-not-allowed'}`}
|
|
226
|
+
onClick={() => handleTableClick(table)}
|
|
227
|
+
disabled={isTableLoading}
|
|
228
|
+
>
|
|
229
|
+
{table}
|
|
230
|
+
</button>
|
|
231
|
+
))}
|
|
200
232
|
</div>
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
{filteredTables.map((table) => (
|
|
204
|
-
<button
|
|
205
|
-
key={table}
|
|
206
|
-
className={`w-full text-left text-sm font-medium rounded-md transition-colors px-2 py-2
|
|
207
|
-
${currentView === 'table-view' && selectedTable === table
|
|
208
|
-
? 'bg-[#F0F0F0] text-neutral-900 font-semibold'
|
|
209
|
-
: 'text-neutral-700 hover:bg-[#F2F2F2]'}
|
|
210
|
-
${isTableLoading && 'opacity-50 cursor-not-allowed'}`}
|
|
211
|
-
onClick={() => handleTableClick(table)}
|
|
212
|
-
disabled={isTableLoading}
|
|
213
|
-
>
|
|
214
|
-
{table}
|
|
215
|
-
</button>
|
|
216
|
-
))}
|
|
233
|
+
</div>
|
|
217
234
|
</div>
|
|
218
235
|
</div>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
|
|
237
|
+
{/* Cloudflare Credentials Modal */}
|
|
238
|
+
<CloudflareCredentialsModal
|
|
239
|
+
open={showCredentialsModal}
|
|
240
|
+
onClose={() => {
|
|
241
|
+
setShowCredentialsModal(false);
|
|
242
|
+
setEnvironment('local');
|
|
243
|
+
}}
|
|
244
|
+
onSubmit={connectToCloudflare}
|
|
245
|
+
/>
|
|
246
|
+
</aside>
|
|
247
|
+
|
|
232
248
|
{/* Preview UI */}
|
|
233
249
|
{PreviewUI}
|
|
234
250
|
</>
|
|
235
|
-
);
|
|
251
|
+
);
|
|
236
252
|
}
|