alchemy 0.13.0 → 0.14.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 (80) hide show
  1. package/lib/apply.d.ts.map +1 -1
  2. package/lib/apply.js +0 -1
  3. package/lib/apply.js.map +1 -1
  4. package/lib/cloudflare/api.d.ts +5 -5
  5. package/lib/cloudflare/api.d.ts.map +1 -1
  6. package/lib/cloudflare/api.js +51 -10
  7. package/lib/cloudflare/api.js.map +1 -1
  8. package/lib/cloudflare/auth.d.ts +24 -55
  9. package/lib/cloudflare/auth.d.ts.map +1 -1
  10. package/lib/cloudflare/auth.js +15 -72
  11. package/lib/cloudflare/auth.js.map +1 -1
  12. package/lib/cloudflare/bundle/alias-plugin.d.ts +6 -0
  13. package/lib/cloudflare/bundle/alias-plugin.d.ts.map +1 -0
  14. package/lib/cloudflare/bundle/alias-plugin.js +36 -0
  15. package/lib/cloudflare/bundle/alias-plugin.js.map +1 -0
  16. package/lib/cloudflare/bundle/build-failures.d.ts +12 -0
  17. package/lib/cloudflare/bundle/build-failures.d.ts.map +1 -0
  18. package/lib/cloudflare/bundle/build-failures.js +45 -0
  19. package/lib/cloudflare/bundle/build-failures.js.map +1 -0
  20. package/lib/cloudflare/bundle/bundle-worker.d.ts +7 -0
  21. package/lib/cloudflare/bundle/bundle-worker.d.ts.map +1 -0
  22. package/lib/cloudflare/bundle/bundle-worker.js +69 -0
  23. package/lib/cloudflare/bundle/bundle-worker.js.map +1 -0
  24. package/lib/cloudflare/bundle/external.d.ts +1 -0
  25. package/lib/cloudflare/bundle/external.d.ts.map +1 -1
  26. package/lib/cloudflare/bundle/external.js +8 -1
  27. package/lib/cloudflare/bundle/external.js.map +1 -1
  28. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.d.ts +1 -1
  29. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.d.ts.map +1 -1
  30. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.js +6 -6
  31. package/lib/cloudflare/bundle/local-dev-cloudflare-shim.js.map +1 -1
  32. package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts +17 -0
  33. package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts.map +1 -0
  34. package/lib/cloudflare/bundle/nodejs-compat-mode.js +27 -0
  35. package/lib/cloudflare/bundle/nodejs-compat-mode.js.map +1 -0
  36. package/lib/cloudflare/bundle/nodejs-compat.d.ts +11 -0
  37. package/lib/cloudflare/bundle/nodejs-compat.d.ts.map +1 -0
  38. package/lib/cloudflare/bundle/{hybrid-nodejs-compat.js → nodejs-compat.js} +6 -5
  39. package/lib/cloudflare/bundle/nodejs-compat.js.map +1 -0
  40. package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
  41. package/lib/cloudflare/queue-consumer.js +0 -4
  42. package/lib/cloudflare/queue-consumer.js.map +1 -1
  43. package/lib/cloudflare/user.d.ts +51 -0
  44. package/lib/cloudflare/user.d.ts.map +1 -0
  45. package/lib/cloudflare/user.js +62 -0
  46. package/lib/cloudflare/user.js.map +1 -0
  47. package/lib/cloudflare/worker.d.ts +18 -3
  48. package/lib/cloudflare/worker.d.ts.map +1 -1
  49. package/lib/cloudflare/worker.js +7 -44
  50. package/lib/cloudflare/worker.js.map +1 -1
  51. package/lib/esbuild/bundle.d.ts.map +1 -1
  52. package/lib/esbuild/bundle.js +0 -1
  53. package/lib/esbuild/bundle.js.map +1 -1
  54. package/lib/test/bun.d.ts.map +1 -1
  55. package/lib/test/bun.js +2 -8
  56. package/lib/test/bun.js.map +1 -1
  57. package/package.json +4 -1
  58. package/src/apply.ts +0 -1
  59. package/src/cloudflare/api.ts +63 -14
  60. package/src/cloudflare/auth.ts +43 -158
  61. package/src/cloudflare/bundle/alias-plugin.ts +48 -0
  62. package/src/cloudflare/bundle/build-failures.ts +55 -0
  63. package/src/cloudflare/bundle/bundle-worker.ts +89 -0
  64. package/src/cloudflare/bundle/external.ts +9 -1
  65. package/src/cloudflare/bundle/local-dev-cloudflare-shim.ts +7 -6
  66. package/src/cloudflare/bundle/nodejs-compat-mode.ts +49 -0
  67. package/src/cloudflare/bundle/{hybrid-nodejs-compat.ts → nodejs-compat.ts} +6 -5
  68. package/src/cloudflare/queue-consumer.ts +1 -7
  69. package/src/cloudflare/user.ts +142 -0
  70. package/src/cloudflare/worker.ts +26 -51
  71. package/src/esbuild/bundle.ts +0 -1
  72. package/src/test/bun.ts +2 -7
  73. package/lib/cloudflare/account-id.d.ts +0 -6
  74. package/lib/cloudflare/account-id.d.ts.map +0 -1
  75. package/lib/cloudflare/account-id.js +0 -6
  76. package/lib/cloudflare/account-id.js.map +0 -1
  77. package/lib/cloudflare/bundle/hybrid-nodejs-compat.d.ts +0 -8
  78. package/lib/cloudflare/bundle/hybrid-nodejs-compat.d.ts.map +0 -1
  79. package/lib/cloudflare/bundle/hybrid-nodejs-compat.js.map +0 -1
  80. package/src/cloudflare/account-id.ts +0 -12
