wrangler 0.0.0-e7cf0caa → 0.0.0-e87ad068

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 (85) hide show
  1. package/miniflare-dist/index.mjs +167 -93
  2. package/package.json +6 -6
  3. package/src/__tests__/configuration.test.ts +218 -0
  4. package/src/__tests__/constellation.test.ts +371 -0
  5. package/src/__tests__/d1/migrate.test.ts +100 -0
  6. package/src/__tests__/index.test.ts +4 -2
  7. package/src/__tests__/init.test.ts +109 -3
  8. package/src/__tests__/mtls-certificates.test.ts +2 -1
  9. package/src/__tests__/pages/functions-build.test.ts +77 -0
  10. package/src/__tests__/pages-deployment-tail.test.ts +2 -0
  11. package/src/__tests__/publish.test.ts +646 -187
  12. package/src/__tests__/tail.test.ts +49 -7
  13. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  14. package/src/__tests__/unstableDev.test.ts +61 -0
  15. package/src/__tests__/user.test.ts +1 -1
  16. package/src/api/dev.ts +12 -0
  17. package/src/api/pages/create-worker-bundle-contents.ts +4 -0
  18. package/src/api/pages/publish.tsx +28 -12
  19. package/src/bundle.ts +58 -14
  20. package/src/cfetch/internal.ts +19 -14
  21. package/src/config/environment.ts +41 -0
  22. package/src/config/index.ts +21 -0
  23. package/src/config/validation.ts +182 -0
  24. package/src/constellation/createProject.tsx +51 -0
  25. package/src/constellation/deleteProject.ts +51 -0
  26. package/src/constellation/deleteProjectModel.ts +76 -0
  27. package/src/constellation/index.ts +75 -0
  28. package/src/constellation/listCatalog.tsx +35 -0
  29. package/src/constellation/listModel.tsx +49 -0
  30. package/src/constellation/listProject.tsx +28 -0
  31. package/src/constellation/listRuntime.tsx +28 -0
  32. package/src/constellation/options.ts +17 -0
  33. package/src/constellation/types.ts +17 -0
  34. package/src/constellation/uploadModel.tsx +84 -0
  35. package/src/constellation/utils.ts +90 -0
  36. package/src/create-worker-upload-form.ts +25 -0
  37. package/src/d1/backups.tsx +4 -4
  38. package/src/d1/constants.ts +3 -0
  39. package/src/d1/create.tsx +77 -43
  40. package/src/d1/delete.ts +1 -1
  41. package/src/d1/execute.tsx +27 -13
  42. package/src/d1/list.tsx +13 -11
  43. package/src/d1/migrations/apply.tsx +29 -6
  44. package/src/d1/migrations/helpers.ts +8 -9
  45. package/src/d1/types.ts +7 -0
  46. package/src/dev/dev.tsx +9 -2
  47. package/src/dev/local.tsx +52 -20
  48. package/src/dev/remote.tsx +4 -0
  49. package/src/dev/start-server.ts +64 -40
  50. package/src/dev/use-esbuild.ts +70 -43
  51. package/src/dev-registry.ts +11 -0
  52. package/src/dev.tsx +23 -6
  53. package/src/docs/helpers.ts +50 -0
  54. package/src/docs/index.ts +25 -68
  55. package/src/entry.ts +8 -1
  56. package/src/environment-variables/factory.ts +2 -1
  57. package/src/generate/index.ts +5 -0
  58. package/src/index.ts +12 -1
  59. package/src/init.ts +52 -10
  60. package/src/inspect.ts +107 -6
  61. package/src/kv/helpers.ts +7 -4
  62. package/src/logger.ts +5 -1
  63. package/src/miniflare-cli/index.ts +2 -2
  64. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  65. package/src/module-collection.ts +1 -1
  66. package/src/pages/build.ts +30 -17
  67. package/src/pages/dev.ts +51 -8
  68. package/src/pages/functions/buildPlugin.ts +1 -0
  69. package/src/pages/functions/buildWorker.ts +92 -2
  70. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  71. package/src/publish/publish.ts +9 -1
  72. package/src/secret/index.ts +4 -0
  73. package/src/sites.ts +164 -52
  74. package/src/tail/createTail.ts +9 -0
  75. package/src/tail/printing.ts +12 -0
  76. package/src/traverse-module-graph.ts +2 -1
  77. package/src/type-generation.ts +6 -0
  78. package/src/user/user.ts +1 -0
  79. package/src/utils/render.ts +1 -1
  80. package/src/worker.ts +26 -0
  81. package/templates/__tests__/tsconfig.tsbuildinfo +1 -1
  82. package/templates/pages-dev-util.ts +4 -1
  83. package/templates/tsconfig.tsbuildinfo +1 -1
  84. package/wrangler-dist/cli.d.ts +78 -2
  85. package/wrangler-dist/cli.js +65057 -63883
