wrangler 0.0.0-e33294b0 → 0.0.0-e351afcf

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 (127) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +183 -92
  3. package/package.json +15 -10
  4. package/src/__tests__/api-devregistry.test.ts +121 -0
  5. package/src/__tests__/api.test.ts +27 -5
  6. package/src/__tests__/configuration.test.ts +294 -18
  7. package/src/__tests__/constellation.test.ts +371 -0
  8. package/src/__tests__/d1/execute.test.ts +3 -1
  9. package/src/__tests__/d1/migrate.test.ts +102 -0
  10. package/src/__tests__/delete.test.ts +6 -0
  11. package/src/__tests__/deployments.test.ts +335 -95
  12. package/src/__tests__/dev.test.tsx +87 -57
  13. package/src/__tests__/generate.test.ts +3 -4
  14. package/src/__tests__/guess-worker-format.test.ts +35 -0
  15. package/src/__tests__/helpers/mock-console.ts +6 -0
  16. package/src/__tests__/helpers/msw/handlers/deployments.ts +70 -3
  17. package/src/__tests__/helpers/msw/index.ts +4 -2
  18. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  19. package/src/__tests__/index.test.ts +14 -6
  20. package/src/__tests__/init.test.ts +136 -104
  21. package/src/__tests__/jest.setup.ts +4 -0
  22. package/src/__tests__/kv.test.ts +9 -9
  23. package/src/__tests__/logger.test.ts +68 -2
  24. package/src/__tests__/middleware.scheduled.test.ts +2 -2
  25. package/src/__tests__/middleware.test.ts +4 -3
  26. package/src/__tests__/mtls-certificates.test.ts +7 -3
  27. package/src/__tests__/pages/deployment-list.test.ts +2 -0
  28. package/src/__tests__/pages/functions-build.test.ts +159 -39
  29. package/src/__tests__/pages/project-list.test.ts +2 -0
  30. package/src/__tests__/pages/project-upload.test.ts +43 -24
  31. package/src/__tests__/pages/publish.test.ts +267 -148
  32. package/src/__tests__/publish.test.ts +1040 -339
  33. package/src/__tests__/pubsub.test.ts +3 -0
  34. package/src/__tests__/queues.test.ts +5 -2
  35. package/src/__tests__/test-old-node-version.js +3 -3
  36. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  37. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  38. package/src/__tests__/type-generation.test.ts +1 -0
  39. package/src/__tests__/user.test.ts +2 -2
  40. package/src/__tests__/worker-namespace.test.ts +1 -0
  41. package/src/api/dev.ts +15 -22
  42. package/src/api/pages/create-worker-bundle-contents.ts +1 -0
  43. package/src/api/pages/publish.tsx +64 -61
  44. package/src/bundle.ts +51 -16
  45. package/src/config/environment.ts +36 -4
  46. package/src/config/index.ts +30 -2
  47. package/src/config/validation-helpers.ts +1 -1
  48. package/src/config/validation.ts +149 -5
  49. package/src/constellation/createProject.tsx +51 -0
  50. package/src/constellation/deleteProject.ts +51 -0
  51. package/src/constellation/deleteProjectModel.ts +68 -0
  52. package/src/constellation/index.ts +75 -0
  53. package/src/constellation/listCatalog.tsx +35 -0
  54. package/src/constellation/listModel.tsx +41 -0
  55. package/src/constellation/listProject.tsx +28 -0
  56. package/src/constellation/listRuntime.tsx +28 -0
  57. package/src/constellation/options.ts +17 -0
  58. package/src/constellation/types.ts +17 -0
  59. package/src/constellation/uploadModel.tsx +64 -0
  60. package/src/constellation/utils.ts +90 -0
  61. package/src/create-worker-preview.ts +19 -8
  62. package/src/create-worker-upload-form.ts +28 -3
  63. package/src/d1/backups.tsx +19 -15
  64. package/src/d1/create.tsx +45 -39
  65. package/src/d1/delete.ts +1 -1
  66. package/src/d1/execute.tsx +23 -20
  67. package/src/d1/list.tsx +14 -12
  68. package/src/d1/migrations/apply.tsx +36 -30
  69. package/src/d1/migrations/create.tsx +15 -12
  70. package/src/d1/migrations/helpers.ts +5 -8
  71. package/src/d1/migrations/list.tsx +10 -7
  72. package/src/deployments.ts +260 -8
  73. package/src/dev/dev.tsx +6 -4
  74. package/src/dev/local.tsx +65 -40
  75. package/src/dev/start-server.ts +57 -52
  76. package/src/dev/use-esbuild.ts +59 -52
  77. package/src/dev/validate-dev-props.ts +9 -0
  78. package/src/dev-registry.ts +2 -1
  79. package/src/dev.tsx +38 -18
  80. package/src/docs/helpers.ts +50 -0
  81. package/src/docs/index.ts +25 -68
  82. package/src/entry.ts +19 -9
  83. package/src/environment-variables/factory.ts +2 -1
  84. package/src/generate/index.ts +2 -2
  85. package/src/index.ts +87 -24
  86. package/src/init.ts +144 -134
  87. package/src/inspect.ts +16 -1
  88. package/src/kv/helpers.ts +7 -4
  89. package/src/logger.ts +23 -4
  90. package/src/metrics/send-event.ts +2 -1
  91. package/src/miniflare-cli/assets.ts +8 -7
  92. package/src/miniflare-cli/index.ts +3 -3
  93. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  94. package/src/module-collection.ts +92 -26
  95. package/src/pages/build.ts +290 -100
  96. package/src/pages/buildFunctions.ts +20 -10
  97. package/src/pages/deployments.tsx +3 -5
  98. package/src/pages/dev.ts +44 -26
  99. package/src/pages/errors.ts +1 -0
  100. package/src/pages/functions/buildPlugin.ts +57 -34
  101. package/src/pages/functions/buildWorker.ts +91 -31
  102. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  103. package/src/pages/projects.tsx +2 -5
  104. package/src/pages/publish.tsx +1 -10
  105. package/src/pages/upload.tsx +29 -9
  106. package/src/paths.ts +1 -1
  107. package/src/publish/index.ts +1 -1
  108. package/src/publish/publish.ts +29 -34
  109. package/src/queues/cli/commands/consumer/add.ts +6 -0
  110. package/src/queues/client.ts +1 -0
  111. package/src/r2/helpers.ts +1 -0
  112. package/src/secret/index.ts +2 -1
  113. package/src/sites.ts +164 -52
  114. package/src/traverse-module-graph.ts +53 -0
  115. package/src/type-generation.ts +1 -1
  116. package/src/user/user.ts +2 -1
  117. package/src/utils/render.ts +93 -0
  118. package/src/worker.ts +18 -1
  119. package/templates/d1-beta-facade.js +5 -2
  120. package/templates/gitignore +1 -0
  121. package/templates/middleware/middleware-miniflare3-json-error.ts +17 -5
  122. package/templates/pages-template-plugin.ts +7 -3
  123. package/templates/tsconfig.init.json +1 -2
  124. package/templates/tsconfig.tsbuildinfo +1 -1
  125. package/wrangler-dist/cli.d.ts +552 -16
  126. package/wrangler-dist/cli.js +32141 -24052
  127. package/src/__tests__/api-devregistry.test.js +0 -64
