diff --git a/.changeset/beige-aliens-tickle.md b/.changeset/beige-aliens-tickle.md new file mode 100644 index 000000000..cece85de5 --- /dev/null +++ b/.changeset/beige-aliens-tickle.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/cloudflare": minor +--- + +use `wrangler r2 bulk put` for R2 cache population diff --git a/packages/cloudflare/README.md b/packages/cloudflare/README.md index 9b765e0f3..cc1f5e72a 100644 --- a/packages/cloudflare/README.md +++ b/packages/cloudflare/README.md @@ -55,30 +55,3 @@ Deploy your application to production with the following: # or bun opennextjs-cloudflare build && bun opennextjs-cloudflare deploy ``` - -### Batch Cache Population (Optional, Recommended) - -For improved performance with large caches, you can enable batch upload by providing R2 credentials via .env or environment variables. - -Create a `.env` file in your project root (automatically loaded by the CLI): - -```bash -R2_ACCESS_KEY_ID=your_access_key_id -R2_SECRET_ACCESS_KEY=your_secret_access_key -CF_ACCOUNT_ID=your_account_id -``` - -You can also set the environment variables for CI builds. - -**Note:** - -You can follow documentation https://developers.cloudflare.com/r2/api/tokens/ for creating API tokens with appropriate permissions for R2 access. - -**Benefits:** - -- Significantly faster uploads for large caches using parallel transfers -- Reduced API calls to Cloudflare -- Automatically enabled when credentials are provided - -**Fallback:** -If these environment variables are not set, the CLI will use standard Wrangler uploads. Both methods work correctly - batch upload is simply faster for large caches. diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index c091177c8..4b5fc1aa9 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -55,11 +55,9 @@ "@ast-grep/napi": "0.40.0", "@dotenvx/dotenvx": "catalog:", "@opennextjs/aws": "3.8.5", - "@types/rclone.js": "^0.6.3", "cloudflare": "^4.4.1", "enquirer": "^2.4.1", "glob": "catalog:", - "rclone.js": "^0.6.6", "ts-tqdm": "^0.8.6", "yargs": "catalog:" }, diff --git a/packages/cloudflare/src/api/cloudflare-context.ts b/packages/cloudflare/src/api/cloudflare-context.ts index f9d0106a9..fbdc111fe 100644 --- a/packages/cloudflare/src/api/cloudflare-context.ts +++ b/packages/cloudflare/src/api/cloudflare-context.ts @@ -79,13 +79,8 @@ declare global { CF_PREVIEW_DOMAIN?: string; // Should have the `Workers Scripts:Read` permission CF_WORKERS_SCRIPTS_API_TOKEN?: string; - - // Cloudflare account id - needed for skew protection and R2 batch population + // Cloudflare account id - needed for skew protection CF_ACCOUNT_ID?: string; - - // R2 API credentials for batch cache population (optional, enables faster uploads) - R2_ACCESS_KEY_ID?: string; - R2_SECRET_ACCESS_KEY?: string; } } diff --git a/packages/cloudflare/src/cli/commands/populate-cache.spec.ts b/packages/cloudflare/src/cli/commands/populate-cache.spec.ts index 6743d5bc5..a9ffdc078 100644 --- a/packages/cloudflare/src/cli/commands/populate-cache.spec.ts +++ b/packages/cloudflare/src/cli/commands/populate-cache.spec.ts @@ -78,44 +78,7 @@ vi.mock("./helpers.js", () => ({ quoteShellMeta: vi.fn((s) => s), })); -// Mock rclone.js promises API to simulate successful copy operations by default -vi.mock("rclone.js", () => ({ - default: { - promises: { - copy: vi.fn(() => Promise.resolve("")), - }, - }, -})); - describe("populateCache", () => { - // Test fixtures - const createTestBuildOptions = (): BuildOptions => - ({ - outputDir: "/test/output", - }) as BuildOptions; - - const createTestOpenNextConfig = () => ({ - default: { - override: { - incrementalCache: "cf-r2-incremental-cache", - }, - }, - }); - - const createTestWranglerConfig = () => ({ - r2_buckets: [ - { - binding: "NEXT_INC_CACHE_R2_BUCKET", - bucket_name: "test-bucket", - }, - ], - }); - - const createTestPopulateCacheOptions = () => ({ - target: "local" as const, - shouldUsePreviewId: false, - }); - const setupMockFileSystem = () => { mockFs({ "/test/output": { @@ -132,153 +95,48 @@ describe("populateCache", () => { }); }; - describe("R2 incremental cache", () => { - afterEach(() => { - mockFs.restore(); - vi.unstubAllEnvs(); - }); - - test("uses sequential upload for local target (skips batch upload)", async () => { - const { runWrangler } = await import("../utils/run-wrangler.js"); - const rcloneModule = (await import("rclone.js")).default; - - setupMockFileSystem(); - vi.mocked(runWrangler).mockClear(); - vi.mocked(rcloneModule.promises.copy).mockClear(); - - // Test with local target - should skip batch upload even with credentials - await populateCache( - createTestBuildOptions(), - createTestOpenNextConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - createTestWranglerConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - { target: "local" as const, shouldUsePreviewId: false }, - { - R2_ACCESS_KEY_ID: "test_access_key", - R2_SECRET_ACCESS_KEY: "test_secret_key", - CF_ACCOUNT_ID: "test_account_id", - } as any // eslint-disable-line @typescript-eslint/no-explicit-any - ); - - // Should use sequential upload (runWrangler), not batch upload (rclone.js) - expect(runWrangler).toHaveBeenCalled(); - expect(rcloneModule.promises.copy).not.toHaveBeenCalled(); - }); - - test("uses sequential upload when R2 credentials are not provided", async () => { - const { runWrangler } = await import("../utils/run-wrangler.js"); - const rcloneModule = (await import("rclone.js")).default; - - setupMockFileSystem(); - vi.mocked(runWrangler).mockClear(); - vi.mocked(rcloneModule.promises.copy).mockClear(); - - // Test uses partial types for simplicity - full config not needed - // Pass empty envVars to simulate no R2 credentials - await populateCache( - createTestBuildOptions(), - createTestOpenNextConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - createTestWranglerConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - createTestPopulateCacheOptions(), - {} as any // eslint-disable-line @typescript-eslint/no-explicit-any - ); - - expect(runWrangler).toHaveBeenCalled(); - expect(rcloneModule.promises.copy).not.toHaveBeenCalled(); - }); - - test("uses batch upload with temporary config for remote target when R2 credentials are provided", async () => { - const rcloneModule = (await import("rclone.js")).default; - - setupMockFileSystem(); - vi.mocked(rcloneModule.promises.copy).mockClear(); - - // Test uses partial types for simplicity - full config not needed - // Pass envVars with R2 credentials and remote target to enable batch upload - await populateCache( - createTestBuildOptions(), - createTestOpenNextConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - createTestWranglerConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - { target: "remote" as const, shouldUsePreviewId: false }, - { - R2_ACCESS_KEY_ID: "test_access_key", - R2_SECRET_ACCESS_KEY: "test_secret_key", - CF_ACCOUNT_ID: "test_account_id", - } as any // eslint-disable-line @typescript-eslint/no-explicit-any - ); - - // Verify batch upload was used with correct parameters and temporary config - expect(rcloneModule.promises.copy).toHaveBeenCalledWith( - expect.any(String), // staging directory - "r2:test-bucket", - expect.objectContaining({ - progress: true, - transfers: 16, - checkers: 8, - env: expect.objectContaining({ - RCLONE_CONFIG: expect.stringMatching(/rclone-config-\d+\.conf$/), - }), - }) - ); - }); - - test("handles rclone errors with status > 0 for remote target", async () => { - const { runWrangler } = await import("../utils/run-wrangler.js"); - const rcloneModule = (await import("rclone.js")).default; - - setupMockFileSystem(); - - // Mock rclone failure - Promise rejection - vi.mocked(rcloneModule.promises.copy).mockRejectedValueOnce( - new Error("rclone copy failed with exit code 7") - ); - - vi.mocked(runWrangler).mockClear(); - - // Pass envVars with R2 credentials and remote target to enable batch upload (which will fail) - await populateCache( - createTestBuildOptions(), - createTestOpenNextConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - createTestWranglerConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - { target: "remote" as const, shouldUsePreviewId: false }, - { - R2_ACCESS_KEY_ID: "test_access_key", - R2_SECRET_ACCESS_KEY: "test_secret_key", - CF_ACCOUNT_ID: "test_account_id", - } as any // eslint-disable-line @typescript-eslint/no-explicit-any - ); - - // Should fall back to sequential upload when batch upload fails - expect(runWrangler).toHaveBeenCalled(); - }); - - test("handles rclone errors with stderr output for remote target", async () => { - const { runWrangler } = await import("../utils/run-wrangler.js"); - const rcloneModule = (await import("rclone.js")).default; - - setupMockFileSystem(); - - // Mock rclone error - Promise rejection with stderr message - vi.mocked(rcloneModule.promises.copy).mockRejectedValueOnce( - new Error("ERROR : Failed to copy: AccessDenied: Access Denied (403)") - ); - - vi.mocked(runWrangler).mockClear(); - - // Pass envVars with R2 credentials and remote target to enable batch upload (which will fail) - await populateCache( - createTestBuildOptions(), - createTestOpenNextConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - createTestWranglerConfig() as any, // eslint-disable-line @typescript-eslint/no-explicit-any - { target: "remote" as const, shouldUsePreviewId: false }, - { - R2_ACCESS_KEY_ID: "test_access_key", - R2_SECRET_ACCESS_KEY: "test_secret_key", - CF_ACCOUNT_ID: "test_account_id", - } as any // eslint-disable-line @typescript-eslint/no-explicit-any - ); - - // Should fall back to standard upload when batch upload fails - expect(runWrangler).toHaveBeenCalled(); - }); - }); + describe.each([{ target: "local" as const }, { target: "remote" as const }])( + "R2 incremental cache", + ({ target }) => { + afterEach(() => { + mockFs.restore(); + }); + + test(target, async () => { + const { runWrangler } = await import("../utils/run-wrangler.js"); + + setupMockFileSystem(); + vi.mocked(runWrangler).mockClear(); + + await populateCache( + { + outputDir: "/test/output", + } as BuildOptions, + { + default: { + override: { + incrementalCache: "cf-r2-incremental-cache", + }, + }, + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + { + r2_buckets: [ + { + binding: "NEXT_INC_CACHE_R2_BUCKET", + bucket_name: "test-bucket", + }, + ], + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + { target, shouldUsePreviewId: false }, + {} as any // eslint-disable-line @typescript-eslint/no-explicit-any + ); + + expect(runWrangler).toHaveBeenCalledWith( + expect.anything(), + expect.arrayContaining(["r2 bulk put", "test-bucket"]), + expect.objectContaining({ target }) + ); + }); + } + ); }); diff --git a/packages/cloudflare/src/cli/commands/populate-cache.ts b/packages/cloudflare/src/cli/commands/populate-cache.ts index 9d50f8e59..43b6fccfb 100644 --- a/packages/cloudflare/src/cli/commands/populate-cache.ts +++ b/packages/cloudflare/src/cli/commands/populate-cache.ts @@ -1,5 +1,6 @@ -import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; +import fs from "node:fs"; +import fsp from "node:fs/promises"; +import os from "node:os"; import path from "node:path"; import type { BuildOptions } from "@opennextjs/aws/build/helper.js"; @@ -12,7 +13,6 @@ import type { } from "@opennextjs/aws/types/open-next.js"; import type { IncrementalCache, TagCache } from "@opennextjs/aws/types/overrides.js"; import { globSync } from "glob"; -import rclone from "rclone.js"; import { tqdm } from "ts-tqdm"; import type { Unstable_Config as WranglerConfig } from "wrangler"; import type yargs from "yargs"; @@ -91,7 +91,7 @@ export async function populateCache( ) { const { incrementalCache, tagCache } = config.default.override ?? {}; - if (!existsSync(buildOpts.outputDir)) { + if (!fs.existsSync(buildOpts.outputDir)) { logger.error("Unable to populate cache: Open Next build not found"); process.exit(1); } @@ -143,11 +143,12 @@ export function getCacheAssets(opts: BuildOptions): CacheAsset[] { windowsPathsNoEscape: true, }).filter((f) => f.isFile()); + const baseCacheDir = path.join(opts.outputDir, "cache"); const assets: CacheAsset[] = []; for (const file of allFiles) { const fullPath = file.fullpath(); - const relativePath = normalizePath(path.relative(path.join(opts.outputDir, "cache"), fullPath)); + const relativePath = normalizePath(path.relative(baseCacheDir, fullPath)); if (relativePath.startsWith("__fetch")) { const [__fetch, buildId, ...keyParts] = relativePath.split("/"); @@ -197,7 +198,7 @@ type PopulateCacheOptions = { /** * Chunk sizes to use when populating KV cache. Ignored for R2. * - * @default 25 for KV + * @default 25 for KV, 50 for R2 */ cacheChunkSize?: number; /** @@ -206,167 +207,6 @@ type PopulateCacheOptions = { shouldUsePreviewId: boolean; }; -/** - * Create a temporary configuration file for batch upload from environment variables - * @returns Path to the temporary config file or null if env vars not available - */ -function createTempRcloneConfig(accessKey: string, secretKey: string, accountId: string): string | null { - const tempDir = tmpdir(); - const tempConfigPath = path.join(tempDir, `rclone-config-${Date.now()}.conf`); - - const configContent = `[r2] -type = s3 -provider = Cloudflare -access_key_id = ${accessKey} -secret_access_key = ${secretKey} -endpoint = https://${accountId}.r2.cloudflarestorage.com -acl = private -`; - - /** - * 0o600 is an octal number (the 0o prefix indicates octal in JavaScript) - * that represents Unix file permissions: - * - * - 6 (owner): read (4) + write (2) = readable and writable by the file owner - * - 0 (group): no permissions for the group - * - 0 (others): no permissions for anyone else - * - * In symbolic notation, this is: rw------- - */ - writeFileSync(tempConfigPath, configContent, { mode: 0o600 }); - return tempConfigPath; -} - -/** - * Populate R2 incremental cache using batch upload for better performance - * Uses parallel transfers to significantly speed up cache population - */ -async function populateR2IncrementalCacheWithBatchUpload( - bucket: string, - prefix: string | undefined, - assets: CacheAsset[], - envVars: WorkerEnvVar -) { - const accessKey = envVars.R2_ACCESS_KEY_ID || null; - const secretKey = envVars.R2_SECRET_ACCESS_KEY || null; - const accountId = envVars.CF_ACCOUNT_ID || null; - - // Ensure all required env vars are set correctly - if (!accessKey || !secretKey || !accountId) { - throw new Error( - "Please set R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, and CF_ACCOUNT_ID environment variables to enable faster batch upload for remote R2." - ); - } - - logger.info("\nPopulating remote R2 incremental cache using batch upload..."); - - // Create temporary config from env vars - required for batch upload - const tempConfigPath = createTempRcloneConfig(accessKey, secretKey, accountId); - if (!tempConfigPath) { - throw new Error("Failed to create temporary rclone config for R2 batch upload."); - } - - const env = { - ...process.env, - RCLONE_CONFIG: tempConfigPath, - }; - - logger.info("Using batch upload with R2 credentials from environment variables"); - - // Create a staging dir in temp directory with proper key paths - const tempDir = tmpdir(); - const stagingDir = path.join(tempDir, `.r2-staging-${Date.now()}`); - - // Track success to ensure cleanup happens correctly - let success = null; - - try { - mkdirSync(stagingDir, { recursive: true }); - - for (const { fullPath, key, buildId, isFetch } of assets) { - const cacheKey = computeCacheKey(key, { - prefix, - buildId, - cacheType: isFetch ? "fetch" : "cache", - }); - const destPath = path.join(stagingDir, cacheKey); - mkdirSync(path.dirname(destPath), { recursive: true }); - copyFileSync(fullPath, destPath); - } - - // Use rclone.js to sync the R2 - const remote = `r2:${bucket}`; - - // Using rclone.js Promise-based API for the copy operation - await rclone.promises.copy(stagingDir, remote, { - progress: true, - transfers: 16, - checkers: 8, - env, - }); - - logger.info(`Successfully uploaded ${assets.length} assets to R2 using batch upload`); - success = true; - } finally { - try { - // Cleanup temporary staging directory - rmSync(stagingDir, { recursive: true, force: true }); - } catch { - console.warn(`Failed to remove temporary staging directory at ${stagingDir}`); - } - - try { - // Cleanup temporary config file - rmSync(tempConfigPath); - } catch { - console.warn(`Failed to remove temporary config at ${tempConfigPath}`); - } - } - - if (!success) { - throw new Error("R2 batch upload failed, falling back to sequential uploads..."); - } -} - -/** - * Populate R2 incremental cache using sequential Wrangler uploads - * Falls back to this method when batch upload is not available or fails - */ -async function populateR2IncrementalCacheWithSequentialUpload( - buildOpts: BuildOptions, - bucket: string, - prefix: string | undefined, - assets: CacheAsset[], - populateCacheOptions: PopulateCacheOptions -) { - logger.info("Using sequential cache uploads."); - - for (const { fullPath, key, buildId, isFetch } of tqdm(assets)) { - const cacheKey = computeCacheKey(key, { - prefix, - buildId, - cacheType: isFetch ? "fetch" : "cache", - }); - runWrangler( - buildOpts, - [ - "r2 object put", - quoteShellMeta(normalizePath(path.join(bucket, cacheKey))), - `--file ${quoteShellMeta(fullPath)}`, - ], - { - target: populateCacheOptions.target, - configPath: populateCacheOptions.wranglerConfigPath, - // R2 does not support the environment flag and results in the following error: - // Incorrect type for the 'cacheExpiry' field on 'HttpMetadata': the provided value is not of type 'date'. - environment: undefined, - logging: "error", - } - ); - } - logger.info(`Successfully populated cache with ${assets.length} assets`); -} - async function populateR2IncrementalCache( buildOpts: BuildOptions, config: WranglerConfig, @@ -375,7 +215,9 @@ async function populateR2IncrementalCache( ) { logger.info("\nPopulating R2 incremental cache..."); - const binding = config.r2_buckets.find(({ binding }) => binding === R2_CACHE_BINDING_NAME); + const binding = config.r2_buckets.find( + ({ binding }: { binding: string }) => binding === R2_CACHE_BINDING_NAME + ); if (!binding) { throw new Error(`No R2 binding ${JSON.stringify(R2_CACHE_BINDING_NAME)} found!`); } @@ -389,34 +231,37 @@ async function populateR2IncrementalCache( const assets = getCacheAssets(buildOpts); - // Force sequential upload for local target - if (populateCacheOptions.target === "local") { - logger.info("Using sequential upload for local R2 (batch upload only works with remote R2)"); - return await populateR2IncrementalCacheWithSequentialUpload( - buildOpts, - bucket, + const objectList = assets.map(({ fullPath, key, buildId, isFetch }) => ({ + key: computeCacheKey(key, { prefix, - assets, - populateCacheOptions - ); - } + buildId, + cacheType: isFetch ? "fetch" : "cache", + }), + file: fullPath, + })); - try { - // Attempt batch upload first (using rclone) - only for remote target - return await populateR2IncrementalCacheWithBatchUpload(bucket, prefix, assets, envVars); - } catch (error) { - logger.warn(`Batch upload failed: ${error instanceof Error ? error.message : error}`); - logger.info("Falling back to sequential uploads..."); + const tempDir = await fsp.mkdtemp(path.join(os.tmpdir(), "open-next-")); + const listFile = path.join(tempDir, `r2-bulk-list.json`); + fs.writeFileSync(listFile, JSON.stringify(objectList)); - // Sequential upload fallback (using Wrangler) - return await populateR2IncrementalCacheWithSequentialUpload( - buildOpts, - bucket, - prefix, - assets, - populateCacheOptions - ); - } + const concurrency = Math.max(1, populateCacheOptions.cacheChunkSize ?? 50); + + runWrangler( + buildOpts, + ["r2 bulk put", bucket, `--filename ${quoteShellMeta(listFile)}`, `--concurrency ${concurrency}`], + { + target: populateCacheOptions.target, + configPath: populateCacheOptions.wranglerConfigPath, + // R2 does not support the environment flag and results in the following error: + // Incorrect type for the 'cacheExpiry' field on 'HttpMetadata': the provided value is not of type 'date'. + environment: undefined, + logging: "error", + } + ); + + fs.rmSync(listFile, { force: true }); + + logger.info(`Successfully populated cache with ${assets.length} assets`); } async function populateKVIncrementalCache( @@ -427,7 +272,9 @@ async function populateKVIncrementalCache( ) { logger.info("\nPopulating KV incremental cache..."); - const binding = config.kv_namespaces.find(({ binding }) => binding === KV_CACHE_BINDING_NAME); + const binding = config.kv_namespaces.find( + ({ binding }: { binding: string }) => binding === KV_CACHE_BINDING_NAME + ); if (!binding) { throw new Error(`No KV binding ${JSON.stringify(KV_CACHE_BINDING_NAME)} found!`); } @@ -441,8 +288,10 @@ async function populateKVIncrementalCache( logger.info(`Inserting ${assets.length} assets to KV in chunks of ${chunkSize}`); + const tempDir = await fsp.mkdtemp(path.join(os.tmpdir(), "open-next-")); + for (const i of tqdm(Array.from({ length: totalChunks }, (_, i) => i))) { - const chunkPath = path.join(buildOpts.outputDir, "cloudflare", `cache-chunk-${i}.json`); + const chunkPath = path.join(tempDir, `cache-chunk-${i}.json`); const kvMapping = assets .slice(i * chunkSize, (i + 1) * chunkSize) @@ -452,10 +301,10 @@ async function populateKVIncrementalCache( buildId, cacheType: isFetch ? "fetch" : "cache", }), - value: readFileSync(fullPath, "utf8"), + value: fs.readFileSync(fullPath, "utf8"), })); - writeFileSync(chunkPath, JSON.stringify(kvMapping)); + fs.writeFileSync(chunkPath, JSON.stringify(kvMapping)); runWrangler( buildOpts, @@ -473,7 +322,7 @@ async function populateKVIncrementalCache( } ); - rmSync(chunkPath); + fs.rmSync(chunkPath, { force: true }); } logger.info(`Successfully populated cache with ${assets.length} assets`); @@ -486,7 +335,9 @@ function populateD1TagCache( ) { logger.info("\nCreating D1 table if necessary..."); - const binding = config.d1_databases.find(({ binding }) => binding === D1_TAG_BINDING_NAME); + const binding = config.d1_databases.find( + ({ binding }: { binding: string }) => binding === D1_TAG_BINDING_NAME + ); if (!binding) { throw new Error(`No D1 binding ${JSON.stringify(D1_TAG_BINDING_NAME)} found!`); } @@ -513,7 +364,7 @@ function populateD1TagCache( function populateStaticAssetsIncrementalCache(options: BuildOptions) { logger.info("\nPopulating Workers static assets..."); - cpSync( + fs.cpSync( path.join(options.outputDir, "cache"), path.join(options.outputDir, "assets", STATIC_ASSETS_CACHE_DIR), { recursive: true } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 271039455..d1d837f94 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -85,8 +85,8 @@ catalogs: specifier: ^2.1.1 version: 2.1.1 wrangler: - specifier: ^4.38.0 - version: 4.38.0 + specifier: ^4.49.0 + version: 4.49.0 yargs: specifier: ^18.0.0 version: 18.0.0 @@ -198,7 +198,7 @@ importers: version: 5.7.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/bugs/gh-219: dependencies: @@ -325,7 +325,7 @@ importers: version: 39.4.2(rollup@4.40.1) wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250109.0) + version: 4.49.0(@cloudflare/workers-types@4.20250109.0) examples/bugs/gh-223: dependencies: @@ -380,7 +380,7 @@ importers: version: 5.7.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250109.0) + version: 4.49.0(@cloudflare/workers-types@4.20250109.0) examples/create-next-app: dependencies: @@ -426,7 +426,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/e2e/app-pages-router: dependencies: @@ -472,7 +472,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/e2e/app-router: dependencies: @@ -518,7 +518,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/e2e/experimental: dependencies: @@ -552,7 +552,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/e2e/pages-router: dependencies: @@ -598,7 +598,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/e2e/shared: dependencies: @@ -657,7 +657,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/next-partial-prerendering: dependencies: @@ -718,7 +718,7 @@ importers: version: 5.5.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/overrides/d1-tag-next: dependencies: @@ -752,7 +752,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/overrides/kv-tag-next: dependencies: @@ -786,7 +786,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/overrides/memory-queue: dependencies: @@ -820,7 +820,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/overrides/r2-incremental-cache: dependencies: @@ -854,7 +854,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/overrides/static-assets-incremental-cache: dependencies: @@ -888,7 +888,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/playground14: dependencies: @@ -913,7 +913,7 @@ importers: version: 22.2.0 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/playground15: dependencies: @@ -938,7 +938,7 @@ importers: version: 22.2.0 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/prisma: dependencies: @@ -978,7 +978,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/ssg-app: dependencies: @@ -1012,7 +1012,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) examples/vercel-blog-starter: dependencies: @@ -1067,7 +1067,7 @@ importers: version: 5.9.3 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) packages/cloudflare: dependencies: @@ -1080,9 +1080,6 @@ importers: '@opennextjs/aws': specifier: 3.8.5 version: 3.8.5 - '@types/rclone.js': - specifier: ^0.6.3 - version: 0.6.3 cloudflare: specifier: ^4.4.1 version: 4.4.1 @@ -1092,15 +1089,12 @@ importers: glob: specifier: 'catalog:' version: 12.0.0 - rclone.js: - specifier: ^0.6.6 - version: 0.6.6 ts-tqdm: specifier: ^0.8.6 version: 0.8.6 wrangler: specifier: 'catalog:' - version: 4.38.0(@cloudflare/workers-types@4.20250924.0) + version: 4.49.0(@cloudflare/workers-types@4.20250924.0) yargs: specifier: 'catalog:' version: 18.0.0 @@ -1824,41 +1818,41 @@ packages: resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} engines: {node: '>=18.0.0'} - '@cloudflare/unenv-preset@2.7.4': - resolution: {integrity: sha512-KIjbu/Dt50zseJIoOOK5y4eYpSojD9+xxkePYVK1Rg9k/p/st4YyMtz1Clju/zrenJHrOH+AAcjNArOPMwH4Bw==} + '@cloudflare/unenv-preset@2.7.10': + resolution: {integrity: sha512-mvsNAiJSduC/9yxv1ZpCxwgAXgcuoDvkl8yaHjxoLpFxXy2ugc6TZK20EKgv4yO0vZhAEKwqJm+eGOzf8Oc45w==} peerDependencies: - unenv: 2.0.0-rc.21 - workerd: ^1.20250912.0 + unenv: 2.0.0-rc.24 + workerd: ^1.20251106.1 peerDependenciesMeta: workerd: optional: true - '@cloudflare/workerd-darwin-64@1.20250917.0': - resolution: {integrity: sha512-0kL/kFnKUSycoo7b3PgM0nRyZ+1MGQAKaXtE6a2+SAeUkZ2FLnuFWmASi0s4rlWGsf/rlTw4AwXROePir9dUcQ==} + '@cloudflare/workerd-darwin-64@1.20251113.0': + resolution: {integrity: sha512-GBlun9onB69rDMZIJ9TdvQ9d3KS5L2FXwlzJ9+AjrbHqYnIif8eH5wyLPIR5wfkXNyrEFiWtEYses+aUQZQLWQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20250917.0': - resolution: {integrity: sha512-3/N1QmEJsC8Byxt1SGgVp5o0r+eKjuUEMbIL2yzLk/jrMdErPXy/DGf/tXZoACU68a/gMEbbT1itkYrm85iQHg==} + '@cloudflare/workerd-darwin-arm64@1.20251113.0': + resolution: {integrity: sha512-CFakh0Plmkwe8BHuc3iQ0rSIMttvJ3XpWYPjhWUL6KxA2zL6FvYUiWG0hpaEW60KPqgFMisBoPzH0kzyzSKMhg==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20250917.0': - resolution: {integrity: sha512-E7sEow7CErbWY3olMmlbj6iss9r7Xb2uMyc+MKzYC9/J6yFlJd/dNHvjey9QIdxzbkC9qGe90a+KxQrjs+fspA==} + '@cloudflare/workerd-linux-64@1.20251113.0': + resolution: {integrity: sha512-6JqK+Csie47656Kr+48GHl8v1zK940ruOczY4Da67xvsUAsFkUEOQkes4rW5i3I3XjNbcnyf96l0gnI6lzTKlQ==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20250917.0': - resolution: {integrity: sha512-roOnRjxut2FUxo6HA9spbfs32naXAsnSQqsgku3iq6BYKv1QqGiFoY5bReK72N5uxmhxo7+RiTo8ZEkxA/vMIQ==} + '@cloudflare/workerd-linux-arm64@1.20251113.0': + resolution: {integrity: sha512-Ye9I2AeXZ2IPcWOYD9xIrjcFrnH0UkS/ijvgI81mJCr8w7dMd4ONb+BK5oXUJtBW8IEAV3yRU7Mz7DBLaXe/AQ==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20250917.0': - resolution: {integrity: sha512-gslh6Ou9+kshHjR1BJX47OsbPw3/cZCvGDompvaW/URCgr7aMzljbgmBb7p0uhwGy1qCXcIt31St6pd3IEcLng==} + '@cloudflare/workerd-windows-64@1.20251113.0': + resolution: {integrity: sha512-H2sq6H2sMhjt/72S3ZAsZV+GC3chRJkwwGq7AGVjIehR66e/z5KKhxOX8u29iqtShyERvFUVHyfCzRBKfmJwfw==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -5021,9 +5015,6 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/rclone.js@0.6.3': - resolution: {integrity: sha512-BssKAAVRY//fxGKso8SatyOwiD7X0toDofNnVxZlIXmN7UHrn2UBTxldNAjgUvWA91qJyeEPfKmeJpZVhLugXg==} - '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} @@ -5327,10 +5318,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - adm-zip@0.5.16: - resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} - engines: {node: '>=12.0'} - agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -5928,9 +5915,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -6690,9 +6674,6 @@ packages: resolution: {integrity: sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==} engines: {node: '>= 18'} - exsolve@1.0.7: - resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} - extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -7843,8 +7824,8 @@ packages: resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} hasBin: true - miniflare@4.20250917.0: - resolution: {integrity: sha512-A7kYEc/Y6ohiiTji4W/qGJj3aJNc/9IMj/6wLy2phD/iMjcoY8t35654gR5mHbMx0AgUolDdr3HOsHB0cYBf+Q==} + miniflare@4.20251113.0: + resolution: {integrity: sha512-uaNiBJu8JQY27pcM7Q/E+hLggClmJCQji9uOOBdlZV+aJ7rk7tFnyIvjpLxYJRpryrMjm3aKNeMvE8ham01DtA==} engines: {node: '>=18.0.0'} hasBin: true @@ -8302,9 +8283,6 @@ packages: obliterator@1.6.1: resolution: {integrity: sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==} - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - oidc-token-hash@5.0.3: resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==} engines: {node: ^10.13.0 || >=12.0.0} @@ -8767,13 +8745,6 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - rclone.js@0.6.6: - resolution: {integrity: sha512-Dxh34cab/fNjFq5SSm0fYLNkGzG2cQSBy782UW9WwxJCEiVO4cGXkvaXcNlgv817dK8K8PuQ+NHUqSAMMhWujQ==} - engines: {node: '>=12'} - cpu: [arm, arm64, mips, mipsel, x32, x64] - os: [darwin, freebsd, linux, openbsd, sunos, win32] - hasBin: true - react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -9650,8 +9621,8 @@ packages: resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==} engines: {node: '>=20.18.1'} - unenv@2.0.0-rc.21: - resolution: {integrity: sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==} + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -9890,17 +9861,17 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workerd@1.20250917.0: - resolution: {integrity: sha512-0D+wWaccyYQb2Zx2DZDC77YDn9kOpkpGMCgyKgIHilghut5hBQ/adUIEseS4iuIZxBPeFSn6zFtICP0SxZ3z0g==} + workerd@1.20251113.0: + resolution: {integrity: sha512-XLQKbzzn6DndOosyCviYc0ExQVKPem5KAqvsgY+yrsJXvQnKXojIG8rtI0JQgKflHD6sHwjjg17P+q4lPvaLGQ==} engines: {node: '>=16'} hasBin: true - wrangler@4.38.0: - resolution: {integrity: sha512-ITL4VZ4KWs8LMDEttDTrAKLktwtv1NxHBd5QIqHOczvcjnAQr+GQoE6XYQws+w8jlOjDV7KyvbFqAdyRh5om3g==} - engines: {node: '>=18.0.0'} + wrangler@4.49.0: + resolution: {integrity: sha512-AptJADXtZwDiYS5b0G3kYNYnW4fsoInMBxw++eCs5wot1h0Q6B7HXNaoizD11rLGkU03Tpsh49hYqYyT5qkIvg==} + engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20250917.0 + '@cloudflare/workers-types': ^4.20251113.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -11691,25 +11662,25 @@ snapshots: dependencies: mime: 3.0.0 - '@cloudflare/unenv-preset@2.7.4(unenv@2.0.0-rc.21)(workerd@1.20250917.0)': + '@cloudflare/unenv-preset@2.7.10(unenv@2.0.0-rc.24)(workerd@1.20251113.0)': dependencies: - unenv: 2.0.0-rc.21 + unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20250917.0 + workerd: 1.20251113.0 - '@cloudflare/workerd-darwin-64@1.20250917.0': + '@cloudflare/workerd-darwin-64@1.20251113.0': optional: true - '@cloudflare/workerd-darwin-arm64@1.20250917.0': + '@cloudflare/workerd-darwin-arm64@1.20251113.0': optional: true - '@cloudflare/workerd-linux-64@1.20250917.0': + '@cloudflare/workerd-linux-64@1.20251113.0': optional: true - '@cloudflare/workerd-linux-arm64@1.20250917.0': + '@cloudflare/workerd-linux-arm64@1.20251113.0': optional: true - '@cloudflare/workerd-windows-64@1.20250917.0': + '@cloudflare/workerd-windows-64@1.20251113.0': optional: true '@cloudflare/workers-types@4.20250109.0': {} @@ -13525,8 +13496,8 @@ snapshots: '@prisma/config@6.7.0': dependencies: - esbuild: 0.25.4 - esbuild-register: 3.6.0(esbuild@0.25.4) + esbuild: 0.27.0 + esbuild-register: 3.6.0(esbuild@0.27.0) transitivePeerDependencies: - supports-color @@ -14707,10 +14678,6 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/rclone.js@0.6.3': - dependencies: - '@types/node': 20.14.10 - '@types/react-dom@18.3.0': dependencies: '@types/react': 19.0.8 @@ -15368,8 +15335,6 @@ snapshots: acorn@8.15.0: {} - adm-zip@0.5.16: {} - agent-base@6.0.2: dependencies: debug: 4.4.0 @@ -15967,8 +15932,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - defu@6.1.4: {} - delayed-stream@1.0.0: {} depd@1.1.2: {} @@ -16318,10 +16281,10 @@ snapshots: transitivePeerDependencies: - supports-color - esbuild-register@3.6.0(esbuild@0.25.4): + esbuild-register@3.6.0(esbuild@0.27.0): dependencies: debug: 4.4.0 - esbuild: 0.25.4 + esbuild: 0.27.0 transitivePeerDependencies: - supports-color @@ -17405,8 +17368,6 @@ snapshots: transitivePeerDependencies: - supports-color - exsolve@1.0.7: {} - extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -18774,7 +18735,7 @@ snapshots: mini-svg-data-uri@1.4.4: {} - miniflare@4.20250917.0: + miniflare@4.20251113.0: dependencies: '@cspotcode/source-map-support': 0.8.1 acorn: 8.14.0 @@ -18784,7 +18745,7 @@ snapshots: sharp: 0.33.5 stoppable: 1.1.0 undici: 7.14.0 - workerd: 1.20250917.0 + workerd: 1.20251113.0 ws: 8.18.0 youch: 4.1.0-beta.10 zod: 3.22.3 @@ -19287,8 +19248,6 @@ snapshots: obliterator@1.6.1: {} - ohash@2.0.11: {} - oidc-token-hash@5.0.3: {} on-finished@2.4.1: @@ -19811,11 +19770,6 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - rclone.js@0.6.6: - dependencies: - adm-zip: 0.5.16 - mri: 1.2.0 - react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 @@ -21079,13 +21033,9 @@ snapshots: undici@7.14.0: {} - unenv@2.0.0-rc.21: + unenv@2.0.0-rc.24: dependencies: - defu: 6.1.4 - exsolve: 1.0.7 - ohash: 2.0.11 pathe: 2.0.3 - ufo: 1.6.1 unified@11.0.5: dependencies: @@ -21368,24 +21318,24 @@ snapshots: word-wrap@1.2.5: {} - workerd@1.20250917.0: + workerd@1.20251113.0: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20250917.0 - '@cloudflare/workerd-darwin-arm64': 1.20250917.0 - '@cloudflare/workerd-linux-64': 1.20250917.0 - '@cloudflare/workerd-linux-arm64': 1.20250917.0 - '@cloudflare/workerd-windows-64': 1.20250917.0 + '@cloudflare/workerd-darwin-64': 1.20251113.0 + '@cloudflare/workerd-darwin-arm64': 1.20251113.0 + '@cloudflare/workerd-linux-64': 1.20251113.0 + '@cloudflare/workerd-linux-arm64': 1.20251113.0 + '@cloudflare/workerd-windows-64': 1.20251113.0 - wrangler@4.38.0(@cloudflare/workers-types@4.20250109.0): + wrangler@4.49.0(@cloudflare/workers-types@4.20250109.0): dependencies: '@cloudflare/kv-asset-handler': 0.4.0 - '@cloudflare/unenv-preset': 2.7.4(unenv@2.0.0-rc.21)(workerd@1.20250917.0) + '@cloudflare/unenv-preset': 2.7.10(unenv@2.0.0-rc.24)(workerd@1.20251113.0) blake3-wasm: 2.1.5 esbuild: 0.25.4 - miniflare: 4.20250917.0 + miniflare: 4.20251113.0 path-to-regexp: 6.3.0 - unenv: 2.0.0-rc.21 - workerd: 1.20250917.0 + unenv: 2.0.0-rc.24 + workerd: 1.20251113.0 optionalDependencies: '@cloudflare/workers-types': 4.20250109.0 fsevents: 2.3.3 @@ -21393,16 +21343,16 @@ snapshots: - bufferutil - utf-8-validate - wrangler@4.38.0(@cloudflare/workers-types@4.20250924.0): + wrangler@4.49.0(@cloudflare/workers-types@4.20250924.0): dependencies: '@cloudflare/kv-asset-handler': 0.4.0 - '@cloudflare/unenv-preset': 2.7.4(unenv@2.0.0-rc.21)(workerd@1.20250917.0) + '@cloudflare/unenv-preset': 2.7.10(unenv@2.0.0-rc.24)(workerd@1.20251113.0) blake3-wasm: 2.1.5 esbuild: 0.25.4 - miniflare: 4.20250917.0 + miniflare: 4.20251113.0 path-to-regexp: 6.3.0 - unenv: 2.0.0-rc.21 - workerd: 1.20250917.0 + unenv: 2.0.0-rc.24 + workerd: 1.20251113.0 optionalDependencies: '@cloudflare/workers-types': 4.20250924.0 fsevents: 2.3.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 76eef7173..10ac8892f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -35,7 +35,7 @@ catalog: typescript-eslint: ^8.37.0 typescript: ^5.9.3 vitest: ^2.1.1 - wrangler: ^4.38.0 + wrangler: ^4.49.0 yargs: ^18.0.0 # e2e tests