wrangler 2.2.2 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/d1.test.ts +12 -10
  3. package/src/__tests__/deployments.test.ts +10 -10
  4. package/src/__tests__/generate.test.ts +3 -3
  5. package/src/__tests__/helpers/msw/handlers/deployments.ts +1 -1
  6. package/src/__tests__/index.test.ts +2 -2
  7. package/src/__tests__/pages-deployment-tail.test.ts +820 -0
  8. package/src/__tests__/pages.test.ts +1 -0
  9. package/src/__tests__/publish.test.ts +4 -4
  10. package/src/__tests__/queues.test.ts +1 -1
  11. package/src/__tests__/type-generation.test.ts +30 -22
  12. package/src/config/environment.ts +6 -0
  13. package/src/create-worker-upload-form.ts +11 -8
  14. package/src/d1/constants.ts +2 -0
  15. package/src/d1/create.tsx +18 -9
  16. package/src/d1/execute.tsx +94 -49
  17. package/src/d1/index.ts +24 -1
  18. package/src/d1/migrations.tsx +446 -0
  19. package/src/d1/options.ts +10 -0
  20. package/src/d1/types.tsx +10 -0
  21. package/src/d1/utils.ts +10 -1
  22. package/src/deployments.ts +7 -3
  23. package/src/dev/local.tsx +59 -30
  24. package/src/dev/start-server.ts +13 -7
  25. package/src/dialogs.tsx +14 -8
  26. package/src/index.tsx +4 -5
  27. package/src/metrics/send-event.ts +2 -0
  28. package/src/pages/build.tsx +1 -1
  29. package/src/pages/deployment-tails.tsx +284 -0
  30. package/src/pages/deployments.tsx +5 -27
  31. package/src/pages/dev.tsx +1 -1
  32. package/src/pages/functions.tsx +1 -1
  33. package/src/pages/index.tsx +8 -0
  34. package/src/pages/prompt-select-project.tsx +31 -0
  35. package/src/pages/publish.tsx +4 -19
  36. package/src/pages/types.ts +1 -9
  37. package/src/pages/upload.tsx +2 -1
  38. package/src/pages/utils.ts +11 -0
  39. package/src/publish/publish.ts +2 -2
  40. package/src/tail/createTail.ts +66 -2
  41. package/src/type-generation.ts +58 -44
  42. package/src/worker.ts +5 -1
  43. package/src/yargs-types.ts +4 -0
  44. package/templates/d1-beta-facade.js +47 -25
  45. package/wrangler-dist/cli.d.ts +6 -0
  46. package/wrangler-dist/cli.js +1947 -1248
@@ -821,13 +821,13 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
821
821
 