@@ -0,0 +1,17 @@
1
+ export type Project = {
2
+ id: string;
3
+ name: string;
4
+ runtime: string;
5
+ };
6
+
7
+ export type Model = {
8
+ id: string;
9
+ project_id: string;
10
+ name: string;
11
+ description: string;
12
+ };
13
+
14
+ export type CatalogEntry = {
15
+ project: Project;
16
+ models: Model[];
17
+ };
@@ -0,0 +1,64 @@
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 { takeName } from "./options";
8
+ import { constellationBetaWarning, getProjectByName } from "./utils";
9
+ import type {
10
+ CommonYargsArgv,
11
+ StrictYargsOptionsToInterface,
12
+ } from "../yargs-types";
13
+ import type { Model } from "./types";
14
+
15
+ export function options(yargs: CommonYargsArgv) {
16
+ return takeName(yargs)
17
+ .positional("modelName", {
18
+ describe: "The name of the uploaded model",
19
+ type: "string",
20
+ demandOption: true,
21
+ })
22
+ .positional("modelFile", {
23
+ describe: "The name of the local file with the model contents",
24
+ type: "string",
25
+ demandOption: true,
26
+ })
27
+ .epilogue(constellationBetaWarning);
28
+ }
29
+ type HandlerOptions = StrictYargsOptionsToInterface<typeof options>;
30
+ export const handler = withConfig<HandlerOptions>(
31
+ async ({ name, modelName, modelFile, config }): Promise<void> => {
32
+ const accountId = await requireAuth(config);
33
+ logger.log(constellationBetaWarning);
34
+
35
+ const proj = await getProjectByName(config, accountId, name);
36
+
37
+ const formData = new FormData();
38
+ formData.set(
39
+ "file",
40
+ new File([readFileSync(modelFile)], modelFile, {
41
+ type: "application/octet-stream",
42
+ })
43
+ );
44
+ formData.set("name", modelName);
45
+
46
+ let model: Model;
47
+ try {
48
+ model = await fetchResult(
49
+ `/accounts/${accountId}/constellation/project/${proj.id}/model`,
50
+ {
51
+ method: "POST",
52
+ body: formData,
53
+ }
54
+ );
55
+ } catch (e) {
56
+ if ((e as { code: number }).code === 7408) {
57
+ throw new Error("A model with that name already exists");
58
+ }
59
+ throw e;
60
+ }
61
+
62
+ logger.log(`✅ Successfully uploaded Model "${model.name}"!`);
63
+ }
64
+ );
@@ -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 AI 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
+ };
@@ -109,6 +109,14 @@ function randomId(): string {
109
109
  });
