wrangler 0.0.0-e14e589 → 0.0.0-e1c615f

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 (41) hide show
  1. package/README.md +51 -0
  2. package/package.json +39 -26
  3. package/pages/functions/buildWorker.ts +57 -0
  4. package/pages/functions/filepath-routing.test.ts +39 -0
  5. package/pages/functions/filepath-routing.ts +221 -0
  6. package/pages/functions/identifiers.ts +78 -0
  7. package/pages/functions/routes.ts +158 -0
  8. package/pages/functions/template-worker.ts +137 -0
  9. package/src/__tests__/dev.test.tsx +66 -0
  10. package/src/__tests__/index.test.ts +254 -120
  11. package/src/__tests__/jest.setup.ts +22 -0
  12. package/src/__tests__/kv.test.ts +1098 -0
  13. package/src/__tests__/mock-cfetch.ts +171 -0
  14. package/src/__tests__/mock-dialogs.ts +65 -0
  15. package/src/__tests__/run-in-tmp.ts +19 -0
  16. package/src/__tests__/run-wrangler.ts +32 -0
  17. package/src/api/form_data.ts +78 -72
  18. package/src/api/inspect.ts +0 -11
  19. package/src/api/preview.ts +29 -24
  20. package/src/api/worker.ts +46 -31
  21. package/src/cfetch/index.ts +102 -0
  22. package/src/cfetch/internal.ts +69 -0
  23. package/src/cli.ts +6 -7
  24. package/src/config.ts +39 -4
  25. package/src/dev.tsx +332 -128
  26. package/src/dialogs.tsx +4 -12
  27. package/src/index.tsx +397 -222
  28. package/src/kv.tsx +101 -45
  29. package/src/module-collection.ts +64 -0
  30. package/src/pages.tsx +839 -211
  31. package/src/proxy.ts +103 -0
  32. package/src/publish.ts +117 -45
  33. package/src/sites.tsx +6 -7
  34. package/src/tail.tsx +6 -4
  35. package/src/user.tsx +9 -16
  36. package/wrangler-dist/cli.js +123794 -528
  37. package/wrangler-dist/cli.js.map +3 -3
  38. package/src/__tests__/fixtures/init/.gitkeep +0 -0
  39. package/src/__tests__/mock-cfetch.js +0 -46
  40. package/src/cfetch.ts +0 -72
  41. package/src/util/fetch.ts +0 -74
