d1s 0.2.13 → 0.3.0

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 (403) hide show
  1. package/README.md +14 -1
  2. package/dist/.next/.next/BUILD_ID +1 -1
  3. package/dist/.next/.next/app-build-manifest.json +121 -79
  4. package/dist/.next/.next/app-path-routes-manifest.json +1 -1
  5. package/dist/.next/.next/build-manifest.json +7 -7
  6. package/dist/.next/.next/cache/.rscinfo +1 -1
  7. package/dist/.next/.next/cache/.tsbuildinfo +1 -1
  8. package/dist/.next/.next/cache/webpack/client-development/0.pack.gz +0 -0
  9. package/dist/.next/.next/cache/webpack/client-development/1.pack.gz +0 -0
  10. package/dist/.next/.next/cache/webpack/client-development/index.pack.gz +0 -0
  11. package/dist/.next/.next/cache/webpack/client-development/index.pack.gz.old +0 -0
  12. package/dist/.next/.next/cache/webpack/client-production/0.pack +0 -0
  13. package/dist/.next/.next/cache/webpack/client-production/1.pack +0 -0
  14. package/dist/.next/.next/cache/webpack/client-production/10.pack +0 -0
  15. package/dist/.next/.next/cache/webpack/client-production/11.pack +0 -0
  16. package/dist/.next/.next/cache/webpack/client-production/12.pack +0 -0
  17. package/dist/.next/.next/cache/webpack/client-production/2.pack +0 -0
  18. package/dist/.next/.next/cache/webpack/client-production/3.pack +0 -0
  19. package/dist/.next/.next/cache/webpack/client-production/4.pack +0 -0
  20. package/dist/.next/.next/cache/webpack/client-production/5.pack +0 -0
  21. package/dist/.next/.next/cache/webpack/client-production/6.pack +0 -0
  22. package/dist/.next/.next/cache/webpack/client-production/7.pack +0 -0
  23. package/dist/.next/.next/cache/webpack/client-production/8.pack +0 -0
  24. package/dist/.next/.next/cache/webpack/client-production/9.pack +0 -0
  25. package/dist/.next/.next/cache/webpack/client-production/index.pack +0 -0
  26. package/dist/.next/.next/cache/webpack/client-production/index.pack.old +0 -0
  27. package/dist/.next/.next/cache/webpack/edge-server-production/index.pack +0 -0
  28. package/dist/.next/.next/cache/webpack/server-development/0.pack.gz +0 -0
  29. package/dist/.next/.next/cache/webpack/server-development/1.pack.gz +0 -0
  30. package/dist/.next/.next/cache/webpack/server-development/index.pack.gz +0 -0
  31. package/dist/.next/.next/cache/webpack/server-production/0.pack +0 -0
  32. package/dist/.next/.next/cache/webpack/server-production/1.pack +0 -0
  33. package/dist/.next/.next/cache/webpack/server-production/index.pack +0 -0
  34. package/dist/.next/.next/cache/webpack/server-production/index.pack.old +0 -0
  35. package/dist/.next/.next/next-minimal-server.js.nft.json +1 -1
  36. package/dist/.next/.next/next-server.js.nft.json +1 -1
  37. package/dist/.next/.next/prerender-manifest.json +1 -1
  38. package/dist/.next/.next/react-loadable-manifest.json +11 -1
  39. package/dist/.next/.next/required-server-files.json +1 -1
  40. package/dist/.next/.next/routes-manifest.json +1 -1
  41. package/dist/.next/.next/server/app/_not-found/page.js +1 -1
  42. package/dist/.next/.next/server/app/_not-found/page.js.nft.json +1 -1
  43. package/dist/.next/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  44. package/dist/.next/.next/server/app/_not-found.html +1 -1
  45. package/dist/.next/.next/server/app/_not-found.rsc +5 -5
  46. package/dist/.next/.next/server/app/api/cloudflare/route.js +1 -1
  47. package/dist/.next/.next/server/app/api/cloudflare/route.js.nft.json +1 -1
  48. package/dist/.next/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  49. package/dist/.next/.next/server/app/api/databases/route.js +1 -1
  50. package/dist/.next/.next/server/app/api/databases/route.js.nft.json +1 -1
  51. package/dist/.next/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  52. package/dist/.next/.next/server/app/api/migrations/list/route.js +26 -0
  53. package/dist/.next/.next/server/app/api/migrations/list/route.js.nft.json +1 -0
  54. package/dist/.next/.next/server/app/api/migrations/list/route_client-reference-manifest.js +1 -0
  55. package/dist/.next/.next/server/app/api/migrations/sync/route.js +5 -5
  56. package/dist/.next/.next/server/app/api/migrations/sync/route.js.nft.json +1 -1
  57. package/dist/.next/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  58. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js +4 -4
  59. package/dist/.next/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -1
  60. package/dist/.next/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  61. package/dist/.next/.next/server/app/api/pro/route.js +1 -0
  62. package/dist/.next/.next/server/app/api/pro/route.js.nft.json +1 -0
  63. package/dist/.next/.next/server/app/api/pro/route_client-reference-manifest.js +1 -0
  64. package/dist/.next/.next/server/app/api/pull-data/confirm/route.js +1 -1
  65. package/dist/.next/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -1
  66. package/dist/.next/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  67. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js +4 -4
  68. package/dist/.next/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -1
  69. package/dist/.next/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  70. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js +4 -4
  71. package/dist/.next/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -1
  72. package/dist/.next/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  73. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js +6 -6
  74. package/dist/.next/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -1
  75. package/dist/.next/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  76. package/dist/.next/.next/server/app/api/push-remote/preview/route.js +6 -6
  77. package/dist/.next/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -1
  78. package/dist/.next/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  79. package/dist/.next/.next/server/app/api/query/route.js +9 -9
  80. package/dist/.next/.next/server/app/api/query/route.js.nft.json +1 -1
  81. package/dist/.next/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  82. package/dist/.next/.next/server/app/api/schema/route.js +1 -0
  83. package/dist/.next/.next/server/app/api/schema/route.js.nft.json +1 -0
  84. package/dist/.next/.next/server/app/api/schema/route_client-reference-manifest.js +1 -0
  85. package/dist/.next/.next/server/app/api/tables/[name]/import/route.js +1 -0
  86. package/dist/.next/.next/server/app/api/tables/[name]/import/route.js.nft.json +1 -0
  87. package/dist/.next/.next/server/app/api/tables/[name]/import/route_client-reference-manifest.js +1 -0
  88. package/dist/.next/.next/server/app/api/tables/[name]/route.js +5 -5
  89. package/dist/.next/.next/server/app/api/tables/[name]/route.js.nft.json +1 -1
  90. package/dist/.next/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  91. package/dist/.next/.next/server/app/api/tables/route.js +2 -2
  92. package/dist/.next/.next/server/app/api/tables/route.js.nft.json +1 -1
  93. package/dist/.next/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  94. package/dist/.next/.next/server/app/api/time-travel/preview/route.js +1 -0
  95. package/dist/.next/.next/server/app/api/time-travel/preview/route.js.nft.json +1 -0
  96. package/dist/.next/.next/server/app/api/time-travel/preview/route_client-reference-manifest.js +1 -0
  97. package/dist/.next/.next/server/app/api/time-travel/restore/route.js +1 -0
  98. package/dist/.next/.next/server/app/api/time-travel/restore/route.js.nft.json +1 -0
  99. package/dist/.next/.next/server/app/api/time-travel/restore/route_client-reference-manifest.js +1 -0
  100. package/dist/.next/.next/server/app/api/update/route.js +1 -1
  101. package/dist/.next/.next/server/app/api/update/route.js.nft.json +1 -1
  102. package/dist/.next/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  103. package/dist/.next/.next/server/app/index.html +5 -3
  104. package/dist/.next/.next/server/app/index.rsc +6 -6
  105. package/dist/.next/.next/server/app/page.js +15 -15
  106. package/dist/.next/.next/server/app/page.js.nft.json +1 -1
  107. package/dist/.next/.next/server/app/page_client-reference-manifest.js +1 -1
  108. package/dist/.next/.next/server/app-paths-manifest.json +10 -4
  109. package/dist/.next/.next/server/chunks/226.js +12 -12
  110. package/dist/.next/.next/server/chunks/391.js +1 -1
  111. package/dist/.next/.next/server/chunks/452.js +1 -1
  112. package/dist/.next/.next/server/chunks/487.js +1 -0
  113. package/dist/.next/.next/server/chunks/572.js +1 -1
  114. package/dist/.next/.next/server/chunks/992.js +3 -3
  115. package/dist/.next/{server/chunks/638.js → .next/server/chunks/994.js} +3 -3
  116. package/dist/.next/.next/server/middleware-build-manifest.js +1 -1
  117. package/dist/.next/.next/server/middleware-react-loadable-manifest.js +1 -1
  118. package/dist/.next/.next/server/next-font-manifest.js +1 -1
  119. package/dist/.next/.next/server/next-font-manifest.json +1 -1
  120. package/dist/.next/.next/server/pages/404.html +1 -1
  121. package/dist/.next/.next/server/pages/500.html +1 -1
  122. package/dist/.next/.next/server/pages-manifest.json +1 -1
  123. package/dist/.next/.next/server/server-reference-manifest.json +1 -1
  124. package/dist/.next/.next/static/-OO4tE7EKr8o62Bne-ODo/_buildManifest.js +1 -0
  125. package/dist/.next/.next/static/3kAeIJC56X7aw1Fk5_OXO/_buildManifest.js +1 -0
  126. package/dist/.next/.next/static/J8r9W6xxmYYvuKehItNuW/_buildManifest.js +1 -0
  127. package/dist/.next/.next/static/arc9h7hbaQzL1Dl0iuVrT/_buildManifest.js +1 -0
  128. package/dist/.next/.next/static/chunks/1a258343.3b3e7ba5ba0bd0d2.js +1 -0
  129. package/dist/.next/.next/static/chunks/345.8fc37569d5708622.js +1 -0
  130. package/dist/.next/.next/static/chunks/480-85b6c8ae3f51b156.js +1 -0
  131. package/dist/.next/.next/static/chunks/52.2cdc9bdb75e1fc2e.js +1 -0
  132. package/dist/.next/.next/static/chunks/803-a2fcfbd00e6b3b38.js +1 -0
  133. package/dist/.next/.next/static/chunks/{92-5f7522943fcb72a8.js → 92-a84bdac2be7c8d7a.js} +1 -1
  134. package/dist/.next/.next/static/chunks/app/api/cloudflare/route-d0c1dc2a9e7dce36.js +1 -0
  135. package/dist/.next/.next/static/chunks/app/api/databases/route-cd322321212797cf.js +1 -0
  136. package/dist/.next/.next/static/chunks/app/api/migrations/list/route-cd710ff75b6bcd02.js +1 -0
  137. package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-ee522f232b9f0a9c.js +1 -0
  138. package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-79ee2c26f87d3bc7.js +1 -0
  139. package/dist/.next/.next/static/chunks/app/api/pro/route-c90c1f901fc00d38.js +1 -0
  140. package/dist/.next/.next/static/chunks/app/api/pull-data/confirm/route-118764086af798f8.js +1 -0
  141. package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-2b0ade4ebfcea0bc.js +1 -0
  142. package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-342db7ea13e6f447.js +1 -0
  143. package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-b778c053bd515abd.js +1 -0
  144. package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-ab090482f299f57f.js +1 -0
  145. package/dist/.next/.next/static/chunks/app/api/query/route-4d21a8b1d34491f1.js +1 -0
  146. package/dist/.next/.next/static/chunks/app/api/schema/route-cb17a387d6b557ad.js +1 -0
  147. package/dist/.next/.next/static/chunks/app/api/tables/[name]/import/route-510472de7a5c29bd.js +1 -0
  148. package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-6a1fa95c303ce0de.js +1 -0
  149. package/dist/.next/.next/static/chunks/app/api/tables/route-daa975df4ea8e8f8.js +1 -0
  150. package/dist/.next/.next/static/chunks/app/api/time-travel/preview/route-5787d7e8f17bd539.js +1 -0
  151. package/dist/.next/.next/static/chunks/app/api/time-travel/restore/route-84b64a27e831e21c.js +1 -0
  152. package/dist/.next/.next/static/chunks/app/api/update/route-54ee900537982652.js +1 -0
  153. package/dist/.next/.next/static/chunks/app/{layout-40ec07d04681ba81.js → layout-f0ec4d636ee0f763.js} +1 -1
  154. package/dist/.next/.next/static/chunks/app/page-358bf2112802ff85.js +1 -0
  155. package/dist/.next/.next/static/chunks/webpack-024900a94af4f0a7.js +1 -0
  156. package/dist/.next/.next/static/css/2c165a0ede9b2442.css +3 -0
  157. package/dist/.next/.next/static/css/32df9a4d493f8b0f.css +31 -0
  158. package/dist/.next/.next/static/fiesjBWbrmSSyLf4biwrX/_buildManifest.js +1 -0
  159. package/dist/.next/.next/static/ft39e6W6vSgUL7peRo7pE/_buildManifest.js +1 -0
  160. package/dist/.next/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  161. package/dist/.next/.next/static/u7ssdTycF4iQ-w-pQZhxg/_buildManifest.js +1 -0
  162. package/dist/.next/.next/trace +3 -3
  163. package/dist/.next/.next/types/app/api/migrations/list/route.ts +347 -0
  164. package/dist/.next/.next/types/app/api/pro/route.ts +347 -0
  165. package/dist/.next/.next/types/app/api/schema/route.ts +347 -0
  166. package/dist/.next/.next/types/app/api/tables/[name]/import/route.ts +347 -0
  167. package/dist/.next/.next/types/app/api/time-travel/preview/route.ts +347 -0
  168. package/dist/.next/.next/types/app/api/time-travel/restore/route.ts +347 -0
  169. package/dist/.next/BUILD_ID +1 -1
  170. package/dist/.next/app-build-manifest.json +122 -80
  171. package/dist/.next/app-path-routes-manifest.json +1 -1
  172. package/dist/.next/build-manifest.json +7 -7
  173. package/dist/.next/cache/.rscinfo +1 -1
  174. package/dist/.next/cache/.tsbuildinfo +1 -1
  175. package/dist/.next/cache/webpack/client-production/0.pack +0 -0
  176. package/dist/.next/cache/webpack/client-production/index.pack +0 -0
  177. package/dist/.next/cache/webpack/edge-server-production/index.pack +0 -0
  178. package/dist/.next/cache/webpack/server-production/0.pack +0 -0
  179. package/dist/.next/cache/webpack/server-production/index.pack +0 -0
  180. package/dist/.next/next-minimal-server.js.nft.json +1 -1
  181. package/dist/.next/next-server.js.nft.json +1 -1
  182. package/dist/.next/prerender-manifest.json +1 -1
  183. package/dist/.next/react-loadable-manifest.json +11 -1
  184. package/dist/.next/required-server-files.json +1 -1
  185. package/dist/.next/routes-manifest.json +1 -1
  186. package/dist/.next/server/app/_not-found/page.js +1 -1
  187. package/dist/.next/server/app/_not-found/page.js.nft.json +1 -1
  188. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  189. package/dist/.next/server/app/_not-found.html +1 -1
  190. package/dist/.next/server/app/_not-found.rsc +5 -5
  191. package/dist/.next/server/app/api/cloudflare/route.js +1 -1
  192. package/dist/.next/server/app/api/cloudflare/route.js.nft.json +1 -1
  193. package/dist/.next/server/app/api/cloudflare/route_client-reference-manifest.js +1 -1
  194. package/dist/.next/server/app/api/databases/route.js +1 -1
  195. package/dist/.next/server/app/api/databases/route.js.nft.json +1 -1
  196. package/dist/.next/server/app/api/databases/route_client-reference-manifest.js +1 -1
  197. package/dist/.next/server/app/api/migrations/list/route.js +26 -0
  198. package/dist/.next/server/app/api/migrations/list/route.js.nft.json +1 -0
  199. package/dist/.next/server/app/api/migrations/list/route_client-reference-manifest.js +1 -0
  200. package/dist/.next/server/app/api/migrations/sync/route.js +5 -5
  201. package/dist/.next/server/app/api/migrations/sync/route.js.nft.json +1 -1
  202. package/dist/.next/server/app/api/migrations/sync/route_client-reference-manifest.js +1 -1
  203. package/dist/.next/server/app/api/migrations/sync-files/route.js +4 -4
  204. package/dist/.next/server/app/api/migrations/sync-files/route.js.nft.json +1 -1
  205. package/dist/.next/server/app/api/migrations/sync-files/route_client-reference-manifest.js +1 -1
  206. package/dist/.next/server/app/api/pro/route.js +1 -0
  207. package/dist/.next/server/app/api/pro/route.js.nft.json +1 -0
  208. package/dist/.next/server/app/api/pro/route_client-reference-manifest.js +1 -0
  209. package/dist/.next/server/app/api/pull-data/confirm/route.js +1 -1
  210. package/dist/.next/server/app/api/pull-data/confirm/route.js.nft.json +1 -1
  211. package/dist/.next/server/app/api/pull-data/confirm/route_client-reference-manifest.js +1 -1
  212. package/dist/.next/server/app/api/pull-remote/confirm/route.js +4 -4
  213. package/dist/.next/server/app/api/pull-remote/confirm/route.js.nft.json +1 -1
  214. package/dist/.next/server/app/api/pull-remote/confirm/route_client-reference-manifest.js +1 -1
  215. package/dist/.next/server/app/api/pull-remote/preview/route.js +4 -4
  216. package/dist/.next/server/app/api/pull-remote/preview/route.js.nft.json +1 -1
  217. package/dist/.next/server/app/api/pull-remote/preview/route_client-reference-manifest.js +1 -1
  218. package/dist/.next/server/app/api/push-remote/confirm/route.js +6 -6
  219. package/dist/.next/server/app/api/push-remote/confirm/route.js.nft.json +1 -1
  220. package/dist/.next/server/app/api/push-remote/confirm/route_client-reference-manifest.js +1 -1
  221. package/dist/.next/server/app/api/push-remote/preview/route.js +6 -6
  222. package/dist/.next/server/app/api/push-remote/preview/route.js.nft.json +1 -1
  223. package/dist/.next/server/app/api/push-remote/preview/route_client-reference-manifest.js +1 -1
  224. package/dist/.next/server/app/api/query/route.js +9 -9
  225. package/dist/.next/server/app/api/query/route.js.nft.json +1 -1
  226. package/dist/.next/server/app/api/query/route_client-reference-manifest.js +1 -1
  227. package/dist/.next/server/app/api/schema/route.js +1 -0
  228. package/dist/.next/server/app/api/schema/route.js.nft.json +1 -0
  229. package/dist/.next/server/app/api/schema/route_client-reference-manifest.js +1 -0
  230. package/dist/.next/server/app/api/tables/[name]/import/route.js +1 -0
  231. package/dist/.next/server/app/api/tables/[name]/import/route.js.nft.json +1 -0
  232. package/dist/.next/server/app/api/tables/[name]/import/route_client-reference-manifest.js +1 -0
  233. package/dist/.next/server/app/api/tables/[name]/route.js +5 -5
  234. package/dist/.next/server/app/api/tables/[name]/route.js.nft.json +1 -1
  235. package/dist/.next/server/app/api/tables/[name]/route_client-reference-manifest.js +1 -1
  236. package/dist/.next/server/app/api/tables/route.js +2 -2
  237. package/dist/.next/server/app/api/tables/route.js.nft.json +1 -1
  238. package/dist/.next/server/app/api/tables/route_client-reference-manifest.js +1 -1
  239. package/dist/.next/server/app/api/time-travel/preview/route.js +1 -0
  240. package/dist/.next/server/app/api/time-travel/preview/route.js.nft.json +1 -0
  241. package/dist/.next/server/app/api/time-travel/preview/route_client-reference-manifest.js +1 -0
  242. package/dist/.next/server/app/api/time-travel/restore/route.js +1 -0
  243. package/dist/.next/server/app/api/time-travel/restore/route.js.nft.json +1 -0
  244. package/dist/.next/server/app/api/time-travel/restore/route_client-reference-manifest.js +1 -0
  245. package/dist/.next/server/app/api/update/route.js +1 -1
  246. package/dist/.next/server/app/api/update/route.js.nft.json +1 -1
  247. package/dist/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  248. package/dist/.next/server/app/index.html +5 -3
  249. package/dist/.next/server/app/index.rsc +6 -6
  250. package/dist/.next/server/app/page.js +15 -15
  251. package/dist/.next/server/app/page.js.nft.json +1 -1
  252. package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
  253. package/dist/.next/server/app-paths-manifest.json +11 -5
  254. package/dist/.next/server/chunks/226.js +12 -12
  255. package/dist/.next/server/chunks/391.js +1 -1
  256. package/dist/.next/server/chunks/452.js +1 -1
  257. package/dist/.next/server/chunks/487.js +1 -0
  258. package/dist/.next/server/chunks/572.js +1 -1
  259. package/dist/.next/server/chunks/992.js +3 -3
  260. package/dist/.next/{.next/server/chunks/638.js → server/chunks/994.js} +3 -3
  261. package/dist/.next/server/middleware-build-manifest.js +1 -1
  262. package/dist/.next/server/middleware-react-loadable-manifest.js +1 -1
  263. package/dist/.next/server/next-font-manifest.js +1 -1
  264. package/dist/.next/server/next-font-manifest.json +1 -1
  265. package/dist/.next/server/pages/404.html +1 -1
  266. package/dist/.next/server/pages/500.html +1 -1
  267. package/dist/.next/server/pages-manifest.json +1 -1
  268. package/dist/.next/server/server-reference-manifest.json +1 -1
  269. package/dist/.next/static/chunks/1a258343.3b3e7ba5ba0bd0d2.js +1 -0
  270. package/dist/.next/static/chunks/345.8fc37569d5708622.js +1 -0
  271. package/dist/.next/static/chunks/480-85b6c8ae3f51b156.js +1 -0
  272. package/dist/.next/static/chunks/52.2cdc9bdb75e1fc2e.js +1 -0
  273. package/dist/.next/static/chunks/803-a2fcfbd00e6b3b38.js +1 -0
  274. package/dist/.next/static/chunks/{92-5f7522943fcb72a8.js → 92-a84bdac2be7c8d7a.js} +1 -1
  275. package/dist/.next/static/chunks/app/api/cloudflare/route-d0c1dc2a9e7dce36.js +1 -0
  276. package/dist/.next/static/chunks/app/api/databases/route-cd322321212797cf.js +1 -0
  277. package/dist/.next/static/chunks/app/api/migrations/list/route-cd710ff75b6bcd02.js +1 -0
  278. package/dist/.next/static/chunks/app/api/migrations/sync/route-ee522f232b9f0a9c.js +1 -0
  279. package/dist/.next/static/chunks/app/api/migrations/sync-files/route-79ee2c26f87d3bc7.js +1 -0
  280. package/dist/.next/static/chunks/app/api/pro/route-c90c1f901fc00d38.js +1 -0
  281. package/dist/.next/static/chunks/app/api/pull-data/confirm/route-118764086af798f8.js +1 -0
  282. package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-2b0ade4ebfcea0bc.js +1 -0
  283. package/dist/.next/static/chunks/app/api/pull-remote/preview/route-342db7ea13e6f447.js +1 -0
  284. package/dist/.next/static/chunks/app/api/push-remote/confirm/route-b778c053bd515abd.js +1 -0
  285. package/dist/.next/static/chunks/app/api/push-remote/preview/route-ab090482f299f57f.js +1 -0
  286. package/dist/.next/static/chunks/app/api/query/route-4d21a8b1d34491f1.js +1 -0
  287. package/dist/.next/static/chunks/app/api/schema/route-cb17a387d6b557ad.js +1 -0
  288. package/dist/.next/static/chunks/app/api/tables/[name]/import/route-510472de7a5c29bd.js +1 -0
  289. package/dist/.next/static/chunks/app/api/tables/[name]/route-6a1fa95c303ce0de.js +1 -0
  290. package/dist/.next/static/chunks/app/api/tables/route-daa975df4ea8e8f8.js +1 -0
  291. package/dist/.next/static/chunks/app/api/time-travel/preview/route-5787d7e8f17bd539.js +1 -0
  292. package/dist/.next/static/chunks/app/api/time-travel/restore/route-84b64a27e831e21c.js +1 -0
  293. package/dist/.next/static/chunks/app/api/update/route-54ee900537982652.js +1 -0
  294. package/dist/.next/static/chunks/app/{layout-40ec07d04681ba81.js → layout-f0ec4d636ee0f763.js} +1 -1
  295. package/dist/.next/static/chunks/app/page-358bf2112802ff85.js +1 -0
  296. package/dist/.next/static/chunks/webpack-024900a94af4f0a7.js +1 -0
  297. package/dist/.next/static/css/2c165a0ede9b2442.css +3 -0
  298. package/dist/.next/static/css/32df9a4d493f8b0f.css +31 -0
  299. package/dist/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  300. package/dist/.next/static/zh4Fz2tbm8GRka4woRrGp/_buildManifest.js +1 -0
  301. package/dist/.next/trace +18 -3
  302. package/dist/.next/types/app/api/migrations/list/route.ts +347 -0
  303. package/dist/.next/types/app/api/pro/route.ts +347 -0
  304. package/dist/.next/types/app/api/schema/route.ts +347 -0
  305. package/dist/.next/types/app/api/tables/[name]/import/route.ts +347 -0
  306. package/dist/.next/types/app/api/time-travel/preview/route.ts +347 -0
  307. package/dist/.next/types/app/api/time-travel/restore/route.ts +347 -0
  308. package/dist/app/api/databases/route.js +2 -1
  309. package/dist/app/api/migrations/list/route.js +137 -0
  310. package/dist/app/api/migrations/sync-files/route.js +2 -1
  311. package/dist/app/api/pro/route.js +7 -0
  312. package/dist/app/api/pull-remote/confirm/route.js +138 -146
  313. package/dist/app/api/pull-remote/preview/route.js +49 -84
  314. package/dist/app/api/push-remote/confirm/route.js +31 -12
  315. package/dist/app/api/push-remote/preview/route.js +27 -12
  316. package/dist/app/api/query/route.js +24 -13
  317. package/dist/app/api/schema/route.js +63 -0
  318. package/dist/app/api/tables/[name]/import/route.js +112 -0
  319. package/dist/app/api/tables/[name]/route.js +38 -29
  320. package/dist/app/api/tables/route.js +29 -16
  321. package/dist/app/api/time-travel/preview/route.js +122 -0
  322. package/dist/app/api/time-travel/restore/route.js +106 -0
  323. package/dist/app/page.jsx +26 -8
  324. package/dist/d1-studio.js +129 -23
  325. package/dist/lib/license.js +99 -71
  326. package/dist/lib/local-db.js +223 -0
  327. package/dist/lib/migrations.js +40 -2
  328. package/dist/lib/parse-sql-error.js +99 -160
  329. package/dist/lib/sql-operations.js +28 -10
  330. package/dist/lib/telemetry.js +39 -0
  331. package/package.json +6 -2
  332. package/dist/.next/.next/cache/webpack/server-production/2.pack +0 -0
  333. package/dist/.next/.next/cache/webpack/server-production/3.pack +0 -0
  334. package/dist/.next/.next/static/FEsQ9jwPUQv5A3fwg6Opl/_buildManifest.js +0 -1
  335. package/dist/.next/.next/static/Y9mYu4WBghepP5oT_3OdR/_buildManifest.js +0 -1
  336. package/dist/.next/.next/static/ae3gNmoSGm-R5LJC4UagI/_buildManifest.js +0 -1
  337. package/dist/.next/.next/static/bKfUJeuvAQlBmR3TjrfkH/_buildManifest.js +0 -1
  338. package/dist/.next/.next/static/chunks/576-18a2209e1ed26aad.js +0 -1
  339. package/dist/.next/.next/static/chunks/735-b885dfec6353171d.js +0 -1
  340. package/dist/.next/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +0 -1
  341. package/dist/.next/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +0 -1
  342. package/dist/.next/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +0 -1
  343. package/dist/.next/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +0 -1
  344. package/dist/.next/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +0 -1
  345. package/dist/.next/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +0 -1
  346. package/dist/.next/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +0 -1
  347. package/dist/.next/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +0 -1
  348. package/dist/.next/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +0 -1
  349. package/dist/.next/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +0 -1
  350. package/dist/.next/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +0 -1
  351. package/dist/.next/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +0 -1
  352. package/dist/.next/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +0 -1
  353. package/dist/.next/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +0 -1
  354. package/dist/.next/.next/static/chunks/app/page-f2bc307c0d8acdaa.js +0 -1
  355. package/dist/.next/.next/static/chunks/webpack-c76ac1e586b2802a.js +0 -1
  356. package/dist/.next/.next/static/css/7c16f57d325d0d7d.css +0 -3
  357. package/dist/.next/.next/static/ejYPqJ2kVicVp5EFWOZIC/_buildManifest.js +0 -1
  358. package/dist/.next/.next/static/gABGrAoO8IPArDo_Ns_7g/_buildManifest.js +0 -1
  359. package/dist/.next/.next/static/gh-QfIUVo4FTTduYCVKT6/_buildManifest.js +0 -1
  360. package/dist/.next/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
  361. package/dist/.next/.next/static/thaCy2qVeNqYYhdayr13C/_buildManifest.js +0 -1
  362. package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_buildManifest.js +0 -1
  363. package/dist/.next/.next/static/ybCx6L6gHqtODbKmlhU-d/_ssgManifest.js +0 -1
  364. package/dist/.next/cache/webpack/client-production/1.pack +0 -0
  365. package/dist/.next/cache/webpack/client-production/2.pack +0 -0
  366. package/dist/.next/cache/webpack/client-production/index.pack.old +0 -0
  367. package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_buildManifest.js +0 -1
  368. package/dist/.next/static/IX-QLbm7scYnyqWeeimal/_ssgManifest.js +0 -1
  369. package/dist/.next/static/chunks/576-18a2209e1ed26aad.js +0 -1
  370. package/dist/.next/static/chunks/735-b885dfec6353171d.js +0 -1
  371. package/dist/.next/static/chunks/app/api/cloudflare/route-b77846f372b01f38.js +0 -1
  372. package/dist/.next/static/chunks/app/api/databases/route-407794f8145d9a0b.js +0 -1
  373. package/dist/.next/static/chunks/app/api/migrations/sync/route-9f480f5590369a8f.js +0 -1
  374. package/dist/.next/static/chunks/app/api/migrations/sync-files/route-92010db279b4dd8e.js +0 -1
  375. package/dist/.next/static/chunks/app/api/pull-data/confirm/route-a02fe6d3cdd0a535.js +0 -1
  376. package/dist/.next/static/chunks/app/api/pull-remote/confirm/route-f401a03507d1da50.js +0 -1
  377. package/dist/.next/static/chunks/app/api/pull-remote/preview/route-3c53814b5cb8b6b0.js +0 -1
  378. package/dist/.next/static/chunks/app/api/push-remote/confirm/route-8f359249e907c63b.js +0 -1
  379. package/dist/.next/static/chunks/app/api/push-remote/preview/route-b51bf94f39c17a9d.js +0 -1
  380. package/dist/.next/static/chunks/app/api/query/route-87bae2d4aebaf859.js +0 -1
  381. package/dist/.next/static/chunks/app/api/tables/[name]/route-d20ca163b9c03e7c.js +0 -1
  382. package/dist/.next/static/chunks/app/api/tables/route-0f46f911562abcdf.js +0 -1
  383. package/dist/.next/static/chunks/app/api/update/route-14edc1917760bce0.js +0 -1
  384. package/dist/.next/static/chunks/app/page-f05cd0fc436bf9bc.js +0 -1
  385. package/dist/.next/static/chunks/webpack-c76ac1e586b2802a.js +0 -1
  386. package/dist/.next/static/css/7c16f57d325d0d7d.css +0 -3
  387. package/dist/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
  388. /package/dist/.next/.next/static/{FEsQ9jwPUQv5A3fwg6Opl → -OO4tE7EKr8o62Bne-ODo}/_ssgManifest.js +0 -0
  389. /package/dist/.next/.next/static/{Y9mYu4WBghepP5oT_3OdR → 3kAeIJC56X7aw1Fk5_OXO}/_ssgManifest.js +0 -0
  390. /package/dist/.next/.next/static/{ae3gNmoSGm-R5LJC4UagI → J8r9W6xxmYYvuKehItNuW}/_ssgManifest.js +0 -0
  391. /package/dist/.next/.next/static/{bKfUJeuvAQlBmR3TjrfkH → arc9h7hbaQzL1Dl0iuVrT}/_ssgManifest.js +0 -0
  392. /package/dist/.next/.next/static/chunks/{4bd1b696-8c908eb707f85a27.js → 4bd1b696-124ea104c06f6cea.js} +0 -0
  393. /package/dist/.next/.next/static/chunks/{517-3b698a5d3da06ff7.js → 517-c876ce2f00030cd0.js} +0 -0
  394. /package/dist/.next/.next/static/chunks/{692-ede418e1d28a1394.js → 692-9e59d546afd11ec3.js} +0 -0
  395. /package/dist/.next/.next/static/chunks/app/_not-found/{page-b786c3dd79ad15a5.js → page-3e24b81707d98126.js} +0 -0
  396. /package/dist/.next/.next/static/{ejYPqJ2kVicVp5EFWOZIC → fiesjBWbrmSSyLf4biwrX}/_ssgManifest.js +0 -0
  397. /package/dist/.next/.next/static/{gABGrAoO8IPArDo_Ns_7g → ft39e6W6vSgUL7peRo7pE}/_ssgManifest.js +0 -0
  398. /package/dist/.next/.next/static/{gh-QfIUVo4FTTduYCVKT6 → u7ssdTycF4iQ-w-pQZhxg}/_ssgManifest.js +0 -0
  399. /package/dist/.next/static/chunks/{4bd1b696-8c908eb707f85a27.js → 4bd1b696-124ea104c06f6cea.js} +0 -0
  400. /package/dist/.next/static/chunks/{517-3b698a5d3da06ff7.js → 517-c876ce2f00030cd0.js} +0 -0
  401. /package/dist/.next/static/chunks/{692-ede418e1d28a1394.js → 692-9e59d546afd11ec3.js} +0 -0
  402. /package/dist/.next/static/chunks/app/_not-found/{page-b786c3dd79ad15a5.js → page-3e24b81707d98126.js} +0 -0
  403. /package/dist/.next/{.next/static/thaCy2qVeNqYYhdayr13C → static/zh4Fz2tbm8GRka4woRrGp}/_ssgManifest.js +0 -0