@@ -0,0 +1,84 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { FormData, File } from "undici";
3
+ import { fetchResult } from "../cfetch";
4
+ import { withConfig } from "../config";
5
+ import { logger } from "../logger";
6
+ import { requireAuth } from "../user";
7
+ import { constellationBetaWarning, getProjectByName } from "./utils";
8
+ import type {
9
+ CommonYargsArgv,
10
+ StrictYargsOptionsToInterface,
11
+ } from "../yargs-types";
12
+ import type { Model } from "./types";
13
+
14
+ export function options(yargs: CommonYargsArgv) {
15
+ return yargs
16
+ .positional("projectName", {
17
+ describe: "The name of the project",
18
+ type: "string",
19
+ demandOption: true,
20
+ })
21
+ .positional("modelName", {
22
+ describe: "The name of the uploaded model",
23
+ type: "string",
24
+ demandOption: true,
25
+ })
26
+ .positional("modelFile", {
27
+ describe: "The name of the local file with the model contents",
28
+ type: "string",
29
+ demandOption: true,
30
+ })
31
+ .option("description", {
32
+ describe: "include a description of the model",
33
+ type: "string",
34
+ demandOption: false,
35
+ alias: "d",
36
+ })
37
+ .epilogue(constellationBetaWarning);
38
+ }
39
+ type HandlerOptions = StrictYargsOptionsToInterface<typeof options>;
40
+ export const handler = withConfig<HandlerOptions>(
41
+ async ({
42
+ projectName,
43
+ modelName,
44
+ modelFile,
45
+ description,
46
+ config,
47
+ }): Promise<void> => {
48
+ const accountId = await requireAuth(config);
49
+ logger.log(constellationBetaWarning);
50
+
51
+ const proj = await getProjectByName(config, accountId, projectName);
52
+
53
+ const formData = new FormData();
54
+ formData.set(
55
+ "file",
56
+ new File([readFileSync(modelFile)], modelFile, {
57
+ type: "application/octet-stream",
58
+ })
59
+ );
60
+ formData.set("name", modelName);
61
+
62
+ if (description !== undefined) {
63
+ formData.set("description", description);
64
+ }
65
+
66
+ let model: Model;
67
+ try {
68
+ model = await fetchResult(
69
+ `/accounts/${accountId}/constellation/project/${proj.id}/model`,
70
+ {
71
+ method: "POST",
72
+ body: formData,
73
+ }
74
+ );
75
+ } catch (e) {
76
+ if ((e as { code: number }).code === 7408) {
77
+ throw new Error("A model with that name already exists");
78
+ }
79
+ throw e;
80
+ }
81
+
82
+ logger.log(`✅ Successfully uploaded Model "${model.name}"!`);
83
+ }
84
+ );
@@ -0,0 +1,90 @@
1
+ import { fetchResult } from "../cfetch";
2
+ import { getEnvironmentVariableFactory } from "../environment-variables/factory";
3
+ import type { Config } from "../config";
4
+ import type { Project, Model, CatalogEntry } from "./types";
5
+
6
+ export const getConstellationWarningFromEnv = getEnvironmentVariableFactory({
7
+ variableName: "NO_CONSTELLATION_WARNING",
8
+ });
9
+
10
+ export const constellationBetaWarning =
11
+ getConstellationWarningFromEnv() !== undefined
12
+ ? ""
13
+ : "--------------------\n🚧 Constellation is currently in open alpha and is not recommended for production data and traffic\n🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose\n🚧 To give feedback, visit https://discord.gg/cloudflaredev\n--------------------\n";
14
+
15
+ export const getProjectByName = async (
16
+ config: Config,
17
+ accountId: string,
18
+ name: string
19
+ ): Promise<Project> => {
20
+ const allProjects = await listProjects(accountId);
21
+ const matchingProj = allProjects.find((proj) => proj.name === name);
22
+ if (!matchingProj) {
23
+ throw new Error(`Couldn't find Project with name '${name}'`);
24
+ }
25
+ return matchingProj;
26
+ };
27
+
28
+ export const getProjectModelByName = async (
29
+ config: Config,
30
+ accountId: string,
31
+ proj: Project,
32
+ modelName: string
33
+ ): Promise<Model> => {
34
+ const allModels = await listModels(accountId, proj);
35
+ const matchingModel = allModels.find((model) => model.name === modelName);
36
+ if (!matchingModel) {
37
+ throw new Error(`Couldn't find Model with name '${modelName}'`);
38
+ }
39
+ return matchingModel;
40
+ };
41
+
42
+ export async function constellationList<ResponseType>(
43
+ accountId: string,
44
+ partialUrl: string
45
+ ): Promise<Array<ResponseType>> {
46
+ const pageSize = 50;
47
+ let page = 1;
48
+ const results = [];
49
+ while (results.length % pageSize === 0) {
50
+ const json: Array<ResponseType> = await fetchResult(
51
+ `/accounts/${accountId}/constellation/${partialUrl}`,
52
+ {},
53
+ new URLSearchParams({
54
+ per_page: pageSize.toString(),
55
+ page: page.toString(),
56
+ })
57
+ );
58
+ page++;
59
+ results.push(...json);
60
+ if (json.length < pageSize) {
61
+ break;
62
+ }
63
+ }
64
+ return results;
65
+ }
66
+
67
+ export const listCatalogEntries = async (
68
+ accountId: string
69
+ ): Promise<Array<CatalogEntry>> => {
70
+ return await constellationList(accountId, "catalog");
71
+ };
72
+
73
+ export const listModels = async (
74
+ accountId: string,
75
+ proj: Project
76
+ ): Promise<Array<Model>> => {
77
+ return constellationList(accountId, `project/${proj.id}/model`);
78
+ };
79
+
80
+ export const listProjects = async (
81
+ accountId: string
82
+ ): Promise<Array<Project>> => {
83
+ return await constellationList(accountId, "project");
84
+ };
85
+
86
+ export const listRuntimes = async (
87
+ accountId: string
88
+ ): Promise<Array<string>> => {
89
+ return await constellationList(accountId, "runtime");
90
+ };
@@ -4,6 +4,8 @@ import type {
4
4
  CfWorkerInit,
5
5
  CfModuleType,
6
6
  CfDurableObjectMigrations,
7
+ CfPlacement,
8
+ CfTailConsumer,
7
9
  } from "./worker.js";
