wrangler 0.0.0-e6e1daba → 0.0.0-e7cf0caa

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 (101) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +1 -1
  3. package/package.json +14 -9
  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__/d1/execute.test.ts +3 -1
  8. package/src/__tests__/d1/migrate.test.ts +2 -0
  9. package/src/__tests__/delete.test.ts +6 -0
  10. package/src/__tests__/deployments.test.ts +335 -95
  11. package/src/__tests__/dev.test.tsx +87 -57
  12. package/src/__tests__/generate.test.ts +3 -4
  13. package/src/__tests__/helpers/mock-console.ts +6 -0
  14. package/src/__tests__/helpers/msw/handlers/deployments.ts +70 -3
  15. package/src/__tests__/helpers/msw/index.ts +4 -2
  16. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  17. package/src/__tests__/index.test.ts +10 -4
  18. package/src/__tests__/init.test.ts +136 -104
  19. package/src/__tests__/jest.setup.ts +4 -0
  20. package/src/__tests__/kv.test.ts +9 -9
  21. package/src/__tests__/logger.test.ts +68 -2
  22. package/src/__tests__/middleware.scheduled.test.ts +2 -2
  23. package/src/__tests__/middleware.test.ts +4 -3
  24. package/src/__tests__/mtls-certificates.test.ts +5 -2
  25. package/src/__tests__/pages/deployment-list.test.ts +2 -0
  26. package/src/__tests__/pages/functions-build.test.ts +91 -41
  27. package/src/__tests__/pages/project-list.test.ts +2 -0
  28. package/src/__tests__/pages/project-upload.test.ts +43 -24
  29. package/src/__tests__/pages/publish.test.ts +267 -148
  30. package/src/__tests__/publish.test.ts +420 -164
  31. package/src/__tests__/pubsub.test.ts +3 -0
  32. package/src/__tests__/queues.test.ts +5 -2
  33. package/src/__tests__/test-old-node-version.js +3 -3
  34. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  35. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  36. package/src/__tests__/type-generation.test.ts +1 -0
  37. package/src/__tests__/user.test.ts +1 -1
  38. package/src/__tests__/worker-namespace.test.ts +1 -0
  39. package/src/api/dev.ts +10 -22
  40. package/src/api/pages/create-worker-bundle-contents.ts +1 -0
  41. package/src/api/pages/publish.tsx +38 -51
  42. package/src/bundle.ts +44 -13
  43. package/src/config/environment.ts +36 -4
  44. package/src/config/index.ts +30 -2
  45. package/src/config/validation-helpers.ts +1 -1
  46. package/src/config/validation.ts +149 -5
  47. package/src/create-worker-upload-form.ts +28 -3
  48. package/src/d1/backups.tsx +15 -11
  49. package/src/d1/create.tsx +20 -16
  50. package/src/d1/execute.tsx +22 -19
  51. package/src/d1/list.tsx +2 -2
  52. package/src/d1/migrations/apply.tsx +35 -29
  53. package/src/d1/migrations/create.tsx +15 -12
  54. package/src/d1/migrations/list.tsx +10 -7
  55. package/src/deployments.ts +260 -8
  56. package/src/dev/dev.tsx +4 -4
  57. package/src/dev/local.tsx +14 -16
  58. package/src/dev/start-server.ts +12 -16
  59. package/src/dev/use-esbuild.ts +11 -13
  60. package/src/dev/validate-dev-props.ts +9 -0
  61. package/src/dev-registry.ts +2 -1
  62. package/src/dev.tsx +28 -13
  63. package/src/entry.ts +18 -8
  64. package/src/generate/index.ts +2 -2
  65. package/src/index.ts +76 -23
  66. package/src/init.ts +144 -134
  67. package/src/logger.ts +18 -3
  68. package/src/metrics/send-event.ts +2 -1
  69. package/src/miniflare-cli/index.ts +1 -1
  70. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  71. package/src/module-collection.ts +91 -25
  72. package/src/pages/build.ts +277 -99
  73. package/src/pages/buildFunctions.ts +20 -10
  74. package/src/pages/deployments.tsx +3 -5
  75. package/src/pages/dev.ts +21 -21
  76. package/src/pages/errors.ts +1 -0
  77. package/src/pages/functions/buildPlugin.ts +57 -34
  78. package/src/pages/functions/buildWorker.ts +34 -31
  79. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  80. package/src/pages/projects.tsx +2 -5
  81. package/src/pages/publish.tsx +1 -10
  82. package/src/pages/upload.tsx +29 -9
  83. package/src/paths.ts +1 -1
  84. package/src/publish/index.ts +1 -1
  85. package/src/publish/publish.ts +29 -34
  86. package/src/queues/cli/commands/consumer/add.ts +6 -0
  87. package/src/queues/client.ts +1 -0
  88. package/src/secret/index.ts +2 -1
  89. package/src/traverse-module-graph.ts +53 -0
  90. package/src/type-generation.ts +1 -1
  91. package/src/user/user.ts +1 -1
  92. package/src/utils/render.ts +93 -0
  93. package/src/worker.ts +18 -1
  94. package/templates/d1-beta-facade.js +5 -2
  95. package/templates/gitignore +1 -0
  96. package/templates/middleware/middleware-miniflare3-json-error.ts +17 -5
  97. package/templates/tsconfig.init.json +1 -2
  98. package/templates/tsconfig.tsbuildinfo +1 -1
  99. package/wrangler-dist/cli.d.ts +33 -13
  100. package/wrangler-dist/cli.js +20732 -19984
  101. package/src/__tests__/api-devregistry.test.js +0 -64
