Skip to content

Commit 341a44b

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

File tree

2 files changed

+542
-62
lines changed

2 files changed

+542
-62
lines changed

examples/workers/script-upload.ts

Lines changed: 131 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,155 @@
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(`Worker ${config.workerName} does not exist. Creating it...`);
85+
console.log(`✏️ Creating Worker ${config.workerName}...`);
86+
worker = await client.workers.beta.workers.create({
87+
account_id: config.accountId,
88+
name: config.workerName,
89+
subdomain: {
90+
enabled: config.subdomain !== undefined,
91+
},
92+
observability: {
93+
enabled: true,
94+
},
95+
});
96+
}
5297

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!',
98+
console.log(`⚙️ Worker id: ${worker.id}`);
99+
console.log('✏️ Creating Worker version...');
100+
101+
// Create the first version of the Worker
102+
const version = await client.workers.beta.workers.versions.create(worker.id, {
103+
account_id: config.accountId,
104+
main_module: SCRIPT_FILENAME,
105+
compatibility_date: new Date().toISOString().split('T')[0]!,
106+
bindings: [
107+
{
108+
type: 'plain_text',
109+
name: 'MESSAGE',
110+
text: 'Hello World!',
111+
},
112+
],
113+
modules: [
114+
{
115+
name: SCRIPT_FILENAME,
116+
content_type: 'application/javascript+module',
117+
content_base64: Buffer.from(scriptContent).toString('base64'),
118+
},
119+
],
120+
});
121+
122+
console.log(`⚙️ Version id: ${version.id}`);
123+
console.log('🚚 Creating Worker deployment...');
124+
125+
// Create a deployment and point all traffic to the version we created
126+
await client.workers.scripts.deployments.create(config.workerName, {
127+
account_id: config.accountId,
128+
strategy: 'percentage',
129+
versions: [
130+
{
131+
percentage: 100,
132+
version_id: version.id,
65133
},
66134
],
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-
],
78135
});
79-
console.log('Script Upload success!');
80-
console.log(JSON.stringify(script, null, 2));
136+
137+
console.log('✅ Deployment successful!');
138+
139+
if (config.subdomain) {
140+
console.log(`
141+
🌍 Your Worker is live!
142+
📍 URL: https://${config.workerName}.${config.subdomain}.workers.dev/
143+
`);
144+
} else {
145+
console.log(`
146+
⚠️ Set up a route, custom domain, or workers.dev subdomain to access your Worker.
147+
Add CLOUDFLARE_SUBDOMAIN to your environment variables to set one up automatically.
148+
`);
149+
}
81150
} catch (error) {
82-
console.error('Script Upload failure!');
83-
console.error(error);
151+
console.error('❌ Deployment failed:', error);
152+
exit(1);
84153
}
85154
}
86155

0 commit comments

Comments
 (0)