Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/fix-hotkeys-case-insensitive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

fix: hotkeys now work with Caps Lock enabled

Wrangler's dev server hotkeys (e.g. `b` to open browser and `x` to exit) did not respond when Caps Lock was enabled. These hotkeys now work consistently whether or not Caps Lock is on.
22 changes: 22 additions & 0 deletions .changeset/preview-json-vars.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"wrangler": patch
---

preserve native shape of non-string `vars` in worker previews

`wrangler preview` previously coerced every non-string entry in `previews.vars` (arrays, objects, numbers, booleans) into a `plain_text` binding via `JSON.stringify`, so at runtime the worker saw a literal string instead of the value declared in `wrangler.jsonc`. `wrangler deploy` already serializes non-string vars as `json` bindings so the Workers runtime parses them back into native JS values; previews now match.

Before:

```ts
// wrangler.jsonc — previews.vars
{ "ALLOWLIST": ["a@example.com", "b@example.com"] }
// runtime
typeof env.ALLOWLIST === "string" // true (was '["a@example.com","b@example.com"]')
```

After:

```ts
typeof env.ALLOWLIST === "object" // Array.isArray(env.ALLOWLIST) === true
```
7 changes: 7 additions & 0 deletions .changeset/propagate-trace-id-header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"miniflare": patch
---

Propagate `cf-trace-id` header on remote binding proxy requests

When the `CF_TRACE_ID` environment variable is set, its value is now forwarded as a `cf-trace-id` header on outgoing remote binding proxy requests. This makes it easier to correlate traces when debugging remote bindings in local development.
7 changes: 7 additions & 0 deletions .changeset/small-rocks-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

Propagate `unsafe.bindings` and service binding `cross_account_grant` to worker previews

Worker previews now propagate `unsafe.bindings` declared on the `previews` config block to the deployment metadata, mirroring the deploy-time behavior. Without this, internal binding shapes that wrangler doesn't yet model (notably service bindings carrying `cross_account_grant`) were silently dropped on previews while working fine on regular deploys. The same change wires through `cross_account_grant` on typed `services` bindings.
7 changes: 7 additions & 0 deletions .changeset/wise-taxis-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": minor
---

Add named tunnel support and tunnel shortcuts to `wrangler dev`

You can now use `wrangler dev --tunnel --tunnel-name <name>` to start a dev session with an existing named Cloudflare Tunnel, or set `--tunnel-name` ahead of time and start it later by pressing `t` to start or close the tunnel. This gives you a stable public hostname for local development instead of the temporary `trycloudflare.com` URL used by Quick Tunnels.
5 changes: 2 additions & 3 deletions .oxlintrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,9 @@
"workers-sdk/no-wrangler-named-imports": "error",
},
},
// Gradually rolling out require-description-when-disabling.
// TODO: Remove the following overrides.
// TODO: Remove the following wrangler override.
{
"files": ["packages/quick-edit-extension/**", "packages/wrangler/**"],
"files": ["packages/wrangler/**"],
"rules": {
"workers-sdk/require-description-when-disabling": "off",
},
Expand Down
9 changes: 9 additions & 0 deletions packages/miniflare/src/plugins/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export function remoteProxyClientWorker(
binding: string,
script?: () => string
) {
const cfTraceId = process.env.CF_TRACE_ID;
return {
compatibilityDate: "2025-01-01",
modules: [
Expand All @@ -104,6 +105,14 @@ export function remoteProxyClientWorker(
name: "binding",
text: binding,
},
...(cfTraceId
? [
{
name: "cfTraceId",
text: cfTraceId,
},
]
: []),
],
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export default class DispatchNamespaceProxy extends WorkerEntrypoint<RemoteBindi
args,
options,
}),
}
},
this.env.cfTraceId
);
}
}
20 changes: 17 additions & 3 deletions packages/miniflare/src/workers/shared/remote-bindings-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { newWebSocketRpcSession } from "capnweb";
export type RemoteBindingEnv = {
remoteProxyConnectionString?: string;
binding: string;
cfTraceId?: string;
};

