wrangler 0.0.0-e30d1013 → 0.0.0-e311bbbf

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 (236) hide show
  1. package/README.md +3 -3
  2. package/bin/wrangler.js +30 -10
  3. package/miniflare-dist/index.mjs +126 -74
  4. package/package.json +26 -19
  5. package/src/__tests__/api-dev.test.ts +65 -36
  6. package/src/__tests__/api-devregistry.test.ts +121 -0
  7. package/src/__tests__/api.test.ts +27 -5
  8. package/src/__tests__/configuration.test.ts +567 -39
  9. package/src/__tests__/d1/d1.test.ts +82 -0
  10. package/src/__tests__/d1/execute.test.ts +66 -0
  11. package/src/__tests__/d1/migrate.test.ts +157 -0
  12. package/src/__tests__/d1/splitter.test.ts +255 -0
  13. package/src/__tests__/delete.test.ts +91 -49
  14. package/src/__tests__/deployments.test.ts +330 -52
  15. package/src/__tests__/dev.test.tsx +198 -90
  16. package/src/__tests__/generate.test.ts +8 -5
  17. package/src/__tests__/guess-worker-format.test.ts +35 -0
  18. package/src/__tests__/helpers/end-event-loop.ts +6 -0
  19. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  20. package/src/__tests__/helpers/mock-console.ts +6 -0
  21. package/src/__tests__/helpers/mock-dialogs.ts +71 -85
  22. package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
  23. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -5
  24. package/src/__tests__/helpers/mock-known-routes.ts +7 -2
  25. package/src/__tests__/helpers/mock-kv.ts +29 -16
  26. package/src/__tests__/helpers/mock-oauth-flow.ts +103 -92
  27. package/src/__tests__/helpers/mock-process.ts +8 -13
  28. package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
  29. package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
  30. package/src/__tests__/helpers/msw/handlers/deployments.ts +127 -26
  31. package/src/__tests__/helpers/msw/handlers/namespaces.ts +18 -41
  32. package/src/__tests__/helpers/msw/handlers/oauth.ts +13 -18
  33. package/src/__tests__/helpers/msw/handlers/r2.ts +14 -34
  34. package/src/__tests__/helpers/msw/handlers/script.ts +9 -28
  35. package/src/__tests__/helpers/msw/handlers/user.ts +13 -24
  36. package/src/__tests__/helpers/msw/handlers/zones.ts +6 -8
  37. package/src/__tests__/helpers/msw/index.ts +32 -1
  38. package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
  39. package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
  40. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  41. package/src/__tests__/index.test.ts +90 -72
  42. package/src/__tests__/init.test.ts +927 -631
  43. package/src/__tests__/jest.setup.ts +19 -42
  44. package/src/__tests__/kv.test.ts +355 -231
  45. package/src/__tests__/logger.test.ts +68 -2
  46. package/src/__tests__/logout.test.ts +47 -0
  47. package/src/__tests__/metrics.test.ts +94 -51
  48. package/src/__tests__/middleware.scheduled.test.ts +42 -32
  49. package/src/__tests__/middleware.test.ts +212 -122
  50. package/src/__tests__/mtls-certificates.test.ts +588 -0
  51. package/src/__tests__/pages/deployment-list.test.ts +80 -0
  52. package/src/__tests__/pages/functions-build.test.ts +452 -0
  53. package/src/__tests__/pages/pages.test.ts +81 -0
  54. package/src/__tests__/pages/project-create.test.ts +63 -0
  55. package/src/__tests__/pages/project-list.test.ts +110 -0
  56. package/src/__tests__/pages/project-upload.test.ts +500 -0
  57. package/src/__tests__/pages/publish.test.ts +2864 -0
  58. package/src/__tests__/pages-deployment-tail.test.ts +955 -0
  59. package/src/__tests__/parse.test.ts +106 -0
  60. package/src/__tests__/publish.test.ts +1620 -830
  61. package/src/__tests__/pubsub.test.ts +226 -100
  62. package/src/__tests__/queues.test.ts +237 -76
  63. package/src/__tests__/r2.test.ts +37 -56
  64. package/src/__tests__/secret.test.ts +179 -130
  65. package/src/__tests__/tail.test.ts +267 -109
  66. package/src/__tests__/test-old-node-version.js +3 -3
  67. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  68. package/src/__tests__/tsconfig-sanity.ts +12 -0
  69. package/src/__tests__/tsconfig.json +8 -0
  70. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  71. package/src/__tests__/type-generation.test.ts +11 -2
  72. package/src/__tests__/user.test.ts +35 -72
  73. package/src/__tests__/whoami.test.tsx +8 -114
  74. package/src/__tests__/worker-namespace.test.ts +83 -69
  75. package/src/api/dev.ts +168 -60
  76. package/src/api/index.ts +10 -1
  77. package/src/api/mtls-certificate.ts +148 -0
  78. package/src/api/pages/create-worker-bundle-contents.ts +76 -0
  79. package/src/api/pages/index.ts +5 -0
  80. package/src/api/pages/publish.tsx +355 -0
  81. package/src/bundle.ts +221 -128
  82. package/src/cfetch/index.ts +0 -2
  83. package/src/cfetch/internal.ts +16 -21
  84. package/src/cli.ts +4 -4
  85. package/src/config/config.ts +14 -7
  86. package/src/config/environment.ts +73 -16
  87. package/src/config/index.ts +99 -30
  88. package/src/config/validation-helpers.ts +1 -1
  89. package/src/config/validation.ts +248 -9
  90. package/src/create-worker-preview.ts +19 -8
  91. package/src/create-worker-upload-form.ts +48 -5
  92. package/src/d1/backups.tsx +43 -42
  93. package/src/d1/create.tsx +26 -21
  94. package/src/d1/{delete.tsx → delete.ts} +11 -14
  95. package/src/d1/execute.tsx +183 -170
  96. package/src/d1/index.ts +7 -6
  97. package/src/d1/list.tsx +22 -10
  98. package/src/d1/migrations/apply.tsx +212 -0
  99. package/src/d1/migrations/create.tsx +79 -0
  100. package/src/d1/migrations/helpers.ts +172 -0
  101. package/src/d1/migrations/index.ts +3 -0
  102. package/src/d1/migrations/list.tsx +95 -0
  103. package/src/d1/migrations/options.ts +23 -0
  104. package/src/d1/options.ts +3 -3
  105. package/src/d1/splitter.ts +161 -0
  106. package/src/d1/{types.tsx → types.ts} +1 -0
  107. package/src/d1/utils.ts +2 -1
  108. package/src/delete.ts +8 -16
  109. package/src/deployments.ts +333 -42
  110. package/src/deprecated/index.ts +8 -302
  111. package/src/dev/dev.tsx +57 -44
  112. package/src/dev/local.tsx +248 -74
  113. package/src/dev/remote.tsx +32 -3
  114. package/src/dev/start-server.ts +81 -66
  115. package/src/dev/use-esbuild.ts +17 -18
  116. package/src/dev/validate-dev-props.ts +9 -0
  117. package/src/{dev-registry.tsx → dev-registry.ts} +2 -1
  118. package/src/dev.tsx +178 -117
  119. package/src/dialogs.ts +136 -0
  120. package/src/dispatch-namespace.ts +21 -17
  121. package/src/docs/index.ts +97 -0
  122. package/src/entry.ts +19 -11
  123. package/src/environment-variables/factory.ts +88 -0
  124. package/src/environment-variables/misc-variables.ts +30 -0
  125. package/src/generate/index.ts +298 -0
  126. package/src/git-client.ts +15 -4
  127. package/src/{index.tsx → index.ts} +134 -59
  128. package/src/init.ts +249 -187
  129. package/src/inspect.ts +16 -1
  130. package/src/jest.d.ts +4 -0
  131. package/src/kv/index.ts +15 -17
  132. package/src/logger.ts +32 -5
  133. package/src/metrics/metrics-config.ts +3 -3
  134. package/src/metrics/send-event.ts +6 -1
  135. package/src/miniflare-cli/assets.ts +64 -28
  136. package/src/miniflare-cli/index.ts +4 -7
  137. package/src/miniflare-cli/tsconfig.json +9 -0
  138. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  139. package/src/miniflare-cli/types.ts +11 -0
  140. package/src/module-collection.ts +91 -25
  141. package/src/mtls-certificate/cli.ts +155 -0
  142. package/src/pages/build.ts +410 -0
  143. package/src/pages/buildFunctions.ts +140 -0
  144. package/src/pages/deployment-tails.ts +281 -0
  145. package/src/pages/deployments.tsx +11 -33
  146. package/src/pages/{dev.tsx → dev.ts} +147 -139
  147. package/src/pages/errors.ts +1 -0
  148. package/src/pages/functions/buildPlugin.ts +61 -54
  149. package/src/pages/functions/buildWorker.ts +159 -33
  150. package/src/pages/functions/tsconfig.json +8 -0
  151. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  152. package/src/pages/{functions.tsx → functions.ts} +8 -4
  153. package/src/pages/{index.tsx → index.ts} +11 -3
  154. package/src/pages/projects.tsx +12 -22
  155. package/src/pages/prompt-select-project.tsx +31 -0
  156. package/src/pages/publish.tsx +46 -225
  157. package/src/pages/types.ts +6 -9
  158. package/src/pages/upload.tsx +58 -14
  159. package/src/pages/utils.ts +12 -1
  160. package/src/parse.ts +23 -1
  161. package/src/paths.ts +1 -1
  162. package/src/proxy.ts +5 -0
  163. package/src/publish/index.ts +20 -16
  164. package/src/publish/publish.ts +71 -46
  165. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +19 -20
  166. package/src/queues/cli/commands/consumer/add.ts +24 -24
  167. package/src/queues/cli/commands/consumer/index.ts +3 -6
  168. package/src/queues/cli/commands/consumer/remove.ts +11 -18
  169. package/src/queues/cli/commands/create.ts +8 -8
  170. package/src/queues/cli/commands/delete.ts +8 -8
  171. package/src/queues/cli/commands/index.ts +6 -4
  172. package/src/queues/cli/commands/list.ts +8 -8
  173. package/src/queues/client.ts +1 -0
  174. package/src/queues/utils.ts +18 -0
  175. package/src/r2/helpers.ts +1 -0
  176. package/src/r2/index.ts +28 -28
  177. package/src/secret/index.ts +14 -16
  178. package/src/{sites.tsx → sites.ts} +1 -1
  179. package/src/tail/createTail.ts +94 -3
  180. package/src/tail/filters.ts +1 -1
  181. package/src/tail/index.ts +8 -11
  182. package/src/tail/printing.ts +15 -0
  183. package/src/traverse-module-graph.ts +53 -0
  184. package/src/tsconfig-sanity.ts +16 -0
  185. package/src/type-generation.ts +28 -20
  186. package/src/user/access.ts +0 -1
  187. package/src/user/auth-variables.ts +113 -0
  188. package/src/user/choose-account.tsx +1 -31
  189. package/src/user/index.ts +0 -1
  190. package/src/user/{user.tsx → user.ts} +123 -82
  191. package/src/utils/render.ts +93 -0
  192. package/src/{whoami.tsx → whoami.ts} +37 -71
  193. package/src/worker.ts +30 -1
  194. package/src/yargs-types.ts +22 -5
  195. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  196. package/templates/__tests__/tsconfig.json +8 -0
  197. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  198. package/templates/checked-fetch.js +9 -3
  199. package/templates/d1-beta-facade.js +51 -3
  200. package/templates/facade.d.ts +14 -0
  201. package/templates/first-party-worker-module-facade.ts +4 -3
  202. package/templates/format-dev-errors.ts +8 -6
  203. package/templates/gitignore +1 -0
  204. package/templates/init-tests/test-jest-new-worker.js +3 -5
  205. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  206. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  207. package/templates/middleware/loader-modules.ts +2 -2
  208. package/templates/middleware/loader-sw.ts +51 -31
  209. package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
  210. package/templates/new-worker.ts +3 -0
  211. package/templates/pages-dev-pipeline.ts +4 -1
  212. package/templates/pages-shim.ts +4 -1
  213. package/templates/pages-template-plugin.ts +19 -10
  214. package/templates/serve-static-assets.ts +17 -14
  215. package/templates/service-bindings-module-facade.js +1 -0
  216. package/templates/tsconfig-sanity.ts +11 -0
  217. package/templates/tsconfig.init.json +105 -0
  218. package/templates/tsconfig.json +5 -103
  219. package/templates/tsconfig.tsbuildinfo +1 -0
  220. package/wrangler-dist/cli.d.ts +820 -70
  221. package/wrangler-dist/cli.js +68161 -78780
  222. package/wrangler-dist/wasm-sync.wasm +0 -0
  223. package/src/__tests__/api-devregistry.test.js +0 -56
  224. package/src/__tests__/d1.test.ts +0 -74
  225. package/src/__tests__/dialogs.test.tsx +0 -40
  226. package/src/__tests__/helpers/mock-cfetch.ts +0 -333
  227. package/src/__tests__/pages.test.ts +0 -2387
  228. package/src/d1/migrations.tsx +0 -446
  229. package/src/dialogs.tsx +0 -169
  230. package/src/environment-variables.ts +0 -50
  231. package/src/pages/build.tsx +0 -270
  232. package/src/user/env-vars.ts +0 -46
  233. package/templates/experimental-local-cache-stubs.js +0 -27
  234. /package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  235. /package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  236. /package/src/pages/{hash.tsx → hash.ts} +0 -0
