diff --git a/packages/wrangler/src/api/startDevWorker/types.ts b/packages/wrangler/src/api/startDevWorker/types.ts index 2400b9fb8a5f..649516984d34 100644 --- a/packages/wrangler/src/api/startDevWorker/types.ts +++ b/packages/wrangler/src/api/startDevWorker/types.ts @@ -22,6 +22,7 @@ import type { CfScriptFormat, CfSendEmailBindings, CfService, + CfUnsafe, CfVectorize, CfWorkerInit, } from "../../deployment-bundle/worker"; @@ -152,6 +153,7 @@ export interface InputStartDevWorkerOptions { assets?: Config["assets"]; enableServiceEnvironments?: boolean; }; + unsafe?: Omit; } export interface StartDevWorkerOptions extends InputStartDevWorkerOptions { diff --git a/packages/wrangler/src/api/startDevWorker/utils.ts b/packages/wrangler/src/api/startDevWorker/utils.ts index 5d241e31ba2d..203e86608f83 100644 --- a/packages/wrangler/src/api/startDevWorker/utils.ts +++ b/packages/wrangler/src/api/startDevWorker/utils.ts @@ -78,6 +78,172 @@ export async function getTextFileContents(file: File) { return readFile(file.path, "utf8"); } +export function convertCfWorkerInitBindingstoBindings( + inputBindings: CfWorkerInit["bindings"] +): StartDevWorkerOptions["bindings"] { + const output: StartDevWorkerOptions["bindings"] = {}; + + // required to retain type information + type Entries = { [K in keyof T]: [K, T[K]] }[keyof T][]; + type BindingsIterable = Entries; + const bindingsIterable = Object.entries(inputBindings) as BindingsIterable; + + for (const [type, info] of bindingsIterable) { + if (info === undefined) { + continue; + } + + switch (type) { + case "vars": { + for (const [key, value] of Object.entries(info)) { + if (typeof value === "string") { + output[key] = { type: "plain_text", value }; + } else { + output[key] = { type: "json", value }; + } + } + break; + } + case "kv_namespaces": { + for (const { binding, ...x } of info) { + output[binding] = { type: "kv_namespace", ...x }; + } + break; + } + case "send_email": { + for (const { name, ...x } of info) { + output[name] = { type: "send_email", ...x }; + } + break; + } + case "wasm_modules": { + for (const [key, value] of Object.entries(info)) { + if (typeof value === "string") { + output[key] = { type: "wasm_module", source: { path: value } }; + } else { + output[key] = { type: "wasm_module", source: { contents: value } }; + } + } + break; + } + case "text_blobs": { + for (const [key, value] of Object.entries(info)) { + output[key] = { type: "text_blob", source: { path: value } }; + } + break; + } + case "data_blobs": { + for (const [key, value] of Object.entries(info)) { + if (typeof value === "string") { + output[key] = { type: "data_blob", source: { path: value } }; + } else { + output[key] = { type: "data_blob", source: { contents: value } }; + } + } + break; + } + case "browser": { + const { binding, ...x } = info; + output[binding] = { type: "browser", ...x }; + break; + } + case "durable_objects": { + for (const { name, ...x } of info.bindings) { + output[name] = { type: "durable_object_namespace", ...x }; + } + break; + } + case "queues": { + for (const { binding, ...x } of info) { + output[binding] = { type: "queue", ...x }; + } + break; + } + case "r2_buckets": { + for (const { binding, ...x } of info) { + output[binding] = { type: "r2_bucket", ...x }; + } + break; + } + case "d1_databases": { + for (const { binding, ...x } of info) { + output[binding] = { type: "d1", ...x }; + } + break; + } + case "constellation": { + for (const { binding, ...x } of info) { + output[binding] = { type: "constellation", ...x }; + } + break; + } + case "services": { + for (const { binding, ...x } of info) { + output[binding] = { type: "service", ...x }; + } + break; + } + case "analytics_engine_datasets": { + for (const { binding, ...x } of info) { + output[binding] = { type: "analytics_engine", ...x }; + } + break; + } + case "dispatch_namespaces": { + for (const { binding, ...x } of info) { + output[binding] = { type: "dispatch_namespace", ...x }; + } + break; + } + case "mtls_certificates": { + for (const { binding, ...x } of info) { + output[binding] = { type: "mtls_certificate", ...x }; + } + break; + } + case "logfwdr": { + for (const { name, ...x } of info.bindings) { + output[name] = { type: "logfwdr", ...x }; + } + break; + } + case "ai": { + const { binding, ...x } = info; + output[binding] = { type: "ai", ...x }; + break; + } + case "version_metadata": { + const { binding, ...x } = info; + output[binding] = { type: "version_metadata", ...x }; + break; + } + case "hyperdrive": { + for (const { binding, ...x } of info) { + output[binding] = { type: "hyperdrive", ...x }; + } + break; + } + case "vectorize": { + for (const { binding, ...x } of info) { + output[binding] = { type: "vectorize", ...x }; + } + break; + } + case "unsafe": { + for (const { type: unsafeType, name } of info.bindings ?? []) { + output[name] = { type: `unsafe_${unsafeType}` }; + } + break; + } + default: { + assertNever(type); + } + } + + return output; + } +} + export async function convertBindingsToCfWorkerInitBindings( inputBindings: StartDevWorkerOptions["bindings"] ): Promise<{ diff --git a/packages/wrangler/src/dev/dev.tsx b/packages/wrangler/src/dev/dev.tsx index 8d760280a41f..c0faf506a4c4 100644 --- a/packages/wrangler/src/dev/dev.tsx +++ b/packages/wrangler/src/dev/dev.tsx @@ -16,7 +16,10 @@ import { useErrorHandler, withErrorBoundary } from "react-error-boundary"; import onExit from "signal-exit"; import { fetch } from "undici"; import { DevEnv } from "../api"; -import { createDeferred } from "../api/startDevWorker/utils"; +import { + convertCfWorkerInitBindingstoBindings, + createDeferred, +} from "../api/startDevWorker/utils"; import { runCustomBuild } from "../deployment-bundle/run-custom-build"; import { getBoundRegisteredWorkers, @@ -381,7 +384,7 @@ function DevSession(props: DevSessionProps) { compatibilityFlags: props.compatibilityFlags, script: { path: props.entry.file }, directory: props.entry.directory, - _bindings: props.bindings, + bindings: convertCfWorkerInitBindingstoBindings(props.bindings), triggers: [...routes, ...queueConsumers, ...crons], env: props.env, @@ -447,6 +450,10 @@ function DevSession(props: DevSessionProps) { assets: props.assetsConfig, enableServiceEnvironments: !props.legacyEnv, }, + unsafe: { + capnp: props.bindings.unsafe?.capnp, + metadata: props.bindings.unsafe?.metadata, + }, } satisfies StartDevWorkerOptions; }, [ props.routes,