Skip to content

Commit 539bc37

Browse files
committed
I used to be a huge Cloudflare fan, but I can't believe they forced me to use tabs rather than spaces. I'm now starting to have doubts. I like to admire my code after I write it, and the tab width is simply too wide in GitHub.
1 parent 5cc1789 commit 539bc37

File tree

9 files changed

+243
-242
lines changed

9 files changed

+243
-242
lines changed

.editorconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
root = true
33

44
[*]
5-
indent_style = tab
5+
indent_style = space
6+
indent_size = 4
67
end_of_line = lf
78
charset = utf-8
89
trim_trailing_whitespace = true

.prettierrc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"printWidth": 140,
3-
"singleQuote": true,
4-
"semi": true,
5-
"useTabs": true
2+
"printWidth": 140,
3+
"singleQuote": true,
4+
"semi": true,
5+
"tabWidth": 4
66
}

src/cors.ts

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
const corsHeaders = {
2-
"Access-Control-Allow-Origin": "*",
3-
"Access-Control-Allow-Methods": "GET,HEAD,POST,PUT,DELETE,OPTIONS",
4-
"Access-Control-Max-Age": "86400",
5-
"Access-Control-Allow-Credentials": "true",
6-
"Access-Control-Expose-Headers": "X-LZ-Request-ID",
2+
"Access-Control-Allow-Origin": "*",
3+
"Access-Control-Allow-Methods": "GET,HEAD,POST,PUT,DELETE,OPTIONS",
4+
"Access-Control-Max-Age": "86400",
5+
"Access-Control-Allow-Credentials": "true",
6+
"Access-Control-Expose-Headers": "X-LZ-Request-ID",
77
};
88

99
/**
@@ -12,33 +12,33 @@ const corsHeaders = {
1212
* @returns
1313
*/
1414
export async function handleOptions(request: Request, env: Env): Promise<Response> {
15-
const origin = request.headers.get("Origin") ?? '';
15+
const origin = request.headers.get("Origin") ?? '';
1616

17-
if (!env.LZ_ALLOWED_ORIGINS.includes(origin)) {
18-
return new Response(`Origin ${origin} not allowed`, { status: 403 });
19-
}
17+
if (!env.LZ_ALLOWED_ORIGINS.includes(origin)) {
18+
return new Response(`Origin ${origin} not allowed`, { status: 403 });
19+
}
2020

21-
if (
22-
request.headers.get("Origin") !== null &&
23-
request.headers.get("Access-Control-Request-Method") !== null &&
24-
request.headers.get("Access-Control-Request-Headers") !== null
25-
) {
26-
// Handle CORS preflight requests.
27-
return new Response(null, {
28-
headers: {
29-
...corsHeaders,
30-
"Access-Control-Allow-Origin": request.headers.get("Origin") ?? '',
31-
"Access-Control-Allow-Headers": request.headers.get("Access-Control-Request-Headers") ?? '',
32-
},
33-
});
34-
} else {
35-
// Handle standard OPTIONS request.
36-
return new Response(null, {
37-
headers: {
38-
Allow: "GET,HEAD,POST,PUT,DELETE,OPTIONS",
39-
},
40-
});
41-
}
21+
if (
22+
request.headers.get("Origin") !== null &&
23+
request.headers.get("Access-Control-Request-Method") !== null &&
24+
request.headers.get("Access-Control-Request-Headers") !== null
25+
) {
26+
// Handle CORS preflight requests.
27+
return new Response(null, {
28+
headers: {
29+
...corsHeaders,
30+
"Access-Control-Allow-Origin": request.headers.get("Origin") ?? '',
31+
"Access-Control-Allow-Headers": request.headers.get("Access-Control-Request-Headers") ?? '',
32+
},
33+
});
34+
} else {
35+
// Handle standard OPTIONS request.
36+
return new Response(null, {
37+
headers: {
38+
Allow: "GET,HEAD,POST,PUT,DELETE,OPTIONS",
39+
},
40+
});
41+
}
4242
}
4343