package/dist/d1-studio.js CHANGED
@@ -2,14 +2,63 @@
2
2
  import chalk from 'chalk';
3
3
  import open from 'open';
4
4
  import { fileURLToPath } from 'url';
5
- import { dirname, join } from 'path';
5
+ import { dirname, join, resolve } from 'path';
6
+ import { existsSync, readFileSync } from 'fs';
7
+ import { homedir } from 'os';
6
8
  import express from 'express';
7
9
  import { createServer } from 'http';
8
10
  import next from 'next';
9
11
  import { findWranglerConfig } from './lib/find-wrangler-config.js';
10
12
  import logger from './lib/logger.js';
13
+ import { activateLicense, getOrValidateLicense } from '../src/lib/license.js';
11
14
  import updateNotifier from 'update-notifier';
12
15
  import pkg from '../package.json' with { type: 'json' };
16
+ import { trackEvent } from '../src/lib/telemetry.js';
17
+
18
+ /**
19
+ * Detects wrangler credentials and optionally injects a Cloudflare API token.
20
+ *
21
+ * OAuth tokens from `wrangler login` are intentionally NOT injected as
22
+ * CLOUDFLARE_API_TOKEN — wrangler handles its own OAuth flow (including
23
+ * token refresh) when it finds the config file. Injecting the raw OAuth
24
+ * access token would bypass the refresh cycle and break auth when it expires.
25
+ *
26
+ * Only a real API token (api_token in the config, or CLOUDFLARE_API_TOKEN
27
+ * already in env) is injected so wrangler subprocesses inherit it explicitly.
28
+ *
29
+ * Returns 'injected' | 'oauth' | 'found' | null.
30
+ */
31
+ function loadAndInjectWranglerCredentials() {
32
+ // If an explicit API token is already in the environment, nothing to do
33
+ if (process.env.CLOUDFLARE_API_TOKEN) return 'injected';
34
+
35
+ const home = homedir();
36
+ const candidates = [
37
+ join(home, 'Library', 'Preferences', '.wrangler', 'config', 'default.toml'), // macOS
38
+ join(home, '.config', '.wrangler', 'config', 'default.toml'), // Linux XDG
39
+ join(home, '.wrangler', 'config', 'default.toml'), // older versions
40
+ ];
41
+
42
+ for (const configPath of candidates) {
43
+ if (!existsSync(configPath)) continue;
44
+ try {
45
+ const content = readFileSync(configPath, 'utf8');
46
+ // Only inject a Cloudflare API token (not an OAuth access token)
47
+ const apiMatch = content.match(/api_token\s*=\s*"([^"]+)"/);
48
+ if (apiMatch?.[1]) {
49
+ process.env.CLOUDFLARE_API_TOKEN = apiMatch[1];
50
+ return 'injected';
51
+ }
52
+ // OAuth credentials from `wrangler login` — wrangler reads these itself
53
+ if (/oauth_token\s*=\s*"[^"]+"/.test(content)) return 'oauth';
54
+ // File exists but no usable token
55
+ return 'found';
56
+ } catch {
57
+ // Ignore read/parse errors, try next candidate
58
+ }
59
+ }
60
+ return null;
61
+ }
13
62
 
