Skip to content

Commit 443ef3e

Browse files
committed
feat: add artifacts binding support to wrangler
Add wrangler configuration, deployment, and type generation support for the Artifacts binding (git-compatible file storage). Config (workers-utils): - environment.ts: add artifacts binding option - validation.ts: add validateArtifactsBinding validator - config.ts: add default empty array - types.ts: add artifacts binding type - worker.ts: add CfArtifacts interface - map-worker-metadata-bindings.ts: handle artifacts type Wrangler: - create-worker-upload-form.ts: serialize artifacts bindings - bindings.ts: pass through artifacts config - type-generation/index.ts: generate Artifacts type reference - print-bindings.ts: display artifacts bindings - dev.ts, start-dev.ts: wire up artifacts config - dev/miniflare/index.ts: pass to miniflare - api/startDevWorker/utils.ts: handle artifacts binding type - secret/index.ts: include in empty bindings - add-created-resource-config.ts: include in resource types Binding config example: { "artifacts": [{ "binding": "MY_ARTIFACTS", "namespace": "default" }] } Type generation produces: MY_ARTIFACTS: Artifacts Ref: cloudflare/ai-agents/artifacts#4
1 parent 62fd118 commit 443ef3e

16 files changed

Lines changed: 145 additions & 0 deletions

File tree