@@ -358,6 +358,26 @@ function normalizeAndValidateMainField(
358
358
  }
359
359
  }
360
360
 
361
+ /**
362
+ * Validate the `base_dir` field and return the normalized values.
363
+ */
364
+ function normalizeAndValidateBaseDirField(
365
+ configPath: string | undefined,
366
+ rawDir: string | undefined
367
+ ): string | undefined {
368
+ const configDir = path.dirname(configPath ?? "wrangler.toml");
369
+ if (rawDir !== undefined) {
370
+ if (typeof rawDir === "string") {
371
+ const directory = path.resolve(configDir);
372
+ return path.resolve(directory, rawDir);
373
+ } else {
374
+ return rawDir;
375
+ }
376
+ } else {
377
+ return;
378
+ }
379
+ }
380
+
361
381
  /**
362
382
  * Validate the `dev` configuration and return the normalized values.
363
383
  */
@@ -1011,6 +1031,17 @@ function normalizeAndValidateEnvironment(
1011
1031
  ),
1012
1032
  deprecatedUpload
1013
1033
  ),
1034
+ base_dir: normalizeAndValidateBaseDirField(
1035
+ configPath,
1036
+ inheritable(
1037
+ diagnostics,
1038
+ topLevelEnv,
1039
+ rawEnv,
1040
+ "base_dir",
1041
+ isString,
1042
+ undefined
1043
+ )
1044
+ ),
1014
1045
  route,
1015
1046
  routes,
1016
1047
  triggers: inheritable(
@@ -1074,6 +1105,16 @@ function normalizeAndValidateEnvironment(
1074
1105
  validateBindingArray(envName, validateKVBinding),
1075
1106
  []
1076
1107
  ),
1108
+ send_email: notInheritable(
1109
+ diagnostics,
1110
+ topLevelEnv,
1111
+ rawConfig,
1112
+ rawEnv,
1113
+ envName,
1114
+ "send_email",
1115
+ validateBindingArray(envName, validateSendEmailBinding),
1116
+ []
1117
+ ),
1077
1118
  queues: notInheritable(
1078
1119
  diagnostics,
1079
1120
  topLevelEnv,
@@ -1162,10 +1203,8 @@ function normalizeAndValidateEnvironment(
1162
1203
  rawEnv,
1163
1204
  envName,
1164
1205
  "unsafe",
1165
- validateBindingsProperty(envName, validateUnsafeBinding),
1166
- {
1167
- bindings: [],
1168
- }
1206
+ validateUnsafeSettings(envName),
1207
+ {}
1169
1208
  ),
1170
1209
  zone_id: rawEnv.zone_id,
1171
1210
  no_bundle: inheritable(
@@ -1495,6 +1534,62 @@ const validateBindingsProperty =
1495
1534
  return isValid;
1496
1535
  };
1497
1536
 
1537
+ const validateUnsafeSettings =
1538
+ (envName: string): ValidatorFn =>
1539
+ (diagnostics, field, value, config) => {
1540
+ const fieldPath =
1541
+ config === undefined ? `${field}` : `env.${envName}.${field}`;
1542
+
1543
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
1544
+ diagnostics.errors.push(
1545
+ `The field "${fieldPath}" should be an object but got ${JSON.stringify(
1546
+ value
1547
+ )}.`
1548
+ );
1549
+ return false;
1550
+ }
1551
+
1552
+ // At least one of bindings and metadata must exist
1553
+ if (!hasProperty(value, "bindings") && !hasProperty(value, "metadata")) {
1554
+ diagnostics.errors.push(
1555
+ `The field "${fieldPath}" should contain at least one of "bindings" or "metadata" properties but got ${JSON.stringify(
1556
+ value
1557
+ )}.`
1558
+ );
1559
+ return false;
1560
+ }
1561
+
1562
+ // unsafe.bindings
1563
+ if (hasProperty(value, "bindings") && value.bindings !== undefined) {
1564
+ const validateBindingsFn = validateBindingsProperty(
1565
+ envName,
1566
+ validateUnsafeBinding
1567
+ );
1568
+ const valid = validateBindingsFn(diagnostics, field, value, config);
1569
+ if (!valid) {
1570
+ return false;
1571
+ }
1572
+ }
1573
+
1574
+ // unsafe.metadata
1575
+ if (
1576
+ hasProperty(value, "metadata") &&
1577
+ value.metadata !== undefined &&
1578
+ (typeof value.metadata !== "object" ||
1579
+ value.metadata === null ||
1580
+ Array.isArray(value.metadata))
1581
+ ) {
1582
+ diagnostics.errors.push(
1583
+ `The field "${fieldPath}.metadata" should be an object but got ${JSON.stringify(
1584
+ value.metadata
1585
+ )}.`
1586
+ );
1587
+ return false;
1588
+ }
1589
+
1590
+ return true;
1591
+ };
1592
+
1498
1593
  /**
1499
1594
  * Check that the given field is a valid "durable_object" binding object.
1500
1595
  */
@@ -1711,6 +1806,53 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
1711
1806
  return isValid;
1712
1807
  };