8
10
 
9
11
  export function toMimeType(type: CfModuleType): string {
@@ -30,6 +32,7 @@ export type WorkerMetadataBinding =
30
32
  | { type: "json"; name: string; json: unknown }
31
33
  | { type: "wasm_module"; name: string; part: string }
32
34
  | { type: "text_blob"; name: string; part: string }
35
+ | { type: "browser"; name: string }
33
36
  | { type: "data_blob"; name: string; part: string }
34
37
  | { type: "kv_namespace"; name: string; namespace_id: string }
35
38
  | {
@@ -48,6 +51,7 @@ export type WorkerMetadataBinding =
48
51
  | { type: "queue"; name: string; queue_name: string }
49
52
  | { type: "r2_bucket"; name: string; bucket_name: string }
50
53
  | { type: "d1"; name: string; id: string; internalEnv?: string }
54
+ | { type: "constellation"; name: string; project: string }
51
55
  | { type: "service"; name: string; service: string; environment?: string }
52
56
  | { type: "analytics_engine"; name: string; dataset?: string }
53
57
  | { type: "dispatch_namespace"; name: string; namespace: string }
@@ -71,6 +75,8 @@ export interface WorkerMetadata {
71
75
  bindings: WorkerMetadataBinding[];
72
76
  keep_bindings?: WorkerMetadataBinding["type"][];
73
77
  logpush?: boolean;
78
+ placement?: CfPlacement;
79
+ tail_consumers?: CfTailConsumer[];
74
80
  // Allow unsafe.metadata to add arbitary properties at runtime
75
81
  [key: string]: unknown;
76
82
  }
@@ -89,6 +95,8 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
89
95
  compatibility_flags,
90
96
  keepVars,
91
97
  logpush,
98
+ placement,
99
+ tail_consumers,
92
100
  } = worker;
93
101
 
94
102
  let { modules } = worker;
@@ -161,6 +169,14 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
161
169
  }