110
110
  }
111
111
 
112
+ // URLs are often relative to the zone. Sometimes the base zone
113
+ // will be grey-clouded, and so the host must be swapped out for
114
+ // the worker route host, which is more likely to be orange-clouded
115
+ function switchHost(originalUrl: string, host?: string): URL {
116
+ const url = new URL(originalUrl);
117
+ url.hostname = host ?? url.hostname;
118
+ return url;
119
+ }
112
120
  /**
113
121
  * Generates a preview session token.
114
122
  */
@@ -129,9 +137,13 @@ export async function createPreviewSession(
129
137
  abortSignal
130
138
  );
131
139
 
132
- logger.debug(`-- START EXCHANGE API REQUEST: GET ${exchange_url}`);
140
+ const switchedExchangeUrl = switchHost(exchange_url, ctx.host).toString();
141
+
142
+ logger.debug(`-- START EXCHANGE API REQUEST: GET ${switchedExchangeUrl}`);
133
143
  logger.debug("-- END EXCHANGE API REQUEST");
134
- const exchangeResponse = await fetch(exchange_url, { signal: abortSignal });
144
+ const exchangeResponse = await fetch(switchedExchangeUrl, {
145
+ signal: abortSignal,
146
+ });
135
147
  const bodyText = await exchangeResponse.text();
136
148
  logger.debug(
137
149
  "-- START EXCHANGE API RESPONSE:",
@@ -147,16 +159,15 @@ export async function createPreviewSession(
147
159
  token: string;
148
160
  prewarm: string;
149
161
  }>(bodyText);
150
-
151
- const { host } = new URL(inspector_websocket);
152
- const query = `cf_workers_preview_token=${token}`;
162
+ const inspector = new URL(inspector_websocket);
163
+ inspector.searchParams.append("cf_workers_preview_token", token);
153
164
 
154
165
  return {
155
166
  id: randomId(),
156
167
  value: token,
157
- host,
158
- inspectorUrl: new URL(`${inspector_websocket}?${query}`),
159
- prewarmUrl: new URL(prewarm),
168
+ host: ctx.host ?? inspector.host,
169
+ inspectorUrl: switchHost(inspector.href, ctx.host),
170
+ prewarmUrl: switchHost(prewarm, ctx.host),
160
171
  };
161
172
  }
162
173
 
@@ -23,7 +23,7 @@ export function toMimeType(type: CfModuleType): string {
23
23
  }
24
24
  }
25
25
 
26
- type WorkerMetadataBinding =
26
+ export type WorkerMetadataBinding =
27
27
  // If you add any new binding types here, also add it to safeBindings
28
28
  // under validateUnsafeBinding in config/validation.ts
29
29
  | { type: "plain_text"; name: string; text: string }
@@ -32,6 +32,12 @@ type WorkerMetadataBinding =
32
32
  | { type: "text_blob"; name: string; part: string }
