Skip to content

Commit cb55a45

Browse files
committed
Add workers assets example and update workers upload example
1 parent 450515b commit cb55a45

File tree

2 files changed

+541
-62
lines changed

2 files changed

+541
-62
lines changed

examples/workers/script-upload.ts

Lines changed: 130 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,154 @@
11
#!/usr/bin/env -S npm run tsn -T
22

3-
/*
4-
* Generate an API token: https://developers.cloudflare.com/fundamentals/api/get-started/create-token/
5-
* (Not Global API Key!)
3+
/**
4+
* Create and deploy a Worker
5+
*
6+
* Docs:
7+
* - https://developers.cloudflare.com/workers/configuration/versions-and-deployments/
8+
* - https://developers.cloudflare.com/workers/platform/infrastructure-as-code/
9+
*
10+
* Prerequisites:
11+
* 1. Generate an API token: https://developers.cloudflare.com/fundamentals/api/get-started/create-token/
12+
* 2. Find your account ID: https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/
13+
* 3. Find your workers.dev subdomain: https://developers.cloudflare.com/workers/configuration/routing/workers-dev/
614
*
7-
* Find your account id: https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/
15+
* Environment variables:
16+
* - CLOUDFLARE_API_TOKEN (required)
17+
* - CLOUDFLARE_ACCOUNT_ID (required)
18+
* - CLOUDFLARE_SUBDOMAIN (optional)
819
*
9-
* Set these environment variables:
10-
* - CLOUDFLARE_API_TOKEN
11-
* - CLOUDFLARE_ACCOUNT_ID
12-
*
13-
* ### Workers for Platforms ###
14-
*
15-
* For uploading a User Worker to a dispatch namespace:
16-
* https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/
17-
*
18-
* Define a "dispatchNamespaceName" variable and change the entire "const script = " line to the following:
19-
* "const script = await client.workersForPlatforms.dispatch.namespaces.scripts.update(dispatchNamespaceName, scriptName, {"
20+
* Usage:
21+
* Run this script to deploy a simple "Hello World" Worker.
22+
* Access it at: my-hello-world-worker.$subdomain.workers.dev
2023
*/
2124

25+
import { exit } from 'node:process';
26+
2227
import Cloudflare from 'cloudflare';
23-
import { toFile } from 'cloudflare/index';
2428

