d1s 0.2.9 → 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.
Files changed (201) hide show
  1. package/dist/.next/.next/BUILD_ID +1 -1
  2. package/dist/.next/.next/app-build-manifest.json +32 -32
  3. package/dist/.next/.next/app-path-routes-manifest.json +1 -1
  4. package/dist/.next/.next/build-manifest.json +3 -3
  5. package/dist/.next/.next/cache/.rscinfo +1 -1
  6. package/dist/.next/.next/cache/.tsbuildinfo +1 -1
  7. package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
  8. package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
  9. package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
  10. package/dist/.next/.next/cache/webpack/client-production/3.pack +0 -0
  11. package/dist/.next/.next/cache/webpack/client-production/4.pack +0 -0
  12. package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
  13. package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
  14. package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
  15. package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
  16. package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
  17. package/dist/.next/.next/cache/webpack/server-production/2.pack +0 -0
  18. package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
  19. package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
  20. package/dist/.next/.next/next-minimal-server.js.nft.json +1 -1
  21. package/dist/.next/.next/next-server.js.nft.json +1 -1
  22. package/dist/.next/.next/prerender-manifest.json +1 -1
  23. package/dist/.next/.next/required-server-files.json +1 -1
  24. package/dist/.next/.next/server/app/_not-found/page.js +1 -1
  25. package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -1
  26. package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  27. package/dist/.next/.next/server/app/_not-found.html +1 -1
  28. package/dist/.next/.next/server/app/_not-found.rsc +4 -4
  29. package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
  30. package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  31. package/dist/.next/.next/server/app/api/databases/route.js +1 -1
  32. package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  33. package/dist/.next/.next/server/app/api/migrations/sync/route.js +3 -3
  34. package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  35. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +8 -8
  36. package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  37. package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -1
  38. package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  39. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +2 -2
  40. package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  41. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +2 -2
  42. package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  43. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +5 -5
  44. package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  45. package/dist/.next/.next/server/app/api/push-remote/preview/route.js +3 -3
  46. package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  47. package/dist/.next/.next/server/app/api/query/route.js +3 -3
  48. package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  49. package/dist/.next/.next/server/app/api/tables/[name]/route.js +2 -2
  50. package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  51. package/dist/.next/.next/server/app/api/tables/route.js +2 -2
  52. package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  53. package/dist/.next/.next/server/app/api/update/route.js +1 -5
  54. package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  55. package/dist/.next/.next/server/app/index.html +2 -2
  56. package/dist/.next/.next/server/app/index.rsc +5 -5
  57. package/dist/.next/.next/server/app/page.js +8 -8
  58. package/dist/.next/.next/server/app/page.js.nft.json +1 -1
  59. package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
  60. package/dist/.next/.next/server/app-paths-manifest.json +3 -3
  61. package/dist/.next/.next/server/chunks/226.js +5 -5
  62. package/dist/.next/.next/server/chunks/90.js +1 -0
  63. package/dist/.next/.next/server/chunks/992.js +1 -1
  64. package/dist/.next/.next/server/middleware-build-manifest.js +1 -1
  65. package/dist/.next/.next/server/next-font-manifest.js +1 -1
  66. package/dist/.next/.next/server/next-font-manifest.json +1 -1
  67. package/dist/.next/.next/server/pages/404.html +1 -1
  68. package/dist/.next/.next/server/pages/500.html +1 -1
  69. package/dist/.next/.next/server/server-reference-manifest.json +1 -1
  70. package/dist/.next/{static/chunks/176-9146975ef8699719.js → .next/static/chunks/700-dc8f9f08b166c5e6.js} +1 -1
  71. package/dist/.next/.next/static/chunks/app/layout-be6ee67cf0c92654.js +1 -0
  72. package/dist/.next/.next/static/chunks/app/page-16ec561fc8bebb5d.js +1 -0
  73. package/dist/.next/.next/static/chunks/{main-app-d36cdfb402b40f13.js → main-app-fa35024de9bd9284.js} +1 -1
  74. package/dist/.next/.next/static/css/0c512cea5f3d317a.css +3 -0
  75. package/dist/.next/.next/static/p8875OZM4iDNsPzmoyLe7/_buildManifest.js +1 -0
  76. package/dist/.next/.next/static/p8875OZM4iDNsPzmoyLe7/_ssgManifest.js +1 -0
  77. package/dist/.next/.next/trace +3 -3
  78. package/dist/.next/.next/types/app/api/cloudflare/route.ts +1 -1
  79. package/dist/.next/.next/types/app/api/databases/route.ts +1 -1
  80. package/dist/.next/.next/types/app/api/migrations/sync/route.ts +1 -1
  81. package/dist/.next/.next/types/app/api/migrations/sync-files/route.ts +1 -1
  82. package/dist/.next/.next/types/app/api/pull-data/confirm/route.ts +1 -1
  83. package/dist/.next/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
  84. package/dist/.next/.next/types/app/api/pull-remote/preview/route.ts +1 -1
  85. package/dist/.next/.next/types/app/api/push-remote/confirm/route.ts +1 -1
  86. package/dist/.next/.next/types/app/api/push-remote/preview/route.ts +1 -1
  87. package/dist/.next/.next/types/app/api/query/route.ts +1 -1
  88. package/dist/.next/.next/types/app/api/tables/[name]/route.ts +1 -1
  89. package/dist/.next/.next/types/app/api/tables/route.ts +1 -1
  90. package/dist/.next/.next/types/app/api/update/route.ts +1 -1
  91. package/dist/.next/.next/types/app/page.ts +1 -1
  92. package/dist/.next/BUILD_ID +1 -1
  93. package/dist/.next/app-build-manifest.json +43 -43
  94. package/dist/.next/app-path-routes-manifest.json +1 -1
  95. package/dist/.next/build-manifest.json +3 -3
  96. package/dist/.next/cache/.rscinfo +1 -1
  97. package/dist/.next/cache/.tsbuildinfo +1 -1
  98. package/dist/.next/cache/webpack/client-production/0.pack +0 -0
  99. package/dist/.next/cache/webpack/client-production/index.pack +0 -0
  100. package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
  101. package/dist/.next/cache/webpack/server-production/0.pack +0 -0
  102. package/dist/.next/cache/webpack/server-production/index.pack +0 -0
  103. package/dist/.next/next-minimal-server.js.nft.json +1 -1
  104. package/dist/.next/next-server.js.nft.json +1 -1
  105. package/dist/.next/prerender-manifest.json +1 -1
  106. package/dist/.next/required-server-files.json +1 -1
  107. package/dist/.next/server/app/_not-found/page.js +1 -1
  108. package/dist/.next/server/app/_not-found/page.js.nft.json +1 -1
  109. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  110. package/dist/.next/server/app/_not-found.html +1 -1
  111. package/dist/.next/server/app/_not-found.rsc +4 -4
  112. package/dist/.next/server/app/api/cloudflare/route.js +1 -1
  113. package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  114. package/dist/.next/server/app/api/databases/route.js +1 -1
  115. package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  116. package/dist/.next/server/app/api/migrations/sync/route.js +3 -3
  117. package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  118. package/dist/.next/server/app/api/migrations/sync-files/route.js +8 -8
  119. package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  120. package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -1
  121. package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  122. package/dist/.next/server/app/api/pull-remote/confirm/route.js +2 -2
  123. package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  124. package/dist/.next/server/app/api/pull-remote/preview/route.js +2 -2
  125. package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  126. package/dist/.next/server/app/api/push-remote/confirm/route.js +5 -5
  127. package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  128. package/dist/.next/server/app/api/push-remote/preview/route.js +3 -3
  129. package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  130. package/dist/.next/server/app/api/query/route.js +3 -3
  131. package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  132. package/dist/.next/server/app/api/tables/[name]/route.js +2 -2
  133. package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  134. package/dist/.next/server/app/api/tables/route.js +2 -2
  135. package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  136. package/dist/.next/server/app/api/update/route.js +1 -5
  137. package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  138. package/dist/.next/server/app/index.html +2 -2
  139. package/dist/.next/server/app/index.rsc +5 -5
  140. package/dist/.next/server/app/page.js +8 -8
  141. package/dist/.next/server/app/page.js.nft.json +1 -1
  142. package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
  143. package/dist/.next/server/app-paths-manifest.json +5 -5
  144. package/dist/.next/server/chunks/226.js +5 -5
  145. package/dist/.next/server/chunks/90.js +1 -0
  146. package/dist/.next/server/chunks/992.js +1 -1
  147. package/dist/.next/server/middleware-build-manifest.js +1 -1
  148. package/dist/.next/server/next-font-manifest.js +1 -1
  149. package/dist/.next/server/next-font-manifest.json +1 -1
  150. package/dist/.next/server/pages/404.html +1 -1
  151. package/dist/.next/server/pages/500.html +1 -1
  152. package/dist/.next/server/server-reference-manifest.json +1 -1
  153. package/dist/.next/{.next/static/chunks/176-9146975ef8699719.js → static/chunks/700-dc8f9f08b166c5e6.js} +1 -1
  154. package/dist/.next/static/chunks/app/layout-be6ee67cf0c92654.js +1 -0
  155. package/dist/.next/static/chunks/app/page-16ec561fc8bebb5d.js +1 -0
  156. package/dist/.next/static/chunks/{main-app-d36cdfb402b40f13.js → main-app-fa35024de9bd9284.js} +1 -1
  157. package/dist/.next/static/css/0c512cea5f3d317a.css +3 -0
  158. package/dist/.next/static 2/5dBGGUmK5q7of4h5Rahrg/_buildManifest.js +1 -0
  159. package/dist/.next/static 2/5dBGGUmK5q7of4h5Rahrg/_ssgManifest.js +1 -0
  160. package/dist/.next/trace +16 -17
  161. package/dist/.next/types/app/api/cloudflare/route.ts +1 -1
  162. package/dist/.next/types/app/api/databases/route.ts +1 -1
  163. package/dist/.next/types/app/api/migrations/sync/route.ts +1 -1
  164. package/dist/.next/types/app/api/migrations/sync-files/route.ts +1 -1
  165. package/dist/.next/types/app/api/pull-data/confirm/route.ts +1 -1
  166. package/dist/.next/types/app/api/pull-remote/confirm/route.ts +1 -1
  167. package/dist/.next/types/app/api/pull-remote/preview/route.ts +1 -1
  168. package/dist/.next/types/app/api/push-remote/confirm/route.ts +1 -1
  169. package/dist/.next/types/app/api/push-remote/preview/route.ts +1 -1
  170. package/dist/.next/types/app/api/query/route.ts +1 -1
  171. package/dist/.next/types/app/api/tables/[name]/route.ts +1 -1
  172. package/dist/.next/types/app/api/tables/route.ts +1 -1
  173. package/dist/.next/types/app/api/update/route.ts +1 -1
  174. package/dist/.next/types/app/page.ts +1 -1
  175. package/dist/app/api/update/route.js +29 -20
  176. package/dist/app/app/api/update/route.js +29 -20
  177. package/dist/app/app/page.jsx +5 -5
  178. package/dist/app/page.jsx +5 -5
  179. package/dist/d1-studio.js +0 -194
  180. package/dist/lib/sql-operations.js +30 -24
  181. package/dist/lib/version-utils.js +34 -0
  182. package/package.json +2 -2
  183. package/scripts/studio.js +0 -194
  184. package/src/app/api/update/route.js +29 -20
  185. package/src/app/page.jsx +5 -5
  186. package/src/components/sidebar.jsx +2 -1
  187. package/src/components/update-banner.jsx +69 -38
  188. package/src/lib/sql-operations.js +30 -24
  189. package/src/lib/version-utils.js +34 -0
  190. package/dist/.next/.next/server/chunks/336.js +0 -1
  191. package/dist/.next/.next/static/chunks/app/layout-8360fab69b848283.js +0 -1
  192. package/dist/.next/.next/static/chunks/app/page-5990cb23b8bd27c4.js +0 -1
  193. package/dist/.next/.next/static/css/674bee6608c638e4.css +0 -3
  194. package/dist/.next/server/chunks/336.js +0 -1
  195. package/dist/.next/static/chunks/app/layout-8360fab69b848283.js +0 -1
  196. package/dist/.next/static/chunks/app/page-5990cb23b8bd27c4.js +0 -1
  197. package/dist/.next/static/css/674bee6608c638e4.css +0 -3
  198. /package/dist/.next/.next/static/{7XBqETNmhSxMXhw8iUpEa → 5dBGGUmK5q7of4h5Rahrg}/_buildManifest.js +0 -0
  199. /package/dist/.next/.next/static/{7XBqETNmhSxMXhw8iUpEa → 5dBGGUmK5q7of4h5Rahrg}/_ssgManifest.js +0 -0
  200. /package/dist/.next/{static/MoZBULXFiTFzrY1JVK_Df → .next/static/PflNFnmFsNegSqhzjI6lA}/_buildManifest.js +0 -0
  201. /package/dist/.next/{static/MoZBULXFiTFzrY1JVK_Df → .next/static/PflNFnmFsNegSqhzjI6lA}/_ssgManifest.js +0 -0