33
33
  | { type: "data_blob"; name: string; part: string }
34
34
  | { type: "kv_namespace"; name: string; namespace_id: string }
35
+ | {
36
+ type: "send_email";
37
+ name: string;
38
+ destination_address?: string;
39
+ allowed_destination_addresses?: string[];
40
+ }
35
41
  | {
36
42
  type: "durable_object_namespace";
37
43
  name: string;
@@ -65,6 +71,8 @@ export interface WorkerMetadata {
65
71
  bindings: WorkerMetadataBinding[];
66
72
  keep_bindings?: WorkerMetadataBinding["type"][];
67
73
  logpush?: boolean;
74
+ // Allow unsafe.metadata to add arbitary properties at runtime
75
+ [key: string]: unknown;
68
76
  }
69
77
 
70
78
  /**
@@ -103,6 +111,17 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
103
111
  });
104
112
  });
105
113
 
114
+ bindings.send_email?.forEach(
115
+ ({ name, destination_address, allowed_destination_addresses }) => {
116
+ metadataBindings.push({
117
+ name: name,
118
+ type: "send_email",
119
+ destination_address,
120
+ allowed_destination_addresses,
121
+ });
122
+ }
123
+ );
124
+
106
125
  bindings.durable_objects?.bindings.forEach(
107
126
  ({ name, class_name, script_name, environment }) => {
108
127
  metadataBindings.push({
@@ -284,9 +303,9 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
284
303
  }
285
304
  }
286
305
 
287
- if (bindings.unsafe) {
306
+ if (bindings.unsafe?.bindings) {
288
307
  // @ts-expect-error unsafe bindings don't need to match a specific type here
289
- metadataBindings.push(...bindings.unsafe);
308
+ metadataBindings.push(...bindings.unsafe.bindings);
290
309
  }
291
310
 
292
311
  const metadata: WorkerMetadata = {
@@ -303,6 +322,12 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
303
322
  ...(logpush !== undefined && { logpush }),
304
323
  };
305
324
 
325
+ if (bindings.unsafe?.metadata !== undefined) {
326
+ for (const key of Object.keys(bindings.unsafe.metadata)) {
327
+ metadata[key] = bindings.unsafe.metadata[key];
328
+ }
329
+ }
330
+
306
331
  formData.set("metadata", JSON.stringify(metadata));
307
332
 
308
333
  if (main.type === "commonjs" && modules && modules.length > 0) {
@@ -1,6 +1,5 @@
1
1
  import fs from "node:fs/promises";
2
2
  import * as path from "path";
3
- import { render } from "ink";
4
3
  import Table from "ink-table";
5
4
  import React from "react";
6
5
  import { fetchResult } from "../cfetch";
@@ -8,6 +7,7 @@ import { performApiFetch } from "../cfetch/internal";
8
7
  import { withConfig } from "../config";
9
8
  import { logger } from "../logger";
10
9
  import { requireAuth } from "../user";
10
+ import { renderToString } from "../utils/render";
11
11
  import { formatBytes, formatTimeAgo } from "./formatTimeAgo";
12
12
  import { Name } from "./options";
13
13
  import { d1BetaWarning, getDatabaseByNameOrBinding } from "./utils";
@@ -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,
@@ -33,11 +33,13 @@ export const ListHandler = withConfig<ListHandlerOptions>(
33
33
  );
34
34
 
35
35
  const backups: Backup[] = await listBackups(accountId, db.uuid);
36
- render(
37
- <Table
38
- data={backups}
39
- columns={["created_at", "id", "num_tables", "size"]}
40
- ></Table>
36
+ logger.log(
37
+ renderToString(
38
+ <Table
39
+ data={backups}
40
+ columns={["created_at", "id", "num_tables", "size"]}
41
+ ></Table>
42
+ )
41
43
  );
42
44
  }
43
45
  );
@@ -85,7 +87,7 @@ type CreateHandlerOptions = StrictYargsOptionsToInterface<typeof CreateOptions>;
85
87
 
86
88
  export const CreateHandler = withConfig<CreateHandlerOptions>(
87
89
  async ({ config, name }): Promise<void> => {
88
- const accountId = await requireAuth({});
90
+ const accountId = await requireAuth(config);
89
91
  logger.log(d1BetaWarning);
90
92
  const db: Database = await getDatabaseByNameOrBinding(
91
93
  config,
@@ -94,11 +96,13 @@ export const CreateHandler = withConfig<CreateHandlerOptions>(
94
96
  );
95
97
 
96
98
  const backup: Backup = await createBackup(accountId, db.uuid);
97
- render(
98
- <Table
99
- data={[backup]}
100
- columns={["created_at", "id", "num_tables", "size", "state"]}
101
- ></Table>
99
+ logger.log(
100
+ renderToString(
101
+ <Table
102
+ data={[backup]}
103
+ columns={["created_at", "id", "num_tables", "size", "state"]}
104
+ ></Table>
105
+ )
102
106
  );
103
107
  }
104
108
  );
@@ -131,7 +135,7 @@ type RestoreHandlerOptions = StrictYargsOptionsToInterface<
131
135
  >;
132
136
  export const RestoreHandler = withConfig<RestoreHandlerOptions>(
133
137
  async ({ config, name, backupId }): Promise<void> => {
134
- const accountId = await requireAuth({});
138
+ const accountId = await requireAuth(config);
135
139
  logger.log(d1BetaWarning);
136
140
  const db: Database = await getDatabaseByNameOrBinding(
137
141
  config,
@@ -179,7 +183,7 @@ type DownloadHandlerOptions = StrictYargsOptionsToInterface<
179
183
  >;
180
184
  export const DownloadHandler = withConfig<DownloadHandlerOptions>(
181
185
  async ({ name, backupId, output, config }): Promise<void> => {
182
- const accountId = await requireAuth({});
186
+ const accountId = await requireAuth(config);
183
187
  logger.log(d1BetaWarning);
184
188
  const db: Database = await getDatabaseByNameOrBinding(
185
189
  config,
package/src/d1/create.tsx CHANGED
@@ -1,8 +1,10 @@
1
- import { render, Text, Box } from "ink";
1
+ import { Text, Box } 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";
7
+ import { renderToString } from "../utils/render";
6
8
  import { d1BetaWarning } from "./utils";
7
9
  import type {
8
10
  CommonYargsArgv,
@@ -20,45 +22,49 @@ export function Options(yargs: CommonYargsArgv) {
20
22
  .epilogue(d1BetaWarning);
21
23
  }
22
24
 
23
- export async function Handler({
24
- name,
25
- }: StrictYargsOptionsToInterface<typeof Options>): Promise<void> {
26
- const accountId = await requireAuth({});
25
+ type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>;
26
+ export const Handler = withConfig<HandlerOptions>(
27
+ async ({ name, config }): Promise<void> => {
28
+ const accountId = await requireAuth(config);
27
29
 
28
- logger.log(d1BetaWarning);
30
+ logger.log(d1BetaWarning);
29
31
 
30
- let db: Database;
31
- try {
32
- db = await fetchResult(`/accounts/${accountId}/d1/database`, {
33
- method: "POST",
34
- headers: {
35
- "Content-Type": "application/json",
36
- },
37
- body: JSON.stringify({
38
- name,
39
- }),
40
- });
41
- } catch (e) {
42
- if ((e as { code: number }).code === 7502) {
43
- throw new Error("A database with that name already exists");
32
+ let db: Database;
33
+ try {
34
+ db = await fetchResult(`/accounts/${accountId}/d1/database`, {
35
+ method: "POST",
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ },
39
+ body: JSON.stringify({
40
+ name,
41
+ }),
42
+ });
43
+ } catch (e) {
44
+ if ((e as { code: number }).code === 7502) {
45
+ throw new Error("A database with that name already exists");
46
+ }
47
+ throw e;
44
48
  }
45
- throw e;
46
- }
47
49
 
48
- render(
49
- <Box flexDirection="column">
50
- <Text>✅ Successfully created DB &apos;{db.name}&apos;!</Text>
51
- <Text>&nbsp;</Text>
52
- <Text>
53
- Add the following to your wrangler.toml to connect to it from a Worker:
54
- </Text>
55
- <Text>&nbsp;</Text>
56
- <Text>[[ d1_databases ]]</Text>
57
- <Text>
58
- binding = &quot;DB&quot; # i.e. available in your Worker on env.DB
59
- </Text>
60
- <Text>database_name = &quot;{db.name}&quot;</Text>
61
- <Text>database_id = &quot;{db.uuid}&quot;</Text>
62
- </Box>
63
- );
64
- }
50
+ logger.log(
51
+ renderToString(
52
+ <Box flexDirection="column">
53
+ <Text>✅ Successfully created DB &apos;{db.name}&apos;!</Text>
54
+ <Text>&nbsp;</Text>
55
+ <Text>
56
+ Add the following to your wrangler.toml to connect to it from a
57
+ Worker:
58
+ </Text>
59
+ <Text>&nbsp;</Text>
60
+ <Text>[[ d1_databases ]]</Text>
61
+ <Text>
62
+ binding = &quot;DB&quot; # i.e. available in your Worker on env.DB
63
+ </Text>
64
+ <Text>database_name = &quot;{db.name}&quot;</Text>
65
+ <Text>database_id = &quot;{db.uuid}&quot;</Text>
66
+ </Box>
67
+ )
68
+ );
69
+ }
70
+ );
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(
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { mkdir } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import chalk from "chalk";
5
- import { render, Static, Text } from "ink";
5
+ import { Static, Text } from "ink";
6
6
  import Table from "ink-table";
7
7
  import { npxImport } from "npx-import";
8
8
  import React from "react";
@@ -14,6 +14,7 @@ import { logger } from "../logger";
14
14
  import { readFileSync } from "../parse";
15
15
  import { readableRelative } from "../paths";
16
16
  import { requireAuth } from "../user";
17
+ import { renderToString } from "../utils/render";
17
18
  import * as options from "./options";
18
19
  import splitSqlQuery from "./splitter";
19
20
  import {
@@ -36,7 +37,7 @@ export type QueryResult = {
36
37
  };
37
38
  query?: string;
38
39
  };
39
- // Max number of bytes to send in a single /execute call
40
+ // Max number of statements to send in a single /execute call
40
41
  const QUERY_LIMIT = 10_000;
41
42
 
42
43
  export function Options(yargs: CommonYargsArgv) {
@@ -110,25 +111,27 @@ export const Handler = async (args: HandlerOptions): Promise<void> => {
110
111
 
111
112
  if (isInteractive && !json) {
112
113
  // Render table if single result
113
- render(
114
- <Static items={response}>
115
- {(result) => {
116
- // batch results
117
- if (!Array.isArray(result)) {
118
- const { results, query } = result;
114
+ logger.log(
115
+ renderToString(
116
+ <Static items={response}>
117
+ {(result) => {
118
+ // batch results
119
+ if (!Array.isArray(result)) {
120
+ const { results, query } = result;
119
121
 
120
- if (Array.isArray(results) && results.length > 0) {
121
- const shortQuery = shorten(query, 48);
122
- return (
123
- <>
124
- {shortQuery ? <Text dimColor>{shortQuery}</Text> : null}
125
- <Table data={results}></Table>
126
- </>
127
- );
122
+ if (Array.isArray(results) && results.length > 0) {
123
+ const shortQuery = shorten(query, 48);
124
+ return (
125
+ <>
126
+ {shortQuery ? <Text dimColor>{shortQuery}</Text> : null}
127
+ <Table data={results}></Table>
128
+ </>
129
+ );
130
+ }
128
131
  }
129
- }
130
- }}
131
- </Static>
132
+ }}
133
+ </Static>
134
+ )
132
135
  );
133
136
  } else {
134
137
  // set loggerLevel back to what it was before to actually output the JSON in stdout
@@ -278,7 +281,7 @@ async function executeRemotely({
278
281
  }
279
282
  }
280
283
 
281
- const accountId = await requireAuth({});
284
+ const accountId = await requireAuth(config);
282
285
  const db: Database = await getDatabaseByNameOrBinding(
283
286
  config,
284
287
  accountId,
package/src/d1/list.tsx CHANGED
@@ -1,9 +1,10 @@
1
- import { render } from "ink";
2
1
  import Table from "ink-table";
3
2
  import React from "react";
4
3
  import { fetchResult } from "../cfetch";
4
+ import { withConfig } from "../config";
5
5
  import { logger } from "../logger";
6
6
  import { requireAuth } from "../user";
7
+ import { renderToString } from "../utils/render";
7
8
  import { d1BetaWarning } from "./utils";
8
9
  import type {
9
10
  CommonYargsArgv,
@@ -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
- render(<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