/** Headers sent alongside proxy requests to provide additional context. */
Expand All @@ -23,7 +24,8 @@ export function throwRemoteRequired(bindingName: string): never {
export function makeFetch(
remoteProxyConnectionString: string | undefined,
bindingName: string,
extraHeaders?: Headers
extraHeaders?: Headers,
cfTraceId?: string
) {
return (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
if (!remoteProxyConnectionString) {
Expand All @@ -43,6 +45,12 @@ export function makeFetch(
}
proxiedHeaders.set("MF-URL", request.url);
proxiedHeaders.set("MF-Binding", bindingName);
if (cfTraceId) {
// Set directly on the outgoing request so Cloudflare's edge tracing picks it up
proxiedHeaders.set("cf-trace-id", cfTraceId);
// Also forward through to the binding call via the MF-Header proxy mechanism
proxiedHeaders.set("MF-Header-cf-trace-id", cfTraceId);
}
const req = new Request(request, {
headers: proxiedHeaders,
});
Expand All @@ -59,7 +67,8 @@ export function makeFetch(
export function makeRemoteProxyStub(
remoteProxyConnectionString: string,
bindingName: string,
metadata?: ProxyMetadata
metadata?: ProxyMetadata,
cfTraceId?: string
): Fetcher {
const url = new URL(remoteProxyConnectionString);
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
Expand Down Expand Up @@ -89,7 +98,12 @@ export function makeRemoteProxyStub(
return new Proxy<ProxiedService>(stub, {
get(_, p) {
if (p === "fetch") {
return makeFetch(remoteProxyConnectionString, bindingName, headers);
return makeFetch(
remoteProxyConnectionString,
bindingName,
headers,
cfTraceId
);
}
return Reflect.get(stub, p);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@ export default class Client extends WorkerEntrypoint<RemoteBindingEnv> {
fetch(request: Request): Promise<Response> {
return makeFetch(
this.env.remoteProxyConnectionString,
this.env.binding
this.env.binding,
undefined,
this.env.cfTraceId
)(request);
}

constructor(ctx: ExecutionContext, env: RemoteBindingEnv) {
super(ctx, env);

const stub = env.remoteProxyConnectionString
? makeRemoteProxyStub(env.remoteProxyConnectionString, env.binding)
? makeRemoteProxyStub(
env.remoteProxyConnectionString,
env.binding,
undefined,
env.cfTraceId
)
: undefined;

return new Proxy(this, {
Expand Down
15 changes: 8 additions & 7 deletions packages/quick-edit-extension/src/cfs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,15 +541,16 @@ declare module "*.bin" {
});
}

/* eslint-disable no-useless-escape --
adapted from vscode-web-playground, see: https://github.com/microsoft/vscode-web-playground/blob/fde7a272cc7de/src/memfs.ts#L399-L401
escapes are redundant in a character class but harmless
*/
private _convertSimple2RegExpPattern(pattern: string): string {
return (
pattern
// eslint-disable-next-line
.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, "\\$&")
// eslint-disable-next-line
.replace(/[\*]/g, ".*")
);
return pattern
.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, "\\$&")
.replace(/[\*]/g, ".*");
}
/* eslint-enable no-useless-escape */

// --- search provider

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe("preview server", () => {
}) => {
vi.mocked(startTunnel).mockReturnValue({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://example.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand Down
8 changes: 8 additions & 0 deletions packages/vite-plugin-cloudflare/src/__tests__/tunnel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe("tunnel plugin", () => {
beforeEach(() => {
vi.mocked(startTunnel).mockReturnValue({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://example.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand All @@ -43,6 +44,7 @@ describe("tunnel plugin", () => {
}) => {
vi.mocked(startTunnel).mockReturnValue({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://example.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand Down Expand Up @@ -96,6 +98,7 @@ describe("tunnel plugin", () => {
}) => {
vi.mocked(startTunnel).mockReturnValue({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://example.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand Down Expand Up @@ -136,13 +139,15 @@ describe("tunnel plugin", () => {
vi.mocked(startTunnel)
.mockReturnValueOnce({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://foo.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
dispose: vi.fn(),
})
.mockReturnValueOnce({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://bar.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand Down Expand Up @@ -214,6 +219,7 @@ describe("tunnel plugin", () => {
vi.mocked(startTunnel)
.mockReturnValueOnce({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://foo.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand All @@ -223,6 +229,7 @@ describe("tunnel plugin", () => {
})
.mockReturnValueOnce({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://bar.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand Down Expand Up @@ -324,6 +331,7 @@ describe("tunnel plugin", () => {
it("prints tunnel details with server.printUrls", async ({ expect }) => {
vi.mocked(startTunnel).mockReturnValue({
ready: vi.fn().mockResolvedValue({
mode: "quick",
publicUrl: new URL("https://example.trycloudflare.com"),
}),
extendExpiry: vi.fn(),
Expand Down
11 changes: 9 additions & 2 deletions packages/vite-plugin-cloudflare/src/plugins/tunnel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,22 @@ export class TunnelManager {

async #waitForPublicUrl(tunnel: Tunnel): Promise<string | null> {
try {
const { publicUrl } = await tunnel.ready();
const result = await tunnel.ready();
if (this.#tunnel !== tunnel) {
debuglog(
"Tunnel was restarted before it finished starting. Ignoring this tunnel's public URL:",
publicUrl
result.mode === "quick" ? result.publicUrl : "(named tunnel)"
);
return null;
}

if (result.mode !== "quick") {
this.#publicUrl = undefined;
return null;
}

const { publicUrl } = result;

debuglog("Tunnel is ready with public URL:", publicUrl);
this.#publicUrl = publicUrl.toString();
return publicUrl.toString();
Expand Down
Loading
Loading