package/scripts/studio.js CHANGED
@@ -3,10 +3,6 @@ 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';
@@ -29,133 +25,6 @@ notifier.notify({ defer: false });
29
25
  const __filename = fileURLToPath(import.meta.url);
30
26
  const __dirname = dirname(__filename);
31
27
 
32
- // License validation utilities
33
- class LicenseError extends Error {
34
- constructor(message, type = 'VALIDATION_ERROR') {
35
- super(message);
36
- this.name = 'LicenseError';
37
- this.type = type;
38
- }
39
- }
40
-
41
- class StudioLicenseManager {
42
- constructor() {
43
- this.licenseDir = join(homedir(), '.d1studio');
44
- this.licensePath = join(this.licenseDir, 'license.json');
45
- }
46
-
47
- async checkLicenseFile() {
48
- try {
49
- const licenseData = JSON.parse(await readFile(this.licensePath, 'utf8'));
50
-
51
- // If no end_date or subscription_status, the license is valid (perpetual license)
52
- if (!licenseData.end_date || !licenseData.subscription_status) {
53
- return {
54
- licenseData,
55
- isValid: true,
56
- isExpiringSoon: false
57
- };
58
- }
59
-
60
- // Check subscription status first
61
- if (licenseData.subscription_status !== 'active') {
62
- return {
63
- licenseData,
64
- isValid: false,
65
- isExpiringSoon: false
66
- };
67
- }
68
-
69
- const endDate = new Date(licenseData.end_date);
70
- const now = new Date();
71
-
72
- // Check if subscription has ended
73
- if (endDate < now) {
74
- return {
75
- licenseData,
76
- isValid: false,
77
- isExpiringSoon: false
78
- };
79
- }
80
-
81
- // Check if subscription ends in next 7 days
82
- const sevenDaysFromNow = new Date(now.getTime() + (7 * 24 * 60 * 60 * 1000));
83
- const isExpiringSoon = endDate <= sevenDaysFromNow;
84
-
85
- return {
86
- licenseData,
87
- isValid: true,
88
- isExpiringSoon
89
- };
90
- } catch (error) {
91
- return null;
92
- }
93
- }
94
-
95
- async saveLicenseFile(licenseData) {
96
- try {
97
- await mkdir(this.licenseDir, { recursive: true });
98
- await writeFile(this.licensePath, JSON.stringify(licenseData, null, 2));
99
- } catch (error) {
100
- throw new LicenseError('Failed to save license information', 'SAVE_ERROR');
101
- }
102
- }
103
- }
104
-
105
- async function generateHardwareId() {
106
- const osInfo = {
107
- platform: process.platform,
108
- arch: process.arch,
109
- cpus: os.cpus().length,
110
- hostname: os.hostname(),
111
- username: os.userInfo().username,
112
- };
113
- const systemString = JSON.stringify(osInfo);
114
- return createHash('sha256').update(systemString).digest('hex');
115
- }
116
-
117
- async function validateLicenseRemote(licenseKey, email, hardwareId) {
118
- const baseUrl =
119
- process.env.NODE_ENV === 'development'
120
- ? 'http://localhost:4000'
121
- : 'https://d1-studio.com';
122
-
123
- try {
124
- const response = await fetch(`${baseUrl}/api/validate-license`, {
125
- method: 'POST',
126
- headers: { 'Content-Type': 'application/json' },
127
- body: JSON.stringify({ licenseKey, email, hardwareId }),
128
- });
129
-
130
- const result = await response.json();
131
-
132
- if (!response.ok) {
133
- throw new LicenseError(
134
- result.message || 'License validation failed',
135
- result.type || 'VALIDATION_ERROR'
136
- );
137
- }
138
-
139
- return result;
140
- } catch (error) {
141
- if (error instanceof LicenseError) {
142
- throw error;
143
- }
144
- if (error.name === 'TypeError' && error.message.includes('fetch')) {
145
- throw new LicenseError(
146
- process.env.NODE_ENV === 'development'
147
- ? 'Unable to connect to local license validation service. Make sure the development server is running.'
148
- : 'Unable to connect to license server. Please check your internet connection.',
149
- 'CONNECTION_ERROR'
150
- );
151
- }
152
- throw new LicenseError(
153
- 'An unexpected error occurred during license validation',
154
- 'VALIDATION_ERROR'
155
- );
156
- }
157
- }
158
-
159
28
  async function startServer(port, projectDirectory) {
160
29
  return new Promise((resolvePromise, rejectPromise) => {
161
30
  // Determine Next.js app directory based on environment:
@@ -210,69 +79,6 @@ async function startStudio() {
210
79
  try {
211
80
  logger.info(chalk.green('Initializing D1 Studio...'));
212
81
 
213
- const licenseManager = new StudioLicenseManager();
214
-
215
- // Check existing license
216
- const licenseCheck = await licenseManager.checkLicenseFile();
217
-
218
- // Handle license validation
219
- if (!licenseCheck || !licenseCheck.isValid) {
220
- // Prompt for license information if needed
221
- const { default: inquirer } = await import('inquirer');
222
- logger.info(chalk.yellow('\nPlease enter your D1 Studio license information:'));
223
-
224
- const answers = await inquirer.prompt([
225
- {
226
- type: 'input',
227
- name: 'licenseKey',
228
- message: 'License Key:',
229
- validate: (input) => input.length > 0 || 'License key is required',
230
- },
231
- {
232
- type: 'input',
233
- name: 'email',
234
- message: 'Email:',
235
- validate: (input) => {
236
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
237
- return emailRegex.test(input) || 'Please enter a valid email';
238
- },
239
- },
240
- ]);
241
-
242
- const hardwareId = await generateHardwareId();
243
-
244
- try {
245
- const validation = await validateLicenseRemote(
246
- answers.licenseKey,
247
- answers.email,
248
- hardwareId
249
- );
250
-
251
- // Save the complete validation response
252
- await licenseManager.saveLicenseFile({
253
- licenseKey: answers.licenseKey,
254
- email: answers.email,
255
- hardwareId,
256
- end_date: validation.end_date,
257
- subscription_status: validation.subscription_status,
258
- type: validation.licenseType,
259
- activatedAt: new Date().toISOString()
260
- });
261
-
262
- logger.info(chalk.green('\nLicense activated successfully!'));
263
- } catch (error) {
264
- logger.error(chalk.red(`\nLicense validation failed: ${error.message}`));
265
- process.exit(1);
266
- }
267
- } else if (licenseCheck.isExpiringSoon) {
268
- // Show warning about expiring subscription
269
- const endDate = new Date(licenseCheck.licenseData.end_date).toLocaleDateString();
270
- logger.warn(chalk.yellow(`
271
- ⚠️ Your subscription will expire on ${endDate}
272
- Please renew your subscription at https://d1-studio.com to continue using D1 Studio.
273
- `));
274
- }
275
-
276
82
  // Get wrangler configuration
277
83
  try {
278
84
  const userProjectPath = process.cwd();
@@ -1,31 +1,40 @@
1
1
  // app/api/update/route.js
2
2
  import { NextResponse } from 'next/server';
3
- import updateNotifier from 'update-notifier';
4
3
  import pkg from '../../../../package.json' assert { type: 'json' };
5
4
 
6
5
  export async function GET() {
7
6
  try {
8
- // Create notifier instance with package info
9
- const notifier = updateNotifier({
10
- pkg,
11
- updateCheckInterval: 1000 * 60 * 60 * 24 // Check once per day
7
+ // Get current version from package.json
8
+ const currentVersion = pkg.version;
9
+
10
+ // Fetch the latest version from npm registry
11
+ const response = await fetch('https://registry.npmjs.org/d1s/latest', {
12
+ headers: {
13
+ 'Accept': 'application/json',
14
+ 'User-Agent': 'd1-studio'
15
+ },
16
+ // Add cache control to prevent excessive requests
17
+ cache: 'no-cache'
12
18
  });
13
-
14
- // If there's an update, notifier.update will contain the update info
15
- if (notifier.update) {
16
- const { latest, current } = notifier.update;
17
-
18
- // Only return update info if versions are different
19
- if (latest !== current) {
20
- return NextResponse.json({
21
- update: {
22
- latest,
23
- current
24
- }
25
- });
26
- }
19
+
20
+ if (!response.ok) {
21
+ throw new Error('Failed to check for updates');
27
22
  }
28
-
23
+
24
+ const data = await response.json();
25
+ const latestVersion = data.version;
26
+
27
+ // Compare versions - only return update info if there's a newer version
28
+ if (latestVersion && currentVersion && latestVersion !== currentVersion) {
29
+ console.log(`Update available: ${currentVersion} → ${latestVersion}`);
30
+ return NextResponse.json({
31
+ update: {
32
+ latest: latestVersion,
33
+ current: currentVersion
34
+ }
35
+ });
36
+ }
37
+
29
38
  // No update available
30
39
  return NextResponse.json({ update: null });
31
40
  } catch (error) {
package/src/app/page.jsx CHANGED
@@ -21,17 +21,17 @@ export default function StudioPage() {
21
21
  {/* Banner */}
22
22
  <UpdateBanner />
23
23
 
24
- {/* Main layout */}
25
- <div className="flex flex-1">
26
- {/* Sidebar */}
24
+ {/* Main layout with adjusted positioning for banner */}
25
+ <div className="flex flex-1 mt-[var(--banner-height,0px)]">
26
+ {/* Sidebar with adjusted height */}
27
27
  <AppSidebar
28
- className="w-64 border-r fixed h-[calc(100vh-var(--banner-height,0px))]"
28
+ className="w-64 border-r fixed top-[var(--banner-height,0px)] h-[calc(100vh-var(--banner-height,0px))]"
29
29
  currentView={currentView}
30
30
  onNavigate={setCurrentView}
31
31
  onTableSelect={handleTableSelect}
32
32
  />
33
33
 
34
- {/* Main content */}
34
+ {/* Main content with adjusted margin-top and height */}
35
35
  <main className="ml-64 flex-1 h-[calc(100vh-var(--banner-height,0px))]">
36
36
  {currentView === 'sql-editor' && <SQLEditor />}
37
37
  {currentView === 'table-view' && selectedTable && (
@@ -133,7 +133,8 @@ export function AppSidebar({
133
133
 
134
134
  return (
135
135
  <>
136
- <aside className={`${className} w-64 fixed top-0 left-0 h-full bg-neutral-50 p-4`}>
136
+ {/* The sidebar now has top position adjusted for the banner */}
137
+ <aside className={`${className} top-[var(--banner-height,0px)] left-0 h-[calc(100vh-var(--banner-height,0px))] bg-neutral-50 p-4`}>
137
138
  <div className="flex flex-col h-full font-sans">
138
139
  {/* Header */}
139
140
  <div className="flex items-center gap-2 mb-4">
@@ -2,61 +2,92 @@
2
2
  'use client'
3
3
 
4
4
  import { useEffect, useState } from 'react';
5
- import { Download } from 'lucide-react';
5
+ import { Info } from 'lucide-react';
6
6
  import axios from 'axios';
7
7
 
8
8
  export default function UpdateBanner() {
9
9
  const [updateInfo, setUpdateInfo] = useState(null);
10
- const [visible, setVisible] = useState(true);
10
+ const [visible, setVisible] = useState(false);
11
+ const [loading, setLoading] = useState(true);
11
12
 
12
13
  useEffect(() => {
13
- const dismissedVersion = localStorage.getItem('updateBannerDismissedVersion');
14
- if (dismissedVersion) {
15
- setVisible(false);
16
- }
17
- }, []);
18
-
19
- useEffect(() => {
20
- const timer = setTimeout(() => {
21
- axios
22
- .get('/api/update')
23
- .then(({ data }) => {
24
- if (data?.update) {
25
- const dismissedVersion = localStorage.getItem('updateBannerDismissedVersion');
26
- if (dismissedVersion !== data.update.latest) {
27
- setUpdateInfo(data.update);
28
- setVisible(true);
29
- }
14
+ const checkForUpdates = async () => {
15
+ try {
16
+ setLoading(true);
17
+
18
+ // Check if we've already dismissed this specific version update
19
+ const dismissedVersion = localStorage.getItem('dismissedVersion');
20
+
21
+ const { data } = await axios.get('/api/update');
22
+
23
+ if (data?.update) {
24
+ // Only show if the user hasn't dismissed this specific version
25
+ if (dismissedVersion !== data.update.latest) {
26
+ setUpdateInfo(data.update);
27
+ setVisible(true);
28
+ } else {
29
+ setVisible(false);
30
30
  }
31
- })
32
- .catch(console.error);
33
- }, 1000);
31
+ } else {
32
+ setVisible(false);
33
+ }
34
+ } catch (error) {
35
+ console.error('Error checking for updates:', error);
36
+ setVisible(false);
37
+ } finally {
38
+ setLoading(false);
39
+ }
40
+ };
34
41
 
35
- return () => clearTimeout(timer);
42
+ // Check immediately and then daily
43
+ checkForUpdates();
44
+ const interval = setInterval(checkForUpdates, 24 * 60 * 60 * 1000); // Check daily
45
+
46
+ return () => clearInterval(interval);
36
47
  }, []);
37
48
 
38
- if (!updateInfo || !visible) return null;
49
+ // If banner is dismissed or no update info, don't render and reset CSS variable
50
+ if (!updateInfo || !visible || loading) {
51
+ // Reset the banner height when hidden
52
+ if (typeof document !== 'undefined') {
53
+ document.documentElement.style.setProperty('--banner-height', '0px');
54
+ }
55
+ return null;
56
+ }
57
+
58
+ // Set the banner height CSS variable when visible
59
+ if (typeof document !== 'undefined') {
60
+ document.documentElement.style.setProperty('--banner-height', '37px'); // Adjust based on actual banner height
61
+ }
39
62
 
40
63
  const handleClose = () => {
41
- localStorage.setItem('updateBannerDismissedVersion', updateInfo.latest);
64
+ // Store the dismissed version to avoid showing the same update again
65
+ if (updateInfo?.latest) {
66
+ localStorage.setItem('dismissedVersion', updateInfo.latest);
67
+ }
42
68
  setVisible(false);
43
69
  };
44
70
 
45
71
  return (
46
- <div className="w-full bg-neutral-100 border-b px-3 py-2 flex items-center justify-between">
47
- <div className="flex items-center gap-2 text-sm">
48
- <Download className="h-4 w-4 text-blue-500" />
49
- <span>
50
- Version {updateInfo.latest} is available — npm install -g d1s@latest
51
- </span>
72
+ <div className="fixed top-0 left-0 right-0 z-50 bg-yellow-200 border-b border-yellow-500 px-3 py-2 font-sans">
73
+ <div className="flex items-center justify-center relative">
74
+ {/* Info icon and text centered */}
75
+ <div className="flex items-center gap-2 mx-auto">
76
+ <Info className="h-4 w-4 text-neutral-900" />
77
+ <span className="text-sm font-medium">
78
+ Version {updateInfo.latest} is available — npm install -g d1s@latest
79
+ </span>
80
+ </div>
81
+
82
+ {/* Close button positioned absolutely on the right */}
83
+ <button
84
+ onClick={handleClose}
85
+ className="absolute right-0 text-neutral-500 hover:text-neutral-700"
86
+ aria-label="Close update banner"
87
+ >
88
+ ×
89
+ </button>
52
90
  </div>
53
- <button
54
- onClick={handleClose}
55
- className="text-neutral-500 hover:text-neutral-700"
56
- aria-label="Close update banner"
57
- >
58
- ×
59
- </button>
60
91
  </div>
61
92
  );
62
93
  }
@@ -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
- // Build a description that uses the index name,
122
- // and appends the columns if they are not already included.
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. "idx_movies_name" or "idx_movies_name-name"
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);
@@ -559,14 +551,14 @@ export function formatMigrationContent(sql) {
559
551
  * @returns {Promise<string>} The migration file content.
560
552
  */
561
553
 
562
- export async function getMigrationFileContent(projectDir, databaseName, migrationFile, env) {
554
+ export async function getMigrationFileContent(projectDir, databaseName, migrationFile, env) {
563
555
  try {
564
556
  // Extract table name using improved helper
565
557
  const tableName = await extractTableNameFromMigration(migrationFile);
566
558
  let sql;
567
559
 
568
- if (tableName) {
569
- // Try getting SQL from sqlite_master for table
560
+ // For non-index migrations, try getting SQL from sqlite_master for table
561
+ if (tableName && !migrationFile.includes('create-index')) {
570
562
  const result = await executeSQL(
571
563
  projectDir,
572
564
  databaseName,
@@ -583,24 +575,38 @@ export function formatMigrationContent(sql) {
583
575
  }
584
576
  }
585
577
 
586
- // 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.
587
579
  if (!sql && migrationFile.includes('create-index')) {
588
- const indexMatch = migrationFile.match(/create-index[-_]([^_.]+)/);
580
+ const indexMatch = migrationFile.match(/create-index[_-](.+)\.sql$/i);
589
581
  if (indexMatch) {
590
- const result = await executeSQL(
582
+ let indexName = indexMatch[1]; // e.g. "idx_technology_timestamp-technology-timestamp"
583
+ let result = await executeSQL(
591
584
  projectDir,
592
585
  databaseName,
593
- `SELECT sql FROM sqlite_master WHERE type='index' AND name='${indexMatch[1]}';`,
586
+ `SELECT sql FROM sqlite_master WHERE type='index' AND name='${indexName}' COLLATE NOCASE;`,
594
587
  env,
595
588
  true
596
589
  );
597
- const parsed = JSON.parse(result);
590
+ let parsed = JSON.parse(result);
598
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
+ }
599
605
  }
600
- }
606
+ }
601
607
 
602
- // If still no SQL, try fetching any object matching the name pattern
603
- 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')) {
604
610
  const result = await executeSQL(
605
611
  projectDir,
606
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
+ }
@@ -1 +0,0 @@
1
- exports.id=336,exports.ids=[336],exports.modules={97928:(e,t,r)=>{Promise.resolve().then(r.t.bind(r,13219,23)),Promise.resolve().then(r.t.bind(r,34863,23)),Promise.resolve().then(r.t.bind(r,25155,23)),Promise.resolve().then(r.t.bind(r,40802,23)),Promise.resolve().then(r.t.bind(r,9350,23)),Promise.resolve().then(r.t.bind(r,48530,23)),Promise.resolve().then(r.t.bind(r,88921,23))},61480:(e,t,r)=>{Promise.resolve().then(r.t.bind(r,66959,23)),Promise.resolve().then(r.t.bind(r,33875,23)),Promise.resolve().then(r.t.bind(r,88903,23)),Promise.resolve().then(r.t.bind(r,57174,23)),Promise.resolve().then(r.t.bind(r,84178,23)),Promise.resolve().then(r.t.bind(r,87190,23)),Promise.resolve().then(r.t.bind(r,61365,23))},99233:(e,t,r)=>{Promise.resolve().then(r.bind(r,13164)),Promise.resolve().then(r.bind(r,91831))},12385:(e,t,r)=>{Promise.resolve().then(r.bind(r,52652)),Promise.resolve().then(r.bind(r,2899))},52652:(e,t,r)=>{"use strict";r.d(t,{Toaster:()=>v});var a=r(45512),s=r(46888),o=r(58009),i=r(68952),n=r(21643),c=r(51255),l=r(3603);let d=i.Kq,u=o.forwardRef(({className:e,...t},r)=>(0,a.jsx)(i.LM,{ref:r,className:(0,l.cn)("fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",e),...t}));u.displayName=i.LM.displayName;let h=(0,n.F)("group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",{variants:{variant:{default:"border bg-background text-foreground",destructive:"destructive group border-destructive bg-destructive text-destructive-foreground"}},defaultVariants:{variant:"default"}}),p=o.forwardRef(({className:e,variant:t,...r},s)=>(0,a.jsx)(i.bL,{ref:s,className:(0,l.cn)(h({variant:t}),e),...r}));p.displayName=i.bL.displayName,o.forwardRef(({className:e,...t},r)=>(0,a.jsx)(i.rc,{ref:r,className:(0,l.cn)("inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",e),...t})).displayName=i.rc.displayName;let m=o.forwardRef(({className:e,...t},r)=>(0,a.jsx)(i.bm,{ref:r,className:(0,l.cn)("absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",e),"toast-close":"",...t,children:(0,a.jsx)(c.A,{className:"h-4 w-4"})}));m.displayName=i.bm.displayName;let f=o.forwardRef(({className:e,...t},r)=>(0,a.jsx)(i.hE,{ref:r,className:(0,l.cn)("text-sm font-semibold [&+div]:text-xs",e),...t}));f.displayName=i.hE.displayName;let b=o.forwardRef(({className:e,...t},r)=>(0,a.jsx)(i.VY,{ref:r,className:(0,l.cn)("text-sm opacity-90",e),...t}));function v(){let{toasts:e}=(0,s.dj)();return(0,a.jsxs)(d,{children:[e.map(function({id:e,title:t,description:r,action:s,...o}){return(0,a.jsxs)(p,{...o,children:[(0,a.jsxs)("div",{className:"grid gap-1",children:[t&&(0,a.jsx)(f,{children:t}),r&&(0,a.jsx)(b,{children:r})]}),s,(0,a.jsx)(m,{})]},e)}),(0,a.jsx)(u,{})]})}b.displayName=i.VY.displayName},98180:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>u,metadata:()=>d});var a=r(62740),s=r(27944),o=r.n(s),i=r(95510),n=r.n(i);r(61135);var c=r(91831),l=r(13164);let d={title:"d1-studio",description:"Native D1 database studio."};function u({children:e}){return(0,a.jsx)("html",{lang:"en",children:(0,a.jsx)("body",{className:`${o().variable} ${n().variable} antialiased`,children:(0,a.jsxs)(c.DatabaseProvider,{children:[e,(0,a.jsx)(l.Toaster,{})," "]})})})}},13164:(e,t,r)=>{"use strict";r.d(t,{Toaster:()=>a});let a=(0,r(46760).registerClientReference)(function(){throw Error("Attempted to call Toaster() from the server but Toaster is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/Users/karenredona/Desktop/d1studio/src/components/ui/toaster.jsx","Toaster")},61135:()=>{},2899:(e,t,r)=>{"use strict";r.d(t,{DatabaseProvider:()=>u,t:()=>h});var a=r(45512),s=r(58009),o=r(46888);let i=new Map;function n(e,t,r=2e3){let a=i.get(e);if(a&&Date.now()-a.timestamp<r)return a.promise;let s=t();return i.set(e,{promise:s,timestamp:Date.now()}),s.finally(()=>{setTimeout(()=>{i.delete(e)},r)}),s}let c=(0,s.createContext)(void 0);class l{constructor(){this.cache=new Map}get(e){return this.cache.get(e)||null}set(e,t,r,a){this.cache.set(e,{data:t,schema:r,meta:a,timestamp:Date.now()})}update(e,t,r,a){let s=this.cache.get(e);s&&this.cache.set(e,{data:t||s.data,schema:r||s.schema,meta:a||s.meta,timestamp:Date.now()})}invalidate(e){this.cache.delete(e)}clear(){this.cache.clear()}}class d{constructor(){this.queue=[],this.processing=!1}async add(e){return new Promise((t,r)=>{this.queue.push({operation:e,resolve:t,reject:r}),this.process()})}async process(){if(this.processing||0===this.queue.length)return;this.processing=!0;let{operation:e,resolve:t,reject:r}=this.queue.shift();try{let r=await e();t(r)}catch(e){r(e)}finally{this.processing=!1,this.process()}}}function u({children:e}){let{toast:t}=(0,o.dj)(),[r,i]=(0,s.useState)([]),[u,h]=(0,s.useState)(!0),[p,m]=(0,s.useState)(null),[f,b]=(0,s.useState)(null);(0,s.useRef)(new d);let[v,y]=(0,s.useState)(null),g=(0,s.useRef)(new l).current,w=(0,s.useCallback)((e,t=1,r=50)=>{let a=`table-${e}-${t}-${r}`;return g.get(a)},[]),x=(0,s.useCallback)(e=>{g.cache.forEach((t,r)=>{r.startsWith(`table-${e}-`)&&g.invalidate(r)})},[]),T=(0,s.useCallback)((e,t,r,a,s=1,o=50)=>{let i=`table-${e}-${s}-${o}`;g.update(i,t,r,a)},[]),S=(0,s.useCallback)(async e=>n(`query-${e}`,async()=>{try{let t=await fetch("/api/query",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:e})});if(!t.ok){let e="Failed to execute query";try{let r=await t.json();e=r?.error?.message||e}catch(e){}throw Error(e)}let r=await t.json();if(!r.success)throw Error(r.error||"Query execution failed");return r}catch(e){throw e||Error("An unknown error occurred")}},1e3),[]),j=(0,s.useCallback)(async e=>{try{let t=await fetch(`/api/tables/${e}`),r=await t.json();if(!t.ok||!r.success)throw Error(r.error||"Failed to fetch table schema");return r.schema||[]}catch(e){throw console.error("Schema fetch error:",e),t({variant:"destructive",title:"Schema Fetch Failed",description:e.message}),e}},[t]),E=(0,s.useCallback)(async(e,r={})=>{let{forceFetch:a=!1,page:s=1,limit:o=50}=r,i=`table-${e}-${s}-${o}`;if(!a){let e=g.get(i);if(e)return e}return n(`table-${e}-${s}-${o}`,async()=>{try{let t=await fetch(`/api/tables/${e}?page=${s}&limit=${o}`,{headers:{"Cache-Control":"no-cache",Pragma:"no-cache"}});if(!t.ok)throw Error("Failed to fetch table data");let r=await t.json();if(!r.success)throw Error(r.error||"Failed to fetch table data");return g.set(i,r.data,r.schema,r.meta),r}catch(e){throw console.error("Error fetching table data:",e),t({variant:"destructive",title:"Data Fetch Failed",description:e.message}),e}},1e3)},[t]),C=(0,s.useCallback)(async e=>{try{return g.invalidate(e),await E(e,{forceFetch:!0})}catch(e){throw console.error("Error updating table data:",e),t({variant:"destructive",title:"Update Failed",description:e.message}),e}},[E,t]),P=(0,s.useCallback)(async(e,t={})=>(y(e),await E(e,t)),[E]),k=(0,s.useCallback)(async()=>n("refresh-tables",async()=>{h(!0),m(null);try{let e=await fetch("/api/tables");if(!e.ok)throw Error("Failed to fetch tables");let t=await e.json();if(t.error)throw Error(t.error);return i(t.tables||[]),t.tables||[]}catch(e){throw m(e.message),t({variant:"destructive",title:"Refresh Failed",description:e.message}),e}finally{h(!1)}},2e3),[t]),D=(0,s.useCallback)(async e=>{try{await S(e),g.clear(),await k(),t({title:"Success",description:"Table created successfully"})}catch(e){throw t({variant:"destructive",title:"Create Table Failed",description:e.message}),Error(`Failed to create table: ${e.message}`)}},[S,k,t]),N=(0,s.useCallback)(async e=>{try{await S(`DROP TABLE ${e};`),g.invalidate(e),await k(),t({title:"Success",description:"Table dropped successfully"})}catch(e){throw t({variant:"destructive",title:"Drop Table Failed",description:e.message}),Error(`Failed to drop table: ${e.message}`)}},[S,k,t]),$=(0,s.useCallback)(async e=>{try{let r=await fetch("/api/migrations/sync",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let e=await r.json();throw Error(e.error?.message||"Failed to sync migrations")}let a=await r.json();return t({title:"Success",description:"Migrations synced successfully"}),a}catch(e){throw console.error("Error syncing migrations:",e),t({variant:"destructive",title:"Sync Failed",description:e.message}),e}},[t]),F=(0,s.useCallback)(async()=>{try{let e=localStorage.getItem("cf_credentials");if(!e)throw Error("No Cloudflare credentials found. Please connect to Cloudflare first.");let t=JSON.parse(e);if(!t.accountId||!t.apiToken)throw Error("Invalid credentials stored. Please reconnect to Cloudflare.");let r=await fetch("/api/pull-remote/confirm",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({accountId:t.accountId,apiToken:t.apiToken})}),a=await r.json();if(!r.ok||!a.success)throw Error(a.error?.message||"Failed to pull from remote");return g.clear(),await k(),a}catch(e){throw console.error("Error pulling from remote:",e),t({variant:"destructive",title:"Pull Failed",description:e.message}),e}},[k,t]),O=(0,s.useCallback)(async e=>{try{let t=await fetch("/api/push-remote",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),r=await t.json();if(!t.ok)throw Error(r.error?.message||"Failed to push to remote");return r}catch(e){throw console.error("Error pushing to remote:",e),e}},[t]),A=(0,s.useMemo)(()=>({tables:r,currentDatabase:f,isLoading:u,error:p,activeTable:v,refreshTables:k,executeQuery:S,fetchTableSchema:j,fetchTableData:E,updateTableData:C,createTable:D,dropTable:N,syncMigrations:$,pullFromRemote:F,pushToRemote:O,getCachedTable:w,updateTableCache:T,invalidateTable:x,switchTable:P}),[r,f,u,p,v,k,S,j,E,C,D,N,$,F,O,w,T,x,P]);return(0,a.jsx)(c.Provider,{value:A,children:e})}function h(){let e=(0,s.useContext)(c);if(!e)throw Error("useDatabase must be used within a DatabaseProvider");return e}},46888:(e,t,r)=>{"use strict";r.d(t,{dj:()=>h});var a=r(58009);let s=0,o=new Map,i=e=>{if(o.has(e))return;let t=setTimeout(()=>{o.delete(e),d({type:"REMOVE_TOAST",toastId:e})},1e6);o.set(e,t)},n=(e,t)=>{switch(t.type){case"ADD_TOAST":return{...e,toasts:[t.toast,...e.toasts].slice(0,1)};case"UPDATE_TOAST":return{...e,toasts:e.toasts.map(e=>e.id===t.toast.id?{...e,...t.toast}:e)};case"DISMISS_TOAST":{let{toastId:r}=t;return r?i(r):e.toasts.forEach(e=>{i(e.id)}),{...e,toasts:e.toasts.map(e=>e.id===r||void 0===r?{...e,open:!1}:e)}}case"REMOVE_TOAST":if(void 0===t.toastId)return{...e,toasts:[]};return{...e,toasts:e.toasts.filter(e=>e.id!==t.toastId)}}},c=[],l={toasts:[]};function d(e){l=n(l,e),c.forEach(e=>{e(l)})}function u({...e}){let t=(s=(s+1)%Number.MAX_SAFE_INTEGER).toString(),r=()=>d({type:"DISMISS_TOAST",toastId:t});return d({type:"ADD_TOAST",toast:{...e,id:t,open:!0,onOpenChange:e=>{e||r()}}}),{id:t,dismiss:r,update:e=>d({type:"UPDATE_TOAST",toast:{...e,id:t}})}}function h(){let[e,t]=a.useState(l);return a.useEffect(()=>(c.push(t),()=>{let e=c.indexOf(t);e>-1&&c.splice(e,1)}),[e]),{...e,toast:u,dismiss:e=>d({type:"DISMISS_TOAST",toastId:e})}}},3603:(e,t,r)=>{"use strict";r.d(t,{cn:()=>o});var a=r(82281),s=r(94805);function o(...e){return(0,s.QP)((0,a.$)(e))}},91831:(e,t,r)=>{"use strict";r.d(t,{DatabaseProvider:()=>s});var a=r(46760);let s=(0,a.registerClientReference)(function(){throw Error("Attempted to call DatabaseProvider() from the server but DatabaseProvider is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/Users/karenredona/Desktop/d1studio/src/context/database-context.js","DatabaseProvider");(0,a.registerClientReference)(function(){throw Error("Attempted to call useDatabase() from the server but useDatabase is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/Users/karenredona/Desktop/d1studio/src/context/database-context.js","useDatabase")}};
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[177],{8671:(e,t,r)=>{Promise.resolve().then(r.t.bind(r,5613,23)),Promise.resolve().then(r.t.bind(r,7207,23)),Promise.resolve().then(r.t.bind(r,347,23)),Promise.resolve().then(r.bind(r,6124)),Promise.resolve().then(r.bind(r,33))},6124:(e,t,r)=>{"use strict";r.d(t,{Toaster:()=>g});var s=r(5155),a=r(6528),o=r(2115),d=r(9930),i=r(1027),n=r(689),l=r(4031);let u=d.Kq,c=o.forwardRef((e,t)=>{let{className:r,...a}=e;return(0,s.jsx)(d.LM,{ref:t,className:(0,l.cn)("fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",r),...a})});c.displayName=d.LM.displayName;let f=(0,i.F)("group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",{variants:{variant:{default:"border bg-background text-foreground",destructive:"destructive group border-destructive bg-destructive text-destructive-foreground"}},defaultVariants:{variant:"default"}}),p=o.forwardRef((e,t)=>{let{className:r,variant:a,...o}=e;return(0,s.jsx)(d.bL,{ref:t,className:(0,l.cn)(f({variant:a}),r),...o})});p.displayName=d.bL.displayName,o.forwardRef((e,t)=>{let{className:r,...a}=e;return(0,s.jsx)(d.rc,{ref:t,className:(0,l.cn)("inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",r),...a})}).displayName=d.rc.displayName;let m=o.forwardRef((e,t)=>{let{className:r,...a}=e;return(0,s.jsx)(d.bm,{ref:t,className:(0,l.cn)("absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",r),"toast-close":"",...a,children:(0,s.jsx)(n.A,{className:"h-4 w-4"})})});m.displayName=d.bm.displayName;let v=o.forwardRef((e,t)=>{let{className:r,...a}=e;return(0,s.jsx)(d.hE,{ref:t,className:(0,l.cn)("text-sm font-semibold [&+div]:text-xs",r),...a})});v.displayName=d.hE.displayName;let x=o.forwardRef((e,t)=>{let{className:r,...a}=e;return(0,s.jsx)(d.VY,{ref:t,className:(0,l.cn)("text-sm opacity-90",r),...a})});function g(){let{toasts:e}=(0,a.dj)();return(0,s.jsxs)(u,{children:[e.map(function(e){let{id:t,title:r,description:a,action:o,...d}=e;return(0,s.jsxs)(p,{...d,children:[(0,s.jsxs)("div",{className:"grid gap-1",children:[r&&(0,s.jsx)(v,{children:r}),a&&(0,s.jsx)(x,{children:a})]}),o,(0,s.jsx)(m,{})]},t)}),(0,s.jsx)(c,{})]})}x.displayName=d.VY.displayName},347:()=>{}},e=>{var t=t=>e(e.s=t);e.O(0,[280,692,92,735,441,517,358],()=>t(8671)),_N_E=e.O()}]);