@@ -0,0 +1,171 @@
1
+ import type { RequestInit } from "node-fetch";
2
+ import type { URLSearchParams } from "node:url";
3
+ import { pathToRegexp } from "path-to-regexp";
4
+ import { CF_API_BASE_URL } from "../cfetch";
5
+ import type { FetchResult } from "../cfetch";
6
+
7
+ /**
8
+ * The signature of the function that will handle a mock request.
9
+ */
10
+ export type MockHandler<ResponseType> = (
11
+ uri: RegExpExecArray,
12
+ init?: RequestInit,
13
+ queryParams?: URLSearchParams
14
+ ) => ResponseType;
15
+
16
+ type RemoveMockFn = () => void;
17
+
18
+ interface MockFetch<ResponseType> {
19
+ regexp: RegExp;
20
+ method: string | undefined;
21
+ handler: MockHandler<ResponseType>;
22
+ }
23
+ const mocks: MockFetch<unknown>[] = [];
24
+
25
+ /**
26
+ * The mock implementation of `cfApi.fetch()`.
27
+ *
28
+ * This function will attempt to match the given request to one of the mock handlers configured by calls to `setMock`.
29
+ *
30
+ * Once found the handler will be used to generate a mock response.
31
+ */
32
+ export async function mockFetchInternal(
33
+ resource: string,
34
+ init: RequestInit = {},
35
+ queryParams?: URLSearchParams
36
+ ) {
37
+ for (const { regexp, method, handler } of mocks) {
38
+ const resourcePath = new URL(resource, CF_API_BASE_URL).pathname;
39
+ const uri = regexp.exec(resourcePath);
40
+ // Do the resource path and (if specified) the HTTP method match?
41
+ if (uri !== null && (!method || method === init.method)) {
42
+ // The `resource` regular expression will extract the labelled groups from the URL.
43
+ // These are passed through to the `handler` call, to allow it to do additional checks or behaviour.
44
+ return handler(uri, init, queryParams); // TODO: should we have some kind of fallthrough system? we'll see.
45
+ }
46
+ }
47
+ throw new Error(`no mocks found for ${init.method}: ${resource}`);
48
+ }
49
+
50
+ /**
51
+ * Specify an expected resource path that is to be handled, resulting in a raw JSON response.
52
+ *
53
+ * @param resource The path of the resource to be matched.
54
+ * This can include wildcards whose value will be passed to the `handler`.
55
+ * @param handler The function that will generate the mock response for this request.
56
+ */
57
+ export function setMockRawResponse<ResponseType>(
58
+ resource: string,
59
+ handler: MockHandler<ResponseType>
60
+ ): RemoveMockFn;
61
+ /**
62
+ * Specify an expected resource path that is to be handled, resulting in a raw JSON response.
63
+ *
64
+ * @param resource The path of the resource to be matched.
65
+ * This can include wildcards whose value will be passed to the `handler`.
66
+ * @param method The HTTP method (e.g. GET, POST, etc) that the request must have to match this mock handler.
67
+ * @param handler The function that will generate the mock response for this request.
68
+ */
69
+ export function setMockRawResponse<ResponseType>(
70
+ resource: string,
71
+ method: string,
72
+ handler: MockHandler<ResponseType>
73
+ ): RemoveMockFn;
74
+ /**
75
+ * Specify an expected resource path that is to be handled, resulting in a raw JSON response.
76
+ */
77
+ export function setMockRawResponse<ResponseType>(
78
+ resource: string,
79
+ ...args: [string, MockHandler<ResponseType>] | [MockHandler<ResponseType>]
80
+ ): RemoveMockFn {
81
+ const handler = args.pop() as MockHandler<ResponseType>;
82
+ const method = args.pop() as string;
83
+ const mock = {
84
+ resource,
85
+ method,
86
+ handler,
87
+ regexp: pathToRegexp(resource),
88
+ };
89
+ mocks.push(mock);
90
+ return () => {
91
+ const mockIndex = mocks.indexOf(mock);
92
+ if (mockIndex !== -1) {
93
+ mocks.splice(mockIndex, 1);
94
+ }
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Specify an expected resource path that is to be handled, resulting in a `FetchRequest`.
100
+ *
101
+ * The mock `handler` should return the `result`, which will then be wrapped in a `FetchRequest` object.
102
+ *
103
+ * @param resource The path of the resource to be matched.
104
+ * This can include wildcards whose value will be passed to the `handler`.
105
+ * @param handler The function that will generate the mock response for this request.
106
+ */
107
+ export function setMockResponse<ResponseType>(
108
+ resource: string,
109
+ handler: MockHandler<ResponseType>
110
+ ): RemoveMockFn;
111
+ /**
112
+ * Specify an expected resource path that is to be handled, resulting in a FetchRequest..
113
+ *
114
+ * @param resource The path of the resource to be matched.
115
+ * This can include wildcards whose value will be passed to the `handler`.
116
+ * @param method The HTTP method (e.g. GET, POST, etc) that the request must have to match this mock handler.
117
+ * @param handler The function that will generate the mock response for this request.
118
+ */
119
+ export function setMockResponse<ResponseType>(
120
+ resource: string,
121
+ method: string,
122
+ handler: MockHandler<ResponseType>
123
+ ): RemoveMockFn;
124
+ /**
125
+ * Specify an expected resource path that is to be handled, resulting in a FetchRequest.
126
+ */
127
+ export function setMockResponse<ResponseType>(
128
+ resource: string,
129
+ ...args: [string, MockHandler<ResponseType>] | [MockHandler<ResponseType>]
130
+ ): RemoveMockFn {
131
+ const handler = args.pop() as MockHandler<ResponseType>;
132
+ const method = args.pop() as string;
133
+ return setMockRawResponse(resource, method, (...handlerArgs) =>
134
+ createFetchResult(handler(...handlerArgs))
135
+ );
136
+ }
137
+
138
+ /**
139
+ * A helper to make it easier to create `FetchResult` objects in tests.
140
+ */
141
+ export function createFetchResult<ResponseType>(
142
+ result: ResponseType,
143
+ success = true,
144
+ errors = [],
145
+ messages = [],
146
+ result_info?: unknown
147
+ ): FetchResult<ResponseType> {
148
+ return result_info
149
+ ? {
150
+ result,
151
+ success,
152
+ errors,
153
+ messages,
154
+ result_info,
155
+ }
156
+ : {
157
+ result,
158
+ success,
159
+ errors,
160
+ messages,
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Remove all the configured mock handlers.
166
+ *
167
+ * This should be called in an `afterEach()` block to ensure that mock handlers do not leak between tests.
168
+ */
169
+ export function unsetAllMocks() {
170
+ mocks.length = 0;
171
+ }
@@ -0,0 +1,65 @@
1
+ import { confirm, prompt } from "../dialogs";
2
+
3
+ /**
4
+ * The expected values for a confirmation request.
5
+ */
6
+ export interface ConfirmExpectation {
7
+ /** The text expected to be seen in the confirmation dialog. */
8
+ text: string;
9
+ /** The mock response send back from the confirmation dialog. */
10
+ result: boolean;
11
+ }
12
+
13
+ /**
14
+ * Mock the implementation of `confirm()` that will respond with configured results
15
+ * for configured confirmation text messages.
16
+ *
17
+ * If there is a call to `confirm()` that does not match any of the expectations
18
+ * then an error is thrown.
19
+ */
20
+ export function mockConfirm(...expectations: ConfirmExpectation[]) {
21
+ (confirm as jest.Mock).mockImplementation((text: string) => {
22
+ for (const { text: expectedText, result } of expectations) {
23
+ if (text === expectedText) {
24
+ return Promise.resolve(result);
25
+ }
26
+ }
27
+ throw new Error(`Unexpected confirmation message: ${text}`);
28
+ });
29
+ }
30
+
31
+ /**
32
+ * The expected values for a prompt request.
33
+ */
34
+ export interface PromptExpectation {
35
+ /** The text expected to be seen in the prompt dialog. */
36
+ text: string;
37
+ /** The type of the prompt. */
38
+ type: "text" | "password";
39
+ /** The mock response send back from the prompt dialog. */
40
+ result: string;
41
+ }
42
+
43
+ /**
44
+ * Mock the implementation of `prompt()` that will respond with configured results
45
+ * for configured prompt text messages.
46
+ *
47
+ * If there is a call to `prompt()` that does not match any of the expectations
48
+ * then an error is thrown.
49
+ */
50
+ export function mockPrompt(...expectations: PromptExpectation[]) {
51
+ (prompt as jest.Mock).mockImplementation(
52
+ (text: string, type: "text" | "password") => {
53
+ for (const {
54
+ text: expectedText,
55
+ type: expectedType,
56
+ result,
57
+ } of expectations) {
58
+ if (text === expectedText && type == expectedType) {
59
+ return Promise.resolve(result);
60
+ }
61
+ }
62
+ throw new Error(`Unexpected confirmation message: ${text}`);
63
+ }
64
+ );
65
+ }
@@ -0,0 +1,19 @@
1
+ import * as os from "node:os";
2
+ import * as path from "node:path";
3
+ import * as fs from "fs";
4
+
5
+ const originalCwd = process.cwd();
6
+
7
+ export function runInTempDir() {
8
+ let tmpDir: string;
9
+
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "wrangler-tests"));
12
+ process.chdir(tmpDir);
13
+ });
14
+
15
+ afterEach(() => {
16
+ process.chdir(originalCwd);
17
+ fs.rmSync(tmpDir, { recursive: true });
18
+ });
19
+ }
@@ -0,0 +1,32 @@
1
+ import { main } from "../index";
2
+
3
+ /**
4
+ * Run the wrangler CLI tool in tests, capturing the logging output.
5
+ */
6
+ export async function runWrangler(cmd?: string) {
7
+ const logSpy = jest.spyOn(console, "log").mockImplementation();
8
+ const errorSpy = jest.spyOn(console, "error").mockImplementation();
9
+ const warnSpy = jest.spyOn(console, "warn").mockImplementation();
10
+ try {
11
+ let error: unknown = undefined;
12
+ try {
13
+ await main(cmd?.split(" ") ?? []);
14
+ } catch (e) {
15
+ error = e;
16
+ }
17
+ return {
18
+ error,
19
+ stdout: captureCalls(logSpy),
20
+ stderr: captureCalls(errorSpy),
21
+ warnings: captureCalls(warnSpy),
22
+ };
23
+ } finally {
24
+ logSpy.mockRestore();
25
+ errorSpy.mockRestore();
26
+ warnSpy.mockRestore();
27
+ }
28
+ }
29
+
30
+ function captureCalls(spy: jest.SpyInstance): string {
31
+ return spy.mock.calls.flat(2).join("\n");
32
+ }
@@ -1,60 +1,11 @@
1
1
  import type {
2
2
  CfWorkerInit,
3
3
  CfModuleType,
4
- CfVariable,
5
4
  CfModule,
6
- CfKvNamespace,
7
- CfCryptoKey,
5
+ CfDurableObjectMigrations,
8
6
  } from "./worker.js";