@@ -1,52 +1,33 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { mkdir } from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { render, Static, Text } from "ink";
4
+ import chalk from "chalk";
5
+ import { Static, Text } from "ink";
5
6
  import Table from "ink-table";
6
7
  import { npxImport } from "npx-import";
7
8
  import React from "react";
8
9
  import { fetchResult } from "../cfetch";
9
- import { withConfig } from "../config";
10
+ import { readConfig } from "../config";
10
11
  import { getLocalPersistencePath } from "../dev/get-local-persistence-path";
11
- import { confirm, logDim } from "../dialogs";
12
+ import { confirm } from "../dialogs";
12
13
  import { logger } from "../logger";
14
+ import { readFileSync } from "../parse";
13
15
  import { readableRelative } from "../paths";
14
16
  import { requireAuth } from "../user";
17
+ import { renderToString } from "../utils/render";
15
18
  import * as options from "./options";
19
+ import splitSqlQuery from "./splitter";
16
20
  import {
17
21
  d1BetaWarning,
18
22
  getDatabaseByNameOrBinding,
19
23
  getDatabaseInfoFromConfig,
20
24
  } from "./utils";
21
25
  import type { Config, ConfigFields, DevConfig, Environment } from "../config";
26
+ import type {
27
+ CommonYargsArgv,
28
+ StrictYargsOptionsToInterface,
29
+ } from "../yargs-types";
22
30
  import type { Database } from "./types";