25-
const apiToken = process.env['CLOUDFLARE_API_TOKEN'] ?? '';
26-
if (!apiToken) {
27-
throw new Error('Please set envar CLOUDFLARE_ACCOUNT_ID');
29+
interface Config {
30+
apiToken: string;
31+
accountId: string;
32+
subdomain: string | undefined;
33+
workerName: string;
2834
}
2935

30-
const accountID = process.env['CLOUDFLARE_ACCOUNT_ID'] ?? '';
31-
if (!accountID) {
32-
throw new Error('Please set envar CLOUDFLARE_API_TOKEN');
36+
const WORKER_NAME = 'my-hello-world-worker';
37+
const SCRIPT_FILENAME = `${WORKER_NAME}.mjs`;
38+
39+
function loadConfig(): Config {
40+
const apiToken = process.env['CLOUDFLARE_API_TOKEN'];
41+
if (!apiToken) {
42+
throw new Error('Missing required environment variable: CLOUDFLARE_API_TOKEN');
43+
}
44+
45+
const accountId = process.env['CLOUDFLARE_ACCOUNT_ID'];
46+
if (!accountId) {
47+
throw new Error('Missing required environment variable: CLOUDFLARE_ACCOUNT_ID');
48+
}
49+
50+
const subdomain = process.env['CLOUDFLARE_SUBDOMAIN'];
51+
52+
return {
53+
apiToken,
54+
accountId,
55+
subdomain: subdomain || undefined,
56+
workerName: WORKER_NAME,
57+
};
3358
}
3459

60+
const config = loadConfig();
3561
const client = new Cloudflare({
36-
apiToken: apiToken,
62+
apiToken: config.apiToken,
3763
});
3864

39-
async function main() {
40-
const scriptName = 'my-hello-world-script';
41-
const scriptFileName = `${scriptName}.mjs`;
65+
async function main(): Promise<void> {
66+
try {
67+
console.log('🚀 Starting Worker creation and deployment...');
4268

43-
// Workers Scripts prefer Module Syntax
44-
// https://blog.cloudflare.com/workers-javascript-modules/
45-
const scriptContent = `
46-
export default {
47-
async fetch(request, env, ctx) {
48-
return new Response(env.MESSAGE, { status: 200 });
49-
}
50-
};
51-
`;
69+
const scriptContent = `
70+
export default {
71+
async fetch(request, env, ctx) {
72+
return new Response(env.MESSAGE, { status: 200 });
73+
},
74+
}`.trim();
75+
76+
let worker;
77+
try {
78+
worker = await client.workers.beta.workers.get(config.workerName, {
79+
account_id: config.accountId,
80+
});
81+
console.log(`♻️ Worker ${config.workerName} already exists. Using it.`);
82+
} catch (error) {
83+
if (!(error instanceof Cloudflare.NotFoundError)) { throw error; }
84+
console.log(`✏️ Creating Worker ${config.workerName}...`);
85+
worker = await client.workers.beta.workers.create({
86+
account_id: config.accountId,
87+
name: config.workerName,
88+
subdomain: {
89+
enabled: config.subdomain !== undefined,
90+
},
91+
observability: {
92+
enabled: true,
93+
},
94+
});
95+
}
5296

53-
try {
54-
// https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/update/
55-
const script = await client.workers.scripts.update(scriptName, {
56-
account_id: accountID,
57-
// https://developers.cloudflare.com/workers/configuration/multipart-upload-metadata/
58-
metadata: {
59-
main_module: scriptFileName,
60-
bindings: [
61-
{
62-
type: 'plain_text',
63-
name: 'MESSAGE',
64-
text: 'Hello World!',
97+
console.log(`⚙️ Worker id: ${worker.id}`);
98+
console.log('✏️ Creating Worker version...');
99+
100+
// Create the first version of the Worker
101+
const version = await client.workers.beta.workers.versions.create(worker.id, {
102+
account_id: config.accountId,
103+
main_module: SCRIPT_FILENAME,
104+
compatibility_date: new Date().toISOString().split('T')[0]!,
105+
bindings: [
106+
{
107+
type: 'plain_text',
108+
name: 'MESSAGE',
109+
text: 'Hello World!',
110+
},
111+
],
112+
modules: [
113+
{
114+
name: SCRIPT_FILENAME,
115+
content_type: 'application/javascript+module',
116+
content_base64: Buffer.from(scriptContent).toString('base64'),
117+
},
118+
],
119+
});
120+
121+
console.log(`⚙️ Version id: ${version.id}`);
122+
console.log('🚚 Creating Worker deployment...');
123+
124+
// Create a deployment and point all traffic to the version we created
125+
await client.workers.scripts.deployments.create(config.workerName, {
126+
account_id: config.accountId,
127+
strategy: 'percentage',
128+
versions: [
129+
{
130+
percentage: 100,
131+
version_id: version.id,
65132
},
66133
],
67-
},
68-
files: [
69-
// Add main_module file
70-
await toFile(Buffer.from(scriptContent), scriptFileName, {
71-
type: 'application/javascript+module',
72-
}),
73-
// Can add other files, such as more modules or source maps
74-
// await toFile(Buffer.from(sourceMapContent), sourceMapFileName, {
75-
// type: 'application/source-map',
76-
// }),
77-
],
78134
});
79-
console.log('Script Upload success!');
80-
console.log(JSON.stringify(script, null, 2));
135+
136+
console.log('✅ Deployment successful!');
137+
138+
if (config.subdomain) {
139+
console.log(`
140+
🌍 Your Worker is live!
141+
📍 URL: https://${config.workerName}.${config.subdomain}.workers.dev/
142+
`);
143+
} else {
144+
console.log(`
145+
⚠️ Set up a route, custom domain, or workers.dev subdomain to access your Worker.
146+
Add CLOUDFLARE_SUBDOMAIN to your environment variables to set one up automatically.
147+
`);
148+
}
81149
} catch (error) {
82-
console.error('Script Upload failure!');
83-
console.error(error);
150+
console.error('❌ Deployment failed:', error);
151+
exit(1);
84152
}
85153
}
86154

0 commit comments

Comments
 (0)