4444
/**
@@ -48,13 +48,13 @@ export async function handleOptions(request: Request, env: Env): Promise<Respons
4848
* @returns
4949
*/
5050
export function responseWithAllowOrigin(response: Response, origin = '*'): Response {
51-
// Clone the response so that it's no longer immutable
52-
const newResponse = new Response(response.body, response);
51+
// Clone the response so that it's no longer immutable
52+
const newResponse = new Response(response.body, response);
5353

54-
// Add cache control headers
55-
newResponse.headers.set('Access-Control-Allow-Origin', origin);
56-
newResponse.headers.set('Access-Control-Allow-Credentials', 'true');
57-
newResponse.headers.set('Access-Control-Expose-Headers', 'X-LZ-Request-ID');
54+
// Add cache control headers
55+
newResponse.headers.set('Access-Control-Allow-Origin', origin);
56+
newResponse.headers.set('Access-Control-Allow-Credentials', 'true');
57+
newResponse.headers.set('Access-Control-Expose-Headers', 'X-LZ-Request-ID');
5858

59-
return newResponse;
59+
return newResponse;
6060
}

src/index.ts

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,37 @@ import { handleOptions, responseWithAllowOrigin } from "./cors";
2222
* @returns
2323
*/
2424
async function handleConversionLog(request: Request<unknown, IncomingRequestCfProperties<unknown>>, env: Env, ctx: ExecutionContext, url: URL): Promise<Response> {
25-
try {
26-
const requestID = new Date().toISOString().substring(0, 19).replaceAll('-', '/').replaceAll('T', '/').replaceAll(':', '') + '--' + crypto.randomUUID();
27-
const loggingEnabled = Math.random() < env.LZ_LOG_SAMPLE_RATE;
28-
29-
// Example path: [0]/[1]api/[2]v2/[3]convert/[4]zpl/[5]to/[6]pdf
30-
const conversionPathParts = url.pathname.split('/');
31-
const sourceFormat = conversionPathParts[4].toLowerCase();
32-
const targetFormat = conversionPathParts[6].toLowerCase();
25+
try {
26+
const requestID = new Date().toISOString().substring(0, 19).replaceAll('-', '/').replaceAll('T', '/').replaceAll(':', '') + '--' + crypto.randomUUID();
27+
const loggingEnabled = Math.random() < env.LZ_LOG_SAMPLE_RATE;
28+
29+
// Example path: [0]/[1]api/[2]v2/[3]convert/[4]zpl/[5]to/[6]pdf
30+
const conversionPathParts = url.pathname.split('/');
31+
const sourceFormat = conversionPathParts[4].toLowerCase();
32+
const targetFormat = conversionPathParts[6].toLowerCase();
3333

34-
// TODO: Unwrap Base64 (if applicable) before storing in R2
35-
36-
// Clone and log request asynchronously
37-
if (loggingEnabled) ctx.waitUntil(Promise.all([
38-
env.LZ_R2_BUCKET.put(requestID + `/in.${sourceFormat}`, request.clone().body), // TODO: Set content type
39-
env.LZ_R2_BUCKET.put(requestID + '/params.json', url.searchParams.get('params'), {httpMetadata:{contentType:'application/json'}})
40-
]));
41-
42-
// Generate response
43-
const response = await proxyRequestToBackend(request, url, env, requestID);
44-
45-
// Clone and log response asynchronously
46-
if (loggingEnabled) ctx.waitUntil(
47-
env.LZ_R2_BUCKET.put(requestID + `/out.${targetFormat}`, response.clone().body) // TODO: Set content type
48-
);
49-
50-
// Return response to client
51-
return response;
52-
} catch (error) {
53-
console.error("error logging conversion data", error);
54-
return await proxyRequestToBackend(request, url, env);
55-
}
34+
// TODO: Unwrap Base64 (if applicable) before storing in R2
35+
36+
// Clone and log request asynchronously
37+
if (loggingEnabled) ctx.waitUntil(Promise.all([
38+
env.LZ_R2_BUCKET.put(requestID + `/in.${sourceFormat}`, request.clone().body), // TODO: Set content type
39+
env.LZ_R2_BUCKET.put(requestID + '/params.json', url.searchParams.get('params'), {httpMetadata:{contentType:'application/json'}})
40+
]));
41+
42+
// Generate response
43+
const response = await proxyRequestToBackend(request, url, env, requestID);
44+
45+
// Clone and log response asynchronously
46+
if (loggingEnabled) ctx.waitUntil(
47+
env.LZ_R2_BUCKET.put(requestID + `/out.${targetFormat}`, response.clone().body) // TODO: Set content type
48+
);
49+
50+
// Return response to client
51+
return response;
52+
} catch (error) {
53+
console.error("error logging conversion data", error);
54+
return await proxyRequestToBackend(request, url, env);
55+
}
5656
}
5757