14
63
  // Check for debug flag
15
64
  const hasDebugFlag = process.argv.includes('--debug');
@@ -18,6 +67,16 @@ if (hasDebugFlag) {
18
67
  logger.debug('Debug mode enabled');
19
68
  }
20
69
 
70
+ // Parse --dir <path> to let users point at a project without cd-ing into it
71
+ const dirFlagIndex = process.argv.indexOf('--dir');
72
+ const dirFlag = dirFlagIndex !== -1 && process.argv[dirFlagIndex + 1]
73
+ ? resolve(process.argv[dirFlagIndex + 1])
74
+ : null;
75
+
76
+ // Parse --license KEY to activate a Pro license
77
+ const licenseFlagIndex = process.argv.indexOf('--license');
78
+ const licenseFlag = licenseFlagIndex !== -1 ? process.argv[licenseFlagIndex + 1] : null;
79
+
21
80
  const notifier = updateNotifier({
22
81
  pkg,
23
82
  updateCheckInterval: 1000 * 60 * 60 * 24,
@@ -31,9 +90,8 @@ if (notifier.update) {
31
90
 
32
91
  // Version-specific messages
33
92
  const versionMessages = {
34
- // Add specific version messages here
35
- '0.2.11': 'Fixed table toolbar and table view horizontal/vertical scroll issues'
36
- // Add more version messages as needed
93
+ '0.2.11': 'Fixed table toolbar and table view horizontal/vertical scroll issues',
94
+ '0.3.0': 'Per-db migrations_dir, seed exclusion from push, sidebar UX improvements',
37
95
  };
38
96
 
39
97
  // Create custom message
@@ -106,22 +164,21 @@ async function startServer(port, projectDirectory) {
106
164
  }
107
165
 
108
166
  async function startStudio() {
167
+ trackEvent('start', pkg.version); // fire-and-forget, never awaited
109
168
  try {
110
169
  logger.info(chalk.green('Initializing D1 Studio...'));
111
170
 
112
171
  // Get wrangler configuration
113
172
  try {
114
- const userProjectPath = process.cwd();
115
- if (!userProjectPath) {
116
- logger.error(chalk.red('Error: Could not determine project directory'));
117
- process.exit(1);
118
- }
173
+ const userProjectPath = dirFlag || process.cwd();
119
174
 
120
175
  const wranglerResult = await findWranglerConfig(userProjectPath);
121
176
  if (!wranglerResult || !wranglerResult.config) {
122
- logger.error(chalk.red('\nError: No wrangler.toml found in current directory'));
123
- logger.info(chalk.yellow('Make sure you are in a Cloudflare Workers project directory'));
124
- logger.info(chalk.yellow('with a valid wrangler.toml file.'));
177
+ logger.error(chalk.red(`\nError: No wrangler.toml found in: ${userProjectPath}`));
178
+ logger.info(chalk.yellow('\nTo fix this, either:'));
179
+ logger.info(chalk.cyan(' 1. cd into your Cloudflare Workers project, then run d1s'));
180
+ logger.info(chalk.cyan(' 2. Run d1s --dir /path/to/your-project'));
181
+ logger.info(chalk.gray('\nThe project must have a wrangler.toml with a [[d1_databases]] entry.'));
125
182
  process.exit(1);
126
183
  }
127
184
 
@@ -143,21 +200,53 @@ async function startStudio() {
143
200
  logger.info(chalk.blue(` - ${db.database_name} (${db.binding})`));
144
201
  });
145
202
 
203
+ const credStatus = loadAndInjectWranglerCredentials();
204
+ if (credStatus === 'injected') {
205
+ logger.info(chalk.green('\n✓ Cloudflare API token found — remote sync & time travel ready'));
206
+ } else if (credStatus === 'oauth') {
207
+ logger.info(chalk.green('\n✓ Cloudflare credentials found (wrangler login) — remote sync & time travel ready'));
208
+ } else if (credStatus === 'found') {
209
+ logger.info(chalk.yellow('\n⚠ Wrangler config found but no usable token — run ' + chalk.cyan('wrangler login') + ' to enable Pro remote features'));
210
+ } else {
211
+ logger.info(chalk.yellow('\n⚠ No Cloudflare credentials — run ' + chalk.cyan('wrangler login') + ' to enable remote sync & time travel'));
212
+ }
213
+
214
+ // Validate license and set Pro status before starting the server
215
+ const license = await getOrValidateLicense();
216
+ process.env.D1_IS_PRO = license.isPro ? 'true' : 'false';
217
+
146
218
  const port = 4000;
147
219
  const url = `http://localhost:${port}`;
148
220
 
149
221
  await startServer(port, projectPath);
150
222
 
151
223
  logger.info(chalk.green(`
152
- ┌─────────────────────────────────────────┐
153
-
154
- D1 Studio is running on port ${port}
155
-
156
- │ Local: ${url}
157
-
158
- └─────────────────────────────────────────┘
224
+ ┌─────────────────────────────────────────────────────┐
225
+
226
+ d1-studio v${pkg.version} is ready
227
+
228
+ │ Local: ${url}
229
+
230
+ │ Free: Table browser · SQL editor · Schema │
231
+ │ Migrations · Import / Export │
232
+ │ Pro: Remote sync · Time travel │
233
+ │ Multi-database switcher │
234
+ │ │
235
+ └─────────────────────────────────────────────────────┘
159
236
  `));
160
237
 
238
+ if (license.isPro) {
239
+ logger.info(chalk.green(` ✓ Pro features active — ${license.email}`));
240
+ } else {
241
+ logger.info(chalk.yellow(` Run ${chalk.cyan('d1s --license YOUR-KEY')} to unlock Pro features`));
242
+ }
243
+
244
+ // Re-validate license every 4 hours in the background
245
+ setInterval(async () => {
246
+ const updated = await getOrValidateLicense().catch(() => null);
247
+ if (updated) process.env.D1_IS_PRO = updated.isPro ? 'true' : 'false';
248
+ }, 4 * 60 * 60 * 1000).unref();
249
+
161
250
  await new Promise(resolve => setTimeout(resolve, 2000));
162
251
 
163
252
  try {
@@ -193,7 +282,24 @@ process.on('SIGTERM', () => {
193
282
  process.exit(0);
194
283
  });
195
284
 
196
- startStudio().catch((error) => {
197
- logger.error(chalk.red(`\nFailed to start D1 Studio: ${error}`));
198
- process.exit(1);
199
- });
285
+ if (licenseFlag) {
286
+ logger.info(chalk.blue('\nActivating license key...'));
287
+ activateLicense(licenseFlag)
288
+ .then((result) => {
289
+ logger.info(chalk.green('\n✓ License activated!'));
290
+ logger.info(chalk.white(` Plan: ${result.plan}`));
291
+ logger.info(chalk.white(` Email: ${result.email}`));
292
+ logger.info(chalk.white(` Expires: ${new Date(result.expiresAt).toLocaleDateString()}`));
293
+ logger.info(chalk.gray('\nRun d1s to start D1 Studio with Pro features.'));
294
+ process.exit(0);
295
+ })
296
+ .catch((err) => {
297
+ logger.error(chalk.red(`\n✗ Activation failed: ${err.message}`));
298
+ process.exit(1);
299
+ });
300
+ } else {
301
+ startStudio().catch((error) => {
302
+ logger.error(chalk.red(`\nFailed to start D1 Studio: ${error}`));
303
+ process.exit(1);
304
+ });
305
+ }
@@ -3,97 +3,125 @@ import os from 'os';
3
3
  import { join } from 'path';
4
4
  import { readFile, writeFile, mkdir } from 'node:fs/promises';
5
5
  import { createHash } from 'crypto';
6
- import { LicenseError } from './errors.js';
7
6
 
8
- export async function generateHardwareId() {
9
- const osInfo = {
7
+ const LICENSE_API =
8
+ process.env.D1STUDIO_API_URL ||
9
+ (process.env.NODE_ENV === 'development' ? 'http://localhost:3001' : 'https://d1-studio.com');
10
+
11
+ const FOUR_HOURS_MS = 4 * 60 * 60 * 1000;
12
+
13
+ const LICENSE_DIR = join(os.homedir(), '.d1studio');
14
+ const LICENSE_PATH = join(LICENSE_DIR, 'license.json');
15
+
16
+ export function generateHardwareId() {
17
+ const info = {
10
18
  platform: process.platform,
11
19
  arch: process.arch,
12
20
  cpus: os.cpus().length,
13
21
  hostname: os.hostname(),
14
- username: os.userInfo().username
22
+ username: os.userInfo().username,
15
23
  };
16
-
17
- const systemString = JSON.stringify(osInfo);
18
- return createHash('sha256').update(systemString).digest('hex');
24
+ return createHash('sha256').update(JSON.stringify(info)).digest('hex');
19
25
  }
20
26
 
21
- export async function checkLicenseFile() {
22
- const licenseDir = join(os.homedir(), '.d1studio');
23
- const licensePath = join(licenseDir, 'license.json');
24
-
27
+ async function readLicenseFile() {
25
28
  try {
26
- const licenseData = JSON.parse(await readFile(licensePath, 'utf8'));
27
- const hardwareId = await generateHardwareId();
28
-
29
- if (licenseData.hardwareId !== hardwareId) {
30
- return null;
31
- }
32
-
33
- return licenseData;
34
- } catch (error) {
29
+ return JSON.parse(await readFile(LICENSE_PATH, 'utf8'));
30
+ } catch {
35
31
  return null;
36
32
  }
37
33
  }
38
34
 
39
- export async function saveLicenseFile(licenseData) {
40
- const licenseDir = join(os.homedir(), '.d1studio');
41
- const licensePath = join(licenseDir, 'license.json');
35
+ export async function saveLicenseFile(data) {
36
+ await mkdir(LICENSE_DIR, { recursive: true });
37
+ await writeFile(LICENSE_PATH, JSON.stringify(data, null, 2));
38
+ }
39
+
40
+ /**
41
+ * Activates a license key for this machine.
42
+ * Called once when user passes --license KEY.
43
+ * Returns { valid, plan, email, expiresAt } on success.
44
+ */
45
+ export async function activateLicense(key) {
46
+ const fingerprint = generateHardwareId();
42
47
 
48
+ const res = await fetch(`${LICENSE_API}/api/license/activate`, {
49
+ method: 'POST',
50
+ headers: { 'Content-Type': 'application/json' },
51
+ body: JSON.stringify({ key: key.trim().toUpperCase(), fingerprint }),
52
+ signal: AbortSignal.timeout(10000),
53
+ });
54
+
55
+ let data;
43
56
  try {
44
- await mkdir(licenseDir, { recursive: true });
45
- await writeFile(licensePath, JSON.stringify(licenseData, null, 2));
46
- } catch (error) {
47
- throw new LicenseError('Failed to save license information', 'SAVE_ERROR');
57
+ data = await res.json();
58
+ } catch {
59
+ throw new Error(`Server returned an invalid response (status ${res.status}). Is d1studio-web running?`);
60
+ }
61
+
62
+ if (!res.ok || !data.valid) {
63
+ throw new Error(data.error || 'License activation failed');
48
64
  }
65
+
66
+ await saveLicenseFile({
67
+ licenseKey: key.trim().toUpperCase(),
68
+ fingerprint,
69
+ email: data.email,
70
+ plan: data.plan,
71
+ expiresAt: data.expiresAt,
72
+ lastValidated: new Date().toISOString(),
73
+ isPro: true,
74
+ });
75
+
76
+ return data;
49
77
  }
50
78
 
51
- export async function validateLicenseRemote(licenseKey, email, hardwareId) {
52
- const baseUrl = process.env.NODE_ENV === 'development'
53
- ? 'http://localhost:4000'
54
- : 'https://d1-studio.com';
79
+ /**
80
+ * Validates the stored license against the remote API.
81
+ * Main entry point — called on startup and every 4 hours.
82
+ * Returns { isPro: boolean, plan?, expiresAt?, email? }
83
+ */
84
+ export async function getOrValidateLicense() {
85
+ const stored = await readLicenseFile();
86
+ if (!stored?.licenseKey) return { isPro: false };
87
+
88
+ const lastValidated = stored.lastValidated ? new Date(stored.lastValidated) : null;
89
+ const isStale = !lastValidated || Date.now() - lastValidated.getTime() > FOUR_HOURS_MS;
90
+
91
+ if (!isStale) {
92
+ return {
93
+ isPro: !!stored.isPro,
94
+ plan: stored.plan,
95
+ expiresAt: stored.expiresAt,
96
+ email: stored.email,
97
+ };
98
+ }
55
99
 
100
+ // Stale — re-validate remotely
56
101
  try {
57
- const response = await fetch(`${baseUrl}/api/validate-license`, {
58
- method: 'POST',
59
- headers: {
60
- 'Content-Type': 'application/json',
61
- },
62
- body: JSON.stringify({
63
- licenseKey,
64
- email,
65
- hardwareId
66
- })
102
+ const res = await fetch(
103
+ `${LICENSE_API}/api/license/validate?key=${encodeURIComponent(stored.licenseKey)}`,
104
+ { signal: AbortSignal.timeout(8000) }
105
+ );
106
+ const remote = await res.json();
107
+ const isPro = remote.valid === true;
108
+
109
+ await saveLicenseFile({
110
+ ...stored,
111
+ isPro,
112
+ plan: remote.plan ?? stored.plan,
113
+ expiresAt: remote.expiresAt ?? stored.expiresAt,
114
+ lastValidated: new Date().toISOString(),
67
115
  });
68
116
 
69
- const result = await response.json();
70
-
71
- if (!response.ok) {
72
- throw new LicenseError(
73
- result.message || 'License validation failed',
74
- result.type || 'VALIDATION_ERROR'
75
- );
76
- }
77
-
78
- return result;
79
-
80
- } catch (error) {
81
- if (error instanceof LicenseError) {
82
- throw error;
83
- }
84
-
85
- if (error.name === 'TypeError' && error.message.includes('fetch')) {
86
- throw new LicenseError(
87
- process.env.NODE_ENV === 'development'
88
- ? 'Unable to connect to local license validation service. Make sure the development server is running.'
89
- : 'Unable to connect to license server. Please check your internet connection.',
90
- 'CONNECTION_ERROR'
91
- );
92
- }
93
-
94
- throw new LicenseError(
95
- 'An unexpected error occurred during license validation',
96
- 'VALIDATION_ERROR'
97
- );
117
+ return { isPro, plan: remote.plan, expiresAt: remote.expiresAt, email: stored.email };
118
+ } catch {
119
+ // Network error — honour existing cached status as grace period
120
+ return {
121
+ isPro: !!stored.isPro,
122
+ plan: stored.plan,
123
+ expiresAt: stored.expiresAt,
124
+ email: stored.email,
125
+ };
98
126
  }
99
- }
127
+ }
@@ -0,0 +1,223 @@
1
+ // lib/local-db.js
2
+ // Direct SQLite access for local D1 databases via better-sqlite3.
3
+ // Falls back gracefully — callers receive null and can retry with wrangler CLI.
4
+
5
+ import crypto from 'crypto';
6
+ import path from 'path';
7
+ import fs from 'fs';
8
+ import Database from 'better-sqlite3';
9
+ import logger from './logger.js';
10
+
11
+ const MINIFLARE_DIR = path.join('.wrangler', 'state', 'v3', 'd1', 'miniflare-D1DatabaseObject');
12
+
13
+ // Cache open Database instances: "projectDir:dbName" → Database
14
+ const dbCache = new Map();
15
+
16
+ function sha256(input) {
17
+ return crypto.createHash('sha256').update(input).digest('hex');
18
+ }
19
+
20
+ /**
21
+ * Locate the SQLite file for a given database config under projectDir.
22
+ * Wrangler/miniflare v3 stores D1 as:
23
+ * .wrangler/state/v3/d1/miniflare-D1DatabaseObject/{hash}.sqlite
24
+ *
25
+ * The hash is SHA256 of the namespace key. We try the most common formulas
26
+ * then fall back to a single-file directory scan.
27
+ */
28
+ function findSqliteFile(projectDir, databaseConfig) {
29
+ const dir = path.join(projectDir, MINIFLARE_DIR);
30
+ if (!fs.existsSync(dir)) return null;
31
+
32
+ const { database_id, database_name, binding } = databaseConfig;
33
+
34
+ // Try known miniflare v3 hash formulas. Wrangler/miniflare derives the SQLite
35
+ // filename as sha256 of a namespace key — try all known patterns.
36
+ const ids = [database_id, database_name, binding].filter(Boolean);
37
+ const prefixes = [
38
+ '',
39
+ 'miniflare-D1DatabaseObject:',
40
+ 'D1DatabaseObject:',
41
+ 'd1:',
42
+ ];
43
+ const candidates = ids.flatMap(id =>
44
+ prefixes.map(prefix => sha256(`${prefix}${id}`))
45
+ ).map(h => path.join(dir, `${h}.sqlite`));
46
+
47
+ const found = candidates.find(p => fs.existsSync(p));
48
+ if (found) return found;
49
+
50
+ // Fallback: scan for .sqlite files.
51
+ // Only use this for single-DB projects — if multiple files exist, returning
52
+ // the wrong one would mix up tables from different databases. In that case
53
+ // return null so the caller falls back to wrangler CLI (which knows the mapping).
54
+ const files = fs.readdirSync(dir)
55
+ .filter(f => f.endsWith('.sqlite'))
56
+ .map(f => ({ name: f, fullPath: path.join(dir, f), mtime: fs.statSync(path.join(dir, f)).mtimeMs }))
57
+ .sort((a, b) => b.mtime - a.mtime);
58
+
59
+ if (files.length === 1) {
60
+ return files[0].fullPath;
61
+ }
62
+
63
+ if (files.length > 1) {
64
+ logger.debug(`[local-db] Multiple SQLite files, no hash matched — falling back to wrangler CLI. dir=${dir}, tried ids=${JSON.stringify(ids)}`);
65
+ }
66
+
67
+ logger.debug(`[local-db] No SQLite files found. dir=${dir}, tried ids=${JSON.stringify(ids)}`);
68
+ return null;
69
+ }
70
+
71
+ /**
72
+ * Returns true if a local SQLite file exists for the given database config.
73
+ * Does NOT open the file — safe for status checks.
74
+ */
75
+ export function hasLocalDb(projectDir, databaseConfig) {
76
+ return findSqliteFile(projectDir, databaseConfig) !== null;
77
+ }
78
+
79
+ /**
80
+ * Get (or create) a cached better-sqlite3 Database instance.
81
+ * Returns null if the SQLite file cannot be located.
82
+ */
83
+ export function getLocalDb(projectDir, databaseConfig) {
84
+ const key = `${projectDir}:${databaseConfig.database_name}`;
85
+ // Always re-resolve the path so stale cache entries (wrong file) are evicted
86
+ const sqlitePath = findSqliteFile(projectDir, databaseConfig);
87
+
88
+ if (dbCache.has(key)) {
89
+ const cached = dbCache.get(key);
90
+ if (cached.path !== sqlitePath) {
91
+ // Path changed or is now null — evict stale entry
92
+ try { cached.db.close(); } catch {}
93
+ dbCache.delete(key);
94
+ } else {
95
+ // Same path — verify the connection is still responsive
96
+ try { cached.db.prepare('SELECT 1').get(); return cached.db; } catch { dbCache.delete(key); }
97
+ }
98
+ }
99
+
100
+ if (!sqlitePath) return null;
101
+
102
+ try {
103
+ const db = new Database(sqlitePath, { fileMustExist: false });
104
+ db.pragma('journal_mode = WAL');
105
+ db.pragma('foreign_keys = ON');
106
+ dbCache.set(key, { db, path: sqlitePath });
107
+ return db;
108
+ } catch {
109
+ return null;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Execute a SQL statement via better-sqlite3 and return a JSON string
115
+ * matching the shape wrangler d1 execute --json returns:
116
+ * [{ results: [...rows], success: true, meta: { ... } }]
117
+ *
118
+ * Returns null if the database file cannot be found (caller should fall back to wrangler CLI).
119
+ * Throws on SQL errors (same contract as executeSQL in sql-operations.js).
120
+ */
121
+ export function executeLocalSQL(projectDir, databaseConfig, sql) {
122
+ const db = getLocalDb(projectDir, databaseConfig);
123
+ if (!db) return null;
124
+
125
+ const trimmed = sql.trim();
126
+ const upper = trimmed.toUpperCase().replace(/\s+/g, ' ');
127
+
128
+ // Multi-statement: split on ';' and run each — needed for DDL batches
129
+ const statements = trimmed
130
+ .split(';')
131
+ .map(s => s.trim())
132
+ .filter(Boolean);
133
+
134
+ if (statements.length > 1) {
135
+ // Run all statements in a single transaction, collect results
136
+ let allResults = [];
137
+ let totalChanges = 0;
138
+ let lastInsertRowid = 0;
139
+
140
+ const runAll = db.transaction(() => {
141
+ for (const stmt of statements) {
142
+ const u = stmt.toUpperCase().replace(/\s+/g, ' ');
143
+ const isRead = u.startsWith('SELECT') || u.startsWith('PRAGMA') || u.startsWith('EXPLAIN');
144
+ if (isRead) {
145
+ const rows = db.prepare(stmt).all();
146
+ allResults = allResults.concat(rows);
147
+ } else {
148
+ const info = db.prepare(stmt).run();
149
+ totalChanges += info.changes;
150
+ lastInsertRowid = info.lastInsertRowid;
151
+ }
152
+ }
153
+ });
154
+
155
+ runAll();
156
+ return JSON.stringify([{
157
+ results: allResults,
158
+ success: true,
159
+ meta: { changes: totalChanges, last_row_id: lastInsertRowid, rows_read: allResults.length, rows_written: totalChanges }
160
+ }]);
161
+ }
162
+
163
+ // Single statement
164
+ const isRead = upper.startsWith('SELECT') || upper.startsWith('PRAGMA') || upper.startsWith('EXPLAIN');
165
+
166
+ if (isRead) {
167
+ const rows = db.prepare(trimmed).all();
168
+ return JSON.stringify([{
169
+ results: rows,
170
+ success: true,
171
+ meta: { rows_read: rows.length, rows_written: 0, changed_db: false }
172
+ }]);
173
+ }
174
+
175
+ const info = db.prepare(trimmed).run();
176
+ return JSON.stringify([{
177
+ results: [],
178
+ success: true,
179
+ meta: {
180
+ changes: info.changes,
181
+ last_row_id: info.lastInsertRowid,
182
+ rows_read: 0,
183
+ rows_written: info.changes,
184
+ changed_db: info.changes > 0
185
+ }
186
+ }]);
187
+ }
188
+
189
+ /**
190
+ * Execute a batch INSERT using a better-sqlite3 transaction.
191
+ * rows: array of value arrays matching the columns order.
192
+ * Returns { changes } on success, null if DB file not found.
193
+ */
194
+ export function executeLocalBatchInsert(projectDir, databaseConfig, sql, rows) {
195
+ const db = getLocalDb(projectDir, databaseConfig);
196
+ if (!db) return null;
197
+
198
+ const stmt = db.prepare(sql);
199
+ let totalChanges = 0;
200
+
201
+ const insertMany = db.transaction((records) => {
202
+ for (const row of records) {
203
+ const info = stmt.run(...row);
204
+ totalChanges += info.changes;
205
+ }
206
+ });
207
+
208
+ insertMany(rows);
209
+ return { changes: totalChanges };
210
+ }
211
+
212
+ /**
213
+ * Invalidate the cached Database instance for a given database.
214
+ * Call this if the SQLite file path may have changed (e.g. after wrangler reinit).
215
+ */
216
+ export function invalidateLocalDb(projectDir, databaseName) {
217
+ const key = `${projectDir}:${databaseName}`;
218
+ const entry = dbCache.get(key);
219
+ if (entry) {
220
+ try { entry.db.close(); } catch { /* ignore */ }
221
+ dbCache.delete(key);
222
+ }
223
+ }