create-cloudflare 2.0.0-next.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/dist/angular/templates/src/_routes.json +3 -3
- package/dist/angular/templates/src/main.server.ts +15 -15
- package/dist/angular/templates/tools/bundle.mjs +44 -44
- package/dist/angular/templates/tools/copy-worker-files.mjs +2 -2
- package/dist/angular/templates/tsconfig.server.json +2 -4
- package/dist/cli.js +5980 -17400
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +18 -23
- package/templates/common/js/.prettierrc +5 -0
- package/templates/common/js/package.json +14 -0
- package/templates/common/js/src/ab-test.js +41 -0
- package/templates/common/js/src/proxy.js +23 -0
- package/templates/common/js/src/redirect.js +13 -0
- package/templates/{examples → common}/js/src/router.js +4 -8
- package/templates/common/js/src/worker.js +46 -0
- package/templates/common/js/wrangler.toml +40 -0
- package/templates/common/ts/.prettierrc +5 -0
- package/templates/common/ts/package.json +15 -0
- package/templates/common/ts/src/ab-test.ts +41 -0
- package/templates/common/ts/src/proxy.ts +23 -0
- package/templates/common/ts/src/redirect.ts +13 -0
- package/templates/{examples → common}/ts/src/router.ts +4 -8
- package/templates/common/ts/src/worker.ts +46 -0
- package/templates/{examples → common}/ts/tsconfig.json +2 -6
- package/templates/common/ts/worker-configuration.d.ts +16 -0
- package/templates/common/ts/wrangler.toml +40 -0
- package/templates/simple/js/.prettierrc +3 -3
- package/templates/simple/js/package.json +12 -12
- package/templates/simple/js/src/worker.js +3 -3
- package/templates/simple/js/wrangler.toml +37 -0
- package/templates/simple/ts/.prettierrc +3 -3
- package/templates/simple/ts/package.json +12 -12
- package/templates/simple/ts/src/worker.ts +17 -14
- package/templates/simple/ts/tsconfig.json +2 -6
- package/templates/simple/ts/wrangler.toml +37 -0
- package/templates/examples/js/.prettierrc +0 -5
- package/templates/examples/js/package.json +0 -14
- package/templates/examples/js/src/ab-test.js +0 -41
- package/templates/examples/js/src/proxy.js +0 -22
- package/templates/examples/js/src/redirect.js +0 -13
- package/templates/examples/js/src/worker.js +0 -37
- package/templates/examples/js/wrangler.toml +0 -7
- package/templates/examples/ts/.prettierrc +0 -5
- package/templates/examples/ts/package.json +0 -15
- package/templates/examples/ts/src/ab-test.ts +0 -41
- package/templates/examples/ts/src/proxy.ts +0 -22
- package/templates/examples/ts/src/redirect.ts +0 -13
- package/templates/examples/ts/src/worker.ts +0 -37
- package/templates/examples/ts/worker-configuration.d.ts +0 -13
- package/templates/examples/ts/wrangler.toml +0 -7
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name = "<TBD>"
|
|
2
|
+
main = "src/worker.ts"
|
|
3
|
+
compatibility_date = "2023-04-21"
|
|
4
|
+
|
|
5
|
+
# # KV Namespace binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/kv
|
|
6
|
+
# [[kv_namespaces]]
|
|
7
|
+
# binding = "MY_KV_NAMESPACE"
|
|
8
|
+
# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
9
|
+
|
|
10
|
+
# # Durable Object binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/durable-objects
|
|
11
|
+
# [[durable_objects]]
|
|
12
|
+
# binding = "MY_DURABLE_OBJECT"
|
|
13
|
+
# class_name = "MyDurableObject"
|
|
14
|
+
|
|
15
|
+
# # Bucket binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/kv#bucket
|
|
16
|
+
# [[buckets]]
|
|
17
|
+
# binding = "MY_BUCKET"
|
|
18
|
+
# name = "my-bucket"
|
|
19
|
+
# bucket_id = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
|
|
20
|
+
|
|
21
|
+
# # Service binding - For more information: https://developers.cloudflare.com/workers/platform/services
|
|
22
|
+
# [[routes]]
|
|
23
|
+
# binding = "MY_SERVICE"
|
|
24
|
+
# pattern = "/api/*"
|
|
25
|
+
# script = "api.js"
|
|
26
|
+
|
|
27
|
+
# # Queue binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/queues
|
|
28
|
+
# [[queues]]
|
|
29
|
+
# binding = "MY_QUEUE"
|
|
30
|
+
# name = "my-queue"
|
|
31
|
+
# zone_id = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
|
32
|
+
|
|
33
|
+
# [env.production]
|
|
34
|
+
# MY_VARIABLE = "production_value"
|
|
35
|
+
|
|
36
|
+
# [env.staging]
|
|
37
|
+
# MY_VARIABLE = "staging_value"
|
|
38
|
+
|
|
39
|
+
# [env.shared]
|
|
40
|
+
# SHARED_VARIABLE = "shared_value"
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
"name": "<TBD>",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"deploy": "wrangler publish",
|
|
7
|
+
"start": "wrangler dev"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@cloudflare/workers-types": "^4.20230419.0",
|
|
11
|
+
"typescript": "^5.0.4",
|
|
12
|
+
"wrangler": "^2.19.0"
|
|
13
|
+
}
|
|
14
14
|
}
|
|
@@ -1,3 +1,40 @@
|
|
|
1
1
|
name = "<TBD>"
|
|
2
2
|
main = "src/worker.ts"
|
|
3
3
|
compatibility_date = "2023-04-21"
|
|
4
|
+
|
|
5
|
+
# # KV Namespace binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/kv
|
|
6
|
+
# [[kv_namespaces]]
|
|
7
|
+
# binding = "MY_KV_NAMESPACE"
|
|
8
|
+
# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
9
|
+
|
|
10
|
+
# # Durable Object binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/durable-objects
|
|
11
|
+
# [[durable_objects]]
|
|
12
|
+
# binding = "MY_DURABLE_OBJECT"
|
|
13
|
+
# class_name = "MyDurableObject"
|
|
14
|
+
|
|
15
|
+
# # Bucket binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/kv#bucket
|
|
16
|
+
# [[buckets]]
|
|
17
|
+
# binding = "MY_BUCKET"
|
|
18
|
+
# name = "my-bucket"
|
|
19
|
+
# bucket_id = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
|
|
20
|
+
|
|
21
|
+
# # Service binding - For more information: https://developers.cloudflare.com/workers/platform/services
|
|
22
|
+
# [[routes]]
|
|
23
|
+
# binding = "MY_SERVICE"
|
|
24
|
+
# pattern = "/api/*"
|
|
25
|
+
# script = "api.js"
|
|
26
|
+
|
|
27
|
+
# # Queue binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/queues
|
|
28
|
+
# [[queues]]
|
|
29
|
+
# binding = "MY_QUEUE"
|
|
30
|
+
# name = "my-queue"
|
|
31
|
+
# zone_id = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
|
32
|
+
|
|
33
|
+
# [env.production]
|
|
34
|
+
# MY_VARIABLE = "production_value"
|
|
35
|
+
|
|
36
|
+
# [env.staging]
|
|
37
|
+
# MY_VARIABLE = "staging_value"
|
|
38
|
+
|
|
39
|
+
# [env.shared]
|
|
40
|
+
# SHARED_VARIABLE = "shared_value"
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
"name": "<TBD>",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"deploy": "wrangler publish",
|
|
7
|
+
"start": "wrangler dev"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@cloudflare/workers-types": "^4.20230419.0",
|
|
11
|
+
"typescript": "^5.0.4",
|
|
12
|
+
"wrangler": "^2.19.0"
|
|
13
|
+
}
|
|
14
14
|
}
|
|
@@ -9,21 +9,24 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export interface Env {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
// Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/
|
|
13
|
+
// MY_KV_NAMESPACE: KVNamespace;
|
|
14
|
+
//
|
|
15
|
+
// Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/
|
|
16
|
+
// MY_DURABLE_OBJECT: DurableObjectNamespace;
|
|
17
|
+
//
|
|
18
|
+
// Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/
|
|
19
|
+
// MY_BUCKET: R2Bucket;
|
|
20
|
+
//
|
|
21
|
+
// Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/
|
|
22
|
+
// MY_SERVICE: Fetcher;
|
|
23
|
+
//
|
|
24
|
+
// Example binding to a Queue. Learn more at https://developers.cloudflare.com/queues/javascript-apis/
|
|
25
|
+
// MY_QUEUE: Queue;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export default {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
30
|
+
return new Response('Hello World!');
|
|
31
|
+
},
|
|
29
32
|
};
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
/* Language and Environment */
|
|
14
14
|
"target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
|
15
|
-
"lib": [
|
|
16
|
-
"es2021"
|
|
17
|
-
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
|
|
15
|
+
"lib": ["es2021"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
|
|
18
16
|
"jsx": "react" /* Specify what JSX code is generated. */,
|
|
19
17
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
|
20
18
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
|
@@ -33,9 +31,7 @@
|
|
|
33
31
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
|
34
32
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
|
35
33
|
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
|
36
|
-
"types": [
|
|
37
|
-
"@cloudflare/workers-types"
|
|
38
|
-
] /* Specify type package names to be included without being referenced in a source file. */,
|
|
34
|
+
"types": ["@cloudflare/workers-types"] /* Specify type package names to be included without being referenced in a source file. */,
|
|
39
35
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
40
36
|
"resolveJsonModule": true /* Enable importing .json files */,
|
|
41
37
|
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
|
@@ -1,3 +1,40 @@
|
|
|
1
1
|
name = "<TBD>"
|
|
2
2
|
main = "src/worker.ts"
|
|
3
3
|
compatibility_date = "2023-04-21"
|
|
4
|
+
|
|
5
|
+
# # KV Namespace binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/kv
|
|
6
|
+
# [[kv_namespaces]]
|
|
7
|
+
# binding = "MY_KV_NAMESPACE"
|
|
8
|
+
# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
9
|
+
|
|
10
|
+
# # Durable Object binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/durable-objects
|
|
11
|
+
# [[durable_objects]]
|
|
12
|
+
# binding = "MY_DURABLE_OBJECT"
|
|
13
|
+
# class_name = "MyDurableObject"
|
|
14
|
+
|
|
15
|
+
# # Bucket binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/kv#bucket
|
|
16
|
+
# [[buckets]]
|
|
17
|
+
# binding = "MY_BUCKET"
|
|
18
|
+
# name = "my-bucket"
|
|
19
|
+
# bucket_id = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
|
|
20
|
+
|
|
21
|
+
# # Service binding - For more information: https://developers.cloudflare.com/workers/platform/services
|
|
22
|
+
# [[routes]]
|
|
23
|
+
# binding = "MY_SERVICE"
|
|
24
|
+
# pattern = "/api/*"
|
|
25
|
+
# script = "api.js"
|
|
26
|
+
|
|
27
|
+
# # Queue binding - For more information: https://developers.cloudflare.com/workers/runtime-apis/queues
|
|
28
|
+
# [[queues]]
|
|
29
|
+
# binding = "MY_QUEUE"
|
|
30
|
+
# name = "my-queue"
|
|
31
|
+
# zone_id = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
|
32
|
+
|
|
33
|
+
# [env.production]
|
|
34
|
+
# MY_VARIABLE = "production_value"
|
|
35
|
+
|
|
36
|
+
# [env.staging]
|
|
37
|
+
# MY_VARIABLE = "staging_value"
|
|
38
|
+
|
|
39
|
+
# [env.shared]
|
|
40
|
+
# SHARED_VARIABLE = "shared_value"
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "<TBD>",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"start": "wrangler dev",
|
|
7
|
-
"deploy": "wrangler publish"
|
|
8
|
-
},
|
|
9
|
-
"devDependencies": {
|
|
10
|
-
"@cloudflare/workers-types": "^4.20230419.0",
|
|
11
|
-
"itty-router": "^3.0.12",
|
|
12
|
-
"wrangler": "^2.19.0"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const ORIGIN_URL = 'https://example.com';
|
|
2
|
-
const EXPERIMENTS = [
|
|
3
|
-
{ name: 'big-button', threshold: 0.5 }, // enable the Big Button experiment for 50% of users
|
|
4
|
-
{ name: 'new-brand', threshold: 0.1 }, // enable the New Brand experiment for 10% of users
|
|
5
|
-
{ name: 'new-layout', threshold: 0.02 }, // enable the New Layout experiment for 2% of users
|
|
6
|
-
];
|
|
7
|
-
|
|
8
|
-
export default {
|
|
9
|
-
async fetch(request, env, ctx) {
|
|
10
|
-
const fingerprint = [request.headers.get('cf-connecting-ip'), request.cf?.postalCode]; // add any values you want considered as a fingerprint
|
|
11
|
-
const activeExperiments = await getActiveExperiments(fingerprint, EXPERIMENTS);
|
|
12
|
-
|
|
13
|
-
// add a data-experiments attribute to the <body> tag
|
|
14
|
-
// which can be styled in CSS with a wildcard selector like [data-experiments*="big-button"]
|
|
15
|
-
const rewriter = new HTMLRewriter().on('body', {
|
|
16
|
-
element(element) {
|
|
17
|
-
element.setAttribute('data-experiments', activeExperiments.join(' '));
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const res = await fetch(ORIGIN_URL, request);
|
|
22
|
-
|
|
23
|
-
return rewriter.transform(res);
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// Get active experiments by hashing a fingerprint
|
|
28
|
-
async function getActiveExperiments(fingerprint, experiments) {
|
|
29
|
-
const fingerprintHash = await hash('SHA-1', JSON.stringify(fingerprint));
|
|
30
|
-
const MAX_UINT8 = 255;
|
|
31
|
-
const activeExperiments = experiments.filter((exp, i) => fingerprintHash[i] <= exp.threshold * MAX_UINT8);
|
|
32
|
-
return activeExperiments.map((exp) => exp.name);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Hash a string using the Web Crypto API
|
|
36
|
-
async function hash(algorithm, message) {
|
|
37
|
-
const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
|
|
38
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); // hash the message
|
|
39
|
-
const hashArray = new Uint8Array(hashBuffer); // convert buffer to byte array
|
|
40
|
-
return hashArray;
|
|
41
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
async fetch(request, env, ctx) {
|
|
3
|
-
const url = new URL(request.url);
|
|
4
|
-
|
|
5
|
-
const proxyUrl = url.searchParams.get('proxyUrl'); // get a query param value (?proxyUrl=...)
|
|
6
|
-
const modify = url.searchParams.has('modify'); // check if a query param is set (?proxyUrl=...&modify)
|
|
7
|
-
|
|
8
|
-
if (!proxyUrl) {
|
|
9
|
-
return new Response('Bad request: Missing `proxyUrl` query param', { status: 400 });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// make subrequests with the global `fetch()` function
|
|
13
|
-
const res = await fetch(proxyUrl, request);
|
|
14
|
-
|
|
15
|
-
// optionally, modify the respone
|
|
16
|
-
if (modify) {
|
|
17
|
-
res.headers.set('X-My-Header', 'My Header Value');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return res;
|
|
21
|
-
},
|
|
22
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
async fetch(request, env, ctx) {
|
|
3
|
-
const url = new URL(request.url);
|
|
4
|
-
const redirectUrl = url.searchParams.get('redirectUrl'); // get a query param value (?redirectUrl=...)
|
|
5
|
-
|
|
6
|
-
if (!redirectUrl) {
|
|
7
|
-
return new Response('Bad request: Missing `redirectUrl` query param', { status: 400 });
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// The Response class has static methods to create common Response objects as a convenience
|
|
11
|
-
return Response.redirect(redirectUrl);
|
|
12
|
-
},
|
|
13
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Welcome to Cloudflare Workers! This is your first worker.
|
|
3
|
-
*
|
|
4
|
-
* - Run `npm run dev` in your terminal to start a development server
|
|
5
|
-
* - Open a browser tab at http://localhost:8787/ to see your worker in action
|
|
6
|
-
* - Run `npm run deploy` to publish your worker
|
|
7
|
-
*
|
|
8
|
-
* Learn more at https://developers.cloudflare.com/workers/
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import handleProxy from './proxy';
|
|
12
|
-
import handleRedirect from './redirect';
|
|
13
|
-
import apiRouter from './router';
|
|
14
|
-
|
|
15
|
-
// Export a default object containing event handlers
|
|
16
|
-
export default {
|
|
17
|
-
// The fetch handler is invoked when this worker receives a HTTP(S) request
|
|
18
|
-
// and should return a Response (optionally wrapped in a Promise)
|
|
19
|
-
async fetch(request, env, ctx) {
|
|
20
|
-
// You'll find it helpful to parse the request.url string into a URL object. Learn more at https://developer.mozilla.org/en-US/docs/Web/API/URL
|
|
21
|
-
const url = new URL(request.url);
|
|
22
|
-
|
|
23
|
-
// You can get pretty far with simple logic like if/switch-statements
|
|
24
|
-
switch (url.pathname) {
|
|
25
|
-
case '/redirect':
|
|
26
|
-
return handleRedirect.fetch(request, env, ctx);
|
|
27
|
-
|
|
28
|
-
case '/proxy':
|
|
29
|
-
return handleProxy.fetch(request, env, ctx);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (url.pathname.startsWith('/api/')) {
|
|
33
|
-
// You can also use more robust routing
|
|
34
|
-
return apiRouter.handle(request);
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "<TBD>",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"start": "wrangler dev",
|
|
7
|
-
"deploy": "wrangler publish"
|
|
8
|
-
},
|
|
9
|
-
"devDependencies": {
|
|
10
|
-
"@cloudflare/workers-types": "^4.20230419.0",
|
|
11
|
-
"itty-router": "^3.0.12",
|
|
12
|
-
"typescript": "^5.0.4",
|
|
13
|
-
"wrangler": "^2.19.0"
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const ORIGIN_URL = 'https://example.com';
|
|
2
|
-
const EXPERIMENTS = [
|
|
3
|
-
{ name: 'big-button', threshold: 0.5 }, // enable the Big Button experiment for 50% of users
|
|
4
|
-
{ name: 'new-brand', threshold: 0.1 }, // enable the New Brand experiment for 10% of users
|
|
5
|
-
{ name: 'new-layout', threshold: 0.02 }, // enable the New Layout experiment for 2% of users
|
|
6
|
-
];
|
|
7
|
-
|
|
8
|
-
export default {
|
|
9
|
-
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
10
|
-
const fingerprint = [request.headers.get('cf-connecting-ip'), request.cf?.postalCode]; // add any values you want considered as a fingerprint
|
|
11
|
-
const activeExperiments = await getActiveExperiments(fingerprint, EXPERIMENTS);
|
|
12
|
-
|
|
13
|
-
// add a data-experiments attribute to the <body> tag
|
|
14
|
-
// which can be styled in CSS with a wildcard selector like [data-experiments*="big-button"]
|
|
15
|
-
const rewriter = new HTMLRewriter().on('body', {
|
|
16
|
-
element(element: Element) {
|
|
17
|
-
element.setAttribute('data-experiments', activeExperiments.join(' '));
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const res = await fetch(ORIGIN_URL, request);
|
|
22
|
-
|
|
23
|
-
return rewriter.transform(res);
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// Get active experiments by hashing a fingerprint
|
|
28
|
-
async function getActiveExperiments(fingerprint: unknown, experiments: Array<{ name: string; threshold: number }>) {
|
|
29
|
-
const fingerprintHash: Uint8Array = await hash('SHA-1', JSON.stringify(fingerprint));
|
|
30
|
-
const MAX_UINT8 = 255;
|
|
31
|
-
const activeExperiments = experiments.filter((exp, i) => fingerprintHash[i] <= exp.threshold * MAX_UINT8);
|
|
32
|
-
return activeExperiments.map((exp) => exp.name);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Hash a string using the Web Crypto API
|
|
36
|
-
async function hash(algorithm: 'SHA-1' | 'SHA-256' | 'SHA-512', message: string): Promise<Uint8Array> {
|
|
37
|
-
const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
|
|
38
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); // hash the message
|
|
39
|
-
const hashArray = new Uint8Array(hashBuffer); // convert buffer to byte array
|
|
40
|
-
return hashArray;
|
|
41
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
3
|
-
const url = new URL(request.url);
|
|
4
|
-
|
|
5
|
-
const proxyUrl = url.searchParams.get('proxyUrl'); // get a query param value (?proxyUrl=...)
|
|
6
|
-
const modify = url.searchParams.has('modify'); // check if a query param is set (?proxyUrl=...&modify)
|
|
7
|
-
|
|
8
|
-
if (!proxyUrl) {
|
|
9
|
-
return new Response('Bad request: Missing `proxyUrl` query param', { status: 400 });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// make subrequests with the global `fetch()` function
|
|
13
|
-
const res = await fetch(proxyUrl, request);
|
|
14
|
-
|
|
15
|
-
// optionally, modify the respone
|
|
16
|
-
if (modify) {
|
|
17
|
-
res.headers.set('X-My-Header', 'My Header Value');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return res;
|
|
21
|
-
},
|
|
22
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
3
|
-
const url = new URL(request.url);
|
|
4
|
-
const redirectUrl = url.searchParams.get('redirectUrl'); // get a query param value (?redirectUrl=...)
|
|
5
|
-
|
|
6
|
-
if (!redirectUrl) {
|
|
7
|
-
return new Response('Bad request: Missing `redirectUrl` query param', { status: 400 });
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// The Response class has static methods to create common Response objects as a convenience
|
|
11
|
-
return Response.redirect(redirectUrl);
|
|
12
|
-
},
|
|
13
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Welcome to Cloudflare Workers! This is your first worker.
|
|
3
|
-
*
|
|
4
|
-
* - Run `npm run dev` in your terminal to start a development server
|
|
5
|
-
* - Open a browser tab at http://localhost:8787/ to see your worker in action
|
|
6
|
-
* - Run `npm run deploy` to publish your worker
|
|
7
|
-
*
|
|
8
|
-
* Learn more at https://developers.cloudflare.com/workers/
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import handleProxy from './proxy';
|
|
12
|
-
import handleRedirect from './redirect';
|
|
13
|
-
import apiRouter from './router';
|
|
14
|
-
|
|
15
|
-
// Export a default object containing event handlers
|
|
16
|
-
export default {
|
|
17
|
-
// The fetch handler is invoked when this worker receives a HTTP(S) request
|
|
18
|
-
// and should return a Response (optionally wrapped in a Promise)
|
|
19
|
-
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
20
|
-
// You'll find it helpful to parse the request.url string into a URL object. Learn more at https://developer.mozilla.org/en-US/docs/Web/API/URL
|
|
21
|
-
const url = new URL(request.url);
|
|
22
|
-
|
|
23
|
-
// You can get pretty far with simple logic like if/switch-statements
|
|
24
|
-
switch (url.pathname) {
|
|
25
|
-
case '/redirect':
|
|
26
|
-
return handleRedirect.fetch(request, env, ctx);
|
|
27
|
-
|
|
28
|
-
case '/proxy':
|
|
29
|
-
return handleProxy.fetch(request, env, ctx);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (url.pathname.startsWith('/api/')) {
|
|
33
|
-
// You can also use more robust routing
|
|
34
|
-
return apiRouter.handle(request);
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
interface Env {
|
|
2
|
-
// Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/
|
|
3
|
-
// MY_KV_NAMESPACE: KVNamespace;
|
|
4
|
-
//
|
|
5
|
-
// Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/
|
|
6
|
-
// MY_DURABLE_OBJECT: DurableObjectNamespace;
|
|
7
|
-
//
|
|
8
|
-
// Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/
|
|
9
|
-
// MY_BUCKET: R2Bucket;
|
|
10
|
-
//
|
|
11
|
-
// Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/
|
|
12
|
-
// MY_SERVICE: Fetcher;
|
|
13
|
-
}
|