11import assert from "node:assert" ;
22import path from "node:path" ;
33import { fileURLToPath } from "node:url" ;
4+ import {
5+ normalizeAndValidateConfig ,
6+ UserError ,
7+ } from "@cloudflare/workers-utils" ;
48import { Headers , Request } from "miniflare" ;
9+ import { validateNodeCompatMode } from "../deployment-bundle/node-compat" ;
510import { logger } from "../logger" ;
11+ import { getSiteAssetPaths } from "../sites" ;
612import { requireApiToken , requireAuth } from "../user" ;
713import { DevEnv } from "./startDevWorker/DevEnv" ;
814import { MultiworkerRuntimeController } from "./startDevWorker/MultiworkerRuntimeController" ;
@@ -18,9 +24,11 @@ import type {
1824 FetcherScheduledOptions ,
1925 FetcherScheduledResult ,
2026} from "@cloudflare/workers-types/experimental" ;
21- import type { RawEnvironment } from "@cloudflare/workers-utils" ;
27+ import type { Config , RawConfig } from "@cloudflare/workers-utils" ;
2228import type { DispatchFetch , RequestInfo } from "miniflare" ;
2329
30+ export type InlineConfig = Omit < RawConfig , "env" > ;
31+
2432export type WorkerInput =
2533 | {
2634 root ?: string ;
@@ -29,7 +37,7 @@ export type WorkerInput =
2937 }
3038 | {
3139 root ?: string ;
32- config : RawEnvironment ;
40+ config : InlineConfig ;
3341 } ;
3442
3543type DevServerOptions = Exclude <
@@ -92,6 +100,31 @@ function resolvePath(basePath: string, maybePath: string | URL): string {
92100 : path . resolve ( basePath , maybePath ) ;
93101}
94102
103+ function normalizeInlineWorkerConfig (
104+ config : InlineConfig ,
105+ root : string
106+ ) : Config {
107+ const configPath = path . join ( root , "wrangler.jsonc" ) ;
108+ const { config : normalizedConfig , diagnostics } = normalizeAndValidateConfig (
109+ config ,
110+ configPath ,
111+ configPath ,
112+ { }
113+ ) ;
114+
115+ if ( diagnostics . hasWarnings ( ) ) {
116+ logger . warn ( diagnostics . renderWarnings ( ) ) ;
117+ }
118+
119+ if ( diagnostics . hasErrors ( ) ) {
120+ throw new UserError ( diagnostics . renderErrors ( ) , {
121+ telemetryMessage : "create server inline config validation failed" ,
122+ } ) ;
123+ }
124+
125+ return normalizedConfig ;
126+ }
127+
95128async function resolveFetchInput (
96129 input : RequestInfo ,
97130 session : ServerSession
@@ -128,60 +161,79 @@ function resolveWorkerInputs(
128161 return options . workers . map ( ( input , index , list ) => {
129162 const isPrimaryWorker = index === 0 ;
130163 const isMultiworker = list . length > 1 ;
131- const dev : StartDevWorkerInput [ "dev" ] = {
132- auth,
133- remote : options . allowRemoteBindings ? undefined : false ,
134- server : options . server ?? { hostname : "127.0.0.1" , port : 0 } ,
135- logLevel : options . logLevel ?? "error" ,
136- watch : options . watch ?? false ,
137- persist :
138- options . persist === true ? undefined : ( options . persist ?? false ) ,
139- inspector : options . inspector ?? false ,
140- outboundService :
141- options . outboundService ??
142- ( ( request ) => {
143- return globalThis . fetch ( request . url , request ) ;
144- } ) ,
145- multiworkerPrimary : isPrimaryWorker && isMultiworker ? true : undefined ,
146- } ;
147164 const root = input . root ?? options . root ?? cwd ;
165+ const inlineConfig =
166+ "config" in input
167+ ? normalizeInlineWorkerConfig ( input . config , root )
168+ : undefined ;
148169
149- if ( "config" in input ) {
150- const config = input . config ;
151-
152- return {
153- // FIXME: to avoid dev env from auto discovering a config file and merging it with the inline config
154- config : "" ,
155- name : config . name ,
156- entrypoint : config . main ? resolvePath ( root , config . main ) : undefined ,
157- compatibilityDate : config . compatibility_date ,
158- compatibilityFlags : config . compatibility_flags ,
159- complianceRegion : config . compliance_region ,
160- bindings : convertConfigToBindings ( config , { usePreviewIds : true } ) ,
161- migrations : config . migrations ,
162- containers : config . containers ,
163- triggers : config . triggers ?. crons ?. map ( ( cron ) => ( {
164- type : "cron" ,
165- cron,
166- } ) ) ,
167- tailConsumers : config . tail_consumers ,
168- streamingTailConsumers : config . streaming_tail_consumers ,
169- assets : config . assets ?. directory ,
170- dev,
171- } ;
172- }
170+ return {
171+ // Uses an empty string to avoid dev env from auto discovering a config file and merging it with the inline config
172+ config : "configPath" in input ? resolvePath ( root , input . configPath ) : "" ,
173+ env : "configPath" in input ? input . env : undefined ,
174+ name : inlineConfig ?. name ,
175+ entrypoint : inlineConfig ?. main ,
176+ compatibilityDate : inlineConfig ?. compatibility_date ,
177+ compatibilityFlags : inlineConfig ?. compatibility_flags ,
178+ complianceRegion : inlineConfig ?. compliance_region ,
179+ pythonModules : inlineConfig ?. python_modules ,
180+ bindings : inlineConfig
181+ ? convertConfigToBindings ( inlineConfig , { usePreviewIds : true } )
182+ : undefined ,
183+ migrations : inlineConfig ?. migrations ,
184+ containers : inlineConfig ?. containers ,
185+ triggers : inlineConfig ?. triggers ?. crons ?. map ( ( cron ) => ( {
186+ type : "cron" as const ,
187+ cron,
188+ } ) ) ,
189+ tailConsumers : inlineConfig ?. tail_consumers ,
190+ streamingTailConsumers : inlineConfig ?. streaming_tail_consumers ,
191+ assets : inlineConfig ?. assets ?. directory ,
192+ dev : {
193+ auth,
194+ remote : options . allowRemoteBindings ? undefined : false ,
195+ server : options . server ?? { hostname : "127.0.0.1" , port : 0 } ,
196+ logLevel : options . logLevel ?? "error" ,
197+ watch : options . watch ?? false ,
198+ persist :
199+ options . persist === true ? undefined : ( options . persist ?? false ) ,
200+ inspector : options . inspector ?? false ,
201+ outboundService :
202+ options . outboundService ??
203+ ( ( request ) => {
204+ return globalThis . fetch ( request . url , request ) ;
205+ } ) ,
206+ multiworkerPrimary : isPrimaryWorker && isMultiworker ? true : undefined ,
207+ } ,
208+ build : {
209+ nodejsCompatMode : ( config ) => {
210+ const hookConfig = inlineConfig ?? config ;
211+ return validateNodeCompatMode (
212+ hookConfig . compatibility_date ,
213+ hookConfig . compatibility_flags ?? [ ] ,
214+ { noBundle : hookConfig . no_bundle }
215+ ) ;
216+ } ,
217+ } ,
218+ legacy : {
219+ site : ( config ) => {
220+ const legacyAssetPaths = getSiteAssetPaths ( inlineConfig ?? config ) ;
173221
174- if ( "configPath" in input ) {
175- return {
176- config : resolvePath ( root , input . configPath ) ,
177- env : input . env ,
178- dev,
179- } ;
180- }
222+ if ( ! legacyAssetPaths ) {
223+ return undefined ;
224+ }
181225
182- throw new Error (
183- `Invalid worker input at index ${ index } . Expected an object with either a "config" property or a "configPath" property.`
184- ) ;
226+ return {
227+ bucket : path . join (
228+ legacyAssetPaths . baseDirectory ,
229+ legacyAssetPaths . assetDirectory
230+ ) ,
231+ include : legacyAssetPaths . includePatterns ,
232+ exclude : legacyAssetPaths . excludePatterns ,
233+ } ;
234+ } ,
235+ } ,
236+ } ;
185237 } ) ;
186238}
187239
0 commit comments