1713
1808
 
1809
+ const validateSendEmailBinding: ValidatorFn = (diagnostics, field, value) => {
1810
+ if (typeof value !== "object" || value === null) {
1811
+ diagnostics.errors.push(
1812
+ `"send_email" bindings should be objects, but got ${JSON.stringify(
1813
+ value
1814
+ )}`
1815
+ );
1816
+ return false;
1817
+ }
1818
+ let isValid = true;
1819
+ // send email bindings must have a name.
1820
+ if (!isRequiredProperty(value, "name", "string")) {
1821
+ diagnostics.errors.push(
1822
+ `"${field}" bindings should have a string "name" field but got ${JSON.stringify(
1823
+ value
1824
+ )}.`
1825
+ );
1826
+ isValid = false;
1827
+ }
1828
+ if (!isOptionalProperty(value, "destination_address", "string")) {
1829
+ diagnostics.errors.push(
1830
+ `"${field}" bindings should, optionally, have a string "destination_address" field but got ${JSON.stringify(
1831
+ value
1832
+ )}.`
1833
+ );
1834
+ isValid = false;
1835
+ }
1836
+ if (!isOptionalProperty(value, "allowed_destination_addresses", "object")) {
1837
+ diagnostics.errors.push(
1838
+ `"${field}" bindings should, optionally, have a []string "allowed_destination_addresses" field but got ${JSON.stringify(
1839
+ value
1840
+ )}.`
1841
+ );
1842
+ isValid = false;
1843
+ }
1844
+ if (
1845
+ "destination_address" in value &&
1846
+ "allowed_destination_addresses" in value
1847
+ ) {
1848
+ diagnostics.errors.push(
1849
+ `"${field}" bindings should have either a "destination_address" or "allowed_destination_addresses" field, but not both.`
1850
+ );
1851
+ isValid = false;
1852
+ }
1853
+ return isValid;
1854
+ };
1855
+
1714
1856
  const validateQueueBinding: ValidatorFn = (diagnostics, field, value) => {
1715
1857
  if (typeof value !== "object" || value === null) {
1716
1858
  diagnostics.errors.push(
@@ -2161,6 +2303,7 @@ const validateConsumer: ValidatorFn = (diagnostics, field, value, _config) => {
2161
2303
  "max_batch_timeout",
2162
2304
  "max_retries",
2163
2305
  "dead_letter_queue",
2306
+ "max_concurrency",
2164
2307
  ])
2165
2308
  ) {
2166
2309
  isValid = false;
@@ -2176,12 +2319,13 @@ const validateConsumer: ValidatorFn = (diagnostics, field, value, _config) => {
2176
2319
 
2177
2320
  const options: {
2178
2321
  key: string;
2179
- type: "number" | "string";
2322
+ type: "number" | "string" | "boolean";
2180
2323
  }[] = [
2181
2324
  { key: "max_batch_size", type: "number" },
2182
2325
  { key: "max_batch_timeout", type: "number" },
2183
2326
  { key: "max_retries", type: "number" },
2184
2327
  { key: "dead_letter_queue", type: "string" },
2328
+ { key: "max_concurrency", type: "number" },
2185
2329
  ];
2186
2330
  for (const optionalOpt of options) {
2187
2331
  if (!isOptionalProperty(value, optionalOpt.key, optionalOpt.type)) {
@@ -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";
@@ -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
  );
@@ -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
  );
package/src/d1/create.tsx CHANGED
@@ -1,8 +1,9 @@
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
4
  import { logger } from "../logger";
5
5
  import { requireAuth } from "../user";
6
+ import { renderToString } from "../utils/render";
6
7
  import { d1BetaWarning } from "./utils";
7
8
  import type {
8
9
  CommonYargsArgv,
@@ -45,20 +46,23 @@ export async function Handler({
45
46
  throw e;
46
47
  }
47
48
 
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>
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
+ )
63
67
  );
64
68
  }
@@ -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
package/src/d1/list.tsx CHANGED
@@ -1,9 +1,9 @@
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
8
  import type {
9
9
  CommonYargsArgv,
@@ -31,7 +31,7 @@ export async function Handler({
31
31
  logger.log(JSON.stringify(dbs, null, 2));
32
32
  } else {
33
33
  logger.log(d1BetaWarning);
34
- render(<Table data={dbs}></Table>);
34
+ logger.log(renderToString(<Table data={dbs}></Table>));
35
35
  }
36
36
  }
37
37
 
@@ -1,7 +1,7 @@
1
1
  import assert from "node:assert";
2
2
  import fs from "node:fs";
3
3
  import path from "path";
4
- import { Box, render, Text } from "ink";
4
+ import { Box, Text } from "ink";
5
5
  import Table from "ink-table";
6
6
  import React from "react";
7
7
  import { withConfig } from "../../config";
@@ -10,6 +10,7 @@ import { CI } from "../../is-ci";
10
10
  import isInteractive from "../../is-interactive";
11
11
  import { logger } from "../../logger";
12
12
  import { requireAuth } from "../../user";
13
+ import { renderToString } from "../../utils/render";
13
14
  import { createBackup } from "../backups";
14
15
  import { DEFAULT_MIGRATION_PATH, DEFAULT_MIGRATION_TABLE } from "../constants";
15
16
  import { executeSql } from "../execute";
@@ -97,14 +98,16 @@ export const ApplyHandler = withConfig<ApplyHandlerOptions>(
97
98
  });
98
99
 
99
100
  if (unappliedMigrations.length === 0) {
100
- render(<Text>✅ No migrations to apply!</Text>);
101
+ logger.log(renderToString(<Text>✅ No migrations to apply!</Text>));
101
102
  return;
102
103
  }
103
- render(
104
- <Box flexDirection="column">
105
- <Text>Migrations to be applied:</Text>
106
- <Table data={unappliedMigrations} columns={["Name"]}></Table>
107
- </Box>
104
+ logger.log(
105
+ renderToString(
106
+ <Box flexDirection="column">
107
+ <Text>Migrations to be applied:</Text>
108
+ <Table data={unappliedMigrations} columns={["Name"]}></Table>
109
+ </Box>
110
+ )
108
111
  );
109
112
  const ok = await confirm(
110
113
  `About to apply ${unappliedMigrations.length} migration(s)
@@ -118,7 +121,7 @@ Your database may not be available to serve requests during the migration, conti
118
121
  databaseInfo,
119
122
  "In non-local mode `databaseInfo` should be defined."
120
123
  );
121
- render(<Text>🕒 Creating backup...</Text>);
124
+ logger.log(renderToString(<Text>🕒 Creating backup...</Text>));
122
125
  const accountId = await requireAuth({});
123
126
  await createBackup(accountId, databaseInfo.uuid);
124
127
  }
@@ -169,35 +172,38 @@ Your database may not be available to serve requests during the migration, conti
169
172
  }
170
173
  } catch (e) {
171
174
  const err = e as ParseError;
175
+ const maybeCause = (err.cause ?? err) as Error;
172
176
 
173
177
  success = false;
174
178
  errorNotes = err.notes?.map((msg) => msg.text) ?? [
175
- err.message ?? err.toString(),
179
+ maybeCause?.message ?? maybeCause.toString(),
176
180
  ];
177
181
  }
178
182
 
179
183
  migration.Status = success ? "✅" : "❌";
180
184
 
181
- render(
182
- <Box flexDirection="column">
183
- <Table
184
- data={unappliedMigrations}
185
- columns={["Name", "Status"]}
186
- ></Table>
187
- {errorNotes.length > 0 && (
188
- <Box flexDirection="column">
189
- <Text>&nbsp;</Text>
190
- <Text>
191
- ❌ Migration {migration.Name} failed with following Errors
192
- </Text>
193
- <Table
194
- data={errorNotes.map((err) => {
195
- return { Error: err };
196
- })}
197
- ></Table>
198
- </Box>
199
- )}
200
- </Box>
185
+ logger.log(
186
+ renderToString(
187
+ <Box flexDirection="column">
188
+ <Table
189
+ data={unappliedMigrations}
190
+ columns={["Name", "Status"]}
191
+ ></Table>
192
+ {errorNotes.length > 0 && (
193
+ <Box flexDirection="column">
194
+ <Text>&nbsp;</Text>
195
+ <Text>
196
+ ❌ Migration {migration.Name} failed with following Errors
197
+ </Text>
198
+ <Table
199
+ data={errorNotes.map((err) => {
200
+ return { Error: err };
201
+ })}
202
+ ></Table>
203
+ </Box>
204
+ )}
205
+ </Box>
206
+ )
201
207
  );
202
208
 
203
209
  if (errorNotes.length > 0) return;
@@ -1,9 +1,10 @@
1
1
  import fs from "node:fs";
2
2
  import path from "path";
3
- import { Box, render, Text } from "ink";
3
+ import { Box, Text } from "ink";
4
4
  import React from "react";
5
5
  import { withConfig } from "../../config";
6
6
  import { logger } from "../../logger";
7
+ import { renderToString } from "../../utils/render";
7
8
  import { DEFAULT_MIGRATION_PATH } from "../constants";
8
9
  import { Database } from "../options";
9
10
  import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
@@ -54,17 +55,19 @@ export const CreateHandler = withConfig<CreateHandlerOptions>(
54
55
  `-- Migration number: ${nextMigrationNumber} \t ${new Date().toISOString()}\n`
55
56
  );
56
57
 
57
- render(
58
- <Box flexDirection="column">
59
- <Text>
60
- ✅ Successfully created Migration &apos;{newMigrationName}&apos;!
61
- </Text>
62
- <Text>&nbsp;</Text>
63
- <Text>The migration is available for editing here</Text>
64
- <Text>
65
- {migrationsPath}/{newMigrationName}
66
- </Text>
67
- </Box>
58
+ logger.log(
59
+ renderToString(
60
+ <Box flexDirection="column">
61
+ <Text>
62
+ ✅ Successfully created Migration &apos;{newMigrationName}&apos;!
63
+ </Text>
64
+ <Text>&nbsp;</Text>
65
+ <Text>The migration is available for editing here</Text>
66
+ <Text>
67
+ {migrationsPath}/{newMigrationName}
68
+ </Text>
69
+ </Box>
70
+ )
68
71
  );
69
72
  }
70
73
  );
@@ -1,10 +1,11 @@
1
1
  import path from "path";
2
- import { Box, render, Text } from "ink";
2
+ import { Box, Text } from "ink";
3
3
  import Table from "ink-table";
4
4
  import React from "react";
5
5
  import { withConfig } from "../../config";
6
6
  import { logger } from "../../logger";
7
7
  import { requireAuth } from "../../user";
8
+ import { renderToString } from "../../utils/render";
8
9
  import { DEFAULT_MIGRATION_PATH, DEFAULT_MIGRATION_TABLE } from "../constants";
9
10
  import { d1BetaWarning, getDatabaseInfoFromConfig } from "../utils";
10
11
  import {
@@ -78,15 +79,17 @@ export const ListHandler = withConfig<ListHandlerOptions>(
78
79
  });
79
80
 
80
81
  if (unappliedMigrations.length === 0) {
81
- render(<Text>✅ No migrations to apply!</Text>);
82
+ logger.log(renderToString(<Text>✅ No migrations to apply!</Text>));
82
83
  return;
83
84
  }
84
85
 
85
- render(
86
- <Box flexDirection="column">
87
- <Text>Migrations to be applied:</Text>
88
- <Table data={unappliedMigrations} columns={["Name"]}></Table>
89
- </Box>
86
+ logger.log(
87
+ renderToString(
88
+ <Box flexDirection="column">
89
+ <Text>Migrations to be applied:</Text>
90
+ <Table data={unappliedMigrations} columns={["Name"]}></Table>
91
+ </Box>
92
+ )
90
93
  );
91
94
  }
92
95
  );