diff --git a/.github/workflows/check-starters.yml b/.github/workflows/check-starters.yml deleted file mode 100644 index da3c20cff..000000000 --- a/.github/workflows/check-starters.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Starters Checks - -on: - push: - branches: - - main - paths-ignore: - - "docs/**" - pull_request: - paths-ignore: - - "docs/**" - -jobs: - check-starters: - runs-on: ubuntu-latest - - # context(justinvdm, 2025-05-12): - # Only run this job for PRs from the same repository and pushes to main - # For security, GH won't expose secrets for fork PRs - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - - - run: | - corepack enable - pnpm install - - - name: Link latest SDK - run: pnpm link-sdk - - - name: Run checks for each starter - run: pnpm -r --filter="@redwoodjs/starter-*" check - - - name: Test dev server for each starter - run: pnpm check-starters:dev - - - name: Test building and preview server for each starter - run: pnpm check-starters:preview diff --git a/.github/workflows/playground-e2e-tests.yml b/.github/workflows/playground-e2e-tests.yml index 9ca44852d..2da5d76d7 100644 --- a/.github/workflows/playground-e2e-tests.yml +++ b/.github/workflows/playground-e2e-tests.yml @@ -6,11 +6,15 @@ on: - main paths-ignore: - "docs/**" + - ".notes/**" + - "*.md" pull_request: branches: - main paths-ignore: - "docs/**" + - ".notes/**" + - "*.md" workflow_dispatch: inputs: os: diff --git a/.github/workflows/smoke-test-starters.yml b/.github/workflows/smoke-test-starters.yml index ddc996715..857998a64 100644 --- a/.github/workflows/smoke-test-starters.yml +++ b/.github/workflows/smoke-test-starters.yml @@ -6,11 +6,15 @@ on: - main paths-ignore: - "docs/**" + - ".notes/**" + - "*.md" pull_request: branches: - main paths-ignore: - "docs/**" + - ".notes/**" + - "*.md" workflow_dispatch: inputs: starter: diff --git a/.gitignore b/.gitignore index e4a79ed9b..9df6d9767 100644 --- a/.gitignore +++ b/.gitignore @@ -187,4 +187,5 @@ smoke-test-artifacts # But we also don't want to commit the cursor rules to this repo starters/standard/.cursor/rules/* starters/standard/.pnpm-store + .cursor/rules/user diff --git a/.notes/justin/worklogs/2025-09-21-fix-esbuild-scanner-error.md b/.notes/justin/worklogs/2025-09-21-fix-esbuild-scanner-error.md new file mode 100644 index 000000000..b503f162e --- /dev/null +++ b/.notes/justin/worklogs/2025-09-21-fix-esbuild-scanner-error.md @@ -0,0 +1,290 @@ +# 2025-09-21: Fix esbuild scanner error after dependency updates + +## Problem + +After updating dependencies, particularly Vite, our custom directive scanner which uses esbuild is failing with the error: `error: Must use "outdir" when there are multiple input files`. This is happening even though we have `write: false` in our esbuild configuration, which should prevent esbuild from writing to the filesystem and thus not require an `outdir`. + +This seems to be caused by a dependency update to Vite, which in turn updated its internal esbuild version. + +## Plan + +1. Investigate recent changes in `esbuild` to see if there's a breaking change related to `bundle`, `entryPoints`, `write: false`, and `outdir`. +2. Examine how we're using `esbuild` in `runDirectivesScan.mts` and if our usage is still valid. +3. Apply a fix to the scanner. + +## Investigation: esbuild version change + +Checked Vite's dependencies: +- Vite `7.1.5` depends on `esbuild: ^0.23.0`. +- Vite `7.1.6` depends on `esbuild: ^0.24.0`. + +This confirms an upgrade of `esbuild` from `0.23.x` to `0.24.x`. + +A search of the `esbuild` changelog for version `0.24.0` revealed a breaking change: + +> The `write: false` setting is now an error when used with multiple entry points and `bundle: true` unless you are also using `outdir`. Previously this combination of settings would silently throw away all but one of the output files. This was a bug. The fix is to use `outdir` when you have multiple entry points. + +This is exactly the situation in our scanner. It uses multiple entry points with `bundle: true` and `write: false`. + +## Solution + +The fix is to provide an `outdir` to the `esbuild.build` call in `runDirectivesScan.mts`. Since `write: false` is set, no files will actually be written to disk. The `outdir` is used by esbuild to structure the in-memory output. A temporary directory will be used. + +I will add an `outdir` to the esbuild configuration. + + +## Follow-up Issue + +After applying the fix, a new error appeared: + +``` +error: The entry point "/Users/justin/rw/worktrees/sdk_renovate-starter-peer-deps/playground/hello-world/virtual:cloudflare/worker-entry" cannot be marked as external +``` + +This suggests that the scanner is now encountering a virtual module (`virtual:cloudflare/worker-entry`) and trying to mark it as external, but esbuild doesn't allow virtual modules to be external. This might be related to the Cloudflare Vite plugin update in the dependency changes. + +Need to investigate how to handle virtual modules in the scanner's esbuild configuration. + +## Additional Fix + +The issue is that the scanner is receiving virtual modules (like `virtual:cloudflare/worker-entry`) as entry points from the Vite configuration. Virtual modules cannot be resolved to absolute file paths and cannot be marked as external in esbuild. + +The solution is to filter out virtual modules from the entry points before passing them to esbuild, since virtual modules don't contain actual source code that can be scanned for directives anyway. + +Applied fix: Added a filter to remove any entry that contains `virtual:` before processing the entries for the esbuild scan. + +## CI Type Compatibility Issue + +After fixing the scanner issues, CI is now failing with TypeScript errors related to Vite type incompatibilities. The error shows that the SDK (compiled against Vite `7.1.5`) has incompatible types with the starters using Vite `7.1.6`. + +Key incompatibilities: +- `BuilderOptions` and `ViteBuilder` types +- `BuildEnvironment` and plugin interfaces +- `HotUpdateOptions` and `WebSocketServer` types + +This suggests that Vite `7.1.6` introduced breaking changes to its TypeScript interfaces. The SDK needs to be updated to handle these type changes or the dependency versions need to be aligned. + +## Investigation: Vite Type Compatibility + +Analyzed the CI error and identified the specific type incompatibilities: + +1. **HotUpdateOptions interface**: The `hotUpdate` method in `miniflareHMRPlugin.mts` was using an untyped parameter, causing conflicts between Vite versions. +2. **ViteBuilder interface**: The `buildApp` method in `configPlugin.mts` was using an untyped parameter. +3. **WebSocketServer interface**: The error shows that `ctx.server.ws` is missing the `[isWebSocketServer]` property in the newer version. + +## Type Compatibility Fixes + +Applied the following fixes to resolve the type incompatibilities: + +1. **Updated miniflareHMRPlugin.mts**: + - Added `HotUpdateOptions` import from Vite + - Explicitly typed the `hotUpdate` method parameter: `async hotUpdate(ctx: HotUpdateOptions)` + +2. **Updated configPlugin.mts**: + - Added `ViteBuilder` import from Vite + - Explicitly typed the `buildApp` method parameter: `async buildApp(builder: ViteBuilder)` + +These changes ensure that the plugin methods use the correct TypeScript interfaces from the current Vite version, resolving the type compatibility issues between Vite 7.1.5 and 7.1.6. + +## Replaced CI Starter Checks + +The `check-starters.yml` workflow was removed because it used workspace linking which caused version conflicts and did not accurately reflect a real user installation. + +To replace this, `npm run check` is now integrated into the E2E and smoke test environments, ensuring that type checking is performed in a clean, isolated tarball-based environment that better simulates a real user installation. + +## Document Component Type Investigation + +Initially attempted to fix Document component type issues by changing from `React.FC<{ children: React.ReactNode }>` to `DocumentProps`. However, this approach was incorrect - the Document components should maintain their simple signature as they are user-controlled templates that only need to render children. + +The Document component changes were reverted to maintain the original, correct type signature across all starters and playground examples. + +## Broken Symlinks in Tarball Installation + +After fixing the Document component types, the CI tests were still failing with `Cannot find module` errors for `typescript`. + +An investigation revealed that the issue was caused by broken symbolic links in the `node_modules` directory of the temporary test environments. The monorepo uses `pnpm`, which creates symlinked `node_modules`. The E2E test setup was copying these directories, including the now-broken symlinks, into the temporary test environment. + +When `npm install` was run in the temporary directory, it failed to correctly resolve dependencies due to the presence of these broken symlinks. + +The fix, confirmed by manual testing, is to remove the existing `node_modules` directory and any lock files (`pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`) from the temporary directory before running `npm install`. This ensures a clean, fresh installation without interference from the pre-existing broken symlinks. + +## Code Deduplication and Refactoring + +Identified significant code duplication between smoke tests and tarball setup for copying projects to temporary directories. Both were implementing similar logic for: +- Copying project files while excluding `node_modules` +- Respecting `.gitignore` patterns +- Installing dependencies +- Replacing workspace dependencies + +Refactored to create a shared `copyProjectToTempDir` function in `environment.mts` that handles both use cases: +- Extended the function to support both 'smoke' and 'tarball' test types +- Added tarball-specific configuration (frozen lockfile settings) +- Added `installTarballDependencies` function for tarball installation +- Simplified `setupTarballEnvironment` to use the shared function + +This eliminates code duplication and ensures both smoke tests and E2E tests use the same reliable file copying and dependency installation logic, including proper `.gitignore` respect and cross-platform compatibility via `fs-extra`. + +## Redundant Type Checks + +The explicit `npm run check` calls were removed from the E2E and smoke test infrastructure. It was discovered that these checks were redundant. The `npm run generate` command, which is a necessary step in both testing setups to generate application types, already includes a type-checking step. + +Running the type check separately was problematic because it would run before the necessary types had been generated. Relying on the `generate` script's built-in type check ensures that types are checked at the correct point in the process, resolving the CI failures. + +## `vite-plugin-cloudflare` Build Process Conflict + +After fixing the scanner and type issues, a series of build failures pointed to a deep incompatibility between our multi-pass build process and recent changes in `@cloudflare/vite-plugin` (v1.13.3) and Vite/Rollup. + +### Problem + +The core issue stemmed from two conflicting requirements: + +1. **Cloudflare Plugin Requirement**: The updated `@cloudflare/vite-plugin` asserts that the main entry chunk for a worker build *must* be named `index`. To achieve this, Rollup's `input` option must be an object with an `index` key (e.g., `{ index: '...' }`). +2. **Rollup Requirement**: A recent Vite/Rollup update prohibits the use of `output.inlineDynamicImports: true` (which is essential for creating a single-file worker bundle) when the `input` option is an object. Rollup now requires a simple string input for this option. + +This created a deadlock: our build process needed to produce a single file, which required `inlineDynamicImports: true`, but the Cloudflare plugin's requirement for an `index` chunk forced an input configuration that Rollup rejected. + +### Investigation + +Analysis of the `@cloudflare/vite-plugin` playground examples revealed that the plugin is designed to manage the entire worker build configuration implicitly when a simple setup is detected. Our highly customized, multi-pass build in `buildApp.mts`, which manually configured Rollup options, was interfering with the plugin's intended operation. + +The architecture (`docs/architecture/productionBuildProcess.md`) confirms a two-pass worker build is essential: a "discovery" pass to produce an intermediate bundle and a "linker" pass to produce the final, single-file artifact. The solution needed to respect this architecture while yielding control of the Rollup configuration to the Cloudflare plugin. + +### Solution + +The solution was to stop fighting the plugin and instead adapt our build orchestrator (`buildApp.mts`) to work with it: + +1. **Remove Manual Rollup Config**: In `sdk/src/vite/configPlugin.mts`, all manual `rollupOptions` for the worker build were removed. This allows the `@cloudflare/vite-plugin` to inject its own, correct configuration for generating a single-file worker bundle with an `index` chunk. + +2. **Adapt the Linker Pass**: The linker pass in `buildApp.mts` was updated. Instead of defining its own `rollupOptions`, it now modifies the *existing* configuration that the plugin created. It re-points the `index` entry to the intermediate worker artifact from the first pass (`dist/worker/index.js`). + + ```typescript + // in buildApp.mts, during the linker pass + const workerConfig = workerEnv.config; + workerConfig.build!.emptyOutDir = false; + workerConfig.build!.rollupOptions!.input = { + index: resolve(projectRootDir, "dist", "worker", "index.js"), + }; + ``` + +This approach resolves the conflict by allowing the Cloudflare plugin to control the build process as intended, while our orchestrator hooks into the process to execute the necessary multi-pass logic. This ensures the final `worker.js` is a single, correctly transformed bundle that meets the requirements of both Rollup and the Cloudflare runtime. + +## SSR Build Failure and Reversion + +The previous fix, which involved letting the Cloudflare plugin manage the worker build, was successful. However, a follow-up build failure occurred: + +``` +[vite]: Rollup failed to resolve import ".../ssr_bridge.js" from ".../index.js". +``` + +### Investigation + +This error indicated that the linker pass could not find the `ssr_bridge.js` artifact. The root cause was an unnecessary change I had made to the SSR build configuration in `sdk/src/vite/configPlugin.mts`. + +In an earlier attempt to fix the `inlineDynamicImports` error, I had changed both the `worker` and `ssr` build inputs from an object to a string. While the `worker` build change was the source of the conflict with the Cloudflare plugin, the change to the `ssr` build was an incorrect overreach. The `ssr` environment is not processed by the Cloudflare plugin and did not have the same issue. + +My incorrect modification to the SSR config's `lib.entry` caused the `ssr_bridge.js` to be bundled in a way that the linker pass could no longer resolve. + +### Solution + +The fix was to revert the `ssr` build configuration in `sdk/src/vite/configPlugin.mts` to its original state, which uses an object for `lib.entry` to correctly name the output chunk. The `worker` build changes were kept, as they were the correct fix for the Cloudflare plugin conflict. + +This reversion ensures the SSR artifact is produced correctly, allowing the linker pass to resolve it and complete the build. + +## Directive Scan Failure in Dev Mode and Final Fix + +After resolving the build-time conflicts, a new issue appeared when running the dev server (`npm run dev`): + +``` +Error: (ssr) No module found for '/src/app/pages/user/Login.tsx' in module lookup for "use client" directive +``` + +### Investigation + +The debug logs for the directive scanner revealed the root cause: + +``` +rwsdk:vite:run-directives-scan Starting directives scan for worker environment with entries: [] +``` + +The scanner was running with no entry points. This was a regression caused by the fix for the production build. To allow the `@cloudflare/vite-plugin` to control the `build`, I had removed the `rollupOptions.input` from the worker's configuration in `sdk/src/vite/configPlugin.mts`. However, the directive scanner, which runs as part of the `dev` command, relied on this configuration to find its starting point. + +Further investigation revealed that the `config` hook in our Vite plugin was not being reliably called for the `worker` environment before the directive scan was initiated. The configuration was not yet fully resolved at the point the scanner needed it. + +### Solution + +The solution was to make the directive scanner's entry point explicit, decoupling it from the Vite environment configuration. + +1. **Modified `runDirectivesScan`**: The function was updated to accept an `entries` array as a direct parameter. +2. **Updated Call Sites**: + * In `sdk/src/vite/buildApp.mts` (for production builds), the worker entry point is read from the now-resolved config and passed to the scanner. + * In `sdk/src/vite/directiveModulesDevPlugin.mts` (for the dev server), the `workerEntryPathname` is now passed through from the main `redwoodPlugin` and then to the scanner. +3. **Cleaned up `configPlugin.mts`**: With the scanner's entry point now handled explicitly, the conditional `rollupOptions` were no longer needed and were removed. + +This way, the directive scanner always has the correct entry point, both in development and production, resolving the final issue. + +## PR Description + +### Manual Changes and Fixes + +This PR includes manual changes to address issues that arose from automated dependency updates. + +#### Vite Upgrade (`7.1.5` -> `7.1.6`) and Directive Scanner Failures + +**Problem** + +We have a custom directive scanner that discovers `"use client"` and `"use server"` files. To minimize user dependencies and ensure consistent behavior, this scanner relies on the `esbuild` binary that ships with Vite. + +The upgrade to Vite `7.1.6` introduced a breaking change via its internal `esbuild` dependency, which was updated from `^0.23.0` to `^0.24.0`. The new `esbuild` version changed its API behavior, making it an error to use `write: false` with `bundle: true` for multiple entry points without specifying an `outdir`. This caused our directive scanner to fail. A follow-up issue also occurred where the scanner failed on virtual modules provided by Vite's config. + +**Solution** + +The scanner's `esbuild` configuration was updated to be compatible with the new API. This involved two changes: +1. Adding a temporary `outdir` to the configuration. Since `write: false` is still set, no files are written to disk. +2. Adding a filter to ignore virtual modules (e.g., `virtual:cloudflare/worker-entry`) before passing entry points to `esbuild`. + +--- + +#### `@cloudflare/vite-plugin` (`1.12.4` -> `1.13.3`) and Build Process Conflict + +**Problem** + +Our production build is a multi-pass process orchestrated by `buildApp.mts`. It first builds an intermediate worker bundle, then "links" it with an SSR bridge to produce the final single-file artifact. This process must work in harmony with the Cloudflare plugin. + +The updated `@cloudflare/vite-plugin` now requires the main worker entry chunk to be named `index`. This requires a Rollup input config like `{ index: '...' }`. However, to create a single-file worker bundle, we need `inlineDynamicImports: true`, and a recent Rollup update requires this option to be used with a simple string input, not an object. This created a deadlock, preventing a successful build. + +**Solution** + +The solution was to adapt our build process to cooperate with the plugin: +1. The manual `rollupOptions` for the worker build were removed from our `configPlugin.mts`, allowing the `@cloudflare/vite-plugin` to take control and generate a valid intermediate build with an `index.js` chunk. +2. The "linker" pass in `buildApp.mts` was updated to hook into the plugin-generated configuration. It now modifies the existing config, re-pointing the `input` to the intermediate `index.js` artifact from the first pass. + +This resolves the conflict by letting the plugin manage the build while still allowing our orchestrator to perform its essential multi-pass logic. + +--- + +#### Dev Server Directive Scan Regression + +**Problem** + +The fix for the production build involved removing the manual `rollupOptions` from the worker's Vite configuration, allowing the Cloudflare plugin to manage the build. This change, while correct for production, had an unintended side-effect on the development server. The dev server failed because the directive scanner, which runs on startup, no longer had an entry point. It relied on the `rollupOptions` that had been removed, and it was executing before the full Vite configuration for the worker environment was resolved. + +**Solution** + +The dependency on the implicit Vite configuration was removed. The `runDirectivesScan` function was updated to accept an explicit `entries` parameter. This entry point is now passed directly from the main `redwoodPlugin` (for the `dev` command) and the `buildApp` function (for the `build` command), ensuring the scanner always has the correct starting point. + +--- + +#### CI Infrastructure Changes: Switching to Tarball-Based Testing + +**Problem** + +The investigation into the build failures revealed that the existing CI setup, which relied on workspace linking, was running tests against stale dependencies from the monorepo's `node_modules`. This meant the CI was not testing against the newly upgraded package versions, which hid the build and type errors. + +**Solution** + +To ensure the CI accurately validates the project against the upgraded dependencies, the test environments for both smoke tests and E2E tests were switched to use a tarball-based installation. This process involves: +1. Packing the SDK into a tarball. +2. Copying the test project (e.g., a starter or playground app) to a clean, temporary directory. +3. Installing dependencies in the isolated environment using the SDK tarball. + +This approach guarantees that tests run in a clean environment with the correct, newly-updated dependencies, accurately simulating a real user installation. As part of this change, the redundant `check-starters.yml` workflow was removed, as its type-checking coverage is now handled more reliably by the playground E2E tests. diff --git a/.notes/justin/worklogs/205-09-21-fix-esbuild-scanner-error.md b/.notes/justin/worklogs/205-09-21-fix-esbuild-scanner-error.md new file mode 100644 index 000000000..ad754749d --- /dev/null +++ b/.notes/justin/worklogs/205-09-21-fix-esbuild-scanner-error.md @@ -0,0 +1,27 @@ +Running the type check separately was problematic because it would run before the necessary types had been generated. Relying on the `generate` script's built-in type check ensures that types are checked at the correct point in the process, resolving the CI failures. + +## PR Description + +### Manual Changes and Fixes + +This PR includes manual changes to address issues that arose from the automated dependency updates. + +#### Problem + +The dependency updates, primarily to Vite and its internal esbuild version, introduced several breaking changes and revealed weaknesses in the CI process: + +1. **Build Failures**: An esbuild version bump caused a breaking change in its API, leading to build failures in the directive scanner. +2. **CI Blind Spots**: The existing CI (`check-starters.yml`) used workspace linking, which masked type inconsistencies and did not accurately simulate a real user's package installation. This allowed type errors related to Vite's updated plugin API to go undetected. +3. **Brittle Test Environments**: Attempts to improve CI by running `npm run check` in isolated environments failed. This was due to broken `pnpm` symlinks being copied into test directories, which prevented clean dependency installation. +4. **Code Duplication**: The setup logic for smoke tests and the E2E tests was heavily duplicated, making maintenance difficult. + +#### Solution + +A series of fixes and refactorings were implemented to resolve these issues and make the testing process more robust: + +1. **Build Fixes**: The esbuild scanner was updated to be compatible with the new API. A TypeScript error in an E2E test file related to `null` values was also corrected. +2. **Tarball-Based Testing**: The CI process was refactored to use tarball-based installations for E2E and smoke tests. This more accurately reflects a real user environment and successfully caught the underlying type errors. +3. **Test Environment Refactoring**: The project-copying and environment setup logic for both smoke and E2E tests were consolidated into a single, shared, cross-platform function. This new function correctly excludes `node_modules` to ensure clean dependency installs, resolving the broken symlink issue. +4. **Simplified Type Checking**: Redundant `npm run check` commands were removed from the test harnesses. The type check that runs as part of the `npm run generate` command is now the single source of truth, ensuring types are checked only after they have been correctly generated. + +These changes ensure the codebase is compatible with the updated dependencies and strengthen the CI process to prevent similar issues in the future. diff --git a/playground/hello-world/package.json b/playground/hello-world/package.json index 0877b53f7..ffdaf2f5f 100644 --- a/playground/hello-world/package.json +++ b/playground/hello-world/package.json @@ -23,19 +23,20 @@ }, "dependencies": { "rwsdk": "workspace:*", - "react": "19.2.0-canary-3fb190f7-20250908", - "react-dom": "19.2.0-canary-3fb190f7-20250908", - "react-server-dom-webpack": "19.2.0-canary-3fb190f7-20250908" + "react": "19.2.0-canary-d415fd3e-20250919", + "react-dom": "19.2.0-canary-d415fd3e-20250919", + "react-server-dom-webpack": "19.2.0-canary-d415fd3e-20250919" }, "devDependencies": { - "@cloudflare/vite-plugin": "1.12.4", - "@cloudflare/workers-types": "4.20250913.0", + "@cloudflare/vite-plugin": "1.13.3", + "@cloudflare/workers-types": "4.20250921.0", "@types/node": "22.14.0", "@types/react": "19.1.2", "@types/react-dom": "19.1.2", "typescript": "5.8.3", - "vite": "7.1.5", - "wrangler": "4.35.0" + "vite": "7.1.6", + "vitest": "^3.1.1", + "wrangler": "4.38.0" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/playground/hello-world/worker-configuration.d.ts b/playground/hello-world/worker-configuration.d.ts index e41b15fdb..996ad7147 100644 --- a/playground/hello-world/worker-configuration.d.ts +++ b/playground/hello-world/worker-configuration.d.ts @@ -1,7 +1,10 @@ /* eslint-disable */ -// Generated by Wrangler by running `wrangler types` (hash: 187132f48ddf0f604882ba8213fe386f) -// Runtime types generated with workerd@1.20250906.0 2025-08-21 nodejs_compat +// Generated by Wrangler by running `wrangler types` (hash: 6b6db21c80ba9cfeb812f12bd8b8b3e4) +// Runtime types generated with workerd@1.20250917.0 2025-08-21 nodejs_compat declare namespace Cloudflare { + interface GlobalProps { + mainModule: typeof import("./src/worker"); + } interface Env { ASSETS: Fetcher; } @@ -340,10 +343,10 @@ declare const origin: string; declare const navigator: Navigator; interface TestController { } -interface ExecutionContext { +interface ExecutionContext { waitUntil(promise: Promise): void; passThroughOnException(): void; - props: any; + readonly props: Props; } type ExportedHandlerFetchHandler = (request: Request>, env: Env, ctx: ExecutionContext) => Response | Promise; type ExportedHandlerTailHandler = (events: TraceItem[], env: Env, ctx: ExecutionContext) => void | Promise; @@ -430,9 +433,11 @@ type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "ap interface DurableObjectNamespaceGetDurableObjectOptions { locationHint?: DurableObjectLocationHint; } -interface DurableObjectState { +interface DurableObjectClass<_T extends Rpc.DurableObjectBranded | undefined = undefined> { +} +interface DurableObjectState { waitUntil(promise: Promise): void; - props: any; + readonly props: Props; readonly id: DurableObjectId; readonly storage: DurableObjectStorage; container?: Container; @@ -2569,6 +2574,17 @@ declare class MessageChannel { interface MessagePortPostMessageOptions { transfer?: any[]; } +type LoopbackForExport Rpc.EntrypointBranded) | ExportedHandler | undefined = undefined> = T extends new (...args: any[]) => Rpc.WorkerEntrypointBranded ? LoopbackServiceStub> : T extends new (...args: any[]) => Rpc.DurableObjectBranded ? LoopbackDurableObjectClass> : T extends ExportedHandler ? LoopbackServiceStub : undefined; +type LoopbackServiceStub = Fetcher & (T extends CloudflareWorkersModule.WorkerEntrypoint ? (opts: { + props?: Props; +}) => Fetcher : (opts: { + props?: any; +}) => Fetcher); +type LoopbackDurableObjectClass = DurableObjectClass & (T extends CloudflareWorkersModule.DurableObject ? (opts: { + props?: Props; +}) => DurableObjectClass : (opts: { + props?: any; +}) => DurableObjectClass); interface SyncKvStorage { get(key: string): T | undefined; list(options?: SyncKvListOptions): Iterable<[ @@ -2586,6 +2602,34 @@ interface SyncKvListOptions { reverse?: boolean; limit?: number; } +interface WorkerStub { + getEntrypoint(name?: string, options?: WorkerStubEntrypointOptions): Fetcher; +} +interface WorkerStubEntrypointOptions { + props?: any; +} +interface WorkerLoader { + get(name: string, getCode: () => WorkerLoaderWorkerCode | Promise): WorkerStub; +} +interface WorkerLoaderModule { + js?: string; + cjs?: string; + text?: string; + data?: ArrayBuffer; + json?: any; + py?: string; +} +interface WorkerLoaderWorkerCode { + compatibilityDate: string; + compatibilityFlags?: string[]; + allowExperimental?: boolean; + mainModule: string; + modules: Record; + env?: any; + globalOutbound?: (Fetcher | null); + tails?: Fetcher[]; + streamingTails?: Fetcher[]; +} type AiImageClassificationInput = { image: number[]; }; @@ -6305,6 +6349,11 @@ interface D1Meta { */ sql_duration_ms: number; }; + /** + * Number of total attempts to execute the query, due to automatic retries. + * Note: All other fields in the response like `timings` only apply to the last attempt. + */ + total_attempts?: number; } interface D1Response { success: true; @@ -6322,11 +6371,11 @@ type D1SessionConstraint = // Indicates that the first query should go to the primary, and the rest queries // using the same D1DatabaseSession will go to any replica that is consistent with // the bookmark maintained by the session (returned by the first query). -"first-primary" +'first-primary' // Indicates that the first query can go anywhere (primary or replica), and the rest queries // using the same D1DatabaseSession will go to any replica that is consistent with // the bookmark maintained by the session (returned by the first query). - | "first-unconstrained"; + | 'first-unconstrained'; type D1SessionBookmark = string; declare abstract class D1Database { prepare(query: string): D1PreparedStatement; @@ -6951,8 +7000,47 @@ declare namespace Rpc { }; } declare namespace Cloudflare { + // Type of `env`. + // + // The specific project can extend `Env` by redeclaring it in project-specific files. Typescript + // will merge all declarations. + // + // You can use `wrangler types` to generate the `Env` type automatically. interface Env { } + // Project-specific parameters used to inform types. + // + // This interface is, again, intended to be declared in project-specific files, and then that + // declaration will be merged with this one. + // + // A project should have a declaration like this: + // + // interface GlobalProps { + // // Declares the main module's exports. Used to populate Cloudflare.Exports aka the type + // // of `ctx.exports`. + // mainModule: typeof import("my-main-module"); + // + // // Declares which of the main module's exports are configured with durable storage, and + // // thus should behave as Durable Object namsepace bindings. + // durableNamespaces: "MyDurableObject" | "AnotherDurableObject"; + // } + // + // You can use `wrangler types` to generate `GlobalProps` automatically. + interface GlobalProps { + } + // Evaluates to the type of a property in GlobalProps, defaulting to `Default` if it is not + // present. + type GlobalProp = K extends keyof GlobalProps ? GlobalProps[K] : Default; + // The type of the program's main module exports, if known. Requires `GlobalProps` to declare the + // `mainModule` property. + type MainModule = GlobalProp<"mainModule", {}>; + // The type of ctx.exports, which contains loopback bindings for all top-level exports. + type Exports = { + [K in keyof MainModule]: LoopbackForExport + // If the export is listed in `durableNamespaces`, then it is also a + // DurableObjectNamespace. + & (K extends GlobalProp<"durableNamespaces", never> ? MainModule[K] extends new (...args: any[]) => infer DoInstance ? DoInstance extends Rpc.DurableObjectBranded ? DurableObjectNamespace : DurableObjectNamespace : DurableObjectNamespace : {}); + }; } declare module 'cloudflare:node' { export interface DefaultHandler { @@ -6967,7 +7055,7 @@ declare module 'cloudflare:node' { port: number; }, handlers?: Omit): DefaultHandler; } -declare module 'cloudflare:workers' { +declare namespace CloudflareWorkersModule { export type RpcStub = Rpc.Stub; export const RpcStub: { new (value: T): Rpc.Stub; @@ -6976,9 +7064,9 @@ declare module 'cloudflare:workers' { [Rpc.__RPC_TARGET_BRAND]: never; } // `protected` fields don't appear in `keyof`s, so can't be accessed over RPC - export abstract class WorkerEntrypoint implements Rpc.WorkerEntrypointBranded { + export abstract class WorkerEntrypoint implements Rpc.WorkerEntrypointBranded { [Rpc.__WORKER_ENTRYPOINT_BRAND]: never; - protected ctx: ExecutionContext; + protected ctx: ExecutionContext; protected env: Env; constructor(ctx: ExecutionContext, env: Env); fetch?(request: Request): Response | Promise; @@ -6988,9 +7076,9 @@ declare module 'cloudflare:workers' { queue?(batch: MessageBatch): void | Promise; test?(controller: TestController): void | Promise; } - export abstract class DurableObject implements Rpc.DurableObjectBranded { + export abstract class DurableObject implements Rpc.DurableObjectBranded { [Rpc.__DURABLE_OBJECT_BRAND]: never; - protected ctx: DurableObjectState; + protected ctx: DurableObjectState; protected env: Env; constructor(ctx: DurableObjectState, env: Env); fetch?(request: Request): Response | Promise; @@ -7043,6 +7131,9 @@ declare module 'cloudflare:workers' { export function waitUntil(promise: Promise): void; export const env: Cloudflare.Env; } +declare module 'cloudflare:workers' { + export = CloudflareWorkersModule; +} interface SecretsStoreSecret { /** * Get a secret from the Secrets Store, returning a string of the secret value diff --git a/playground/render-apis/package.json b/playground/render-apis/package.json index f05ca3df6..bef79c1f5 100644 --- a/playground/render-apis/package.json +++ b/playground/render-apis/package.json @@ -23,19 +23,20 @@ }, "dependencies": { "rwsdk": "workspace:*", - "react": "19.2.0-canary-3fb190f7-20250908", - "react-dom": "19.2.0-canary-3fb190f7-20250908", - "react-server-dom-webpack": "19.2.0-canary-3fb190f7-20250908" + "react": "19.2.0-canary-d415fd3e-20250919", + "react-dom": "19.2.0-canary-d415fd3e-20250919", + "react-server-dom-webpack": "19.2.0-canary-d415fd3e-20250919" }, "devDependencies": { - "@cloudflare/vite-plugin": "1.12.4", - "@cloudflare/workers-types": "4.20250913.0", + "@cloudflare/vite-plugin": "1.13.3", + "@cloudflare/workers-types": "4.20250921.0", "@types/node": "22.14.0", "@types/react": "19.1.2", "@types/react-dom": "19.1.2", "typescript": "5.8.3", - "vite": "7.1.5", - "wrangler": "4.35.0" + "vite": "7.1.6", + "vitest": "^3.1.1", + "wrangler": "4.38.0" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/playground/useid-test/__tests__/e2e.test.mts b/playground/useid-test/__tests__/e2e.test.mts index 47102736e..b67d854b6 100644 --- a/playground/useid-test/__tests__/e2e.test.mts +++ b/playground/useid-test/__tests__/e2e.test.mts @@ -177,7 +177,9 @@ describe("useId Playground", () => { page.evaluate((element: Element) => element.textContent, el), ), ); - return statuses.every((status: string) => status.includes("Hydrated")); + return statuses.every( + (status: string | null) => status?.includes("Hydrated") ?? false, + ); }); // Get IDs after hydration diff --git a/playground/useid-test/package.json b/playground/useid-test/package.json index ac76b913f..e4a1aa9c5 100644 --- a/playground/useid-test/package.json +++ b/playground/useid-test/package.json @@ -23,19 +23,20 @@ }, "dependencies": { "rwsdk": "workspace:*", - "react": "19.2.0-canary-3fb190f7-20250908", - "react-dom": "19.2.0-canary-3fb190f7-20250908", - "react-server-dom-webpack": "19.2.0-canary-3fb190f7-20250908" + "react": "19.2.0-canary-d415fd3e-20250919", + "react-dom": "19.2.0-canary-d415fd3e-20250919", + "react-server-dom-webpack": "19.2.0-canary-d415fd3e-20250919" }, "devDependencies": { - "@cloudflare/vite-plugin": "1.12.4", - "@cloudflare/workers-types": "4.20250913.0", + "@cloudflare/vite-plugin": "1.13.3", + "@cloudflare/workers-types": "4.20250921.0", "@types/node": "22.14.0", "@types/react": "19.1.2", "@types/react-dom": "19.1.2", "typescript": "5.8.3", - "vite": "7.1.5", - "wrangler": "4.35.0" + "vite": "7.1.6", + "vitest": "^3.1.1", + "wrangler": "4.38.0" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d656dcde..00b2a7431 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 3.1.1(@types/debug@4.1.12)(@types/node@20.19.17)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) wrangler: specifier: ^4.35.0 - version: 4.35.0(@cloudflare/workers-types@4.20250913.0) + version: 4.35.0(@cloudflare/workers-types@4.20250921.0) docs: dependencies: @@ -87,24 +87,24 @@ importers: playground/hello-world: dependencies: react: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908 + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919 react-dom: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) react-server-dom-webpack: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1) rwsdk: specifier: workspace:* version: link:../../sdk devDependencies: '@cloudflare/vite-plugin': - specifier: 1.12.4 - version: 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) + specifier: 1.13.3 + version: 1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) '@cloudflare/workers-types': - specifier: 4.20250913.0 - version: 4.20250913.0 + specifier: 4.20250921.0 + version: 4.20250921.0 '@types/node': specifier: 22.14.0 version: 22.14.0 @@ -118,33 +118,36 @@ importers: specifier: 5.8.3 version: 5.8.3 vite: - specifier: 7.1.5 - version: 7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + specifier: 7.1.6 + version: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + vitest: + specifier: ^3.1.1 + version: 3.1.1(@types/debug@4.1.12)(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) wrangler: - specifier: 4.35.0 - version: 4.35.0(@cloudflare/workers-types@4.20250913.0) + specifier: 4.38.0 + version: 4.38.0(@cloudflare/workers-types@4.20250921.0) playground/render-apis: dependencies: react: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908 + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919 react-dom: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) react-server-dom-webpack: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1) rwsdk: specifier: workspace:* version: link:../../sdk devDependencies: '@cloudflare/vite-plugin': - specifier: 1.12.4 - version: 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) + specifier: 1.13.3 + version: 1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) '@cloudflare/workers-types': - specifier: 4.20250913.0 - version: 4.20250913.0 + specifier: 4.20250921.0 + version: 4.20250921.0 '@types/node': specifier: 22.14.0 version: 22.14.0 @@ -158,33 +161,36 @@ importers: specifier: 5.8.3 version: 5.8.3 vite: - specifier: 7.1.5 - version: 7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + specifier: 7.1.6 + version: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + vitest: + specifier: ^3.1.1 + version: 3.1.1(@types/debug@4.1.12)(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) wrangler: - specifier: 4.35.0 - version: 4.35.0(@cloudflare/workers-types@4.20250913.0) + specifier: 4.38.0 + version: 4.38.0(@cloudflare/workers-types@4.20250921.0) playground/useid-test: dependencies: react: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908 + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919 react-dom: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) react-server-dom-webpack: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1) rwsdk: specifier: workspace:* version: link:../../sdk devDependencies: '@cloudflare/vite-plugin': - specifier: 1.12.4 - version: 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) + specifier: 1.13.3 + version: 1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) '@cloudflare/workers-types': - specifier: 4.20250913.0 - version: 4.20250913.0 + specifier: 4.20250921.0 + version: 4.20250921.0 '@types/node': specifier: 22.14.0 version: 22.14.0 @@ -198,11 +204,14 @@ importers: specifier: 5.8.3 version: 5.8.3 vite: - specifier: 7.1.5 - version: 7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + specifier: 7.1.6 + version: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + vitest: + specifier: ^3.1.1 + version: 3.1.1(@types/debug@4.1.12)(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) wrangler: - specifier: 4.35.0 - version: 4.35.0(@cloudflare/workers-types@4.20250913.0) + specifier: 4.38.0 + version: 4.38.0(@cloudflare/workers-types@4.20250921.0) sdk: dependencies: @@ -211,7 +220,7 @@ importers: version: 0.38.5 '@cloudflare/vite-plugin': specifier: ^1.12.4 - version: 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250407.0)) + version: 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250407.0)) '@cloudflare/workers-types': specifier: ^4.20250407.0 version: 4.20250407.0 @@ -285,17 +294,17 @@ importers: specifier: ^22.8.1 version: 22.15.0 react: - specifier: 19.2.0-canary-3fb190f7-20250908 <20.0.0 - version: 19.2.0-canary-3fb190f7-20250908 + specifier: '>=19.2.0-canary-3fb190f7-20250908 <20.0.0' + version: 19.2.0-canary-d415fd3e-20250919 react-dom: - specifier: 19.2.0-canary-3fb190f7-20250908 <20.0.0 - version: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + specifier: '>=19.2.0-canary-3fb190f7-20250908 <20.0.0' + version: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) react-is: specifier: ^19.0.0 version: 19.0.0 react-server-dom-webpack: specifier: '>=19.2.0-canary-3fb190f7-20250908 <20.0.0' - version: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1) + version: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1) rsc-html-stream: specifier: ^0.0.6 version: 0.0.6 @@ -355,24 +364,24 @@ importers: starters/minimal: dependencies: react: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908 + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919 react-dom: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) react-server-dom-webpack: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1) rwsdk: specifier: 1.0.0-alpha.1-test.20250911154541 - version: 1.0.0-alpha.1-test.20250911154541(@cloudflare/vite-plugin@1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)))(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react-server-dom-webpack@19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1))(react@19.2.0-canary-3fb190f7-20250908)(typescript@5.8.3)(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) + version: 1.0.0-alpha.1-test.20250911154541(@cloudflare/vite-plugin@1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)))(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react-server-dom-webpack@19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1))(react@19.2.0-canary-d415fd3e-20250919)(typescript@5.8.3)(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) devDependencies: '@cloudflare/vite-plugin': - specifier: 1.12.4 - version: 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) + specifier: 1.13.3 + version: 1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) '@cloudflare/workers-types': - specifier: 4.20250913.0 - version: 4.20250913.0 + specifier: 4.20250921.0 + version: 4.20250921.0 '@types/node': specifier: 22.14.0 version: 22.14.0 @@ -386,11 +395,11 @@ importers: specifier: 5.8.3 version: 5.8.3 vite: - specifier: 7.1.5 - version: 7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + specifier: 7.1.6 + version: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) wrangler: - specifier: 4.35.0 - version: 4.35.0(@cloudflare/workers-types@4.20250913.0) + specifier: 4.38.0 + version: 4.38.0(@cloudflare/workers-types@4.20250921.0) starters/standard: dependencies: @@ -407,24 +416,24 @@ importers: specifier: 13.1.1 version: 13.1.1 react: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908 + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919 react-dom: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) react-server-dom-webpack: - specifier: 19.2.0-canary-3fb190f7-20250908 - version: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1) + specifier: 19.2.0-canary-d415fd3e-20250919 + version: 19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1) rwsdk: specifier: 1.0.0-alpha.1-test.20250911154541 - version: 1.0.0-alpha.1-test.20250911154541(@cloudflare/vite-plugin@1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)))(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react-server-dom-webpack@19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1))(react@19.2.0-canary-3fb190f7-20250908)(typescript@5.8.3)(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) + version: 1.0.0-alpha.1-test.20250911154541(@cloudflare/vite-plugin@1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)))(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react-server-dom-webpack@19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1))(react@19.2.0-canary-d415fd3e-20250919)(typescript@5.8.3)(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) devDependencies: '@cloudflare/vite-plugin': - specifier: 1.12.4 - version: 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) + specifier: 1.13.3 + version: 1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) '@cloudflare/workers-types': - specifier: 4.20250913.0 - version: 4.20250913.0 + specifier: 4.20250921.0 + version: 4.20250921.0 '@types/node': specifier: 22.14.0 version: 22.14.0 @@ -444,11 +453,11 @@ importers: specifier: 0.2.31 version: 0.2.31 vite: - specifier: 7.1.5 - version: 7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + specifier: 7.1.6 + version: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) wrangler: - specifier: 4.35.0 - version: 4.35.0(@cloudflare/workers-types@4.20250913.0) + specifier: 4.38.0 + version: 4.38.0(@cloudflare/workers-types@4.20250921.0) packages: @@ -778,12 +787,27 @@ packages: workerd: optional: true + '@cloudflare/unenv-preset@2.7.4': + resolution: {integrity: sha512-KIjbu/Dt50zseJIoOOK5y4eYpSojD9+xxkePYVK1Rg9k/p/st4YyMtz1Clju/zrenJHrOH+AAcjNArOPMwH4Bw==} + peerDependencies: + unenv: 2.0.0-rc.21 + workerd: ^1.20250912.0 + peerDependenciesMeta: + workerd: + optional: true + '@cloudflare/vite-plugin@1.12.4': resolution: {integrity: sha512-hyvTk/uBk5g9nUFwmjLzSyE+1/WABGulbAA6QXK1wDY5/Xxz2w59yKl2vNV2R7/+/jsHC29n0DKEA4pb/QTKPQ==} peerDependencies: vite: ^6.1.0 || ^7.0.0 wrangler: ^4.35.0 + '@cloudflare/vite-plugin@1.13.3': + resolution: {integrity: sha512-y6N5lkUON0Q+7zy8bd00bV3PXDSj3wkYLp6HUBwttfuVDRmiiV1QTxPoSSK9GAjHzNT65Pd2beepeSDIzCnjtw==} + peerDependencies: + vite: ^6.1.0 || ^7.0.0 + wrangler: ^4.38.0 + '@cloudflare/workerd-darwin-64@1.20250405.0': resolution: {integrity: sha512-K3izJ+H6S+U/fIaYwArz5J3t55D//YTWV2XBz55j67tK0CkBQwnCR6vVVM4kA39GhtknrhXrYq45g0uP0rnE+A==} engines: {node: '>=16'} @@ -796,6 +820,12 @@ packages: cpu: [x64] os: [darwin] + '@cloudflare/workerd-darwin-64@1.20250917.0': + resolution: {integrity: sha512-0kL/kFnKUSycoo7b3PgM0nRyZ+1MGQAKaXtE6a2+SAeUkZ2FLnuFWmASi0s4rlWGsf/rlTw4AwXROePir9dUcQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20250405.0': resolution: {integrity: sha512-iSYQRBGnWMamCTMqlb0Oho0T8S/y85FsggcI1S9bbHaGqkVdFA1LxLo6WOjtiDT+EYoFcAKCz13OXoFZzIufkQ==} engines: {node: '>=16'} @@ -808,6 +838,12 @@ packages: cpu: [arm64] os: [darwin] + '@cloudflare/workerd-darwin-arm64@1.20250917.0': + resolution: {integrity: sha512-3/N1QmEJsC8Byxt1SGgVp5o0r+eKjuUEMbIL2yzLk/jrMdErPXy/DGf/tXZoACU68a/gMEbbT1itkYrm85iQHg==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + '@cloudflare/workerd-linux-64@1.20250405.0': resolution: {integrity: sha512-JxU5RFe9daw1eWDAah1g/sAbOHBFx5zrmx4Rxgkji6slYO4/ZpIspd+Qm+H6PQidtaFewjA6t+VqL9qurhXfSg==} engines: {node: '>=16'} @@ -820,6 +856,12 @@ packages: cpu: [x64] os: [linux] + '@cloudflare/workerd-linux-64@1.20250917.0': + resolution: {integrity: sha512-E7sEow7CErbWY3olMmlbj6iss9r7Xb2uMyc+MKzYC9/J6yFlJd/dNHvjey9QIdxzbkC9qGe90a+KxQrjs+fspA==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + '@cloudflare/workerd-linux-arm64@1.20250405.0': resolution: {integrity: sha512-bgZMhX+tZVYS4Ck2lgJhywWeP4NG29uMyccj+FulVYdEY+p+F3wi/q47ZjVq+U90CjhcfcAuoER4i6zrsUxXmQ==} engines: {node: '>=16'} @@ -832,6 +874,12 @@ packages: cpu: [arm64] os: [linux] + '@cloudflare/workerd-linux-arm64@1.20250917.0': + resolution: {integrity: sha512-roOnRjxut2FUxo6HA9spbfs32naXAsnSQqsgku3iq6BYKv1QqGiFoY5bReK72N5uxmhxo7+RiTo8ZEkxA/vMIQ==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + '@cloudflare/workerd-windows-64@1.20250405.0': resolution: {integrity: sha512-UmXGt1p+3O84E40tSPeC9l6o03gcf1n2BKFg18R+cNlpw1mbPD0iROLMMgPXCP53EJqtQGjbXuoM5ndrkCL2ww==} engines: {node: '>=16'} @@ -844,14 +892,20 @@ packages: cpu: [x64] os: [win32] + '@cloudflare/workerd-windows-64@1.20250917.0': + resolution: {integrity: sha512-gslh6Ou9+kshHjR1BJX47OsbPw3/cZCvGDompvaW/URCgr7aMzljbgmBb7p0uhwGy1qCXcIt31St6pd3IEcLng==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + '@cloudflare/workers-types@4.20250214.0': resolution: {integrity: sha512-+M8oOFVbyXT5GeJrYLWMUGyPf5wGB4+k59PPqdedtOig7NjZ5r4S79wMdaZ/EV5IV8JPtZBSNjTKpDnNmfxjaQ==} '@cloudflare/workers-types@4.20250407.0': resolution: {integrity: sha512-M6cB247uy32VzM/P4NpRSHNNTcPgTn+s31wBV7gD14hkA07jMGBYlEcAv1LOghLNGZ5AEvYxLxQCVSvkF7HNIw==} - '@cloudflare/workers-types@4.20250913.0': - resolution: {integrity: sha512-JjrYEvRn7cyALxwoFTw3XChaQneHSJOXqz2t5iKEpNzAnC2iPQU75rtTK/gw03Jjy4SHY5aEBh/uqQePtonZlA==} + '@cloudflare/workers-types@4.20250921.0': + resolution: {integrity: sha512-+UDLgnqSYdy1gezjhlZxRAx+tOW+Za8FYxuIMa7VnpgIlQnCL8937rb0uCt/YZuIJFE2T7OK5GvFQ3HeUAkeFQ==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -4336,6 +4390,11 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + miniflare@4.20250917.0: + resolution: {integrity: sha512-A7kYEc/Y6ohiiTji4W/qGJj3aJNc/9IMj/6wLy2phD/iMjcoY8t35654gR5mHbMx0AgUolDdr3HOsHB0cYBf+Q==} + engines: {node: '>=18.0.0'} + hasBin: true + minimatch@10.0.1: resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} engines: {node: 20 || >=22} @@ -4772,10 +4831,10 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-dom@19.2.0-canary-3fb190f7-20250908: - resolution: {integrity: sha512-5uOdo4Zx6ogTJh+pFlF1QzFTVkMTRTXZbJ3m5Uio22QNOg/hv+ElksmMSo21oq208Sn2TpiobdDtB/NkxMJ1dg==} + react-dom@19.2.0-canary-d415fd3e-20250919: + resolution: {integrity: sha512-x6oMy2coDRpRxmci7mbUm8a3SbuMFKAq+4RsnkcdTx9O+9CZh/av8lOSwoNQq83to4exCR5wxBZYeBr7jloZbA==} peerDependencies: - react: 19.2.0-canary-3fb190f7-20250908 + react: 19.2.0-canary-d415fd3e-20250919 react-is@19.0.0: resolution: {integrity: sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==} @@ -4792,8 +4851,16 @@ packages: react-dom: 19.2.0-canary-3fb190f7-20250908 webpack: ^5.59.0 - react@19.2.0-canary-3fb190f7-20250908: - resolution: {integrity: sha512-2WQ3EC+CK5OQhHSTAOy3NcfzuSNAVmT4wWLdIpYLzxSBWoGcUS7rXdcPmMis7iy4sKt5STkGr431DU2drAZ90w==} + react-server-dom-webpack@19.2.0-canary-d415fd3e-20250919: + resolution: {integrity: sha512-yClFbS9ioMA+7U8mPUpM5irfGf6IkA2zpTQeVxgBnXEnaiSO+MIs5XAsojbrzd4NtAVrU5fwbIkhU/j5rdMTVg==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: 19.2.0-canary-d415fd3e-20250919 + react-dom: 19.2.0-canary-d415fd3e-20250919 + webpack: ^5.59.0 + + react@19.2.0-canary-d415fd3e-20250919: + resolution: {integrity: sha512-gNQ6vJjVZ73TiwaX9tRjGj5039lEQuGlkkncdLkA4XLsIyttTY8bmDEq1JtcQdybxsM7/WE1hgT8Xi/nk2LBrw==} engines: {node: '>=0.10.0'} read-pkg-up@7.0.1: @@ -4990,8 +5057,8 @@ packages: sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} - scheduler@0.27.0-canary-3fb190f7-20250908: - resolution: {integrity: sha512-cZnNmE8FnfR/sp6AEITkcCNP1f0zumIrMFoHA4ESUihPIdSwRN7RVlNTcE35Hu/u+9DyOWh+w2C+D+ieYZ7DNg==} + scheduler@0.27.0-canary-d415fd3e-20250919: + resolution: {integrity: sha512-0lNnfpCOaj3cae33jshLBYVKRkLY6ga5JGrSVQX9M+q5Lkoor8PTFNTLNW4s7WlDui78ntyJrOrjirwoBaCWvw==} schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} @@ -5468,6 +5535,10 @@ packages: resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} engines: {node: '>=14.0'} + undici@7.14.0: + resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==} + engines: {node: '>=20.18.1'} + undici@7.16.0: resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} engines: {node: '>=20.18.1'} @@ -5740,6 +5811,46 @@ packages: yaml: optional: true + vite@7.1.6: + resolution: {integrity: sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitefu@1.1.1: resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} peerDependencies: @@ -5845,6 +5956,11 @@ packages: engines: {node: '>=16'} hasBin: true + workerd@1.20250917.0: + resolution: {integrity: sha512-0D+wWaccyYQb2Zx2DZDC77YDn9kOpkpGMCgyKgIHilghut5hBQ/adUIEseS4iuIZxBPeFSn6zFtICP0SxZ3z0g==} + engines: {node: '>=16'} + hasBin: true + wrangler@4.35.0: resolution: {integrity: sha512-HbyXtbrh4Fi3mU8ussY85tVdQ74qpVS1vctUgaPc+bPrXBTqfDLkZ6VRtHAVF/eBhz4SFmhJtCQpN1caY2Ak8A==} engines: {node: '>=18.0.0'} @@ -5855,6 +5971,16 @@ packages: '@cloudflare/workers-types': optional: true + wrangler@4.38.0: + resolution: {integrity: sha512-ITL4VZ4KWs8LMDEttDTrAKLktwtv1NxHBd5QIqHOczvcjnAQr+GQoE6XYQws+w8jlOjDV7KyvbFqAdyRh5om3g==} + engines: {node: '>=18.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20250917.0 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -6416,9 +6542,21 @@ snapshots: optionalDependencies: workerd: 1.20250906.0 - '@cloudflare/vite-plugin@1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250407.0))': + '@cloudflare/unenv-preset@2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250917.0)': dependencies: - '@cloudflare/unenv-preset': 2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0) + unenv: 2.0.0-rc.21 + optionalDependencies: + workerd: 1.20250917.0 + + '@cloudflare/unenv-preset@2.7.4(unenv@2.0.0-rc.21)(workerd@1.20250917.0)': + dependencies: + unenv: 2.0.0-rc.21 + optionalDependencies: + workerd: 1.20250917.0 + + '@cloudflare/vite-plugin@1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250407.0))': + dependencies: + '@cloudflare/unenv-preset': 2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250917.0) '@remix-run/node-fetch-server': 0.8.0 get-port: 7.1.0 miniflare: 4.20250906.0 @@ -6433,17 +6571,17 @@ snapshots: - utf-8-validate - workerd - '@cloudflare/vite-plugin@1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0))': + '@cloudflare/vite-plugin@1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0))': dependencies: - '@cloudflare/unenv-preset': 2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0) + '@cloudflare/unenv-preset': 2.7.4(unenv@2.0.0-rc.21)(workerd@1.20250917.0) '@remix-run/node-fetch-server': 0.8.0 get-port: 7.1.0 - miniflare: 4.20250906.0 + miniflare: 4.20250917.0 picocolors: 1.1.1 tinyglobby: 0.2.15 unenv: 2.0.0-rc.21 - vite: 7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) - wrangler: 4.35.0(@cloudflare/workers-types@4.20250913.0) + vite: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + wrangler: 4.38.0(@cloudflare/workers-types@4.20250921.0) ws: 8.18.0 transitivePeerDependencies: - bufferutil @@ -6456,35 +6594,50 @@ snapshots: '@cloudflare/workerd-darwin-64@1.20250906.0': optional: true + '@cloudflare/workerd-darwin-64@1.20250917.0': + optional: true + '@cloudflare/workerd-darwin-arm64@1.20250405.0': optional: true '@cloudflare/workerd-darwin-arm64@1.20250906.0': optional: true + '@cloudflare/workerd-darwin-arm64@1.20250917.0': + optional: true + '@cloudflare/workerd-linux-64@1.20250405.0': optional: true '@cloudflare/workerd-linux-64@1.20250906.0': optional: true + '@cloudflare/workerd-linux-64@1.20250917.0': + optional: true + '@cloudflare/workerd-linux-arm64@1.20250405.0': optional: true '@cloudflare/workerd-linux-arm64@1.20250906.0': optional: true + '@cloudflare/workerd-linux-arm64@1.20250917.0': + optional: true + '@cloudflare/workerd-windows-64@1.20250405.0': optional: true '@cloudflare/workerd-windows-64@1.20250906.0': optional: true + '@cloudflare/workerd-windows-64@1.20250917.0': + optional: true + '@cloudflare/workers-types@4.20250214.0': {} '@cloudflare/workers-types@4.20250407.0': {} - '@cloudflare/workers-types@4.20250913.0': {} + '@cloudflare/workers-types@4.20250921.0': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -7775,6 +7928,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitejs/plugin-react@4.3.4(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + transitivePeerDependencies: + - supports-color + '@vitest/eslint-plugin@1.3.12(eslint@9.36.0(jiti@2.4.2))(typescript@5.8.3)(vitest@3.1.1(@types/debug@4.1.12)(@types/node@20.19.17)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))': dependencies: '@typescript-eslint/scope-manager': 8.44.0 @@ -10443,6 +10607,24 @@ snapshots: - bufferutil - utf-8-validate + miniflare@4.20250917.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + acorn: 8.14.0 + acorn-walk: 8.3.2 + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + sharp: 0.33.5 + stoppable: 1.1.0 + undici: 7.14.0 + workerd: 1.20250917.0 + ws: 8.18.0 + youch: 4.1.0-beta.10 + zod: 3.22.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + minimatch@10.0.1: dependencies: brace-expansion: 2.0.1 @@ -10886,25 +11068,34 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908): + react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919): dependencies: - react: 19.2.0-canary-3fb190f7-20250908 - scheduler: 0.27.0-canary-3fb190f7-20250908 + react: 19.2.0-canary-d415fd3e-20250919 + scheduler: 0.27.0-canary-d415fd3e-20250919 react-is@19.0.0: {} react-refresh@0.14.2: {} - react-server-dom-webpack@19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1): + react-server-dom-webpack@19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1): dependencies: acorn-loose: 8.4.0 neo-async: 2.6.2 - react: 19.2.0-canary-3fb190f7-20250908 - react-dom: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + react: 19.2.0-canary-d415fd3e-20250919 + react-dom: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) webpack: 5.97.1 webpack-sources: 3.3.3 - react@19.2.0-canary-3fb190f7-20250908: {} + react-server-dom-webpack@19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1): + dependencies: + acorn-loose: 8.4.0 + neo-async: 2.6.2 + react: 19.2.0-canary-d415fd3e-20250919 + react-dom: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) + webpack: 5.97.1 + webpack-sources: 3.3.3 + + react@19.2.0-canary-d415fd3e-20250919: {} read-pkg-up@7.0.1: dependencies: @@ -11189,17 +11380,17 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rwsdk@1.0.0-alpha.1-test.20250911154541(@cloudflare/vite-plugin@1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)))(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react-server-dom-webpack@19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1))(react@19.2.0-canary-3fb190f7-20250908)(typescript@5.8.3)(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)): + rwsdk@1.0.0-alpha.1-test.20250911154541(@cloudflare/vite-plugin@1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)))(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react-server-dom-webpack@19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1))(react@19.2.0-canary-d415fd3e-20250919)(typescript@5.8.3)(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)): dependencies: '@ast-grep/napi': 0.38.5 - '@cloudflare/vite-plugin': 1.12.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250906.0)(wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0)) - '@cloudflare/workers-types': 4.20250913.0 + '@cloudflare/vite-plugin': 1.13.3(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0))(workerd@1.20250917.0)(wrangler@4.38.0(@cloudflare/workers-types@4.20250921.0)) + '@cloudflare/workers-types': 4.20250921.0 '@puppeteer/browsers': 2.10.1 '@types/fs-extra': 11.0.4 '@types/react': 19.1.2 '@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-is': 19.0.0 - '@vitejs/plugin-react': 4.3.4(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0)) + '@vitejs/plugin-react': 4.3.4(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0)) chokidar: 3.6.0 debug: 4.4.1 enhanced-resolve: 5.18.3 @@ -11217,18 +11408,18 @@ snapshots: picocolors: 1.1.1 proper-lockfile: 4.1.2 puppeteer-core: 22.15.0 - react: 19.2.0-canary-3fb190f7-20250908 - react-dom: 19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908) + react: 19.2.0-canary-d415fd3e-20250919 + react-dom: 19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919) react-is: 19.0.0 - react-server-dom-webpack: 19.2.0-canary-3fb190f7-20250908(react-dom@19.2.0-canary-3fb190f7-20250908(react@19.2.0-canary-3fb190f7-20250908))(react@19.2.0-canary-3fb190f7-20250908)(webpack@5.97.1) + react-server-dom-webpack: 19.2.0-canary-d415fd3e-20250919(react-dom@19.2.0-canary-d415fd3e-20250919(react@19.2.0-canary-d415fd3e-20250919))(react@19.2.0-canary-d415fd3e-20250919)(webpack@5.97.1) rsc-html-stream: 0.0.6 tmp-promise: 3.0.3 ts-morph: 25.0.1 unique-names-generator: 4.7.1 vibe-rules: 0.2.31 - vite: 7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) - vite-tsconfig-paths: 5.1.4(typescript@5.8.3)(vite@7.1.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0)) - wrangler: 4.35.0(@cloudflare/workers-types@4.20250913.0) + vite: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + vite-tsconfig-paths: 5.1.4(typescript@5.8.3)(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0)) + wrangler: 4.38.0(@cloudflare/workers-types@4.20250921.0) transitivePeerDependencies: - bare-buffer - bare-url @@ -11241,7 +11432,7 @@ snapshots: sax@1.4.1: {} - scheduler@0.27.0-canary-3fb190f7-20250908: {} + scheduler@0.27.0-canary-d415fd3e-20250919: {} schema-utils@3.3.0: dependencies: @@ -11773,6 +11964,8 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 + undici@7.14.0: {} + undici@7.16.0: {} unenv@2.0.0-rc.21: @@ -12020,6 +12213,17 @@ snapshots: - supports-color - typescript + vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0)): + dependencies: + debug: 4.4.0 + globrex: 0.1.2 + tsconfck: 3.1.4(typescript@5.8.3) + optionalDependencies: + vite: 7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) + transitivePeerDependencies: + - supports-color + - typescript + vite@6.3.6(@types/node@20.19.17)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0): dependencies: esbuild: 0.25.9 @@ -12084,6 +12288,22 @@ snapshots: tsx: 4.19.4 yaml: 2.7.0 + vite@7.1.6(@types/node@22.14.0)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0): + dependencies: + esbuild: 0.25.9 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.50.1 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.14.0 + fsevents: 2.3.3 + jiti: 2.4.2 + terser: 5.44.0 + tsx: 4.19.4 + yaml: 2.7.0 + vitefu@1.1.1(vite@6.3.6(@types/node@24.3.1)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0)): optionalDependencies: vite: 6.3.6(@types/node@24.3.1)(jiti@2.4.2)(terser@5.44.0)(tsx@4.19.4)(yaml@2.7.0) @@ -12262,6 +12482,14 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20250906.0 '@cloudflare/workerd-windows-64': 1.20250906.0 + workerd@1.20250917.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 + wrangler@4.35.0(@cloudflare/workers-types@4.20250407.0): dependencies: '@cloudflare/kv-asset-handler': 0.4.0 @@ -12279,7 +12507,7 @@ snapshots: - bufferutil - utf-8-validate - wrangler@4.35.0(@cloudflare/workers-types@4.20250913.0): + wrangler@4.35.0(@cloudflare/workers-types@4.20250921.0): dependencies: '@cloudflare/kv-asset-handler': 0.4.0 '@cloudflare/unenv-preset': 2.7.3(unenv@2.0.0-rc.21)(workerd@1.20250906.0) @@ -12290,7 +12518,24 @@ snapshots: unenv: 2.0.0-rc.21 workerd: 1.20250906.0 optionalDependencies: - '@cloudflare/workers-types': 4.20250913.0 + '@cloudflare/workers-types': 4.20250921.0 + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + wrangler@4.38.0(@cloudflare/workers-types@4.20250921.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) + blake3-wasm: 2.1.5 + esbuild: 0.25.4 + miniflare: 4.20250917.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.21 + workerd: 1.20250917.0 + optionalDependencies: + '@cloudflare/workers-types': 4.20250921.0 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil diff --git a/sdk/package.json b/sdk/package.json index 12ec8b8c1..e0ae5c537 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -163,8 +163,8 @@ }, "peerDependencies": { "@cloudflare/vite-plugin": "^1.12.4", - "react": "19.2.0-canary-3fb190f7-20250908 <20.0.0", - "react-dom": "19.2.0-canary-3fb190f7-20250908 <20.0.0", + "react": ">=19.2.0-canary-3fb190f7-20250908 <20.0.0", + "react-dom": ">=19.2.0-canary-3fb190f7-20250908 <20.0.0", "react-server-dom-webpack": ">=19.2.0-canary-3fb190f7-20250908 <20.0.0", "vite": "^6.2.6 || 7.x", "wrangler": "^4.35.0" diff --git a/sdk/src/lib/e2e/environment.mts b/sdk/src/lib/e2e/environment.mts index a1d38d93e..d669b7842 100644 --- a/sdk/src/lib/e2e/environment.mts +++ b/sdk/src/lib/e2e/environment.mts @@ -1,8 +1,7 @@ import { join } from "path"; -import { setTimeout } from "node:timers/promises"; import debug from "debug"; -import { mkdirp, pathExists, copy } from "fs-extra"; -import * as fs from "fs/promises"; +import { pathExists, copy, existsSync } from "fs-extra"; +import * as fs from "node:fs"; import tmp from "tmp-promise"; import ignore from "ignore"; import { relative, basename, resolve } from "path"; @@ -11,13 +10,49 @@ import { adjectives, animals, } from "unique-names-generator"; -import { $ } from "../../lib/$.mjs"; -import { debugSync } from "../../scripts/debug-sync.mjs"; import { SmokeTestOptions, TestResources, PackageManager } from "./types.mjs"; import { createHash } from "crypto"; +import { $ } from "../../lib/$.mjs"; +import { ROOT_DIR } from "../constants.mjs"; +import path from "node:path"; +import { cpSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; const log = debug("rwsdk:e2e:environment"); +const createSdkTarball = async (): Promise<{ + tarballPath: string; + cleanupTarball: () => Promise; +}> => { + const packResult = await $({ cwd: ROOT_DIR, stdio: "pipe" })`npm pack`; + const tarballName = packResult.stdout?.trim()!; + const tarballPath = path.join(ROOT_DIR, tarballName); + + log(`๐Ÿ“ฆ Created tarball: ${tarballPath}`); + + const cleanupTarball = async () => { + if (fs.existsSync(tarballPath)) { + log(`๐Ÿงน Cleaning up tarball: ${tarballPath}`); + await fs.promises.rm(tarballPath, { force: true }); + } + }; + + return { tarballPath, cleanupTarball }; +}; + +const setTarballDependency = async ( + targetDir: string, + tarballPath: string, +): Promise => { + const filePath = join(targetDir, "package.json"); + const packageJson = await fs.promises.readFile(filePath, "utf-8"); + const packageJsonContent = JSON.parse(packageJson); + packageJsonContent.dependencies.rwsdk = `file:${tarballPath}`; + await fs.promises.writeFile( + filePath, + JSON.stringify(packageJsonContent, null, 2), + ); +}; + /** * Sets up the test environment, preparing any resources needed for testing */ @@ -61,7 +96,6 @@ export async function setupTestEnvironment( log("Project directory specified: %s", options.projectDir); const { tempDir, targetDir, workerName } = await copyProjectToTempDir( options.projectDir, - options.sync !== false, // default to true if undefined resourceUniqueKey, // Pass in the existing resourceUniqueKey options.packageManager, ); @@ -90,7 +124,6 @@ export async function setupTestEnvironment( */ export async function copyProjectToTempDir( projectDir: string, - sync: boolean = true, resourceUniqueKey: string, packageManager?: PackageManager, ): Promise<{ @@ -98,134 +131,92 @@ export async function copyProjectToTempDir( targetDir: string; workerName: string; }> { - log("Creating temporary directory for project"); - // Create a temporary directory - const tempDir = await tmp.dir({ unsafeCleanup: true }); - - // Create unique project directory name - const originalDirName = basename(projectDir); - const workerName = `${originalDirName}-smoke-test-${resourceUniqueKey}`; - const targetDir = resolve(tempDir.path, workerName); - - console.log(`Copying project from ${projectDir} to ${targetDir}`); - - // Read project's .gitignore if it exists - let ig = ignore(); - const gitignorePath = join(projectDir, ".gitignore"); - - if (await pathExists(gitignorePath)) { - log("Found .gitignore file at %s", gitignorePath); - const gitignoreContent = await fs.readFile(gitignorePath, "utf-8"); - ig = ig.add(gitignoreContent); - } else { - log("No .gitignore found, using default ignore patterns"); - // Add default ignores if no .gitignore exists - ig = ig.add( - [ - "node_modules", - ".git", - "dist", - "build", - ".DS_Store", - "coverage", - ".cache", - ".wrangler", - ".env", - ].join("\n"), - ); - } - - // Copy the project directory, respecting .gitignore - log("Starting copy process with ignored patterns"); - await copy(projectDir, targetDir, { - filter: (src) => { - // Get path relative to project directory - const relativePath = relative(projectDir, src); - if (!relativePath) return true; // Include the root directory - - // Check against ignore patterns - const result = !ig.ignores(relativePath); - return result; - }, - }); - log("Project copy completed successfully"); + const { tarballPath, cleanupTarball } = await createSdkTarball(); + try { + log("Creating temporary directory for project"); + // Create a temporary directory + const tempDir = await tmp.dir({ unsafeCleanup: true }); + + // Create unique project directory name + const originalDirName = basename(projectDir); + const workerName = `${originalDirName}-test-${resourceUniqueKey}`; + const targetDir = resolve(tempDir.path, workerName); + + console.log(`Copying project from ${projectDir} to ${targetDir}`); + + // Read project's .gitignore if it exists + let ig = ignore(); + const gitignorePath = join(projectDir, ".gitignore"); + + if (await pathExists(gitignorePath)) { + log("Found .gitignore file at %s", gitignorePath); + const gitignoreContent = await fs.promises.readFile( + gitignorePath, + "utf-8", + ); + ig = ig.add(gitignoreContent); + } else { + log("No .gitignore found, using default ignore patterns"); + // Add default ignores if no .gitignore exists + ig = ig.add( + [ + "node_modules", + ".git", + "dist", + "build", + ".DS_Store", + "coverage", + ".cache", + ".wrangler", + ".env", + ].join("\n"), + ); + } - // For yarn, create .yarnrc.yml to disable PnP and use node_modules - if (packageManager === "yarn" || packageManager === "yarn-classic") { - const yarnrcPath = join(targetDir, ".yarnrc.yml"); - await fs.writeFile(yarnrcPath, "nodeLinker: node-modules\n"); - log("Created .yarnrc.yml to disable PnP for yarn"); - } + // Copy the project directory, respecting .gitignore + log("Starting copy process with ignored patterns"); + await copy(projectDir, targetDir, { + filter: (src) => { + // Get path relative to project directory + const relativePath = relative(projectDir, src); + if (!relativePath) return true; // Include the root directory + + // Check against ignore patterns + const result = !ig.ignores(relativePath); + return result; + }, + }); + log("Project copy completed successfully"); + + // Configure temp project to not use frozen lockfile + log("โš™๏ธ Configuring temp project to not use frozen lockfile..."); + const npmrcPath = join(targetDir, ".npmrc"); + await fs.promises.writeFile(npmrcPath, "frozen-lockfile=false\n"); + + // For yarn, create .yarnrc.yml to disable PnP and use node_modules + if (packageManager === "yarn" || packageManager === "yarn-classic") { + const yarnrcPath = join(targetDir, ".yarnrc.yml"); + await fs.promises.writeFile(yarnrcPath, "nodeLinker: node-modules\n"); + log("Created .yarnrc.yml to disable PnP for yarn"); + } - // Replace workspace:* dependencies with a placeholder before installing - await replaceWorkspaceDependencies(targetDir); + await setTarballDependency(targetDir, tarballPath); - // Install dependencies in the target directory - await installDependencies(targetDir, packageManager); + // Install dependencies in the target directory + await installDependencies(targetDir, packageManager); - // Sync SDK to the temp dir if requested - if (sync) { - console.log( - `๐Ÿ”„ Syncing SDK to ${targetDir} after installing dependencies...`, + await fs.promises.appendFile( + path.join(projectDir, ".npmrc"), + "frozen-lockfile=false", ); - await debugSync({ targetDir }); - } - - return { tempDir, targetDir, workerName }; -} -/** - * Replace workspace:* dependencies with a placeholder version to allow installation - */ -async function replaceWorkspaceDependencies(targetDir: string): Promise { - const packageJsonPath = join(targetDir, "package.json"); - - try { - const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8"); - const packageJson = JSON.parse(packageJsonContent); - - let modified = false; - - // Replace workspace:* dependencies with a placeholder version - if (packageJson.dependencies) { - for (const [name, version] of Object.entries(packageJson.dependencies)) { - if (version === "workspace:*") { - packageJson.dependencies[name] = "0.0.80"; // Use latest published version as placeholder - modified = true; - log(`Replaced workspace dependency ${name} with placeholder version`); - } - } - } - - if (packageJson.devDependencies) { - for (const [name, version] of Object.entries( - packageJson.devDependencies, - )) { - if (version === "workspace:*") { - packageJson.devDependencies[name] = "0.0.80"; // Use latest published version as placeholder - modified = true; - log( - `Replaced workspace devDependency ${name} with placeholder version`, - ); - } - } - } - - if (modified) { - await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)); - log( - "Updated package.json with placeholder versions for workspace dependencies", - ); - } - } catch (error) { - log("Error replacing workspace dependencies: %O", error); - throw new Error(`Failed to replace workspace dependencies: ${error}`); + // Return the environment details + return { tempDir, targetDir, workerName }; + } finally { + await cleanupTarball(); } } -/** - * Install project dependencies using pnpm - */ async function installDependencies( targetDir: string, packageManager: PackageManager = "pnpm", @@ -238,8 +229,8 @@ async function installDependencies( const installCommand = { pnpm: ["pnpm", "install"], npm: ["npm", "install"], - yarn: ["yarn", "install", "--immutable"], - "yarn-classic": ["yarn", "install", "--immutable"], + yarn: ["yarn", "install"], + "yarn-classic": ["yarn"], }[packageManager]; // Run install command in the target directory @@ -248,6 +239,9 @@ async function installDependencies( const result = await $(command, args, { cwd: targetDir, stdio: "pipe", // Capture output + env: { + YARN_ENABLE_HARDENED_MODE: "0", + }, }); console.log("โœ… Dependencies installed successfully"); diff --git a/sdk/src/lib/e2e/tarball.mts b/sdk/src/lib/e2e/tarball.mts index f95178be5..c856a6ef1 100644 --- a/sdk/src/lib/e2e/tarball.mts +++ b/sdk/src/lib/e2e/tarball.mts @@ -1,8 +1,14 @@ import { $ } from "execa"; import fs from "node:fs"; import path from "node:path"; -import os from "node:os"; -import crypto from "node:crypto"; +import { copyProjectToTempDir } from "./environment.mjs"; +import { + uniqueNamesGenerator, + adjectives, + animals, +} from "unique-names-generator"; +import { createHash } from "crypto"; +import { ROOT_DIR } from "../constants.mjs"; const log = (message: string) => console.log(message); @@ -14,7 +20,6 @@ interface SetupTarballOptions { interface TarballEnvironment { targetDir: string; cleanup: () => Promise; - tarballPath: string; } /** @@ -99,163 +104,55 @@ export async function setupTarballEnvironment({ projectDir, packageManager = "pnpm", }: SetupTarballOptions): Promise { - // Generate unique temp directory name - const randomId = crypto.randomBytes(4).toString("hex"); - const projectName = path.basename(projectDir); - const tempDirName = `${projectName}-e2e-test-${randomId}`; - const targetDir = path.join(os.tmpdir(), tempDirName); + log(`๐Ÿš€ Setting up tarball environment for ${projectDir}`); - log(`๐Ÿ“ Creating temp directory: ${targetDir}`); + // Generate a resource unique key for this test run + const uniqueNameSuffix = uniqueNamesGenerator({ + dictionaries: [adjectives, animals], + separator: "-", + length: 2, + style: "lowerCase", + }); - // Create temp directory - await fs.promises.mkdir(targetDir, { recursive: true }); + // Create a short unique hash based on the timestamp + const hash = createHash("md5") + .update(Date.now().toString()) + .digest("hex") + .substring(0, 8); - try { - // Copy project to temp directory - log(`๐Ÿ“‹ Copying project from ${projectDir} to ${targetDir}`); - await $`cp -a ${projectDir}/. ${targetDir}/`; - - // Configure temp project to not use frozen lockfile - log(`โš™๏ธ Configuring temp project to not use frozen lockfile...`); - const npmrcPath = path.join(targetDir, ".npmrc"); - await fs.promises.writeFile(npmrcPath, "frozen-lockfile=false\n"); - - // Replace workspace:* dependencies with placeholder versions - log(`๐Ÿ”„ Replacing workspace dependencies...`); - const packageJsonPath = path.join(targetDir, "package.json"); - const packageJsonContent = await fs.promises.readFile( - packageJsonPath, - "utf8", - ); - const packageJson = JSON.parse(packageJsonContent); - - // Replace workspace:* dependencies with a placeholder version - const replaceWorkspaceDeps = (deps: Record | undefined) => { - if (!deps) return; - for (const [name, version] of Object.entries(deps)) { - if (version === "workspace:*") { - deps[name] = "0.0.80"; // Use a placeholder version that exists on npm - } - } - }; - - replaceWorkspaceDeps(packageJson.dependencies); - replaceWorkspaceDeps(packageJson.devDependencies); - replaceWorkspaceDeps(packageJson.peerDependencies); + const resourceUniqueKey = `${uniqueNameSuffix}-${hash}`; - await fs.promises.writeFile( - packageJsonPath, - JSON.stringify(packageJson, null, 2), + try { + const { tempDir, targetDir } = await copyProjectToTempDir( + projectDir, + resourceUniqueKey, + packageManager, ); - // Find SDK root directory (relative to current working directory) - const currentDir = process.cwd(); - const sdkRoot = currentDir.includes("/playground") - ? path.join(currentDir, "../sdk") - : currentDir; - - // Pack the SDK - log(`๐Ÿ“ฆ Packing SDK from ${sdkRoot}...`); - const packResult = await $({ cwd: sdkRoot })`npm pack`; - const tarballName = packResult.stdout.trim(); - const tarballPath = path.join(sdkRoot, tarballName); - - // Install the tarball in the temp project - log(`๐Ÿ’ฟ Installing tarball ${tarballName} in ${targetDir}...`); - - if (packageManager === "pnpm") { - await $({ cwd: targetDir })`pnpm add ${tarballPath}`; - } else if (packageManager === "npm") { - await $({ cwd: targetDir })`npm install ${tarballPath}`; - } else if (packageManager === "yarn") { - await $({ cwd: targetDir })`yarn add ${tarballPath}`; - } else { - throw new Error(`Unsupported package manager: ${packageManager}`); - } - // Verify installation const sdkPackageJson = JSON.parse( - await fs.promises.readFile(path.join(sdkRoot, "package.json"), "utf8"), - ); - const packageName = sdkPackageJson.name; - const installedDistPath = path.join( - targetDir, - "node_modules", - packageName, - "dist", + await fs.promises.readFile( + path.join(targetDir, "node_modules/rwsdk/package.json"), + "utf8", + ), ); + log(`โœ… Installed rwsdk version: ${sdkPackageJson.version}`); - log(`๐Ÿ” Verifying installed package contents...`); - if (!fs.existsSync(installedDistPath)) { - throw new Error( - `dist/ directory not found in installed package at ${installedDistPath}`, - ); - } - - // Compare checksums like the release script does - const originalDistPath = path.join(sdkRoot, "dist"); - if (fs.existsSync(originalDistPath)) { - const getDistChecksum = async (distPath: string) => { - const findResult = await $({ cwd: distPath })`find . -type f`; - const sortedFiles = findResult.stdout - .trim() - .split("\n") - .sort() - .join("\n"); - return crypto.createHash("md5").update(sortedFiles).digest("hex"); - }; - - const originalChecksum = await getDistChecksum(originalDistPath); - const installedChecksum = await getDistChecksum(installedDistPath); - - log(` - Original dist checksum: ${originalChecksum}`); - log(` - Installed dist checksum: ${installedChecksum}`); - - if (originalChecksum !== installedChecksum) { - throw new Error( - "File list in installed dist/ does not match original dist/", - ); - } - log(` โœ… Installed package contents match the local build`); - } - - // Copy wrangler cache from monorepo to temp directory for deployment tests + // Copy wrangler cache to improve deployment performance + const sdkRoot = ROOT_DIR; await copyWranglerCache(targetDir, sdkRoot); - // Cleanup function - const cleanup = async () => { - try { - // Remove tarball - if (fs.existsSync(tarballPath)) { - await fs.promises.unlink(tarballPath); - } - // Remove temp directory - if (fs.existsSync(targetDir)) { - await fs.promises.rm(targetDir, { recursive: true, force: true }); - } - } catch (error) { - console.warn( - `Warning: Failed to cleanup temp files: ${(error as Error).message}`, - ); - } - }; + log(`โœ… Tarball environment setup complete`); return { targetDir, - cleanup, - tarballPath, + cleanup: async () => { + log(`๐Ÿงน Cleaning up tarball environment: ${tempDir.path}`); + await tempDir.cleanup(); + }, }; } catch (error) { - // Cleanup on error - try { - if (fs.existsSync(targetDir)) { - await fs.promises.rm(targetDir, { recursive: true, force: true }); - } - } catch (cleanupError) { - console.warn( - `Warning: Failed to cleanup after error: ${(cleanupError as Error).message}`, - ); - } + // Cleanup tarball on error throw error; } } diff --git a/sdk/src/lib/e2e/testHarness.mts b/sdk/src/lib/e2e/testHarness.mts index 266cca778..25b6a95f0 100644 --- a/sdk/src/lib/e2e/testHarness.mts +++ b/sdk/src/lib/e2e/testHarness.mts @@ -19,6 +19,7 @@ import { import { launchBrowser } from "./browser.mjs"; import type { Browser, Page } from "puppeteer-core"; import { dirname, resolve } from "path"; +import { $ } from "execa"; interface PlaygroundEnvironment { projectDir: string; @@ -166,7 +167,8 @@ export function setupPlaygroundEnvironment(sourceProjectDir?: string): void { const tarballEnv = await setupTarballEnvironment({ projectDir, - packageManager: "pnpm", + packageManager: + (process.env.PACKAGE_MANAGER as "pnpm" | "npm" | "yarn") || "pnpm", }); globalPlaygroundEnv = { diff --git a/sdk/src/lib/e2e/types.mts b/sdk/src/lib/e2e/types.mts index 21dc9930d..dca0424cf 100644 --- a/sdk/src/lib/e2e/types.mts +++ b/sdk/src/lib/e2e/types.mts @@ -17,6 +17,7 @@ export interface SmokeTestOptions { realtime?: boolean; skipHmr?: boolean; skipStyleTests?: boolean; + tarballPath?: string; } /** diff --git a/sdk/src/vite/buildApp.mts b/sdk/src/vite/buildApp.mts index a600fa726..c8e3ed852 100644 --- a/sdk/src/vite/buildApp.mts +++ b/sdk/src/vite/buildApp.mts @@ -20,12 +20,14 @@ export async function buildApp({ clientFiles, serverFiles, projectRootDir, + workerEntryPathname, }: { builder: ViteBuilder; clientEntryPoints: Set; clientFiles: Set; serverFiles: Set; projectRootDir: string; + workerEntryPathname: string; }) { const workerEnv = builder.environments.worker; await runDirectivesScan({ @@ -33,6 +35,7 @@ export async function buildApp({ environments: builder.environments, clientFiles, serverFiles, + entries: [workerEntryPathname], }); console.log("Building worker to discover used client components..."); @@ -70,11 +73,15 @@ export async function buildApp({ // Re-configure the worker environment for the linking pass const workerConfig = workerEnv.config; workerConfig.build!.emptyOutDir = false; + + // context(justinvdm, 22 Sep 2025): This is a workaround to satisfy the + // Cloudflare plugin's expectation of an entry chunk named `index`. The plugin + // now manages the worker build, so we no longer set rollup options + // directly. Instead, we re-point the original entry to the intermediate + // worker bundle from the first pass. This allows the linker pass to re-use + // the same plugin-driven configuration while bundling the final worker. workerConfig.build!.rollupOptions!.input = { - worker: resolve(projectRootDir, "dist", "worker", "worker.js"), - }; - workerConfig.build!.rollupOptions!.output! = { - entryFileNames: "worker.js", + index: resolve(projectRootDir, "dist", "worker", "index.js"), }; await builder.build(workerEnv); diff --git a/sdk/src/vite/configPlugin.mts b/sdk/src/vite/configPlugin.mts index 05956724d..f2d35aabb 100644 --- a/sdk/src/vite/configPlugin.mts +++ b/sdk/src/vite/configPlugin.mts @@ -1,15 +1,12 @@ import { Plugin } from "vite"; import path, { resolve } from "node:path"; -import { InlineConfig } from "vite"; +import { InlineConfig, ViteBuilder } from "vite"; import enhancedResolve from "enhanced-resolve"; -import debug from "debug"; import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs"; import { buildApp } from "./buildApp.mjs"; import { externalModules } from "./constants.mjs"; -const log = debug("rwsdk:vite:config"); - export const configPlugin = ({ silent, projectRootDir, @@ -26,7 +23,7 @@ export const configPlugin = ({ clientEntryPoints: Set; }): Plugin => ({ name: "rwsdk:config", - config: async (_) => { + config: async (_, { command }) => { const mode = process.env.NODE_ENV; const workerConfig: InlineConfig = { @@ -69,14 +66,6 @@ export const configPlugin = ({ emitAssets: true, emptyOutDir: false, ssr: true, - rollupOptions: { - output: { - inlineDynamicImports: true, - }, - input: { - worker: workerEntryPathname, - }, - }, }, }; @@ -194,13 +183,14 @@ export const configPlugin = ({ hmr: true, }, builder: { - async buildApp(builder) { + async buildApp(builder: ViteBuilder) { await buildApp({ builder, projectRootDir, clientEntryPoints, clientFiles, serverFiles, + workerEntryPathname, }); }, }, diff --git a/sdk/src/vite/directiveModulesDevPlugin.mts b/sdk/src/vite/directiveModulesDevPlugin.mts index ebebdac97..d18dffbbc 100644 --- a/sdk/src/vite/directiveModulesDevPlugin.mts +++ b/sdk/src/vite/directiveModulesDevPlugin.mts @@ -57,10 +57,12 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, + workerEntryPathname, }: { clientFiles: Set; serverFiles: Set; projectRootDir: string; + workerEntryPathname: string; }): Plugin => { const { promise: scanPromise, resolve: resolveScanPromise } = Promise.withResolvers(); @@ -83,6 +85,7 @@ export const directiveModulesDevPlugin = ({ environments: server.environments, clientFiles, serverFiles, + entries: [workerEntryPathname], }).then(() => { // context(justinvdm, 11 Sep 2025): For vendor barrels, we write the // files directly to disk after the scan. For app barrels, we use a diff --git a/sdk/src/vite/miniflareHMRPlugin.mts b/sdk/src/vite/miniflareHMRPlugin.mts index 5c12c1b30..98078b2fd 100644 --- a/sdk/src/vite/miniflareHMRPlugin.mts +++ b/sdk/src/vite/miniflareHMRPlugin.mts @@ -1,4 +1,4 @@ -import { Plugin, EnvironmentModuleNode, Connect } from "vite"; +import { Plugin, EnvironmentModuleNode, Connect, HotUpdateOptions } from "vite"; import { resolve } from "node:path"; import colors from "picocolors"; import { readFile } from "node:fs/promises"; @@ -110,7 +110,7 @@ export const miniflareHMRPlugin = (givenOptions: { }); }; }, - async hotUpdate(ctx) { + async hotUpdate(ctx: HotUpdateOptions) { if (ctx.file.includes(".wrangler")) { return; } diff --git a/sdk/src/vite/redwoodPlugin.mts b/sdk/src/vite/redwoodPlugin.mts index 39a7b0c57..838a99bd1 100644 --- a/sdk/src/vite/redwoodPlugin.mts +++ b/sdk/src/vite/redwoodPlugin.mts @@ -1,5 +1,5 @@ import { resolve } from "node:path"; -import { InlineConfig } from "vite"; +import { InlineConfig, Plugin } from "vite"; import { unstable_readConfig } from "wrangler"; import { cloudflare } from "@cloudflare/vite-plugin"; @@ -117,6 +117,7 @@ export const redwoodPlugin = async ( clientFiles, serverFiles, projectRootDir, + workerEntryPathname, }), configPlugin({ silent: options.silent ?? false, @@ -134,10 +135,10 @@ export const redwoodPlugin = async ( reactConditionsResolverPlugin({ projectRootDir }), tsconfigPaths({ root: projectRootDir }), shouldIncludeCloudflarePlugin - ? cloudflare({ + ? (cloudflare({ viteEnvironment: { name: "worker" }, configPath: workerConfigPath, - }) + }) as Plugin[]) : [], miniflareHMRPlugin({ clientFiles, diff --git a/sdk/src/vite/runDirectivesScan.mts b/sdk/src/vite/runDirectivesScan.mts index 184fd4f2c..2fe2a43f6 100644 --- a/sdk/src/vite/runDirectivesScan.mts +++ b/sdk/src/vite/runDirectivesScan.mts @@ -7,11 +7,9 @@ import path from "node:path"; import debug from "debug"; import { getViteEsbuild } from "./getViteEsbuild.mjs"; import { normalizeModulePath } from "../lib/normalizeModulePath.mjs"; +import { INTERMEDIATES_OUTPUT_DIR } from "../lib/constants.mjs"; import { externalModules } from "./constants.mjs"; -import { - createViteAwareResolver, - mapViteResolveToEnhancedResolveOptions, -} from "./createViteAwareResolver.mjs"; +import { createViteAwareResolver } from "./createViteAwareResolver.mjs"; import resolve from "enhanced-resolve"; const log = debug("rwsdk:vite:run-directives-scan"); @@ -92,11 +90,13 @@ export const runDirectivesScan = async ({ environments, clientFiles, serverFiles, + entries: initialEntries, }: { rootConfig: ResolvedConfig; environments: Record; clientFiles: Set; serverFiles: Set; + entries: string[]; }) => { console.log("\n๐Ÿ” Scanning for 'use client' and 'use server' directives..."); @@ -105,7 +105,8 @@ export const runDirectivesScan = async ({ try { const esbuild = await getViteEsbuild(rootConfig.root); - const input = environments.worker.config.build.rollupOptions?.input; + const input = + initialEntries ?? environments.worker.config.build.rollupOptions?.input; let entries: string[]; if (Array.isArray(input)) { @@ -125,7 +126,10 @@ export const runDirectivesScan = async ({ return; } - const absoluteEntries = entries.map((entry) => + // Filter out virtual modules since they can't be scanned by esbuild + const realEntries = entries.filter((entry) => !entry.includes("virtual:")); + + const absoluteEntries = realEntries.map((entry) => path.resolve(rootConfig.root, entry), ); @@ -322,6 +326,7 @@ export const runDirectivesScan = async ({ entryPoints: absoluteEntries, bundle: true, write: false, + outdir: path.join(INTERMEDIATES_OUTPUT_DIR, "directive-scan"), platform: "node", format: "esm", logLevel: "silent", diff --git a/starters/minimal/package.json b/starters/minimal/package.json index 61e0db07e..863a6ba01 100644 --- a/starters/minimal/package.json +++ b/starters/minimal/package.json @@ -22,20 +22,20 @@ "types": "tsc" }, "dependencies": { - "react": "19.2.0-canary-3fb190f7-20250908", - "react-dom": "19.2.0-canary-3fb190f7-20250908", - "react-server-dom-webpack": "19.2.0-canary-3fb190f7-20250908", + "react": "19.2.0-canary-d415fd3e-20250919", + "react-dom": "19.2.0-canary-d415fd3e-20250919", + "react-server-dom-webpack": "19.2.0-canary-d415fd3e-20250919", "rwsdk": "1.0.0-alpha.1-test.20250911154541" }, "devDependencies": { - "@cloudflare/vite-plugin": "1.12.4", - "@cloudflare/workers-types": "4.20250913.0", + "@cloudflare/vite-plugin": "1.13.3", + "@cloudflare/workers-types": "4.20250921.0", "@types/node": "22.14.0", "@types/react": "19.1.2", "@types/react-dom": "19.1.2", "typescript": "5.8.3", - "vite": "7.1.5", - "wrangler": "4.35.0" + "vite": "7.1.6", + "wrangler": "4.38.0" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/starters/standard/package.json b/starters/standard/package.json index 27a6cd863..c58e2ca56 100644 --- a/starters/standard/package.json +++ b/starters/standard/package.json @@ -31,22 +31,22 @@ "@prisma/client": "6.8.2", "@simplewebauthn/browser": "13.1.0", "@simplewebauthn/server": "13.1.1", - "react": "19.2.0-canary-3fb190f7-20250908", - "react-dom": "19.2.0-canary-3fb190f7-20250908", - "react-server-dom-webpack": "19.2.0-canary-3fb190f7-20250908", + "react": "19.2.0-canary-d415fd3e-20250919", + "react-dom": "19.2.0-canary-d415fd3e-20250919", + "react-server-dom-webpack": "19.2.0-canary-d415fd3e-20250919", "rwsdk": "1.0.0-alpha.1-test.20250911154541" }, "devDependencies": { - "@cloudflare/vite-plugin": "1.12.4", - "@cloudflare/workers-types": "4.20250913.0", + "@cloudflare/vite-plugin": "1.13.3", + "@cloudflare/workers-types": "4.20250921.0", "@types/node": "22.14.0", "@types/react": "19.1.2", "@types/react-dom": "19.1.2", "prisma": "6.8.2", "typescript": "5.8.3", "vibe-rules": "0.2.31", - "vite": "7.1.5", - "wrangler": "4.35.0" + "vite": "7.1.6", + "wrangler": "4.38.0" }, "pnpm": { "onlyBuiltDependencies": [