5858
/**
@@ -62,20 +62,20 @@ async function handleConversionLog(request: Request<unknown, IncomingRequestCfPr
6262
* @returns
6363
*/
6464
async function proxyRequestToBackend(request: Request, url: URL, env: Env, requestID = ''): Promise<Response> {
65-
const backendUrl = env.LZ_PROD_API_BASE_URL + url.pathname + url.search;
66-
const newRequest = new Request(backendUrl, request);
67-
let ip = request.headers.get("X-Forwarded-For") ?? '';
68-
if (!ip) {
69-
ip = request.headers.get("Cf-Connecting-Ip") ?? '';
70-
}
71-
newRequest.headers.set('X-LZ-IP', ip);
72-
newRequest.headers.set('X-LZ-Secret-Key', env.LZ_PROD_API_SECRET_KEY)
73-
if (requestID) newRequest.headers.set("X-LZ-Request-ID", requestID);
74-
const response = await fetch(newRequest);
65+
const backendUrl = env.LZ_PROD_API_BASE_URL + url.pathname + url.search;
66+
const newRequest = new Request(backendUrl, request);
67+
let ip = request.headers.get("X-Forwarded-For") ?? '';
68+
if (!ip) {
69+
ip = request.headers.get("Cf-Connecting-Ip") ?? '';
70+
}
71+
newRequest.headers.set('X-LZ-IP', ip);
72+
newRequest.headers.set('X-LZ-Secret-Key', env.LZ_PROD_API_SECRET_KEY)
73+
if (requestID) newRequest.headers.set("X-LZ-Request-ID", requestID);
74+
const response = await fetch(newRequest);
7575

7676
// Force redirects to be relative because I couldn't get it to work in Spring Boot
7777
if (response.status === 301 || response.status === 302) {
78-
const locationHeader = response.headers.get('Location') ?? '';
78+
const locationHeader = response.headers.get('Location') ?? '';
7979
if (locationHeader.includes('labelzoom.net/')) {
8080
const url = new URL(locationHeader);
8181

@@ -85,44 +85,44 @@ async function proxyRequestToBackend(request: Request, url: URL, env: Env, reque
8585
}
8686
}
8787

88-
return response;
88+
return response;
8989
}
9090

9191
export default {
92-
async fetch(request, env, ctx): Promise<Response> {
93-
const url = new URL(request.url);
92+
async fetch(request, env, ctx): Promise<Response> {
93+
const url = new URL(request.url);
9494

95-
// API modifiers
96-
if (url.pathname.startsWith('/api/')) {
97-
if (request.method === "OPTIONS") {
98-
// Handle CORS preflight requests
99-
return handleOptions(request, env);
100-
}
101-
if (url.pathname.startsWith('/api/v2/convert/')) {
102-
return responseWithAllowOrigin(
103-
await handleConversionLog(request, env, ctx, url),
104-
request.headers.get('Origin') ?? '*'
105-
);
106-
}
95+
// API modifiers
96+
if (url.pathname.startsWith('/api/')) {
97+
if (request.method === "OPTIONS") {
98+
// Handle CORS preflight requests
99+
return handleOptions(request, env);
100+
}
101+
if (url.pathname.startsWith('/api/v2/convert/')) {
102+
return responseWithAllowOrigin(
103+
await handleConversionLog(request, env, ctx, url),
104+
request.headers.get('Origin') ?? '*'
105+
);
106+
}
107107

108-
// Fallthrough behavior, proxy request to Spring Web
109-
return responseWithAllowOrigin(
110-
await proxyRequestToBackend(request, url, env),
111-
request.headers.get('Origin') ?? '*'
112-
);
113-
} else if (url.pathname === '/api') {
114-
// Force trailing slash after /api
115-
url.pathname = '/api/';
116-
return Response.redirect(url.toString());
117-
}
108+
// Fallthrough behavior, proxy request to Spring Web
109+
return responseWithAllowOrigin(
110+
await proxyRequestToBackend(request, url, env),
111+
request.headers.get('Origin') ?? '*'
112+
);
113+
} else if (url.pathname === '/api') {
114+
// Force trailing slash after /api
115+
url.pathname = '/api/';
116+
return Response.redirect(url.toString());
117+
}
118118

119-
// TODO: Eventually we'll wall off access to the rest of the endpoints once everything has been fully migrated
120-
// return new Response(`Not found`, { status: 404 });
119+
// TODO: Eventually we'll wall off access to the rest of the endpoints once everything has been fully migrated
120+
// return new Response(`Not found`, { status: 404 });
121121

122-
// Fallthrough behavior, proxy request to Spring Web
123-
return responseWithAllowOrigin(
124-
await proxyRequestToBackend(request, url, env),
125-
request.headers.get('Origin') ?? '*'
126-
);
127-
},
122+
// Fallthrough behavior, proxy request to Spring Web
123+
return responseWithAllowOrigin(
124+
await proxyRequestToBackend(request, url, env),
125+
request.headers.get('Origin') ?? '*'
126+
);
127+
},
128128
} satisfies ExportedHandler<Env>;

test/index.spec.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ import worker from '../src/index';
88
const IncomingRequest = Request<unknown, IncomingRequestCfProperties>;
99

1010
describe('LabelZoom Reverse Proxy worker (API routes)', () => {
11-
it('responds with LabelZoom API version (unit style)', async () => {
12-
const request = new IncomingRequest('https://www.labelzoom.net/api/v2/heartbeat');
13-
// Create an empty context to pass to `worker.fetch()`.
14-
const ctx = createExecutionContext();
15-
const response = await worker.fetch(request, env, ctx);
16-
// Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
17-
await waitOnExecutionContext(ctx);
18-
expect(await response.text()).toMatch(/LabelZoom v\d+\.\d+\.\d+/);
19-
});
11+
it('responds with LabelZoom API version (unit style)', async () => {
12+
const request = new IncomingRequest('https://www.labelzoom.net/api/v2/heartbeat');
13+
// Create an empty context to pass to `worker.fetch()`.
14+
const ctx = createExecutionContext();
15+
const response = await worker.fetch(request, env, ctx);
16+
// Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
17+
await waitOnExecutionContext(ctx);
18+
expect(await response.text()).toMatch(/LabelZoom v\d+\.\d+\.\d+/);
19+
});
2020

21-
it('responds with LabelZoom API version (integration style)', async () => {
22-
const response = await SELF.fetch('https://www.labelzoom.net/api/v2/heartbeat');
23-
expect(await response.text()).toMatch(/LabelZoom v\d+\.\d+\.\d+/);
24-
});
21+
it('responds with LabelZoom API version (integration style)', async () => {
22+
const response = await SELF.fetch('https://www.labelzoom.net/api/v2/heartbeat');
23+
expect(await response.text()).toMatch(/LabelZoom v\d+\.\d+\.\d+/);
24+
});
2525
});

test/tsconfig.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
2-
"extends": "../tsconfig.json",
3-
"compilerOptions": {
4-
"types": ["@cloudflare/workers-types/experimental", "@cloudflare/vitest-pool-workers"]
5-
},
6-
"include": ["./**/*.ts", "../src/env.d.ts"],
7-
"exclude": []
2+
"extends": "../tsconfig.json",
3+
"compilerOptions": {
4+
"types": ["@cloudflare/workers-types/experimental", "@cloudflare/vitest-pool-workers"]
5+
},
6+
"include": ["./**/*.ts", "../src/env.d.ts"],
7+
"exclude": []
88
}

0 commit comments

Comments
 (0)