packages/workers-utils/src/config/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ export const defaultWranglerConfig: Config = {
329329
hyperdrive: [],
330330
workflows: [],
331331
secrets_store_secrets: [],
332+
artifacts: [],
332333
services: [],
333334
analytics_engine_datasets: [],
334335
ai: undefined,

packages/workers-utils/src/config/environment.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,24 @@ export interface EnvironmentNonInheritable {
12301230
secret_name: string;
12311231
}[];
12321232

1233+
/**
1234+
* Specifies Artifacts bindings that are bound to this Worker environment.
1235+
* Artifacts provides git-compatible file storage on Cloudflare Workers.
1236+
*
1237+
* NOTE: This field is not automatically inherited from the top level environment,
1238+
* and so must be specified in every named environment.
1239+
*
1240+
* @default []
1241+
* @nonInheritable
1242+
*/
1243+
artifacts: {
1244+
/** The binding name used to refer to the Artifacts instance. */
1245+
binding: string;
1246+
1247+
/** The namespace to use. Defaults to "default" if not specified. */
1248+
namespace?: string;
1249+
}[];
1250+
12331251
/**
12341252
* **DO NOT USE**. Hello World Binding Config to serve as an explanatory example.
12351253
*

packages/workers-utils/src/config/validation.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export const friendlyBindingNames: Record<
9595
workflows: "Workflow",
9696
pipelines: "Pipeline",
9797
secrets_store_secrets: "Secrets Store Secret",
98+
artifacts: "Artifacts",
9899
ratelimits: "Rate Limit",
99100
assets: "Assets",
100101
unsafe_hello_world: "Hello World",
@@ -1714,6 +1715,16 @@ function normalizeAndValidateEnvironment(
17141715
validateBindingArray(envName, validateSecretsStoreSecretBinding),
17151716
[]
17161717
),
1718+
artifacts: notInheritable(
1719+
diagnostics,
1720+
topLevelEnv,
1721+
rawConfig,
1722+
rawEnv,
1723+
envName,
1724+
"artifacts",
1725+
validateBindingArray(envName, validateArtifactsBinding),
1726+
[]
1727+
),
17171728
unsafe_hello_world: notInheritable(
17181729
diagnostics,
17191730
topLevelEnv,
@@ -4276,6 +4287,44 @@ const validateSecretsStoreSecretBinding: ValidatorFn = (
42764287
return isValid;
42774288
};
42784289

4290+
const validateArtifactsBinding: ValidatorFn = (
4291+
diagnostics,
4292+
field,
4293+
value
4294+
) => {
4295+
if (typeof value !== "object" || value === null) {
4296+
diagnostics.errors.push(
4297+
`"artifacts" bindings should be objects, but got ${JSON.stringify(value)}`
4298+
);
4299+
return false;
4300+
}
4301+
let isValid = true;
4302+
if (!isRequiredProperty(value, "binding", "string")) {
4303+
diagnostics.errors.push(
4304+
`"${field}" bindings must have a string "binding" field but got ${JSON.stringify(
4305+
value
4306+
)}.`
4307+
);
4308+
isValid = false;
4309+
}
4310+
4311+
if ("namespace" in value && typeof value.namespace !== "string") {
4312+
diagnostics.errors.push(
4313+
`"${field}" bindings "namespace" field must be a string but got ${JSON.stringify(
4314+
value.namespace
4315+
)}.`
4316+
);
4317+
isValid = false;
4318+
}
4319+
4320+
validateAdditionalProperties(diagnostics, field, Object.keys(value), [
4321+
"binding",
4322+
"namespace",
4323+
]);
4324+
4325+
return isValid;
4326+
};
4327+
42794328
const validateHelloWorldBinding: ValidatorFn = (diagnostics, field, value) => {
42804329
if (typeof value !== "object" || value === null) {
42814330
diagnostics.errors.push(

packages/workers-utils/src/map-worker-metadata-bindings.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,19 @@ export function mapWorkerMetadataBindings(
125125
];
126126
}
127127
break;
128+
case "artifacts":
129+
{
130+
configObj.artifacts = [
131+
...(configObj.artifacts ?? []),
132+
{
133+
binding: binding.name,
134+
...(binding.namespace !== undefined && {
135+
namespace: binding.namespace,
136+
}),
137+
},
138+
];
139+
}
140+
break;
128141
case "unsafe_hello_world": {
129142
configObj.unsafe_hello_world = [
130143
...(configObj.unsafe_hello_world ?? []),

packages/workers-utils/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ export type WorkerMetadataBinding =
115115
store_id: string;
116116
secret_name: string;
117117
}
118+
| {
119+
type: "artifacts";
120+
name: string;
121+
namespace?: string;
122+
}
118123
| {
119124
type: "unsafe_hello_world";
120125
name: string;

packages/workers-utils/src/worker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ export interface CfSecretsStoreSecrets {
225225
secret_name: string;
226226
}
227227

228+
export interface CfArtifacts {
229+
binding: string;
230+
namespace?: string;
231+
}
232+
228233
export interface CfHelloWorld {
229234
binding: string;
230235
enable_timer?: boolean;
@@ -422,6 +427,7 @@ export interface CfWorkerInit {
422427
vectorize: CfVectorize[] | undefined;
423428
hyperdrive: CfHyperdrive[] | undefined;
424429
secrets_store_secrets: CfSecretsStoreSecrets[] | undefined;
430+
artifacts: CfArtifacts[] | undefined;
425431
services: CfService[] | undefined;
426432
vpc_services: CfVpcService[] | undefined;
427433
analytics_engine_datasets: CfAnalyticsEngineDataset[] | undefined;

packages/wrangler/src/api/startDevWorker/utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ export function convertCfWorkerInitBindingsToBindings(
280280
}
281281
break;
282282
}
283+
case "artifacts": {
284+
for (const { binding, ...x } of info) {
285+
output[binding] = { type: "artifacts", ...x };
286+
}
287+
break;
288+
}
283289
case "unsafe_hello_world": {
284290
for (const { binding, ...x } of info) {
285291
output[binding] = { type: "unsafe_hello_world", ...x };
@@ -357,6 +363,7 @@ export async function convertBindingsToCfWorkerInitBindings(
357363
vectorize: undefined,
358364
hyperdrive: undefined,
359365
secrets_store_secrets: undefined,
366+
artifacts: undefined,
360367
services: undefined,
361368
vpc_services: undefined,
362369
analytics_engine_datasets: undefined,
@@ -499,6 +506,9 @@ export async function convertBindingsToCfWorkerInitBindings(
499506
...omitType(binding),
500507
binding: name,
501508
});
509+
} else if (binding.type === "artifacts") {
510+
bindings.artifacts ??= [];
511+
bindings.artifacts.push({ ...omitType(binding), binding: name });
502512
} else if (binding.type === "unsafe_hello_world") {
503513
bindings.unsafe_hello_world ??= [];
504514
bindings.unsafe_hello_world.push({ ...omitType(binding), binding: name });

packages/wrangler/src/deployment-bundle/bindings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export function getBindings(
6161
vectorize: config?.vectorize,
6262
hyperdrive: config?.hyperdrive,
6363
secrets_store_secrets: config?.secrets_store_secrets,
64+
artifacts: config?.artifacts,
6465
services: config?.services,
6566
analytics_engine_datasets: config?.analytics_engine_datasets,
6667
dispatch_namespaces: options?.pages

packages/wrangler/src/deployment-bundle/create-worker-upload-form.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ export function createWorkerUploadForm(
279279
}
280280
);
281281

282+
bindings.artifacts?.forEach(({ binding, namespace }) => {
283+
metadataBindings.push({
284+
name: binding,
285+
type: "artifacts",
286+
...(namespace !== undefined && { namespace }),
287+
});
288+
});
289+
282290
bindings.unsafe_hello_world?.forEach(({ binding, enable_timer }) => {
283291
metadataBindings.push({
284292
name: binding,

packages/wrangler/src/dev.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ export function getBindings(
656656
vectorize: configParam.vectorize,
657657
hyperdrive: hyperdriveBindings,
658658
secrets_store_secrets: configParam.secrets_store_secrets,
659+
artifacts: configParam.artifacts,
659660
services: mergedServiceBindings,
660661
vpc_services: configParam.vpc_services,
661662
analytics_engine_datasets: configParam.analytics_engine_datasets,

0 commit comments

Comments
 (0)