Skip to content

Commit d0d8c77

Browse files
authored
Merge pull request #1 from SableClient/hazre/refactor/web-platform-apis
refactor: remove nodejs_compat, replace Buffer with Web Platform APIs in mxcId
2 parents 58479aa + 1c41470 commit d0d8c77

6 files changed

Lines changed: 56 additions & 107 deletions

File tree

README.md

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,14 @@ Example in TypeScript, as seen in `mxcId.ts`:
1313

1414
```typescript
1515
function toBase64Url(value: string): string {
16-
if (typeof btoa === 'function') {
17-
const bytes = new TextEncoder().encode(value);
18-
let binary = '';
16+
const bytes = new TextEncoder().encode(value);
17+
let binary = '';
1918

20-
for (const byte of bytes) {
21-
binary += String.fromCodePoint(byte);
22-
}
23-
24-
return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replaceAll(/=+$/g, '');
25-
}
26-
27-
if (typeof Buffer !== 'undefined') {
28-
return Buffer.from(value).toString('base64url');
19+
for (const byte of bytes) {
20+
binary += String.fromCodePoint(byte);
2921
}
3022

31-
throw new Error('No base64 encoder available in this runtime');
23+
return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replaceAll(/=+$/g, '');
3224
}
3325

3426
function toMatrixID(fname: string, prefix: string): string {

pnpm-workspace.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
allowBuilds:
2+
esbuild: true
3+
sharp: true
4+
workerd: true
5+
packages:
6+
- '.'

src/mxcId.ts

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,14 @@
2323
* @return {*} {string} the url-safe-base64 encoded string
2424
*/
2525
function toBase64Url(value: string): string {
26-
if (typeof btoa === 'function') {
27-
const bytes = new TextEncoder().encode(value);
28-
let binary = '';
26+
const bytes = new TextEncoder().encode(value);
27+
let binary = '';
2928

30-
for (const byte of bytes) {
31-
binary += String.fromCodePoint(byte);
32-
}
33-
34-
return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replaceAll(/=+$/g, '');
35-
}
36-
37-
if (typeof Buffer !== 'undefined') {
38-
return Buffer.from(value).toString('base64url');
29+
for (const byte of bytes) {
30+
binary += String.fromCodePoint(byte);
3931
}
4032

41-
throw new Error('No base64 encoder available in this runtime');
33+
return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replaceAll(/=+$/g, '');
4234
}
4335

4436
/**
@@ -48,19 +40,11 @@ function toBase64Url(value: string): string {
4840
* @return {*} {string} the usable string
4941
*/
5042
function fromBase64Url(value: string): string {
51-
if (typeof atob === 'function') {
52-
const normalized = value.replace(/-/g, '+').replace(/_/g, '/');
53-
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
54-
const binary = atob(padded);
55-
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
56-
return new TextDecoder().decode(bytes);
57-
}
58-
59-
if (typeof Buffer !== 'undefined') {
60-
return Buffer.from(value, 'base64url').toString();
61-
}
62-
63-
throw new Error('No base64 decoder available in this runtime');
43+
const normalized = value.replace(/-/g, '+').replace(/_/g, '/');
44+
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
45+
const binary = atob(padded);
46+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
47+
return new TextDecoder().decode(bytes);
6448
}
6549

6650
/**

src/proxy.ts

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,42 @@ function decodeMatrixId(rawId: string): string | MatrixError {
4141

4242
return id;
4343
}
44+
type MultipartPartLike = {
45+
headers: HeadersInit;
46+
body?: BodyInit;
47+
};
48+
49+
function encodeMultipart(boundary: string, parts: MultipartPartLike[]): string {
50+
const lines: string[] = [];
51+
52+
for (const part of parts) {
53+
lines.push(`--${boundary}`);
54+
for (const [key, value] of Object.entries(part.headers)) {
55+
lines.push(`${key}: ${value}`);
56+
}
57+
lines.push('');
58+
lines.push(part.body ? String(part.body) : '');
59+
}
60+
61+
lines.push(`--${boundary}--`, '');
62+
return lines.join('\r\n');
63+
}
64+
4465
function buildMultipartRedirect(targetLocation: string): Response {
4566
const boundary = `soliditas${Date.now().toString(16)}${Math.random().toString(16).slice(2)}`;
46-
const body = Buffer.from(
47-
`--${boundary}\r\n` +
48-
`Content-Type: application/json\r\n` +
49-
`\r\n` +
50-
`{}\r\n` +
51-
`--${boundary}\r\n` +
52-
`Content-Type: application/octet-stream\r\n` +
53-
`Location: ${targetLocation}\r\n` +
54-
`\r\n` +
55-
`\r\n` +
56-
`--${boundary}--\r\n`,
57-
'utf8'
58-
);
67+
68+
const body = encodeMultipart(boundary, [
69+
{
70+
headers: { 'Content-Type': 'application/json' },
71+
body: '{}',
72+
},
73+
{
74+
headers: {
75+
'Content-Type': 'application/octet-stream',
76+
'Location': targetLocation,
77+
},
78+
},
79+
]);
5980

6081
return new Response(body, {
6182
headers: {

test/mxcId.spec.ts

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -60,55 +60,3 @@ describe('fromMatrixID', () => {
6060
expect(fromMatrixID(`custom_${encoded.split('_')[1]}`)).toBe('file.txt');
6161
});
6262
});
63-
64-
describe('runtime fallbacks', () => {
65-
const originalBtoa = globalThis.btoa;
66-
const originalAtob = globalThis.atob;
67-
const originalBuffer = globalThis.Buffer;
68-
69-
afterEach(() => {
70-
globalThis.btoa = originalBtoa;
71-
globalThis.atob = originalAtob;
72-
globalThis.Buffer = originalBuffer;
73-
});
74-
75-
it('uses Buffer fallback when btoa is unavailable', () => {
76-
// @ts-expect-error test override
77-
globalThis.btoa = undefined;
78-
79-
const result = toMatrixID('buffer-test.txt', 'mxc_');
80-
81-
expect(result).toBe('mxc_YnVmZmVyLXRlc3QudHh0');
82-
});
83-
84-
it('uses Buffer fallback when atob is unavailable', () => {
85-
// @ts-expect-error test override
86-
globalThis.atob = undefined;
87-
88-
const encoded = toMatrixID('buffer-decode.txt', 'mxc_');
89-
90-
expect(fromMatrixID(encoded)).toBe('buffer-decode.txt');
91-
});
92-
93-
it('throws if no encoder runtime is available', async () => {
94-
// @ts-expect-error test override
95-
globalThis.btoa = undefined;
96-
// @ts-expect-error test override
97-
globalThis.Buffer = undefined;
98-
99-
expect(() => toMatrixID('fail.txt', 'mxc_')).toThrow(
100-
'No base64 encoder available in this runtime',
101-
);
102-
});
103-
104-
it('throws if no decoder runtime is available', async () => {
105-
// @ts-expect-error test override
106-
globalThis.atob = undefined;
107-
// @ts-expect-error test override
108-
globalThis.Buffer = undefined;
109-
110-
expect(() => fromMatrixID('mxc_ZmlsZS50eHQ')).toThrow(
111-
'No base64 decoder available in this runtime',
112-
);
113-
});
114-
});

wrangler.jsonc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
"enabled": true
1212
},
1313
"upload_source_maps": true,
14-
"compatibility_flags": [
15-
"nodejs_compat"
16-
],
14+
"compatibility_flags": [],
1715
/**
1816
* Smart Placement
1917
* https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement

0 commit comments

Comments
 (0)