Skip to content

Commit

Permalink
feat(wrangler): add inherit bindings support (#7385)
Browse files Browse the repository at this point in the history
* feat(wrangler): add inherit bindings support

* add test

* add changeset

* rename file to bindings
  • Loading branch information
edmundhung authored and penalosa committed Jan 10, 2025
1 parent 8ee835d commit 319dae2
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 151 deletions.
5 changes: 5 additions & 0 deletions .changeset/tall-flowers-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": patch
---

The `x-provision` experimental flag now support inherit bindings in deploys
53 changes: 52 additions & 1 deletion packages/wrangler/src/__tests__/deploy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10467,6 +10467,58 @@ export default{
});
});

describe("--x-provision", () => {
it("should accept KV, R2 and D1 bindings without IDs in the configuration file", async () => {
writeWorkerSource();
writeWranglerConfig({
main: "index.js",
kv_namespaces: [{ binding: "KV_NAMESPACE" }],
r2_buckets: [{ binding: "R2_BUCKET" }],
d1_databases: [{ binding: "D1_DATABASE" }],
});
mockUploadWorkerRequest({
// We are treating them as inherited bindings temporarily to test the current implementation only
// This will be updated as we implement the actual provision logic
expectedBindings: [
{
name: "KV_NAMESPACE",
type: "inherit",
},
{
name: "R2_BUCKET",
type: "inherit",
},
{
name: "D1_DATABASE",
type: "inherit",
},
],
});
mockSubDomainRequest();

await expect(
runWrangler("deploy --x-provision")
).resolves.toBeUndefined();
expect(std.out).toMatchInlineSnapshot(`
"Total Upload: xx KiB / gzip: xx KiB
Worker Startup Time: 100 ms
Your worker has access to the following bindings:
- KV Namespaces:
- KV_NAMESPACE: (remote)
- D1 Databases:
- D1_DATABASE: (remote)
- R2 Buckets:
- R2_BUCKET: (remote)
Uploaded test-name (TIMINGS)
Deployed test-name triggers (TIMINGS)
https://test-name.test-sub-domain.workers.dev
Current Version ID: Galaxy-Class"
`);
expect(std.err).toMatchInlineSnapshot(`""`);
expect(std.warn).toMatchInlineSnapshot(`""`);
});
});