23
- import type splitSqlQuery from "@databases/split-sql-query";
24
- import type { SQL, SQLQuery } from "@databases/sql";
25
- import type { Statement as StatementType } from "@miniflare/d1";
26
- import type { createSQLiteDB as createSQLiteDBType } from "@miniflare/shared";
27
- import type { Argv } from "yargs";
28
-
29
- type MiniflareNpxImportTypes = [
30
- {
31
- Statement: typeof StatementType;
32
- },
33
- {
34
- createSQLiteDB: typeof createSQLiteDBType;
35
- }
36
- ];
37
-
38
- export type BaseSqlExecuteArgs = {
39
- config?: string;
40
- database: string;
41
- local?: boolean;
42
- "persist-to"?: string;
43
- yes?: boolean;
44
- };
45
-
46
- type ExecuteArgs = BaseSqlExecuteArgs & {
47
- file?: string;
48
- command?: string;
49
- };
50
31
 
51
32
  export type QueryResult = {
52
33
  results: Record<string, string | number | boolean>[];
@@ -56,10 +37,10 @@ export type QueryResult = {
56
37
  };
57
38
  query?: string;
58
39
  };
59
- // Max number of bytes to send in a single /execute call
40
+ // Max number of statements to send in a single /execute call
60
41
  const QUERY_LIMIT = 10_000;