162
170
  );
163
171
 
172
+ bindings.constellation?.forEach(({ binding, project_id }) => {
173
+ metadataBindings.push({
174
+ name: binding,
175
+ type: "constellation",
176
+ project: project_id,
177
+ });
178
+ });
179
+
164
180
  bindings.services?.forEach(({ binding, service, environment }) => {
165
181
  metadataBindings.push({
166
182
  name: binding,
@@ -217,6 +233,13 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
217
233
  );
218
234
  }
219
235
 
236
+ if (bindings.browser !== undefined) {
237
+ metadataBindings.push({
238
+ name: bindings.browser.binding,
239
+ type: "browser",
240
+ });
241
+ }
242
+
220
243
  for (const [name, filePath] of Object.entries(bindings.text_blobs || {})) {
221
244
  metadataBindings.push({
222
245
  name,
@@ -320,6 +343,8 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
320
343
  capnp_schema: bindings.logfwdr?.schema,
321
344
  ...(keepVars && { keep_bindings: ["plain_text", "json"] }),
322
345
  ...(logpush !== undefined && { logpush }),
346
+ ...(placement && { placement }),
347
+ ...(tail_consumers && { tail_consumers }),
323
348
  };
324
349
 
325
350
  if (bindings.unsafe?.metadata !== undefined) {
@@ -24,7 +24,7 @@ export function ListOptions(yargs: CommonYargsArgv) {
24
24
  type ListHandlerOptions = StrictYargsOptionsToInterface<typeof ListOptions>;
25
25
  export const ListHandler = withConfig<ListHandlerOptions>(
26
26
  async ({ config, name }): Promise<void> => {
27
- const accountId = await requireAuth({});
27
+ const accountId = await requireAuth(config);
28
28
  logger.log(d1BetaWarning);
29
29
  const db: Database = await getDatabaseByNameOrBinding(
30
30
  config,
@@ -87,7 +87,7 @@ type CreateHandlerOptions = StrictYargsOptionsToInterface<typeof CreateOptions>;
87
87
 
88
88
  export const CreateHandler = withConfig<CreateHandlerOptions>(
89
89
  async ({ config, name }): Promise<void> => {
90
- const accountId = await requireAuth({});
90
+ const accountId = await requireAuth(config);
91
91
  logger.log(d1BetaWarning);
92
92
  const db: Database = await getDatabaseByNameOrBinding(
93
93
  config,
@@ -135,7 +135,7 @@ type RestoreHandlerOptions = StrictYargsOptionsToInterface<
135
135
  >;
136
136
  export const RestoreHandler = withConfig<RestoreHandlerOptions>(
137
137
  async ({ config, name, backupId }): Promise<void> => {
138
- const accountId = await requireAuth({});
138
+ const accountId = await requireAuth(config);
139
139
  logger.log(d1BetaWarning);
140
140
  const db: Database = await getDatabaseByNameOrBinding(
141
141
  config,
@@ -183,7 +183,7 @@ type DownloadHandlerOptions = StrictYargsOptionsToInterface<
183
183
  >;
184
184
  export const DownloadHandler = withConfig<DownloadHandlerOptions>(
185
185
  async ({ name, backupId, output, config }): Promise<void> => {
186
- const accountId = await requireAuth({});
186
+ const accountId = await requireAuth(config);
187
187
  logger.log(d1BetaWarning);
188
188
  const db: Database = await getDatabaseByNameOrBinding(
189
189
  config,
@@ -1,2 +1,5 @@
1
1
  export const DEFAULT_MIGRATION_PATH = "./migrations";
2
2
  export const DEFAULT_MIGRATION_TABLE = "d1_migrations";
3
+ export const LOCATION_CHOICES = ["weur", "eeur", "apac", "wnam", "enam"];
4
+ // Max number of statements to send in a single /execute call
5
+ export const DEFAULT_BATCH_SIZE = 10_000;
package/src/d1/create.tsx CHANGED
@@ -1,15 +1,17 @@
1
- import { Text, Box } from "ink";
1
+ import { Box, Text } from "ink";
2
2
  import React from "react";
3
3
  import { fetchResult } from "../cfetch";
4
+ import { withConfig } from "../config";
4
5
  import { logger } from "../logger";
5
6
  import { requireAuth } from "../user";
6
7
  import { renderToString } from "../utils/render";
8
+ import { LOCATION_CHOICES } from "./constants";
7
9
  import { d1BetaWarning } from "./utils";
8
10
  import type {
9
11
  CommonYargsArgv,
10
12
  StrictYargsOptionsToInterface,
11
13
  } from "../yargs-types";
12
- import type { Database } from "./types";
14
+ import type { DatabaseCreationResult } from "./types";
13
15
 
14
16
  export function Options(yargs: CommonYargsArgv) {
15
17
  return yargs
@@ -18,51 +20,83 @@ export function Options(yargs: CommonYargsArgv) {
18
20
  type: "string",
19
21
  demandOption: true,
20
22
  })
23
+ .option("location", {
24
+ describe:
25
+ "A hint for the primary location of the new DB. Options:\nweur: Western Europe\neeur: Eastern Europe\napac: Asia Pacific\nwnam: Western North America\nenam: Eastern North America \n",
26
+ type: "string",
27
+ })
28
+ .option("experimental-backend", {
29
+ default: false,
30
+ describe: "Use new experimental DB backend",
31
+ type: "boolean",
32
+ })
21
33
  .epilogue(d1BetaWarning);
22
34
  }
23
35
 
24
- export async function Handler({
25
- name,
26
- }: StrictYargsOptionsToInterface<typeof Options>): Promise<void> {
27
- const accountId = await requireAuth({});
36
+ type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
37
+ export const Handler = withConfig<HandlerOptions>(
38
+ async ({ name, config, location, experimentalBackend }): Promise<void> => {
39
+ const accountId = await requireAuth(config);
28
40
 
29
- logger.log(d1BetaWarning);
41
+ logger.log(d1BetaWarning);
30
42
 
31
- let db: Database;
32
- try {
33
- db = await fetchResult(`/accounts/${accountId}/d1/database`, {
34
- method: "POST",
35
- headers: {
36
- "Content-Type": "application/json",
37
- },
38
- body: JSON.stringify({
39
- name,
40
- }),
41
- });
42
- } catch (e) {
43
- if ((e as { code: number }).code === 7502) {
44
- throw new Error("A database with that name already exists");
43
+ if (!experimentalBackend && location) {
44
+ if (LOCATION_CHOICES.indexOf(location.toLowerCase()) === -1) {
45
+ throw new Error(
46
+ `Location '${location}' invalid. Valid values are ${LOCATION_CHOICES.join(
47
+ ","
48
+ )}`
49
+ );
50
+ }
45
51
  }
46
- throw e;
47
- }
48
52
 
49
- logger.log(
50
- renderToString(
51
- <Box flexDirection="column">
52
- <Text>✅ Successfully created DB &apos;{db.name}&apos;!</Text>
53
- <Text>&nbsp;</Text>
54
- <Text>
55
- Add the following to your wrangler.toml to connect to it from a
56
- Worker:
57
- </Text>
58
- <Text>&nbsp;</Text>
59
- <Text>[[ d1_databases ]]</Text>
60
- <Text>
61
- binding = &quot;DB&quot; # i.e. available in your Worker on env.DB
62
- </Text>
63
- <Text>database_name = &quot;{db.name}&quot;</Text>
64
- <Text>database_id = &quot;{db.uuid}&quot;</Text>
65
- </Box>
66
- )
67
- );
68
- }
53
+ let db: DatabaseCreationResult;
54
+ try {
55
+ db = await fetchResult(`/accounts/${accountId}/d1/database`, {
56
+ method: "POST",
57
+ headers: {
58
+ "Content-Type": "application/json",
59
+ },
60
+ body: JSON.stringify({
61
+ name,
62
+ ...(location && { primary_location_hint: location }),
63
+ ...(experimentalBackend && { experimental: true }),
64
+ }),
65
+ });
66
+ } catch (e) {
67
+ if ((e as { code: number }).code === 7502) {
68
+ throw new Error("A database with that name already exists");
69
+ }
70
+ throw e;
71
+ }
72
+
73
+ logger.log(
74
+ renderToString(
75
+ <Box flexDirection="column">
76
+ <Text>
77
+ ✅ Successfully created DB &apos;{db.name}&apos;
78
+ {db.created_in_region
79
+ ? ` in region ${db.created_in_region}`
80
+ : location
81
+ ? ` using primary location hint ${location}`
82
+ : ``}
83
+ </Text>
84
+ {experimentalBackend && (
85
+ <Text>
86
+ Created your database using D1&apos;s new storage backend. The new
87
+ storage backend is not yet recommended for production workloads
88
+ and does not yet support backups.
89
+ </Text>
90
+ )}
91
+ <Text>&nbsp;</Text>
92
+ <Text>[[d1_databases]]</Text>
93
+ <Text>
94
+ binding = &quot;DB&quot; # i.e. available in your Worker on env.DB
95
+ </Text>
96
+ <Text>database_name = &quot;{db.name}&quot;</Text>
97
+ <Text>database_id = &quot;{db.uuid}&quot;</Text>
98
+ </Box>
99
+ )
100
+ );
101
+ }
102
+ );
package/src/d1/delete.ts CHANGED
@@ -24,7 +24,7 @@ export function Options(d1ListYargs: CommonYargsArgv) {
24
24
  type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
25
25
  export const Handler = withConfig<HandlerOptions>(
26
26
  async ({ name, skipConfirmation, config }): Promise<void> => {
27
- const accountId = await requireAuth({});
27
+ const accountId = await requireAuth(config);
28
28
  logger.log(d1BetaWarning);
29
29
 
30
30
  const db: Database = await getDatabaseByNameOrBinding(
@@ -15,6 +15,7 @@ import { readFileSync } from "../parse";
15
15
  import { readableRelative } from "../paths";
16
16
  import { requireAuth } from "../user";
17
17
  import { renderToString } from "../utils/render";
18
+ import { DEFAULT_BATCH_SIZE } from "./constants";
18
19
  import * as options from "./options";
19
20
  import splitSqlQuery from "./splitter";
20
21
  import {
@@ -37,8 +38,6 @@ export type QueryResult = {
37
38
  };
38
39
  query?: string;
39
40
  };
40
- // Max number of statements to send in a single /execute call
41
- const QUERY_LIMIT = 10_000;
42
41
 
43
42
  export function Options(yargs: CommonYargsArgv) {
44
43
  return options
@@ -75,14 +74,28 @@ export function Options(yargs: CommonYargsArgv) {
75
74
  describe: "Execute commands/files against a preview D1 DB",
76
75
  type: "boolean",
77
76
  default: false,
77
+ })
78
+ .option("batch-size", {
79
+ describe: "Number of queries to send in a single batch",
80
+ type: "number",
81
+ default: DEFAULT_BATCH_SIZE,
78
82
  });
79
83
  }
80
84
 
81
85
  type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
82
86
 
83
87
  export const Handler = async (args: HandlerOptions): Promise<void> => {
84
- const { local, database, yes, persistTo, file, command, json, preview } =
85
- args;
88
+ const {
89
+ local,
90
+ database,
91
+ yes,
92
+ persistTo,
93
+ file,
94
+ command,
95
+ json,
96
+ preview,
97
+ batchSize,
98
+ } = args;
86
99
  const existingLogLevel = logger.loggerLevel;
87
100
  if (json) {
88
101
  // set loggerLevel to error to avoid readConfig warnings appearing in JSON output
@@ -104,6 +117,7 @@ export const Handler = async (args: HandlerOptions): Promise<void> => {
104
117
  command,
105
118
  json,
106
119
  preview,
120
+ batchSize,
107
121
  });
108
122
 
109
123
  // Early exit if prompt rejected
@@ -150,6 +164,7 @@ export async function executeSql({
150
164
  command,
151
165
  json,
152
166
  preview,
167
+ batchSize,
153
168
  }: {
154
169
  local: boolean | undefined;
155
170
  config: ConfigFields<DevConfig> & Environment;
@@ -160,6 +175,7 @@ export async function executeSql({
160
175
  command: string | undefined;
161
176
  json: boolean | undefined;
162
177
  preview: boolean | undefined;
178
+ batchSize: number;
163
179
  }) {
164
180
  const sql = file ? readFileSync(file) : command;
165
181
  if (!sql) throw new Error(`Error: must provide --command or --file.`);
@@ -192,7 +208,7 @@ export async function executeSql({
192
208
  config,
193
209
  name,
194
210
  shouldPrompt,
195
- batches: batchSplit(queries),
211
+ batches: batchSplit(queries, batchSize),
196
212
  json,
197
213
  preview,
198
214
  });
@@ -281,7 +297,7 @@ async function executeRemotely({
281
297
  }
282
298
  }
283
299
 
284
- const accountId = await requireAuth({});
300
+ const accountId = await requireAuth(config);
285
301
  const db: Database = await getDatabaseByNameOrBinding(
286
302
  config,
287
303
  accountId,
@@ -313,7 +329,7 @@ async function executeRemotely({
313
329
  body: JSON.stringify({ sql }),
314
330
  }
315
331
  );
316
- result.map(logResult);
332
+ logResult(result);
317
333
  results.push(...result);
318
334
  }
319
335
  return results;
@@ -333,18 +349,16 @@ function logResult(r: QueryResult | QueryResult[]) {
333
349
  );
334
350
  }
335
351
 
336
- function batchSplit(queries: string[]) {
352
+ function batchSplit(queries: string[], batchSize: number) {
337
353
  logger.log(`🌀 Parsing ${queries.length} statements`);
338
- const num_batches = Math.ceil(queries.length / QUERY_LIMIT);
354
+ const num_batches = Math.ceil(queries.length / batchSize);
339
355
  const batches: string[] = [];
340
356
  for (let i = 0; i < num_batches; i++) {
341
- batches.push(
342
- queries.slice(i * QUERY_LIMIT, (i + 1) * QUERY_LIMIT).join("; ")
343
- );
357
+ batches.push(queries.slice(i * batchSize, (i + 1) * batchSize).join("; "));
344
358
  }
345
359
  if (num_batches > 1) {
346
360
  logger.log(
347
- `🌀 We are sending ${num_batches} batch(es) to D1 (limited to ${QUERY_LIMIT} statements per batch)`
361
+ `🌀 We are sending ${num_batches} batch(es) to D1 (limited to ${batchSize} statements per batch. Use --batch-size to override.)`
348
362
  );
349
363
  }
350
364
  return batches;
package/src/d1/list.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import Table from "ink-table";
2
2
  import React from "react";
3
3
  import { fetchResult } from "../cfetch";
4
+ import { withConfig } from "../config";
4
5
  import { logger } from "../logger";
5
6
  import { requireAuth } from "../user";
6
7
  import { renderToString } from "../utils/render";
@@ -21,19 +22,20 @@ export function Options(d1ListYargs: CommonYargsArgv) {
21
22
  .epilogue(d1BetaWarning);
22
23
  }
23
24
 
24
- export async function Handler({
25
- json,
26
- }: StrictYargsOptionsToInterface<typeof Options>): Promise<void> {
27
- const accountId = await requireAuth({});
28
- const dbs: Array<Database> = await listDatabases(accountId);
25
+ type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
26
+ export const Handler = withConfig<HandlerOptions>(
27
+ async ({ json, config }): Promise<void> => {
28
+ const accountId = await requireAuth(config);
29
+ const dbs: Array<Database> = await listDatabases(accountId);
29
30
 
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>));
31
+ if (json) {
32
+ logger.log(JSON.stringify(dbs, null, 2));
33
+ } else {
34
+ logger.log(d1BetaWarning);
35
+ logger.log(renderToString(<Table data={dbs}></Table>));
36
+ }
35
37
  }
36
- }
38
+ );
37
39
 
38
40
  export const listDatabases = async (
39
41
  accountId: string
@@ -12,7 +12,11 @@ import { logger } from "../../logger";
12
12
  import { requireAuth } from "../../user";
13
13
  import { renderToString } from "../../utils/render";
14
14
  import { createBackup } from "../backups";
15
- import { DEFAULT_MIGRATION_PATH, DEFAULT_MIGRATION_TABLE } from "../constants";
15
+ import {
16
+ DEFAULT_MIGRATION_PATH,
17
+ DEFAULT_MIGRATION_TABLE,
18
+ DEFAULT_BATCH_SIZE,
19
+ } from "../constants";
16
20
  import { executeSql } from "../execute";
17
21
  import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
18
22
  import {
@@ -28,13 +32,31 @@ import type {
28
32
  } from "../../yargs-types";
29
33
 
30
34
  export function ApplyOptions(yargs: CommonYargsArgv) {
31
- return MigrationOptions(yargs);
35
+ return MigrationOptions(yargs)
36
+ .option("experimentalBackend", {
37
+ default: false,
38
+ describe: "Use new experimental DB backend",
39
+ type: "boolean",
40
+ })
41
+ .option("batch-size", {
42
+ describe: "Number of queries to send in a single batch",
43
+ type: "number",
44
+ default: DEFAULT_BATCH_SIZE,
45
+ });
32
46
  }
33
47
 
34
48
  type ApplyHandlerOptions = StrictYargsOptionsToInterface<typeof ApplyOptions>;
35
49
 
36
50
  export const ApplyHandler = withConfig<ApplyHandlerOptions>(
37
- async ({ config, database, local, persistTo, preview }): Promise<void> => {
51
+ async ({
52
+ config,
53
+ database,
54
+ local,
55
+ persistTo,
56
+ preview,
57
+ experimentalBackend,
58
+ batchSize,
59
+ }): Promise<void> => {
38
60
  logger.log(d1BetaWarning);
39
61
 
40
62
  const databaseInfo = getDatabaseInfoFromConfig(config, database);
@@ -115,14 +137,14 @@ Your database may not be available to serve requests during the migration, conti
115
137
  );
116
138
  if (!ok) return;
117
139
 
118
- // don't backup prod db when applying migrations locally or in preview
119
- if (!local && !preview) {
140
+ // don't backup prod db when applying migrations locally, in preview, or when using the experimental backend
141
+ if (!(local || preview || experimentalBackend)) {
120
142
  assert(
121
143
  databaseInfo,
122
144
  "In non-local mode `databaseInfo` should be defined."
123
145
  );
124
146
  logger.log(renderToString(<Text>🕒 Creating backup...</Text>));
125
- const accountId = await requireAuth({});
147
+ const accountId = await requireAuth(config);
126
148
  await createBackup(accountId, databaseInfo.uuid);
127
149
  }
128
150
 
@@ -149,6 +171,7 @@ Your database may not be available to serve requests during the migration, conti
149
171
  file: undefined,
150
172
  json: undefined,
151
173
  preview,
174
+ batchSize,
152
175
  });
153
176
 
154
177
  if (response === null) {