describe("queues", () => {
const queueId = "queue-id";
const queueName = "queue1";
Expand Down Expand Up @@ -11143,7 +11195,6 @@ export default{
upload_source_maps: true,
});
writeWorkerSource({ format: "ts" });

mockSubDomainRequest();
mockUploadWorkerRequest({
expectedMainModule: "index.js",
Expand Down
40 changes: 5 additions & 35 deletions packages/wrangler/src/api/pages/create-worker-bundle-contents.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { readFileSync } from "node:fs";
import path from "node:path";
import { Response } from "undici";
import { getBindings } from "../../deployment-bundle/bindings";
import { createWorkerUploadForm } from "../../deployment-bundle/create-worker-upload-form";
import { loadSourceMaps } from "../../deployment-bundle/source-maps";
import type { Config } from "../../config";
import type { BundleResult } from "../../deployment-bundle/bundle";
import type { CfPlacement, CfWorkerInit } from "../../deployment-bundle/worker";
import type { CfPlacement } from "../../deployment-bundle/worker";
import type { Blob } from "node:buffer";
import type { FormData } from "undici";

Expand Down Expand Up @@ -44,46 +45,17 @@ function createWorkerBundleFormData(
type: workerBundle.bundleType || "esm",
};

const bindings: CfWorkerInit["bindings"] = {
kv_namespaces: config?.kv_namespaces,
vars: config?.vars,
browser: config?.browser,
ai: config?.ai,
version_metadata: config?.version_metadata,
durable_objects: config?.durable_objects,
workflows: config?.workflows,
queues: config?.queues.producers?.map((producer) => {
return { binding: producer.binding, queue_name: producer.queue };
}),
r2_buckets: config?.r2_buckets,
d1_databases: config?.d1_databases,
vectorize: config?.vectorize,
hyperdrive: config?.hyperdrive,
services: config?.services,
analytics_engine_datasets: config?.analytics_engine_datasets,
mtls_certificates: config?.mtls_certificates,
send_email: undefined,
wasm_modules: undefined,
text_blobs: undefined,
data_blobs: undefined,
dispatch_namespaces: undefined,
pipelines: undefined,
logfwdr: undefined,
unsafe: undefined,
assets: undefined,
};

// The upload API only accepts an empty string or no specified placement for the "off" mode.
const placement: CfPlacement | undefined =
config?.placement?.mode === "smart"
? { mode: "smart", hint: config.placement.hint }
: undefined;

const worker: CfWorkerInit = {
return createWorkerUploadForm({
name: mainModule.name,
main: mainModule,
modules: workerBundle.modules,
bindings,
bindings: getBindings(config, { pages: true }),
migrations: undefined,
compatibility_date: config?.compatibility_date,
compatibility_flags: config?.compatibility_flags,
Expand All @@ -99,7 +71,5 @@ function createWorkerBundleFormData(
limits: config?.limits,
assets: undefined,
observability: undefined,
};

return createWorkerUploadForm(worker);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,9 @@ export class RemoteRuntimeController extends RuntimeController {
configPath: config.config,
});

const bindings = (
await convertBindingsToCfWorkerInitBindings(config.bindings)
).bindings;

const { bindings } = await convertBindingsToCfWorkerInitBindings(
config.bindings
);
const token = await this.#previewToken({
bundle,
modules: bundle.modules,
Expand Down
22 changes: 15 additions & 7 deletions packages/wrangler/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,11 @@ export function findWranglerConfig(
);
}

function addLocalSuffix(id: string | undefined, local: boolean = false) {
if (!id) {
function addLocalSuffix(
id: string | symbol | undefined,
local: boolean = false
) {
if (!id || typeof id === "symbol") {
return local ? "(local)" : "(remote)";
}

Expand Down Expand Up @@ -407,10 +410,12 @@ export function printBindings(
name: friendlyBindingNames.d1_databases,
entries: d1_databases.map(
({ binding, database_name, database_id, preview_database_id }) => {
const remoteDatabaseId =
typeof database_id === "string" ? database_id : null;
let databaseValue =
database_id && database_name
? `${database_name} (${database_id})`
: database_id ?? database_name;
remoteDatabaseId && database_name
? `${database_name} (${remoteDatabaseId})`
: remoteDatabaseId ?? database_name;

//database_id is local when running `wrangler dev --local`
if (preview_database_id && database_id !== "local") {
Expand Down Expand Up @@ -453,12 +458,15 @@ export function printBindings(
output.push({
name: friendlyBindingNames.r2_buckets,
entries: r2_buckets.map(({ binding, bucket_name, jurisdiction }) => {
let name = typeof bucket_name === "string" ? bucket_name : "";

if (jurisdiction !== undefined) {
bucket_name += ` (${jurisdiction})`;
name += ` (${jurisdiction})`;
}

return {
key: binding,
value: addLocalSuffix(bucket_name, context.local),
value: addLocalSuffix(name, context.local),
};
}),
});
Expand Down
37 changes: 5 additions & 32 deletions packages/wrangler/src/deploy/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { cancel } from "@cloudflare/cli";
import { syncAssets } from "../assets";
import { fetchListResult, fetchResult } from "../cfetch";
import { configFileName, formatConfigSnippet, printBindings } from "../config";
import { getBindings } from "../deployment-bundle/bindings";
import { bundleWorker } from "../deployment-bundle/bundle";
import {
printBundleSize,
Expand Down Expand Up @@ -671,50 +672,22 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
props.oldAssetTtl
);

const bindings: CfWorkerInit["bindings"] = {
kv_namespaces: (config.kv_namespaces || []).concat(
const bindings = getBindings({
...config,
kv_namespaces: config.kv_namespaces.concat(
legacyAssets.namespace
? { binding: "__STATIC_CONTENT", id: legacyAssets.namespace }
: []
),
send_email: config.send_email,
vars: { ...config.vars, ...props.vars },
wasm_modules: config.wasm_modules,
browser: config.browser,
ai: config.ai,
version_metadata: config.version_metadata,
text_blobs: {
...config.text_blobs,
...(legacyAssets.manifest &&
format === "service-worker" && {
__STATIC_CONTENT_MANIFEST: "__STATIC_CONTENT_MANIFEST",
}),
},
data_blobs: config.data_blobs,
durable_objects: config.durable_objects,
workflows: config.workflows,
queues: config.queues.producers?.map((producer) => {
return { binding: producer.binding, queue_name: producer.queue };
}),
r2_buckets: config.r2_buckets,
d1_databases: config.d1_databases,
vectorize: config.vectorize,
hyperdrive: config.hyperdrive,
services: config.services,
analytics_engine_datasets: config.analytics_engine_datasets,
dispatch_namespaces: config.dispatch_namespaces,
mtls_certificates: config.mtls_certificates,
pipelines: config.pipelines,
logfwdr: config.logfwdr,
assets: config.assets?.binding
? { binding: config.assets.binding }
: undefined,
unsafe: {
bindings: config.unsafe.bindings,
metadata: config.unsafe.metadata,
capnp: config.unsafe.capnp,
},
};
});

if (legacyAssets.manifest) {
modules.push({
Expand Down
64 changes: 64 additions & 0 deletions packages/wrangler/src/deployment-bundle/bindings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { Config } from "../config";
import type { CfWorkerInit } from "./worker";

/**
* A symbol to inherit a binding from the deployed worker.
*/
export const INHERIT_SYMBOL = Symbol.for("inherit_binding");

export function getBindings(
config: Config | undefined,
options?: {
pages?: boolean;
}
): CfWorkerInit["bindings"] {
return {
kv_namespaces: config?.kv_namespaces?.map((kv) => ({
...kv,
id: kv.id ?? INHERIT_SYMBOL,
})),
send_email: options?.pages ? undefined : config?.send_email,
vars: config?.vars,
wasm_modules: options?.pages ? undefined : config?.wasm_modules,
browser: config?.browser,
ai: config?.ai,
version_metadata: config?.version_metadata,
text_blobs: options?.pages ? undefined : config?.text_blobs,
data_blobs: options?.pages ? undefined : config?.data_blobs,
durable_objects: config?.durable_objects,
workflows: config?.workflows,
queues: config?.queues.producers?.map((producer) => {
return { binding: producer.binding, queue_name: producer.queue };
}),
r2_buckets: config?.r2_buckets?.map((r2) => ({
...r2,
bucket_name: r2.bucket_name ?? INHERIT_SYMBOL,
})),
d1_databases: config?.d1_databases.map((d1) => ({
...d1,
database_id: d1.database_id ?? INHERIT_SYMBOL,
})),
vectorize: config?.vectorize,
hyperdrive: config?.hyperdrive,
services: config?.services,
analytics_engine_datasets: config?.analytics_engine_datasets,
dispatch_namespaces: options?.pages
? undefined
: config?.dispatch_namespaces,
mtls_certificates: config?.mtls_certificates,
pipelines: options?.pages ? undefined : config?.pipelines,
logfwdr: options?.pages ? undefined : config?.logfwdr,
assets: options?.pages
? undefined
: config?.assets?.binding
? { binding: config?.assets?.binding }
: undefined,
unsafe: options?.pages
? undefined
: {
bindings: config?.unsafe.bindings,
metadata: config?.unsafe.metadata,
capnp: config?.unsafe.capnp,
},
};
}
Loading

0 comments on commit 319dae2

Please sign in to comment.