@@ -2,201 +2,86 @@ import fs from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import type { Secret } from "../secret.js";
5
- import type { CloudflareAccountId } from "./account-id.js";
6
- import { handleApiError } from "./api-error.js";
7
5
  /**
8
6
  * Authentication options for Cloudflare API
9
7
  */
10
- export interface CloudflareAuthOptions {
8
+ export type CloudflareAuthOptions =
9
+ | CloudflareApiKeyAuthOptions
10
+ | CloudflareApiTokenAuthOptions;
11
+
12
+ export type CloudflareApiKeyAuthOptions = {
11
13
  /**
12
14
  * API Key to use with API Key
13
15
  */
14
- apiKey?: Secret;
15
-
16
+ apiKey: Secret;
16
17
  /**
17
- * API Token to use with API Key
18
+ * Email to use with API Key
19
+ * If not provided, will attempt to discover from Cloudflare API
18
20
  */
19
- apiToken?: Secret;
21
+ email: string;
20
22
 
21
23
  /**
22
- * Email to use with API Key
23
- * If not provided, will attempt to discover from Cloudflare API
24
+ * API Token to use with API Key
24
25
  */
25
- email?: string;
26
- }
26
+ apiToken?: undefined;
27
+ };
27
28
 
28
- export interface CloudflareAccount {
29
- name: string;
30
- id: CloudflareAccountId;
31
- type: "standard" | "zero_rating" | "full_control";
32
- settings: {
33
- enforce_twofactor: boolean;
34
- api_access_enabled: null;
35
- access_approval_expiry: null;
36
- abuse_contact_email: null;
37
- };
38
- legacy_flags: {
39
- enterprise_zone_quota: {
40
- maximum: number;
41
- current: number;
42
- available: number;
43
- };
44
- };
29
+ export function isCloudflareApiKeyAuthOptions(
30
+ options: CloudflareAuthOptions | undefined,
31
+ ): options is CloudflareApiKeyAuthOptions {
32
+ return options !== undefined && options.apiKey !== undefined;
45
33
  }
46
34
 
47
- export interface CloudflareUserInfo {
35
+ export type CloudflareApiTokenAuthOptions = {
36
+ /**
37
+ * API Token to use with API Key
38
+ */
48
39
  apiToken?: Secret;
49
- apiKey?: Secret;
50
- email: string;
51
- username: string;
52
- accounts: CloudflareAccount[];
53
- organizations: CloudflareOrganization[];
54
- tokenPermissions: string[] | undefined;
55
- first_name: string | null;
56
- last_name: string | null;
57
- telephone: string | null;
58
- country: string | null;
59
- zipcode: string | null;
60
- two_factor_authentication_enabled: boolean;
61
- two_factor_authentication_locked: boolean;
62
- has_pro_zones: boolean;
63
- has_business_zones: boolean;
64
- has_enterprise_zones: boolean;
65
- suspended: boolean;
66
- betas: string[];
67
- }
68
40
 
69
- export interface CloudflareOrganization {
70
- id: string;
71
- name: string;
72
- status: string;
73
- permissions: string[];
74
- roles: string[];
75
- }
41
+ /**
42
+ * API Key to use with API Token
43
+ */
44
+ apiKey?: undefined;
76
45
 
77
- const userInfoCache: Record<string, CloudflareUserInfo> = {};
46
+ /**
47
+ * Email to use with API Token
48
+ */
49
+ email?: undefined;
50
+ };
78
51
 
79
- export async function getCloudflareUserInfo(
80
- options: CloudflareAuthOptions,
81
- ): Promise<CloudflareUserInfo> {
82
- const cacheKey = JSON.stringify({
83
- apiKey: options.apiKey?.unencrypted,
84
- apiToken: options.apiToken?.unencrypted,
85
- email: options.email,
86
- });
87
- if (userInfoCache[cacheKey]) {
88
- return userInfoCache[cacheKey];
89
- }
90
- const headers = await getCloudflareAuthHeaders(options);
91
- const user = await fetch("https://api.cloudflare.com/client/v4/user", {
92
- headers,
93
- });
94
- if (!user.ok) {
95
- if (user.status === 403) {
96
- throw new Error(
97
- "Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY, or CLOUDFLARE_EMAIL, or CLOUDFLARE_API_KEY?",
98
- );
99
- }
100
- await handleApiError(user, "getting", "user", "user");
101
- }
102
- const accounts = await fetch(
103
- "https://api.cloudflare.com/client/v4/accounts",
104
- {
105
- headers,
106
- },
107
- );
108
- const userInfo: CloudflareUserInfo = {
109
- ...((await user.json()) as any).result,
110
- accounts: ((await accounts.json()) as any).result,
111
- };
112
- userInfoCache[cacheKey] = userInfo;
113
- return userInfo;
52
+ export function isCloudflareApiTokenAuthOptions(
53
+ options: CloudflareAuthOptions | undefined,
54
+ ): options is CloudflareApiTokenAuthOptions {
55
+ return options !== undefined && options.apiToken !== undefined;
114
56
  }
115
57
 
116
58
  export async function getCloudflareAuthHeaders(
117
- options: CloudflareAuthOptions = {},
59
+ options: CloudflareAuthOptions | undefined,
118
60
  ): Promise<Record<string, string>> {
119
- // Check for API Token (preferred method)
120
- const apiToken =
121
- options.apiToken?.unencrypted ?? process.env.CLOUDFLARE_API_TOKEN;
122
- if (apiToken) {
61
+ if (isCloudflareApiKeyAuthOptions(options)) {
62
+ // Global API Key
123
63
  return {
124
- Authorization: `Bearer ${apiToken}`,
64
+ "X-Auth-Key": options.apiKey.unencrypted,
65
+ "X-Auth-Email": options.email,
125
66
  };
126
- }
127
-
128
- // Check for API Key
129
- const apiKey = options.apiKey?.unencrypted ?? process.env.CLOUDFLARE_API_KEY;
130
- if (apiKey) {
67
+ } else if (isCloudflareApiTokenAuthOptions(options)) {
68
+ // API Token
131
69
  return {
132
- "X-Auth-Key": apiKey,
133
- "X-Auth-Email":
134
- options.email ??
135
- process.env.CLOUDFLARE_EMAIL ??
136
- (await getUserEmailFromApiKey(apiKey)),
70
+ Authorization: `Bearer ${options.apiToken?.unencrypted}`,
137
71
  };
138
72
  }
139
-
73
+ // Wrangler OAuth Token
140
74
  const authConfig = await getRefreshedAuthConfig();
141
75
  if (authConfig.oauth_token) {
142
76
  return {
143
77
  Authorization: `Bearer ${authConfig.oauth_token}`,
144
78
  };
145
79
  }
146
-
147
80
  throw new Error(
148
- "Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY, or CLOUDFLARE_EMAIL, or CLOUDFLARE_API_KEY?",
81
+ "Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY?",
149
82
  );
150
83
  }
151
84
 
152
- const emailCache: Record<string, string> = {};
153
-
154
- async function getUserEmailFromApiKey(apiKey: string): Promise<string> {
155
- if (emailCache[apiKey]) {
156
- return emailCache[apiKey];
157
- }
158
-
159
- try {
160
- const baseUrl = "https://api.cloudflare.com/client/v4";
161
-
162
- // Call the /user endpoint to get user information
163
- const response = await fetch(`${baseUrl}/user`, {
164
- headers: {
165
- "Content-Type": "application/json",
166
- "X-Auth-Key": apiKey,
167
- },
168
- });
169
-
170
- if (!response.ok) {
171
- throw new Error(
172
- `Failed to get user information: ${response.status} ${response.statusText}`,
173
- );
174
- }
175
-
176
- const data = (await response.json()) as {
177
- success: boolean;
178
- result: {
179
- id: string;
180
- email: string;
181
- name: string;
182
- [key: string]: any;
183
- };
184
- };
185
-
186
- if (!data.success || !data.result || !data.result.email) {
187
- throw new Error("Cloudflare API did not return valid user information");
188
- }
189
-
190
- emailCache[apiKey] = data.result.email;
191
- return data.result.email;
192
- } catch (error) {
193
- console.error("Error retrieving email from Cloudflare API:", error);
194
- throw new Error(
195
- "Failed to automatically discover email for API Key authentication",
196
- );
197
- }
198
- }
199
-
200
85
  async function refreshAuthToken(
201
86
  options: WranglerConfig,
202
87
  ): Promise<WranglerConfig> {
@@ -0,0 +1,48 @@
1
+ import type { Plugin } from "esbuild";
2
+
3
+ export const createAliasPlugin = ({
4
+ alias,
5
+ projectRoot,
6
+ }: {
7
+ alias: Record<string, string>;
8
+ projectRoot: string;
9
+ }): Plugin => ({
10
+ name: "alias",
11
+ setup(build) {
12
+ if (!alias) {
13
+ return;
14
+ }
15
+
16
+ // filter the hook calls to only those that match the alias keys
17
+ // this should avoid slowing down builds which don't use aliasing
18
+ const filter = new RegExp(
19
+ Object.keys(alias)
20
+ .map((key) => escapeRegex(key))
21
+ .join("|"),
22
+ );
23
+
24
+ // reimplement module aliasing as an esbuild plugin onResolve hook
25
+ build.onResolve({ filter }, (args) => {
26
+ const aliasPath = alias[args.path];
27
+ if (aliasPath) {
28
+ return {
29
+ // resolve with node resolution
30
+ path: require.resolve(aliasPath, {
31
+ // From the esbuild alias docs: "Note that when an import path is substituted using an alias, the resulting import path is resolved in the working directory instead of in the directory containing the source file with the import path."
32
+ // https://esbuild.github.io/api/#alias:~:text=Note%20that%20when%20an%20import%20path%20is%20substituted%20using%20an%20alias%2C%20the%20resulting%20import%20path%20is%20resolved%20in%20the%20working%20directory%20instead%20of%20in%20the%20directory%20containing%20the%20source%20file%20with%20the%20import%20path.
33
+ paths: [projectRoot],
34
+ }),
35
+ };
36
+ }
37
+ });
38
+ },
39
+ });
40
+
41
+ // Taken from https://stackoverflow.com/a/3561711
42
+ // which is everything from the tc39 proposal, plus the following two characters: ^/
43
+ // It's also everything included in the URLPattern escape (https://wicg.github.io/urlpattern/#escape-a-regexp-string), plus the following: -
44
+ // As the answer says, there's no downside to escaping these extra characters, so better safe than sorry
45
+ const ESCAPE_REGEX_CHARACTERS = /[-/\\^$*+?.()|[\]{}]/g;
46
+ const escapeRegex = (str: string) => {
47
+ return str.replace(ESCAPE_REGEX_CHARACTERS, "\\$&");
48
+ };
@@ -0,0 +1,55 @@
1
+ import type * as esbuild from "esbuild";
2
+ import type { NodeJSCompatMode } from "miniflare";
3
+ import { builtinModules } from "node:module";
4
+
5
+ /**
6
+ * RegExp matching against esbuild's error text when it is unable to resolve
7
+ * a Node built-in module. If we detect this when node_compat is disabled,
8
+ * we'll rewrite the error to suggest enabling it.
9
+ */
10
+ const nodeBuiltinResolveErrorText = new RegExp(
11
+ '^Could not resolve "(' +
12
+ builtinModules.join("|") +
13
+ "|" +
14
+ builtinModules.map((module) => `node:${module}`).join("|") +
15
+ ')"$',
16
+ );
17
+ /**
18
+ * Rewrites esbuild BuildFailures for failing to resolve Node built-in modules
19
+ * to suggest enabling Node compat as opposed to `platform: "node"`.
20
+ */
21
+ export function rewriteNodeCompatBuildFailure(
22
+ errors: esbuild.Message[],
23
+ compatMode: NodeJSCompatMode = null,
24
+ ) {
25
+ for (const error of errors) {
26
+ const match = nodeBuiltinResolveErrorText.exec(error.text);
27
+ if (match !== null) {
28
+ let text = `The package "${match[1]}" wasn't found on the file system but is built into node.\n`;
29
+
30
+ if (compatMode === null || compatMode === "als") {
31
+ text += `- Add the "nodejs_compat" compatibility flag to your project.\n`;
32
+ } else if (compatMode === "v1" && !match[1].startsWith("node:")) {
33
+ text += `- Make sure to prefix the module name with "node:" or update your compatibility_date to 2024-09-23 or later.\n`;
34
+ }
35
+
36
+ error.notes = [
37
+ {
38
+ location: null,
39
+ text,
40
+ },
41
+ ];
42
+ }
43
+ }
44
+ }
45
+ /**
46
+ * Returns true if the passed value looks like an esbuild BuildFailure object
47
+ */
48
+ export function isBuildFailure(err: unknown): err is esbuild.BuildFailure {
49
+ return (
50
+ typeof err === "object" &&
51
+ err !== null &&
52
+ "errors" in err &&
53
+ "warnings" in err
54
+ );
55
+ }
@@ -0,0 +1,89 @@
1
+ import fs from "node:fs/promises";
2
+ import { Bundle } from "../../esbuild/bundle.js";
3
+ import type { Bindings } from "../bindings.js";
4
+ import type { WorkerProps } from "../worker.js";
5
+ import { createAliasPlugin } from "./alias-plugin.js";
6
+ import {
7
+ isBuildFailure,
8
+ rewriteNodeCompatBuildFailure,
9
+ } from "./build-failures.js";
10
+ import { external, external_als } from "./external.js";
11
+ import { getNodeJSCompatMode } from "./nodejs-compat-mode.js";
12
+ import { nodeJsCompatPlugin } from "./nodejs-compat.js";
13
+
14
+ export async function bundleWorkerScript<B extends Bindings>(
15
+ props: WorkerProps<B> & {
16
+ compatibilityDate: string;
17
+ compatibilityFlags: string[];
18
+ },
19
+ ) {
20
+ const projectRoot = props.projectRoot ?? process.cwd();
21
+
22
+ const nodeJsCompatMode = getNodeJSCompatMode(
23
+ props.compatibilityDate,
24
+ props.compatibilityFlags,
25
+ );
26
+
27
+ if (nodeJsCompatMode === "v1") {
28
+ throw new Error(
29
+ "You must set your compatibilty date >= 2024-09-23 when using 'nodejs_compat' compatibility flag",
30
+ );
31
+ }
32
+
33
+ try {
34
+ const bundle = await Bundle("bundle", {
35
+ entryPoint: props.entrypoint!,
36
+ format: props.format === "cjs" ? "cjs" : "esm", // Use the specified format or default to ESM
37
+ target: "esnext",
38
+ platform: "node",
39
+ minify: false,
40
+ ...(props.bundle || {}),
41
+ conditions: ["workerd", "worker", "browser"],
42
+ options: {
43
+ absWorkingDir: projectRoot,
44
+ ...(props.bundle?.options || {}),
45
+ keepNames: true, // Important for Durable Object classes
46
+ loader: {
47
+ ".sql": "text",
48
+ ".json": "json",
49
+ },
50
+ plugins: [
51
+ ...(nodeJsCompatMode === "v2" ? [await nodeJsCompatPlugin()] : []),
52
+ ...(props.bundle?.alias
53
+ ? [
54
+ createAliasPlugin({
55
+ alias: props.bundle?.alias,
56
+ projectRoot,
57
+ }),
58
+ ]
59
+ : []),
60
+ ],
61
+ },
62
+ external: [
63
+ ...(nodeJsCompatMode === "als" ? external_als : external),
64
+ ...(props.bundle?.external ?? []),
65
+ ...(props.bundle?.options?.external ?? []),
66
+ ],
67
+ });
68
+ if (bundle.content) {
69
+ return bundle.content;
70
+ }
71
+ if (bundle.path) {
72
+ return await fs.readFile(bundle.path, "utf-8");
73
+ }
74
+ throw new Error("Failed to create bundle");
75
+ } catch (e: any) {
76
+ if (e.message?.includes("No such module 'node:")) {
77
+ throw new Error(
78
+ `${e.message}.\nMake sure to set 'nodejs_compat' compatibility flag and compatibilityDate > 2024-09-23`,
79
+ { cause: e },
80
+ );
81
+ }
82
+ if (isBuildFailure(e)) {
83
+ rewriteNodeCompatBuildFailure(e.errors, nodeJsCompatMode);
84
+ throw e;
85
+ }
86
+ console.error("Error reading bundle:", e);
87
+ throw new Error("Error reading bundle");
88
+ }
89
+ }
@@ -5,13 +5,14 @@ const nodejs_compat = [
5
5
  "node:buffer",
6
6
  "node:console",
7
7
  "node:crypto",
8
+ "node:debug",
8
9
  "node:diagnostics_channel",
9
10
  "node:dns",
10
11
  "node:events",
11
12
  "node:inspector",
12
13
  "node:net",
13
14
  "node:path",
14
- "node:perf_hooks",
15
+ "node:perf_hooks", // partially supported
15
16
  "node:process",
16
17
  "node:querystring",
17
18
  "node:stream",
@@ -30,3 +31,10 @@ export const external = [
30
31
  "cloudflare:workers",
31
32
  // "cloudflare:*",
32
33
  ];
34
+
35
+ export const external_als = [
36
+ //
37
+ "node:async_hooks",
38
+ "async_hooks",
39
+ "cloudflare:*",
40
+ ];
@@ -1,3 +1,5 @@
1
+ import { dedent } from "../../util/dedent.js";
2
+
1
3
  /**
2
4
  * TanStackStart server functions and middleware run in Node.js intead of Miniflare when using `vite dev`.
3
5
  *
@@ -13,12 +15,11 @@ export function cloudflareWorkersDevEnvironmentShim() {
13
15
  },
14
16
  load(id: string) {
15
17
  if (id === "cloudflare:workers")
16
- return `
17
- import { getPlatformProxy } from "wrangler";
18
- // TODO: should we export default cloudflare; ??
19
- const cloudflare = await getPlatformProxy();
20
- export const env = cloudflare.env;
21
- `;
18
+ return dedent`
19
+ import { getPlatformProxy } from "wrangler";
20
+ // TODO: should we export default cloudflare; ??
21
+ const cloudflare = await getPlatformProxy();
22
+ export const env = cloudflare.env;`;
22
23
  },
23
24
  } as const;
24
25
  }
@@ -0,0 +1,49 @@
1
+ import type { NodeJSCompatMode } from "miniflare";
2
+ import { getNodeCompat } from "miniflare";
3
+
4
+ /**
5
+ * Computes and validates the Node.js compatibility mode we are running.
6
+ *
7
+ * NOTES:
8
+ * - The v2 mode is configured via `nodejs_compat_v2` compat flag or via `nodejs_compat` plus a compatibility date of Sept 23rd. 2024 or later.
9
+ * - See `EnvironmentInheritable` for `noBundle`.
10
+ *
11
+ * @param compatibilityDateStr The compatibility date
12
+ * @param compatibilityFlags The compatibility flags
13
+ * @param noBundle Whether to skip internal build steps and directly deploy script
14
+ *
15
+ */
16
+ export function getNodeJSCompatMode(
17
+ compatibilityDateStr: string,
18
+ compatibilityFlags: string[],
19
+ props?: {
20
+ noBundle?: boolean;
21
+ },
22
+ ): NodeJSCompatMode {
23
+ const {
24
+ mode,
25
+ hasNodejsCompatFlag,
26
+ hasNodejsCompatV2Flag,
27
+ hasExperimentalNodejsCompatV2Flag,
28
+ } = getNodeCompat(compatibilityDateStr, compatibilityFlags);
29
+
30
+ if (hasExperimentalNodejsCompatV2Flag) {
31
+ throw new Error(
32
+ "The `experimental:` prefix on `nodejs_compat_v2` is no longer valid. Please remove it and try again.",
33
+ );
34
+ }
35
+
36
+ if (hasNodejsCompatFlag && hasNodejsCompatV2Flag) {
37
+ throw new Error(
38
+ "The `nodejs_compat` and `nodejs_compat_v2` compatibility flags cannot be used in together. Please select just one.",
39
+ );
40
+ }
41
+
42
+ if (props?.noBundle && hasNodejsCompatV2Flag) {
43
+ console.warn(
44
+ "`nodejs_compat_v2` compatibility flag and `--no-bundle` can't be used together. If you want to polyfill Node.js built-ins and disable Wrangler's bundling, please polyfill as part of your own bundling process.",
45
+ );
46
+ }
47
+
48
+ return mode;
49
+ }
@@ -1,13 +1,13 @@
1
+ /**
2
+ * Copied from https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/src/deployment-bundle/esbuild-plugins/hybrid-nodejs-compat.ts#L17
3
+ */
4
+
1
5
  import type { Plugin, PluginBuild } from "esbuild";
2
6
  import assert from "node:assert";
3
7
  import { builtinModules } from "node:module";
4
8
  import nodePath from "node:path";
5
9
  import { dedent } from "../../util/dedent.js";
6
10
 
7
- /**
8
- * Copied from https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/src/deployment-bundle/esbuild-plugins/hybrid-nodejs-compat.ts#L17
9
- */
10
-
11
11
  const REQUIRED_NODE_BUILT_IN_NAMESPACE = "node-built-in-modules";
12
12
  const REQUIRED_UNENV_ALIAS_NAMESPACE = "required-unenv-alias";
13
13
 
@@ -16,7 +16,7 @@ const REQUIRED_UNENV_ALIAS_NAMESPACE = "required-unenv-alias";
16
16
  *
17
17
  * @returns ESBuild plugin
18
18
  */
19
- export async function nodejsHybridPlugin(): Promise<Plugin> {
19
+ export async function nodeJsCompatPlugin(): Promise<Plugin> {
20
20
  // `unenv` and `@cloudflare/unenv-preset` only publish esm
21
21
  const { defineEnv } = await import("unenv");
22
22
  const { cloudflare } = await import("@cloudflare/unenv-preset");
@@ -212,6 +212,7 @@ function handleNodeJSGlobals(
212
212
  module,
213
213
  );
214
214
  }
215
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
215
216
  injectsByModule.get(module)!.push({ injectedName, exportName, importName });
216
217
  }
217
218
 
@@ -2,8 +2,8 @@ import type { Context } from "../context.js";
2
2
  import { Resource } from "../resource.js";
3
3
  import { CloudflareApiError, handleApiError } from "./api-error.js";
4
4
  import {
5
- type CloudflareApi,
6
5
  createCloudflareApi,
6
+ type CloudflareApi,
7
7
  type CloudflareApiOptions,
8
8
  } from "./api.js";
9
9
  import type { Queue } from "./queue.js";
@@ -163,10 +163,8 @@ export const QueueConsumer = Resource(
163
163
  let consumerData: CloudflareQueueConsumerResponse;
164
164
 
165
165
  if (this.phase === "create") {
166
- console.log(`Creating Queue Consumer for queue ${queueId}`);
167
166
  consumerData = await createQueueConsumer(api, queueId, props);
168
167
  } else if (this.output?.id) {
169
- console.log(`Updating Queue Consumer ${this.output.id}`);
170
168
  consumerData = await updateQueueConsumer(
171
169
  api,
172
170
  queueId,
@@ -174,10 +172,6 @@ export const QueueConsumer = Resource(
174
172
  props,
175
173
  );
176
174
  } else {
177
- // If no ID exists, fall back to creating a new consumer
178
- console.log(
179
- `No existing Consumer ID found, creating new Queue Consumer for queue ${queueId}`,
180
- );
181
175
  consumerData = await createQueueConsumer(api, queueId, props);
182
176
  }
183
177