822
822
  try {
823
823
  const deploymentsList = await fetchResult<DeploymentListRes>(
824
- `/accounts/${accountId}/workers/versions/by-script/${scriptTag}`
824
+ `/accounts/${accountId}/workers/deployments/by-script/${scriptTag}`
825
825
  );
826
826
 
827
827
  logger.log("Current Deployment ID:", deploymentsList.latest.id);
828
828
  } catch (e) {
829
829
  if ((e as { code: number }).code === 10023) {
830
- // TODO: remove this try/catch once versions is completely rolled out
830
+ // TODO: remove this try/catch once deployments is completely rolled out
831
831
  } else {
832
832
  throw e;
833
833
  }
@@ -7,6 +7,8 @@ export { translateCLICommandToFilterMessage } from "./filters";
7
7
  export { jsonPrintLogs, prettyPrintLogs } from "./printing";
8
8
  import type { Request } from "undici";
9
9
 
10
+ const TRACE_VERSION = "trace-v1";
11
+
10
12
  /**
11
13
  * When creating a Tail, the response from the API contains
12
14
  * - an ID used for identifying the tail
@@ -59,6 +61,68 @@ function makeDeleteTailUrl(
59
61
  : `/accounts/${accountId}/workers/scripts/${workerName}/tails/${tailId}`;
60
62
  }
61
63
 
64
+ interface CreatePagesTailOptions {
65
+ accountId: string;
66
+ projectName: string;
67
+ deploymentId: string;
68
+ filters: TailFilterMessage;
69
+ debug?: boolean;
70
+ }
71
+
72
+ /**
73
+ * Create and connect to a Pages Function Tail.
74
+ *
75
+ * Under the hood, this function
76
+ * - Registers a new Tail with the API
77
+ * - Connects to the tail worker
78
+ * - Sends any filters over the connection
79
+ *
80
+ * @returns a websocket connection, an expiration, and a function to call to delete the tail
81
+ */
82
+ export async function createPagesTail({
83
+ accountId,
84
+ projectName,
85
+ deploymentId,
86
+ filters,
87
+ debug = false,
88
+ }: CreatePagesTailOptions) {
89
+ const tailRecord = await fetchResult<TailCreationApiResponse>(
90
+ `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentId}/tails`,
91
+ {
92
+ method: "POST",
93
+ body: JSON.stringify(filters),
94
+ }
95
+ );
96
+
97
+ const deleteTail = async () =>
98
+ fetchResult(
99
+ `/accounts/${accountId}/pages/projects/${projectName}/deployments/${deploymentId}/tails/${tailRecord.id}`,
100
+ { method: "DELETE" }
101
+ );
102
+
103
+ const tail = new WebSocket(tailRecord.url, TRACE_VERSION, {
104
+ headers: {
105
+ "Sec-WebSocket-Protocol": TRACE_VERSION, // needs to be `trace-v1` to be accepted
106
+ "User-Agent": `wrangler-js/${packageVersion}`,
107
+ },
108
+ });
109
+
110
+ // send filters when we open up
111
+ tail.on("open", () => {
112
+ tail.send(
113
+ JSON.stringify({ debug: debug }),
114
+ { binary: false, compress: false, mask: false, fin: true },
115
+ (err) => {
116
+ if (err) {
117
+ throw err;
118
+ }
119
+ }
120
+ );
121
+ });
122
+
123
+ return { tail, deleteTail, expiration: tailRecord.expires_at };
124
+ }
125
+
62
126
  /**
63
127
  * Create and connect to a tail.
64
128
  *
@@ -102,9 +166,9 @@ export async function createTail(
102
166
  }
103
167
 
104
168
  // connect to the tail
105
- const tail = new WebSocket(websocketUrl, "trace-v1", {
169
+ const tail = new WebSocket(websocketUrl, TRACE_VERSION, {
106
170
  headers: {
107
- "Sec-WebSocket-Protocol": "trace-v1", // needs to be `trace-v1` to be accepted
171
+ "Sec-WebSocket-Protocol": TRACE_VERSION, // needs to be `trace-v1` to be accepted
108
172
  "User-Agent": `wrangler-js/${packageVersion}`,
109
173
  },
110
174
  });
@@ -3,14 +3,11 @@ import { findUpSync } from "find-up";
3
3
  import { getEntry } from "./entry";
4
4
  import { logger } from "./logger";
5
5
  import type { Config } from "./config";
6
- import type { CfWorkerInit } from "./worker";
7
6
 
8
7
  // Currently includes bindings & rules for declaring modules
9
- export type PartialConfigToDTS = CfWorkerInit["bindings"] & {
10
- rules: Config["rules"];
11
- };
8
+
12
9
  export async function generateTypes(
13
- configToDTS: PartialConfigToDTS,
10
+ configToDTS: Partial<Config>,
14
11
  config: Config
15
12
  ) {
16
13
  const entry = await getEntry({}, config, "types");
@@ -85,11 +82,19 @@ export async function generateTypes(
85
82
  }
86
83
 
87
84
  if (configToDTS.unsafe) {
88
- for (const unsafe of configToDTS.unsafe) {
85
+ for (const unsafe of configToDTS.unsafe.bindings) {
89
86
  envTypeStructure.push(` ${unsafe.name}: any;`);
90
87
  }
91
88
  }
92
89
 
90
+ if (configToDTS.queues) {
91
+ if (configToDTS.queues.producers) {
92
+ for (const queue of configToDTS.queues.producers) {
93
+ envTypeStructure.push(` ${queue.binding}: Queue;`);
94
+ }
95
+ }
96
+ }
97
+
93
98
  const modulesTypeStructure: string[] = [];
94
99
  if (configToDTS.rules) {
95
100
  const moduleTypeMap = {
@@ -113,47 +118,56 @@ export async function generateTypes(
113
118
  }
114
119
  }
115
120
 
116
- function writeDTSFile(
117
- typesString: string[],
118
- formatType: "modules" | "service-worker"
119
- ) {
120
- const wranglerOverrideDTSPath = findUpSync("worker-configuration.d.ts");
121
- try {
122
- if (
123
- wranglerOverrideDTSPath !== undefined &&
124
- !fs
125
- .readFileSync(wranglerOverrideDTSPath, "utf8")
126
- .includes("***AUTO GENERATED BY WORKERS CLI WRANGLER***")
127
- ) {
128
- throw new Error(
129
- "A non-wrangler worker-configuration.d.ts already exists, please rename and try again."
130
- );
131
- }
132
- } catch (error) {
133
- if (error instanceof Error && !error.message.includes("not found")) {
134
- throw error;
135
- }
136
- }
137
-
138
- let combinedTypeStrings = "";
139
- if (formatType === "modules") {
140
- combinedTypeStrings = `interface Env {\n${typesString.join(
141
- "\n"
142
- )} \n}\n${modulesTypeStructure.join("\n")}`;
143
- } else {
144
- combinedTypeStrings = `declare global {\n${typesString.join(
145
- "\n"
146
- )} \n}\n${modulesTypeStructure.join("\n")}`;
147
- }
121
+ writeDTSFile({
122
+ envTypeStructure,
123
+ modulesTypeStructure,
124
+ formatType: entry.format,
125
+ });
126
+ }
148
127
 
149
- if (envTypeStructure.length || modulesTypeStructure.length) {
150
- fs.writeFileSync(
151
- "worker-configuration.d.ts",
152
- `// Generated by Wrangler on ${new Date()}` + "\n" + combinedTypeStrings
128
+ function writeDTSFile({
129
+ envTypeStructure,
130
+ modulesTypeStructure,
131
+ formatType,
132
+ }: {
133
+ envTypeStructure: string[];
134
+ modulesTypeStructure: string[];
135
+ formatType: "modules" | "service-worker";
136
+ }) {
137
+ const wranglerOverrideDTSPath = findUpSync("worker-configuration.d.ts");
138
+ try {
139
+ if (
140
+ wranglerOverrideDTSPath !== undefined &&
141
+ !fs
142
+ .readFileSync(wranglerOverrideDTSPath, "utf8")
143
+ .includes("Generated by Wrangler")
144
+ ) {
145
+ throw new Error(
146
+ "A non-wrangler worker-configuration.d.ts already exists, please rename and try again."
153
147
  );
154
- logger.log(combinedTypeStrings);
155
148
  }
149
+ } catch (error) {
150
+ if (error instanceof Error && !error.message.includes("not found")) {
151
+ throw error;
152
+ }
153
+ }
154
+
155
+ let combinedTypeStrings = "";
156
+ if (formatType === "modules") {
157
+ combinedTypeStrings += `interface Env {\n${envTypeStructure.join(
158
+ "\n"
159
+ )} \n}\n${modulesTypeStructure.join("\n")}`;
160
+ } else {
161
+ combinedTypeStrings += `declare global {\n${envTypeStructure.join(
162
+ "\n"
163
+ )} \n}\n${modulesTypeStructure.join("\n")}`;
156
164
  }
157
165
 
158
- writeDTSFile(envTypeStructure, entry.format);
166
+ if (envTypeStructure.length || modulesTypeStructure.length) {
167
+ fs.writeFileSync(
168
+ "worker-configuration.d.ts",
169
+ `// Generated by Wrangler on ${new Date()}` + "\n" + combinedTypeStrings
170
+ );
171
+ logger.log(combinedTypeStrings);
172
+ }
159
173
  }
package/src/worker.ts CHANGED
@@ -126,12 +126,16 @@ export interface CfR2Bucket {
126
126
  export const D1_BETA_PREFIX = `__D1_BETA__` as const;
127
127
  export type D1PrefixedBinding = `${typeof D1_BETA_PREFIX}${string}`;
128
128
 
129
+ // TODO: figure out if this is duplicated in packages/wrangler/src/config/environment.ts
129
130
  export interface CfD1Database {
130
- // For now, all D1 bindings are beta
131
+ // For now, all D1 bindings are alpha
131
132
  binding: D1PrefixedBinding;
132
133
  database_id: string;
133
134
  database_name?: string;
134
135
  preview_database_id?: string;
136
+ database_internal_env?: string;
137
+ migrations_table?: string;
138
+ migrations_dir?: string;
135
139
  }
136
140
 
137
141
  interface CfService {
@@ -9,6 +9,10 @@ export interface CommonYargsOptions {
9
9
  env: string | undefined;
10
10
  }
11
11
 
12
+ export type YargvToInterface<T> = T extends Argv<infer P>
13
+ ? ArgumentsCamelCase<P>
14
+ : never;
15
+
12
16
  /**
13
17
  * Given some Yargs Options function factory, extract the interface
14
18
  * that corresponds to the yargs arguments
@@ -18,10 +18,16 @@ var D1Database = class {
18
18
  },
19
19
  });
20
20
  if (response.status !== 200) {
21
- const err = await response.json();
22
- throw new Error("D1_DUMP_ERROR", {
23
- cause: new Error(err.error),
24
- });
21
+ try {
22
+ const err = await response.json();
23
+ throw new Error("D1_DUMP_ERROR", {
24
+ cause: new Error(err.error),
25
+ });
26
+ } catch (e) {
27
+ throw new Error("D1_DUMP_ERROR", {
28
+ cause: new Error("Status " + response.status),
29
+ });
30
+ }
25
31
  }
26
32
  return await response.arrayBuffer();
27
33
  }
@@ -35,7 +41,7 @@ var D1Database = class {
35
41
  }
36
42
  async exec(query) {
37
43
  const lines = query.trim().split("\n");
38
- const _exec = await this._send("/query", lines, []);
44
+ const _exec = await this._send("/query", lines, [], false);
39
45
  const exec = Array.isArray(_exec) ? _exec : [_exec];
40
46
  const error = exec
41
47
  .map((r) => {
@@ -45,19 +51,24 @@ var D1Database = class {
45
51
  if (error !== -1) {
46
52
  throw new Error("D1_EXEC_ERROR", {
47
53
  cause: new Error(
48
- `Error in line ${error + 1}: ${lines[error]}: ${exec[error].error}`
54
+ "Error in line " +
55
+ (error + 1) +
56
+ ": " +
57
+ lines[error] +
58
+ ": " +
59
+ exec[error].error
49
60
  ),
50
61
  });
51
62
  } else {
52
63
  return {
53
64
  count: exec.length,
54
65
  duration: exec.reduce((p, c) => {
55
- return p + c.duration;
66
+ return p + c.meta.duration;
56
67
  }, 0),
57
68
  };
58
69
  }
59
70
  }
60
- async _send(endpoint, query, params) {
71
+ async _send(endpoint, query, params, dothrow = true) {
61
72
  const body = JSON.stringify(
62
73
  typeof query == "object"
63
74
  ? query.map((s, index) => {
@@ -75,12 +86,21 @@ var D1Database = class {
75
86
  },
76
87
  body,
77
88
  });
78
- if (response.status !== 200) {
79
- const err = await response.json();
80
- throw new Error("D1_ERROR", { cause: new Error(err.error) });
89
+ try {
90
+ const answer = await response.json();
91
+ if (answer.error && dothrow) {
92
+ const err = answer;
93
+ throw new Error("D1_ERROR", { cause: new Error(err.error) });
94
+ } else {
95
+ return Array.isArray(answer)
96
+ ? answer.map((r) => mapD1Result(r))
97
+ : mapD1Result(answer);
98
+ }
99
+ } catch (e) {
100
+ throw new Error("D1_ERROR", {
101
+ cause: new Error(e.cause || "Something went wrong"),
102
+ });
81
103
  }
82
- const answer = await response.json();
83
- return Array.isArray(answer) ? answer : answer;
84
104
  }
85
105
  };
86
106
  var D1PreparedStatement = class {
@@ -97,19 +117,15 @@ var D1PreparedStatement = class {
97
117
  await this.database._send("/query", this.statement, this.params)
98
118
  );
99
119
  const results = info.results;
100
- if (results.length < 1) {
101
- throw new Error("D1_NORESULTS", { cause: new Error("No results") });
102
- }
103
- const result = results[0];
104
120
  if (colName !== void 0) {
105
- if (result[colName] === void 0) {
121
+ if (results.length > 0 && results[0][colName] === void 0) {
106
122
  throw new Error("D1_COLUMN_NOTFOUND", {
107
- cause: new Error(`Column not found`),
123
+ cause: new Error("Column not found"),
108
124
  });
109
125
  }
110
- return result[colName];
126
+ return results.length < 1 ? null : results[0][colName];
111
127
  } else {
112
- return result;
128
+ return results.length < 1 ? null : results[0];
113
129
  }
114
130
  }
115
131
  async run() {
@@ -139,6 +155,15 @@ var D1PreparedStatement = class {
139
155
  function firstIfArray(results) {
140
156
  return Array.isArray(results) ? results[0] : results;
141
157
  }
158
+ function mapD1Result(result) {
159
+ let map = {
160
+ results: result.results || [],
161
+ success: result.success === void 0 ? true : result.success,
162
+ meta: result.meta || {},
163
+ };
164
+ result.error && (map.error = result.error);
165
+ return map;
166
+ }
142
167
 
143
168
  // src/shim.ts
144
169
  var D1_IMPORTS = __D1_IMPORTS__;
@@ -163,12 +188,9 @@ function getMaskedEnv(env) {
163
188
  return newEnvObj;
164
189
  }
165
190
  var shim_default = {
191
+ ...worker,
166
192
  async fetch(request, env, ctx) {
167
193
  return worker.fetch(request, getMaskedEnv(env), ctx);
168
194
  },
169
-
170
- async scheduled(controller, env, ctx) {
171
- return worker.scheduled(controller, getMaskedEnv(env), ctx);
172
- },
173
195
  };
174
196
  export { shim_default as default };
@@ -501,6 +501,12 @@ declare interface EnvironmentNonInheritable {
501
501
  database_id: string;
502
502
  /** The UUID of this D1 database for Wrangler Dev (if specified). */
503
503
  preview_database_id?: string;
504
+ /** The name of the migrations table for this D1 database (defaults to 'd1_migrations'). */
505
+ migrations_table?: string;
506
+ /** The path to the directory of migrations for this D1 database (defaults to './migrations'). */
507
+ migrations_dir?: string;
508
+ /** Internal use only. */
509
+ database_internal_env?: string;
504
510
  }[];
505
511
  /**
506
512
  * Specifies service bindings (worker-to-worker) that are bound to this Worker environment.