61
42
 
62
- export function Options(yargs: Argv): Argv<ExecuteArgs> {
43
+ export function Options(yargs: CommonYargsArgv) {
63
44
  return options
64
45
  .Database(yargs)
65
46
  .option("yes", {
@@ -73,7 +54,7 @@ export function Options(yargs: Argv): Argv<ExecuteArgs> {
73
54
  type: "boolean",
74
55
  })
75
56
  .option("file", {
76
- describe: "A .sql file to injest",
57
+ describe: "A .sql file to ingest",
77
58
  type: "string",
78
59
  })
79
60
  .option("command", {
@@ -84,82 +65,54 @@ export function Options(yargs: Argv): Argv<ExecuteArgs> {
84
65
  describe: "Specify directory to use for local persistence (for --local)",
85
66
  type: "string",
86
67
  requiresArg: true,
68
+ })
69
+ .option("json", {
70
+ describe: "Return output as clean JSON",
71
+ type: "boolean",
72
+ default: false,
73
+ })
74
+ .option("preview", {
75
+ describe: "Execute commands/files against a preview D1 DB",
76
+ type: "boolean",
77
+ default: false,
87
78
  });
88
79
  }
89
80
 
90
- function shorten(query: string | undefined, length: number) {
91
- return query && query.length > length
92
- ? query.slice(0, length) + "..."
93
- : query;
94
- }
95
-
96
- export async function executeSql(
97
- local: undefined | boolean,
98
- config: ConfigFields<DevConfig> & Environment,
99
- name: string,
100
- shouldPrompt: boolean | undefined,
101
- persistTo: undefined | string,
102
- file?: string,
103
- command?: string
104
- ) {
105
- const { parser, splitter } = await loadSqlUtils();
106
-
107
- const sql = file
108
- ? parser.file(file)
109
- : command
110
- ? parser.__dangerous__rawValue(command)
111
- : null;
112
-
113
- if (!sql) throw new Error(`Error: must provide --command or --file.`);
114
- if (persistTo && !local)
115
- throw new Error(`Error: can't use --persist-to without --local`);
81
+ type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
116
82
 
117
- const queries = splitSql(splitter, sql);
118
- if (file && sql) {
119
- if (queries[0].startsWith("SQLite format 3")) {
120
- //TODO: update this error to recommend using `wrangler d1 restore` when it exists
121
- throw new Error(
122
- "Provided file is a binary SQLite database file instead of an SQL text file.\nThe execute command can only process SQL text files.\nPlease export an SQL file from your SQLite database and try again."
123
- );
124
- }
83
+ export const Handler = async (args: HandlerOptions): Promise<void> => {
84
+ const { local, database, yes, persistTo, file, command, json, preview } =
85
+ args;
86
+ const existingLogLevel = logger.loggerLevel;
87
+ if (json) {
88
+ // set loggerLevel to error to avoid readConfig warnings appearing in JSON output
89
+ logger.loggerLevel = "error";
125
90
  }
91
+ const config = readConfig(args.config, args);
92
+ logger.log(d1BetaWarning);
93
+ if (file && command)
94
+ return logger.error(`Error: can't provide both --command and --file.`);
126
95
 
127
- return local
128
- ? await executeLocally(config, name, shouldPrompt, queries, persistTo)
129
- : await executeRemotely(config, name, shouldPrompt, batchSplit(queries));
130
- }
131
-
132
- export const Handler = withConfig<ExecuteArgs>(
133
- async ({
96
+ const isInteractive = process.stdout.isTTY;
97
+ const response: QueryResult[] | null = await executeSql({
98
+ local,
134
99
  config,
135
- database,
100
+ name: database,
101
+ shouldPrompt: isInteractive && !yes,
102
+ persistTo,
136
103
  file,
137
104
  command,
138
- local,
139
- persistTo,
140
- yes,
141
- }): Promise<void> => {
142
- logger.log(d1BetaWarning);
143
- if (file && command)
144
- return console.error(`Error: can't provide both --command and --file.`);
145
-
146
- const isInteractive = process.stdout.isTTY;
147
- const response: QueryResult[] | null = await executeSql(
148
- local,
149
- config,
150
- database,
151
- isInteractive && !yes,
152
- persistTo,
153
- file,
154
- command
155
- );
105
+ json,
106
+ preview,
107
+ });
156
108
 
157
- // Early exit if prompt rejected
158
- if (!response) return;
109
+ // Early exit if prompt rejected
110
+ if (!response) return;
159
111
 
160
- if (isInteractive) {
161
- // Render table if single result
162
- render(
112
+ if (isInteractive && !json) {
113
+ // Render table if single result
114
+ logger.log(
115
+ renderToString(
163
116
  <Static items={response}>
164
117
  {(result) => {
165
118
  // batch results
@@ -178,20 +131,88 @@ export const Handler = withConfig<ExecuteArgs>(
178
131
  }
179
132
  }}
180
133
  </Static>
134
+ )
135
+ );
136
+ } else {
137
+ // set loggerLevel back to what it was before to actually output the JSON in stdout
138
+ logger.loggerLevel = existingLogLevel;
139
+ logger.log(JSON.stringify(response, null, 2));
140
+ }
141
+ };
142
+
143
+ export async function executeSql({
144
+ local,
145
+ config,
146
+ name,
147
+ shouldPrompt,
148
+ persistTo,
149
+ file,
150
+ command,
151
+ json,
152
+ preview,
153
+ }: {
154
+ local: boolean | undefined;
155
+ config: ConfigFields<DevConfig> & Environment;
156
+ name: string;
157
+ shouldPrompt: boolean | undefined;
158
+ persistTo: string | undefined;
159
+ file: string | undefined;
160
+ command: string | undefined;
161
+ json: boolean | undefined;
162
+ preview: boolean | undefined;
163
+ }) {
164
+ const sql = file ? readFileSync(file) : command;
165
+ if (!sql) throw new Error(`Error: must provide --command or --file.`);
166
+ if (preview && local)
167
+ throw new Error(`Error: can't use --preview with --local`);
168
+ if (persistTo && !local)
169
+ throw new Error(`Error: can't use --persist-to without --local`);
170
+ logger.log(`🌀 Mapping SQL input into an array of statements`);
171
+ const queries = splitSqlQuery(sql);
172
+
173
+ if (file && sql) {
174
+ if (queries[0].startsWith("SQLite format 3")) {
175
+ //TODO: update this error to recommend using `wrangler d1 restore` when it exists
176
+ throw new Error(
177
+ "Provided file is a binary SQLite database file instead of an SQL text file.\nThe execute command can only process SQL text files.\nPlease export an SQL file from your SQLite database and try again."
181
178
  );
182
- } else {
183
- console.log(JSON.stringify(response, null, 2));
184
179
  }
185
180
  }
186
- );
187
181
 
188
- async function executeLocally(
189
- config: Config,
190
- name: string,
191
- shouldPrompt: boolean | undefined,
192
- queries: string[],
193
- persistTo: string | undefined
194
- ) {
182
+ return local
183
+ ? await executeLocally({
184
+ config,
185
+ name,
186
+ shouldPrompt,
187
+ queries,
188
+ persistTo,
189
+ json,
190
+ })
191
+ : await executeRemotely({
192
+ config,
193
+ name,
194
+ shouldPrompt,
195
+ batches: batchSplit(queries),
196
+ json,
197
+ preview,
198
+ });
199
+ }
200
+
201
+ async function executeLocally({
202
+ config,
203
+ name,
204
+ shouldPrompt,
205
+ queries,
206
+ persistTo,
207
+ json,
208
+ }: {
209
+ config: Config;
210
+ name: string;
211
+ shouldPrompt: boolean | undefined;
212
+ queries: string[];
213
+ persistTo: string | undefined;
214
+ json: boolean | undefined;
215
+ }) {
195
216
  const localDB = getDatabaseInfoFromConfig(config, name);
196
217
  if (!localDB) {
197
218
  throw new Error(
@@ -207,40 +228,46 @@ async function executeLocally(
207
228
 
208
229
  const dbDir = path.join(persistencePath, "d1");
209
230
  const dbPath = path.join(dbDir, `${localDB.binding}.sqlite3`);
210
- const [{ Statement }, { createSQLiteDB }] =
211
- await npxImport<MiniflareNpxImportTypes>(
212
- ["@miniflare/d1", "@miniflare/shared"],
213
- logDim
214
- );
215
-
216
- if (!existsSync(dbDir) && shouldPrompt) {
217
- const ok = await confirm(
218
- `About to create ${readableRelative(dbPath)}, ok?`
219
- );
231
+ const [{ D1Database, D1DatabaseAPI }, { createSQLiteDB }] = await npxImport<
232
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
233
+ [typeof import("@miniflare/d1"), typeof import("@miniflare/shared")]
234
+ >(["@miniflare/d1", "@miniflare/shared"], logger.log);
235
+
236
+ if (!existsSync(dbDir)) {
237
+ const ok =
238
+ json ||
239
+ !shouldPrompt ||
240
+ (await confirm(`About to create ${readableRelative(dbPath)}, ok?`));
220
241
  if (!ok) return null;
221
242
  await mkdir(dbDir, { recursive: true });
222
243
  }
223
244
 
224
245
  logger.log(`🌀 Loading DB at ${readableRelative(dbPath)}`);
225
- const db = await createSQLiteDB(dbPath);
226
-
227
- const results: QueryResult[] = [];
228
- for (const sql of queries) {
229
- const statement = new Statement(db, sql);
230
- results.push((await statement.all()) as QueryResult);
231
- }
232
246
 
233
- return results;
247
+ const sqliteDb = await createSQLiteDB(dbPath);
248
+ const db = new D1Database(new D1DatabaseAPI(sqliteDb));
249
+ const stmts = queries.map((query) => db.prepare(query));
250
+ return (await db.batch(stmts)) as QueryResult[];
234
251
  }
235
252
 
236
- async function executeRemotely(
237
- config: Config,
238
- name: string,
239
- shouldPrompt: boolean | undefined,
240
- batches: string[]
241
- ) {
253
+ async function executeRemotely({
254
+ config,
255
+ name,
256
+ shouldPrompt,
257
+ batches,
258
+ json,
259
+ preview,
260
+ }: {
261
+ config: Config;
262
+ name: string;
263
+ shouldPrompt: boolean | undefined;
264
+ batches: string[];
265
+ json: boolean | undefined;
266
+ preview: boolean | undefined;
267
+ }) {
242
268
  const multiple_batches = batches.length > 1;
243
- if (multiple_batches) {
269
+ // in JSON mode, we don't want a prompt here
270
+ if (multiple_batches && !json) {
244
271
  const warning = `⚠️ Too much SQL to send at once, this execution will be sent as ${batches.length} batches.`;
245
272
 
246
273
  if (shouldPrompt) {
@@ -250,7 +277,7 @@ async function executeRemotely(
250
277
  if (!ok) return null;
251
278
  logger.log(`🌀 Let's go`);
252
279
  } else {
253
- console.error(warning);
280
+ logger.error(warning);
254
281
  }
255
282
  }
256
283
 
@@ -260,20 +287,23 @@ async function executeRemotely(
260
287
  accountId,
261
288
  name
262
289
  );
263
-
264
- if (shouldPrompt) {
265
- logger.log(`🌀 Executing on ${name} (${db.uuid}):`);
266
-
267
- // Don't output if shouldPrompt is undefined
268
- } else if (shouldPrompt !== undefined) {
269
- // Pipe to error so we don't break jq
270
- console.error(`Executing on ${name} (${db.uuid}):`);
290
+ if (preview && !db.previewDatabaseUuid) {
291
+ throw logger.error(
292
+ "Please define a `preview_database_id` in your wrangler.toml to execute your queries against a preview database"
293
+ );
271
294
  }
295
+ const dbUuid = preview ? db.previewDatabaseUuid : db.uuid;
296
+ logger.log(`🌀 Executing on ${name} (${dbUuid}):`);
272
297
 
273
298
  const results: QueryResult[] = [];
274
299
  for (const sql of batches) {
300
+ if (multiple_batches)
301
+ logger.log(
302
+ chalk.gray(` ${sql.slice(0, 70)}${sql.length > 70 ? "..." : ""}`)
303
+ );
304
+
275
305
  const result = await fetchResult<QueryResult[]>(
276
- `/accounts/${accountId}/d1/database/${db.uuid}/query`,
306
+ `/accounts/${accountId}/d1/database/${dbUuid}/query`,
277
307
  {
278
308
  method: "POST",
279
309
  headers: {
@@ -303,42 +333,25 @@ function logResult(r: QueryResult | QueryResult[]) {
303
333
  );
304
334
  }
305
335
 
306
- function splitSql(splitter: (query: SQLQuery) => SQLQuery[], sql: SQLQuery) {
307
- // We have no interpolations, so convert everything to text
308
- logger.log(`🌀 Mapping SQL input into an array of statements`);
309
- return splitter(sql).map(
310
- (q) =>
311
- q.format({
312
- escapeIdentifier: (_) => "",
313
- formatValue: (_, __) => ({ placeholder: "", value: "" }),
314
- }).text
315
- );
316
- }
317
-
318
336
  function batchSplit(queries: string[]) {
319
337
  logger.log(`🌀 Parsing ${queries.length} statements`);
320
- const batches: string[] = [];
321
338
  const num_batches = Math.ceil(queries.length / QUERY_LIMIT);
339
+ const batches: string[] = [];
322
340
  for (let i = 0; i < num_batches; i++) {
323
341
  batches.push(
324
342
  queries.slice(i * QUERY_LIMIT, (i + 1) * QUERY_LIMIT).join("; ")
325
343
  );
326
344
  }
327
- logger.log(
328
- `🌀 We are sending ${batches.length} batch(es) to D1 (limited to ${QUERY_LIMIT} statements per batch)`
329
- );
345
+ if (num_batches > 1) {
346
+ logger.log(
347
+ `🌀 We are sending ${num_batches} batch(es) to D1 (limited to ${QUERY_LIMIT} statements per batch)`
348
+ );
349
+ }
330
350
  return batches;
331
351
  }
332
352
 
333
- async function loadSqlUtils() {
334
- const [
335
- { default: parser },
336
- {
337
- // No idea why this is doubly-nested, see https://github.com/ForbesLindesay/atdatabases/issues/255
338
- default: { default: splitter },
339
- },
340
- ] = await npxImport<
341
- [{ default: SQL }, { default: { default: typeof splitSqlQuery } }]
342
- >(["@databases/sql@3.2.0", "@databases/split-sql-query@1.0.3"], logDim);
343
- return { parser, splitter };
353
+ function shorten(query: string | undefined, length: number) {
354
+ return query && query.length > length
355
+ ? query.slice(0, length) + "..."
356
+ : query;
344
357
  }
package/src/d1/index.ts CHANGED
@@ -5,10 +5,9 @@ import * as Execute from "./execute";
5
5
  import * as List from "./list";
6
6
  import * as Migrations from "./migrations";
7
7
  import { d1BetaWarning } from "./utils";
8
- import type { CommonYargsOptions } from "../yargs-types";
9
- import type { Argv } from "yargs";
8
+ import type { CommonYargsArgv } from "../yargs-types";
10
9
 
11
- export const d1 = (yargs: Argv<CommonYargsOptions>) => {
10
+ export function d1(yargs: CommonYargsArgv) {
12
11
  return (
13
12
  yargs
14
13
  .command("list", "List D1 databases", List.Options, List.Handler)
@@ -24,8 +23,9 @@ export const d1 = (yargs: Argv<CommonYargsOptions>) => {
24
23
  Delete.Options,
25
24
  Delete.Handler
26
25
  )
27
- .command("backup", "Interact with D1 Backups", (yargs2) =>
28
- yargs2
26
+ .command("backup", "Interact with D1 Backups", (backupArgs) =>
27
+ backupArgs
28
+ .demandCommand()
29
29
  .command(
30
30
  "list <name>",
31
31
  "List your D1 backups",
@@ -74,6 +74,7 @@ export const d1 = (yargs: Argv<CommonYargsOptions>) => {
74
74
  )
75
75
  .command("migrations", "Interact with D1 Migrations", (yargs2) =>
76
76
  yargs2
77
+ .demandCommand()
77
78
  .command(
78
79
  "list <database>",
79
80
  "List your D1 migrations",
@@ -96,4 +97,4 @@ export const d1 = (yargs: Argv<CommonYargsOptions>) => {
96
97
  )
97
98
  .epilogue(d1BetaWarning)
98
99
  );
99
- };
100
+ }
package/src/d1/list.tsx CHANGED
@@ -1,26 +1,38 @@
1
- import { render } from "ink";
2
1
  import Table from "ink-table";
3
2
  import React from "react";
4
3
  import { fetchResult } from "../cfetch";
5
4
  import { logger } from "../logger";
6
5
  import { requireAuth } from "../user";
6
+ import { renderToString } from "../utils/render";
7
7
  import { d1BetaWarning } from "./utils";
8
+ import type {
9
+ CommonYargsArgv,
10
+ StrictYargsOptionsToInterface,
11
+ } from "../yargs-types";
8
12
  import type { Database } from "./types";
9
- import type { ArgumentsCamelCase, Argv } from "yargs";
10
13
 
11
- type ListArgs = Record<string, never>;
12
-
13
- export function Options(d1ListYargs: Argv): Argv<ListArgs> {
14
- return d1ListYargs.epilogue(d1BetaWarning);
14
+ export function Options(d1ListYargs: CommonYargsArgv) {
15
+ return d1ListYargs
16
+ .option("json", {
17
+ describe: "return output as clean JSON",
18
+ type: "boolean",
19
+ default: false,
20
+ })
21
+ .epilogue(d1BetaWarning);
15
22
  }
16
23
 
17
- export async function Handler(_: ArgumentsCamelCase<ListArgs>): Promise<void> {
24
+ export async function Handler({
25
+ json,
26
+ }: StrictYargsOptionsToInterface<typeof Options>): Promise<void> {
18
27
  const accountId = await requireAuth({});
19
- logger.log(d1BetaWarning);
20
-
21
28
  const dbs: Array<Database> = await listDatabases(accountId);
22
29
 
23
- render(<Table data={dbs}></Table>);
30
+ if (json) {
31
+ logger.log(JSON.stringify(dbs, null, 2));
32
+ } else {
33
+ logger.log(d1BetaWarning);
34
+ logger.log(renderToString(<Table data={dbs}></Table>));
35
+ }
24
36
  }
25
37
 
26
38
  export const listDatabases = async (