9
7
  import { FormData, Blob } from "formdata-node";
10
8
 
11
- // Credit: https://stackoverflow.com/a/9458996
12
- function toBase64(source: BufferSource): string {
13
- let result = "";
14
- const buffer = source instanceof ArrayBuffer ? source : source.buffer;
15
- const bytes = new Uint8Array(buffer);
16
- for (let i = 0; i < bytes.byteLength; i++) {
17
- result += String.fromCharCode(bytes[i]);
18
- }
19
- return btoa(result);
20
- }
21
-
22
- function toBinding(
23
- name: string,
24
- variable: CfVariable
25
- ): Record<string, unknown> {
26
- if (typeof variable === "string") {
27
- return { name, type: "plain_text", text: variable };
28
- }
29
-
30
- const { namespaceId } = variable as CfKvNamespace;
31
- if (namespaceId) {
32
- return { name, type: "kv_namespace", namespace_id: namespaceId };
33
- }
34
-
35
- const { format, algorithm, usages, data } = variable as CfCryptoKey;
36
- if (format) {
37
- let key_base64;
38
- let key_jwk;
39
- if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
40
- key_base64 = toBase64(data);
41
- } else {
42
- key_jwk = data;
43
- }
44
- return {
45
- name,
46
- type: "secret_key",
47
- format,
48
- algorithm,
49
- usages,
50
- key_base64,
51
- key_jwk,
52
- };
53
- }
54
-
55
- throw new TypeError("Unsupported variable: " + variable);
56
- }
57
-
58
9
  export function toMimeType(type: CfModuleType): string {
59
10
  switch (type) {
60
11
  case "esm":
@@ -79,37 +30,92 @@ function toModule(module: CfModule, entryType?: CfModuleType): Blob {
79
30
  return new Blob([content], { type });
80
31
  }
81
32
 
33
+ interface WorkerMetadata {
34
+ compatibility_date?: string;
35
+ compatibility_flags?: string[];
36
+ usage_model?: "bundled" | "unbound";
37
+ migrations?: CfDurableObjectMigrations;
38
+ bindings: (
39
+ | { type: "kv_namespace"; name: string; namespace_id: string }
40
+ | { type: "plain_text"; name: string; text: string }
41
+ | {
42
+ type: "durable_object_namespace";
43
+ name: string;
44
+ class_name: string;
45
+ script_name?: string;
46
+ }
47
+ | {
48
+ type: "service";
49
+ name: string;
50
+ service: string;
51
+ environment: string;
52
+ }
53
+ )[];
54
+ }
55
+
82
56
  /**
83
57
  * Creates a `FormData` upload from a `CfWorkerInit`.
84
58
  */
85
59
  export function toFormData(worker: CfWorkerInit): FormData {
86
60
  const formData = new FormData();
87
- const { main, modules, variables, usage_model, compatibility_date } = worker;
88
- const { name, type: mainType } = main;
61
+ const {
62
+ main,
63
+ modules,
64
+ bindings,
65
+ migrations,
66
+ usage_model,
67
+ compatibility_date,
68
+ compatibility_flags,
69
+ } = worker;
89
70
 
90
- const bindings = [];
91
- for (const [name, variable] of Object.entries(variables ?? {})) {
92
- const binding = toBinding(name, variable);
93
- bindings.push(binding);
94
- }
71
+ const metadataBindings: WorkerMetadata["bindings"] = [];
95
72
 
96
- const singleton = mainType === "commonjs";
97
- const metadata = {
98
- main_module: singleton ? undefined : name,
99
- body_part: singleton ? name : undefined,
100
- bindings,
73
+ bindings.kv_namespaces?.forEach(({ id, binding }) => {
74
+ metadataBindings.push({
75
+ name: binding,
76
+ type: "kv_namespace",
77
+ namespace_id: id,
78
+ });
79
+ });
80
+
81
+ bindings.durable_objects?.bindings.forEach(
82
+ ({ name, class_name, script_name }) => {
83
+ metadataBindings.push({
84
+ name,
85
+ type: "durable_object_namespace",
86
+ class_name: class_name,
87
+ ...(script_name && { script_name }),
88
+ });
89
+ }
90
+ );
91
+
92
+ Object.entries(bindings.vars || {})?.forEach(([key, value]) => {
93
+ metadataBindings.push({ name: key, type: "plain_text", text: value });
94
+ });
95
+
96
+ bindings.services?.forEach(({ name, service, environment }) => {
97
+ metadataBindings.push({
98
+ name,
99
+ type: "service",
100
+ service,
101
+ environment,
102
+ });
103
+ });
104
+
105
+ const metadata: WorkerMetadata = {
106
+ ...(main.type !== "commonjs"
107
+ ? { main_module: main.name }
108
+ : { body_part: main.name }),
109
+ bindings: metadataBindings,
110
+ ...(compatibility_date && { compatibility_date }),
111
+ ...(compatibility_flags && { compatibility_flags }),
112
+ ...(usage_model && { usage_model }),
113
+ ...(migrations && { migrations }),
101
114
  };
102
- if (compatibility_date) {
103
- // @ts-expect-error - we should type metadata
104
- metadata.compatibility_date = compatibility_date;
105
- }
106
- if (usage_model) {
107
- // @ts-expect-error - we should type metadata
108
- metadata.usage_model = usage_model;
109
- }
115
+
110
116
  formData.set("metadata", JSON.stringify(metadata));
111
117
 
112
- if (singleton && modules && modules.length > 0) {
118
+ if (main.type === "commonjs" && modules && modules.length > 0) {
113
119
  throw new TypeError(
114
120
  "More than one module can only be specified when type = 'esm'"
115
121
  );
@@ -117,7 +123,7 @@ export function toFormData(worker: CfWorkerInit): FormData {
117
123
 
118
124
  for (const module of [main].concat(modules || [])) {
119
125
  const { name } = module;
120
- const blob = toModule(module, mainType ?? "esm");
126
+ const blob = toModule(module, main.type ?? "esm");
121
127
  formData.set(name, blob, name);
122
128
  }
123
129
 
@@ -140,17 +140,6 @@ export type DtEvent = DtLogEvent | DtExceptionEvent;
140
140
  */
141
141
  export type DtListener = (event: DtEvent) => void;
142
142
 
143
- interface DtProtocolRequest<T> {
144
- id: number;
145
- method: string;
146
- params?: T;
147
- }
148
-
149
- interface DtProtocolResponse<T> {
150
- id: number;
151
- result: T;
152
- }
153
-
154
143
  /**
155
144
  * A DevTools inspector that listens to logs and debug events from a Worker.
156
145
  *
@@ -1,5 +1,5 @@
1
- import cfetch from "../cfetch";
2
- import { fetchJson } from "../util/fetch";
1
+ import fetch from "node-fetch";
2
+ import { fetchResult } from "../cfetch";
3
3
  import { toFormData } from "./form_data";
4
4
  import type { CfAccount, CfWorkerInit } from "./worker";
5
5
 
@@ -9,7 +9,7 @@ import type { CfAccount, CfWorkerInit } from "./worker";
9
9
  * * If true, then using a `workers.dev` subdomain.
10
10
  * * Otherwise, a list of routes under a single zone.
11
11
  */
12
- export type CfPreviewMode = { workers_dev: boolean } | { routes: string[] };
12
+ type CfPreviewMode = { workers_dev: boolean } | { routes: string[] };
13
13
 
14
14
  /**
15
15
  * A preview token.
@@ -60,17 +60,17 @@ async function sessionToken(account: CfAccount): Promise<CfPreviewToken> {
60
60
  ? `/zones/${zoneId}/workers/edge-preview`
61
61
  : `/accounts/${accountId}/workers/subdomain/edge-preview`;
62
62
 
63
- const { exchange_url: tokenUrl } = await cfetch<{ exchange_url: string }>(
64
- initUrl
65
- );
66
- const { inspector_websocket: url, token } = await fetchJson()(tokenUrl);
67
- const { host } = new URL(url);
63
+ const { exchange_url } = await fetchResult<{ exchange_url: string }>(initUrl);
64
+ const { inspector_websocket, token } = (await (
65
+ await fetch(exchange_url)
66
+ ).json()) as { inspector_websocket: string; token: string };
67
+ const { host } = new URL(inspector_websocket);
68
68
  const query = `cf_workers_preview_token=${token}`;
69
69
 
70
70
  return {
71
71
  value: token,
72
72
  host,
73
- inspectorUrl: new URL(`${url}?${query}`),
73
+ inspectorUrl: new URL(`${inspector_websocket}?${query}`),
74
74
  prewarmUrl: new URL(
75
75
  `https://${host}/cdn-cgi/workers/preview/prewarm?${query}`
76
76
  ),
@@ -96,27 +96,32 @@ export async function previewToken(
96
96
  const { value, host, inspectorUrl, prewarmUrl } = await sessionToken(account);
97
97
 
98
98
  const { accountId, zoneId } = account;
99
- const scriptId = zoneId ? randomId() : host.split(".")[0];
99
+ const scriptId = zoneId ? randomId() : worker.name || host.split(".")[0];
100
100
  const url = `/accounts/${accountId}/workers/scripts/${scriptId}/edge-preview`;
101
101
 
102
- const mode = zoneId ? { routes: ["*/*"] } : { workers_dev: true };
102
+ const mode: CfPreviewMode = zoneId
103
+ ? { routes: ["*/*"] }
104
+ : { workers_dev: true };
105
+
103
106
  const formData = toFormData(worker);
104
107
  formData.set("wrangler-session-config", JSON.stringify(mode));
105
108
 
106
- const { preview_token: token } = await cfetch<{ preview_token: string }>(
107
- url,
108
- {
109
- method: "POST",
110
- // @ts-expect-error TODO: fix this
111
- body: formData,
112
- headers: {
113
- "cf-preview-upload-config-token": value,
114
- },
115
- }
116
- );
109
+ const { preview_token } = await fetchResult<{ preview_token: string }>(url, {
110
+ method: "POST",
111
+ // @ts-expect-error TODO: fix this
112
+ body: formData,
113
+ headers: {
114
+ "cf-preview-upload-config-token": value,
115
+ },
116
+ });
117
+
117
118
  return {
118
- value: token,
119
- host,
119
+ value: preview_token,
120
+ // TODO: verify this works with zoned workers
121
+ host:
122
+ worker.name && !zoneId
123
+ ? `${worker.name}.${host.split(".").slice(1).join(".")}`
124
+ : host,
120
125
  inspectorUrl,
121
126
  prewarmUrl,
122
127
  };
package/src/api/worker.ts CHANGED
@@ -62,49 +62,57 @@ export interface CfModule {
62
62
  type?: CfModuleType;
63
63
  }
64
64
 
65
+ /**
66
+ * A map of variable names to values.
67
+ */
68
+ interface CfVars {
69
+ [key: string]: string;
70
+ }
71
+
65
72
  /**
66
73
  * A KV namespace.
67
74
  */
68
- export interface CfKvNamespace {
69
- /**
70
- * The namespace ID.
71
- */
72
- namespaceId: string;
75
+ interface CfKvNamespace {
76
+ binding: string;
77
+ id: string;
73
78
  }
74
79
 
75
80
  /**
76
- * A `WebCrypto` key.
77
- *
78
- * @link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey
81
+ * A Durable Object.
79
82
  */
80
- export interface CfCryptoKey {
81
- /**
82
- * The format.
83
- */
84
- format: string;
85
- /**
86
- * The algorithm.
87
- */
88
- algorithm: string;
89
- /**
90
- * The usages.
91
- */
92
- usages: string[];
93
- /**
94
- * The data.
95
- */
96
- data: BufferSource | JsonWebKey;
83
+ interface CfDurableObject {
84
+ name: string;
85
+ class_name: string;
86
+ script_name?: string;
97
87
  }
98
88
 
99
89
  /**
100
- * A variable (aka. environment variable).
90
+ * A Service.
101
91
  */
102
- export type CfVariable = string | CfKvNamespace | CfCryptoKey;
92
+ interface CfService {
93
+ name: string;
94
+ service: string;
95
+ environment: string;
96
+ }
97
+
98
+ export interface CfDurableObjectMigrations {
99
+ old_tag?: string;
100
+ new_tag: string;
101
+ steps: {
102
+ new_classes?: string[];
103
+ renamed_classes?: string[];
104
+ deleted_classes?: string[];
105
+ }[];
106
+ }
103
107
 
104
108
  /**
105
109
  * Options for creating a `CfWorker`.
106
110
  */
107
111
  export interface CfWorkerInit {
112
+ /**
113
+ * The name of the worker.
114
+ */
115
+ name: string | void;
108
116
  /**
109
117
  * The entrypoint module.
110
118
  */
@@ -114,11 +122,18 @@ export interface CfWorkerInit {
114
122
  */
115
123
  modules: void | CfModule[];
116
124
  /**
117
- * The map of names to variables. (aka. environment variables)
125
+ * All the bindings
118
126
  */
119
- variables?: { [name: string]: CfVariable };
120
- compatibility_date?: string;
121
- usage_model?: void | "bundled" | "unbound";
127
+ bindings: {
128
+ kv_namespaces?: CfKvNamespace[];
129
+ durable_objects?: { bindings: CfDurableObject[] };
130
+ vars?: CfVars;
131
+ services?: CfService[];
132
+ };
133
+ migrations: void | CfDurableObjectMigrations;
134
+ compatibility_date: string | void;
135
+ compatibility_flags: void | string[];
136
+ usage_model: void | "bundled" | "unbound";
122
137
  }
123
138
 
124
139
  /**