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
9 changes: 9 additions & 0 deletions .changeset/angry-carrots-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"wrangler": patch
---

Bump `rosie-skills` from `0.7.6` to `0.8.1` and bundle it into the Wrangler output

The new version of `rosie-skills` is a [pure-TypeScript rewrite](https://github.com/withastro/rosie/pull/21) that removes the previously necessary ~600kb WASM binary. The package now ships only JavaScript with one minimal dependencies (`modern-tar`).

Additionally, `rosie-skills` is now bundled directly into Wrangler's distributable rather than kept as an external runtime dependency. This eliminates the supply chain concern raised in [#14110](https://github.com/cloudflare/workers-sdk/issues/14110): there is no separate package to resolve at install time, since all code is inlined into Wrangler's build output.
7 changes: 7 additions & 0 deletions .changeset/browser-run-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

Update the generated type for browser bindings to `BrowserRun`

When running `wrangler types`, browser bindings were previously typed as the generic `Fetcher`. They now generate the more specific and accurate `BrowserRun` type.
7 changes: 7 additions & 0 deletions .changeset/c3-tanstack-cli-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"create-cloudflare": minor
---

Migrate TanStack Start scaffolding from `@tanstack/create-start` to `@tanstack/cli`

TanStack has consolidated their project scaffolding into a unified CLI package (`@tanstack/cli`) with a `create` subcommand, replacing the previous `@tanstack/create-start` package. This updates C3 to use the new CLI while preserving the same Cloudflare deployment target and React framework options.
9 changes: 9 additions & 0 deletions .changeset/react-router-autoconfig-v8-middleware.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"wrangler": patch
---

Adapt React Router autoconfig based on `v8_middleware` future flag

The React Router autoconfig (`wrangler setup`) now detects whether `v8_middleware: true` is set in the user's `react-router.config.ts`. When it is, the generated `workers/app.ts` uses a simplified fetch handler without `AppLoadContext` module augmentation, and the generated `app/entry.server.tsx` omits the `_loadContext` parameter. When `v8_middleware` is not set, the existing `AppLoadContext` pattern with `env`/`ctx` params is preserved.

This avoids breaking projects that use the `v8_middleware` future flag (which changes the context API from `AppLoadContext` to `RouterContextProvider`), while keeping the traditional pattern for projects that haven't opted in.
10 changes: 10 additions & 0 deletions .changeset/whoami-trailing-period.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"wrangler": patch
---

Fix `wrangler whoami` printing a trailing period after the api-tokens URL

The message `To see token permissions visit https://...api-tokens.` ended with
a period that became part of the URL when clicked in terminals or GitHub Actions
output, causing a 404. The period is removed and a comma added before "visit"
so the sentence reads naturally without a trailing period on the URL.
17 changes: 17 additions & 0 deletions .changeset/workflows-uint8array-sqlite-toobig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@cloudflare/workflows-shared": patch
---

Fix `wrangler dev` Workflows crashing with `SQLITE_TOOBIG` when a step returns a large `Uint8Array`

`JSON.stringify` encodes each byte of a `Uint8Array` as a separate numeric key
(`{"0":1,"1":2,...}`), producing a string ~10× larger than the array's byte
length. A 200 KB `Uint8Array` became a ~2 MB JSON string that exceeded SQLite's
blob limit, crashing the Workflow step. The same bytes returned as an
`ArrayBuffer` succeeded because `JSON.stringify(ArrayBuffer)` → `{}`.

The step log metadata (used by the local Workflows explorer) now stores a
human-readable description for `TypedArray` and `ArrayBuffer` outputs
(`[Uint8Array(200000 bytes)]`) instead of attempting to JSON-serialise the raw
bytes. The actual step value is unaffected — it is preserved in Durable Object
key-value storage via structured clone for replay by subsequent steps.
1 change: 1 addition & 0 deletions .github/opencode.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"provider": {
"cloudflare-ai-gateway": {
"models": {
"anthropic/claude-opus-4-8": {},
"anthropic/claude-sonnet-4-5": {},
"workers-ai/@cf/moonshotai/kimi-k2.6": {}
}
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/bonk-pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ jobs:
CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
with:
model: "cloudflare-ai-gateway/anthropic/claude-opus-4-6"
model: "cloudflare-ai-gateway/anthropic/claude-opus-4-8"
variant: "high"
forks: "false"
permissions: write
opencode_version: "1.4.6" # pin to this version as newer versions are causing ProviderInitError issues
opencode_version: 1.15.13 # pin to this version as certain ones cause ProviderInitError issues
prompt: ${{ steps.prompt.outputs.value }}
5 changes: 3 additions & 2 deletions .github/workflows/bonk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ jobs:
CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
with:
model: "cloudflare-ai-gateway/anthropic/claude-opus-4-6"
model: "cloudflare-ai-gateway/anthropic/claude-opus-4-8"
variant: "high"
mentions: "/bonk,@ask-bonk"
permissions: write
agent: bonk
opencode_version: "1.4.6" # pin to this version as newer versions are causing ProviderInitError issues
opencode_version: 1.15.13 # pin to this version as certain ones cause ProviderInitError issues
prompt: ${{ steps.prompt.outputs.value }}
2 changes: 1 addition & 1 deletion .opencode/agents/bonk.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: Cloudflare Workers SDK engineer. Triages issues, reviews PRs, and implements fixes.
mode: primary
model: anthropic/claude-opus-4-6
model: anthropic/claude-opus-4-8
temperature: 0.2
---

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"check:fixtures": "node -r esbuild-register tools/deployments/validate-fixtures.ts",
"check:format": "oxfmt --check",
"check:lint": "oxlint --deny-warnings --type-aware",
"check:package-deps": "node -r esbuild-register tools/deployments/validate-package-dependencies.ts",
"check:package-deps": "pnpm build && node -r esbuild-register tools/deployments/validate-package-dependencies.ts",
"check:private-packages": "node -r esbuild-register tools/deployments/validate-private-packages.ts",
"check:type": "dotenv -- turbo check:type type:tests",
"check:workflows": "node -r esbuild-register tools/github-workflow-helpers/validate-action-pinning.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-cloudflare/src/frameworks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "frameworks_clis_info",
"dependencies": {
"@angular/create": "21.2.12",
"@tanstack/create-start": "0.59.32",
"@tanstack/cli": "0.68.0",
"create-analog": "2.5.2",
"create-astro": "5.0.6",
"create-docusaurus": "3.10.1",
Expand Down
4 changes: 3 additions & 1 deletion packages/create-cloudflare/templates/tanstack-start/c3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const { npm } = detectPackageManager();

const generate = async (ctx: C3Context) => {
await runFrameworkGenerator(ctx, [
// @tanstack/cli uses `create` as a subcommand
"create",
ctx.project.name,
"--deployment",
"cloudflare",
Expand All @@ -24,7 +26,7 @@ const config: TemplateConfig = {
configVersion: 1,
id: "tanstack-start",
platform: "workers",
frameworkCli: "@tanstack/create-start",
frameworkCli: "@tanstack/cli",
displayName: "TanStack Start",
generate,
transformPackageJson: async () => ({
Expand Down
10 changes: 8 additions & 2 deletions packages/vite-plugin-cloudflare/e2e/global-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ export default async function ({ provide }: TestProject) {
"@cloudflare/vite-plugin"
);

// Create temporary directory to host projects used for testing
const root = await fs.mkdtemp(path.join(os.tmpdir(), "vite-plugin-"));
// Create temporary directory to host projects used for testing.
// On Windows GitHub Actions runners, `os.tmpdir()` returns a path containing
// the 8.3 short name "RUNNER~1". Vite 8.0.16 (and the backports to v6/v7)
// rejects paths containing "~" or ":" as a security fix
// (https://github.com/vitejs/vite/pull/22572, GHSA-fx2h-pf6j-xcff), so we
// resolve the temp dir to its real long-form path first.
const tmpdir = await fs.realpath(os.tmpdir());
const root = await fs.mkdtemp(path.join(tmpdir, "vite-plugin-"));
debuglog("Created temporary directory at " + root);

// The type of the provided `root` is defined in the `ProvidedContent` type above.
Expand Down
20 changes: 19 additions & 1 deletion packages/workflows-shared/src/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ export const DEFAULT_STEP_LIMIT = 10_000;

const PAUSE_DATETIME = "PAUSE_DATETIME";

/**
* JSON.stringify replacer that converts TypedArrays and ArrayBuffers to a
* human-readable description. Without this, JSON.stringify(Uint8Array) encodes
* each byte as a numeric key ({"0":1,"1":2,...}), producing a string ~10x larger
* than byteLength and causing SQLITE_TOOBIG for outputs above ~170 KB.
* The replacer is called recursively by JSON.stringify, so nested binary values
* inside objects or arrays are also handled.
*/
function binaryReplacer(_key: string, value: unknown): unknown {
if (value instanceof ArrayBuffer) {
return `[ArrayBuffer(${value.byteLength} bytes)]`;
}
if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
return `[${value.constructor.name}(${(value as ArrayBufferView).byteLength} bytes)]`;
}
return value;
}

function isStepSuccessEvent(event: InstanceEvent): boolean {
return (
event === InstanceEvent.STEP_SUCCESS ||
Expand Down Expand Up @@ -200,7 +218,7 @@ export class Engine extends DurableObject<Env> {
event,
group,
target,
JSON.stringify(metadata)
JSON.stringify(metadata, binaryReplacer)
);

// Wake any waiters if this is a terminal step event
Expand Down
49 changes: 49 additions & 0 deletions packages/workflows-shared/tests/engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,55 @@ describe("Engine", () => {
).toBe(true);
});

it("should complete a step that returns a large Uint8Array without SQLITE_TOOBIG", async ({
expect,
}) => {
// Regression: JSON.stringify(Uint8Array) encodes each byte as a numeric key,
// producing a string far larger than byteLength. A 200 KB Uint8Array → ~2 MB JSON
// → SQLITE_TOOBIG. writeLog must use a replacer to sanitize TypedArrays.
const instanceId = "LARGE-UINT8ARRAY-RESULT";
const engineId = env.ENGINE.idFromName(instanceId);
const engineStub = env.ENGINE.get(engineId);

await runWorkflowAndAwait(instanceId, async (_event, step) => {
await step.do("large-binary-step", async () => {
return new Uint8Array(200_000); // ~200 KB, triggers SQLITE_TOOBIG without fix
});
});

const logs = (await engineStub.readLogs()) as EngineLogs;
expect(
logs.logs.some((val) => val.event === InstanceEvent.WORKFLOW_SUCCESS)
).toBe(true);
expect(
logs.logs.some((val) => val.event === InstanceEvent.WORKFLOW_FAILURE)
).toBe(false);
});

it("should complete a step that returns an object containing a large Uint8Array without SQLITE_TOOBIG", async ({
expect,
}) => {
// Regression: nested TypedArrays inside objects also cause SQLITE_TOOBIG without
// the JSON.stringify replacer, since sanitization must be recursive.
const instanceId = "NESTED-UINT8ARRAY-RESULT";
const engineId = env.ENGINE.idFromName(instanceId);
const engineStub = env.ENGINE.get(engineId);

await runWorkflowAndAwait(instanceId, async (_event, step) => {
await step.do("nested-binary-step", async () => {
return { payload: new Uint8Array(200_000), label: "test" };
});
});

const logs = (await engineStub.readLogs()) as EngineLogs;
expect(
logs.logs.some((val) => val.event === InstanceEvent.WORKFLOW_SUCCESS)
).toBe(true);
expect(
logs.logs.some((val) => val.event === InstanceEvent.WORKFLOW_FAILURE)
).toBe(false);
});

describe("step limits", () => {
it("should enforce step limit when exceeded", async ({ expect }) => {
const stepLimit = 3;
Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
"esbuild": "catalog:default",
"miniflare": "workspace:*",
"path-to-regexp": "6.3.0",
"rosie-skills": "^0.7.6",
"unenv": "2.0.0-rc.24",
"workerd": "1.20260529.1"
},
Expand Down Expand Up @@ -150,6 +149,7 @@
"qr": "^0.6.0",
"recast": "0.23.11",
"resolve": "^1.22.8",
"rosie-skills": "^0.8.1",
"semiver": "^1.1.0",
"shell-quote": "^1.8.1",
"signal-exit": "catalog:default",
Expand Down
4 changes: 0 additions & 4 deletions packages/wrangler/scripts/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ export const EXTERNAL_DEPENDENCIES = [

// workerd contains a native binary, so must be external. Wrangler depends on a pinned version.
"workerd",

// rosie-skills contains inlined WASM that is loaded at runtime via import.meta.url-relative
// path resolution, so it cannot be bundled.
"rosie-skills",
];

/**
Expand Down
8 changes: 6 additions & 2 deletions packages/wrangler/src/__tests__/agents-skills-install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ vi.unmock("../agents-skills-install");
vi.mock("am-i-vibing");

// Mock rosie-skills to avoid real network/WASM calls.
const mockRosieInstall = vi.fn();
const mockRosieAgents = vi.fn();
// vi.hoisted() is required because vi.mock() factories are hoisted above normal
// variable declarations, so plain `const` variables would still be in the TDZ.
const { mockRosieInstall, mockRosieAgents } = vi.hoisted(() => ({
mockRosieInstall: vi.fn(),
mockRosieAgents: vi.fn(),
}));
vi.mock("rosie-skills", () => ({
install: mockRosieInstall,
agents: mockRosieAgents,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Config } from "@react-router/dev/config";
export default {
ssr: true,
future: {
v8_splitRouteModules: true,
},
} satisfies Config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { Config } from "@react-router/dev/config";
export default {
ssr: true,
future: {
v8_middleware: true,
v8_splitRouteModules: true,
},
} satisfies Config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Config } from "@react-router/dev/config";
export default {
ssr: true,
future: {
v8_middleware: false,
},
} satisfies Config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Config } from "@react-router/dev/config";
export default {
ssr: true,
future: {
v8_middleware: true,
},
} satisfies Config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { Config } from "@react-router/dev/config";
export default {
ssr: true,
} satisfies Config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
ssr: true,
future: {
v8_middleware: true,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { defineConfig } from "vite";
export default defineConfig({ plugins: [] });
Loading
Loading