Skip to content

Commit 5c2a900

Browse files
pescnclaude
andcommitted
fix: use crypto.subtle polyfill instead of custom middleware
Replace the custom static-function-middleware (which depended on internal packages @tanstack/start-client-core and seroval that aren't hoisted in bun) with a lightweight crypto.subtle polyfill. This allows the original @tanstack/start-static-server-functions middleware to work on HTTP. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 915210a commit 5c2a900

4 files changed

Lines changed: 95 additions & 194 deletions

File tree

src/lib/crypto-polyfill.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Polyfill crypto.subtle.digest for non-secure contexts (HTTP).
2+
// crypto.subtle is only available in secure contexts (HTTPS/localhost).
3+
// The staticFunctionMiddleware from @tanstack/start-static-server-functions
4+
// uses crypto.subtle.digest('SHA-1', ...) which fails on HTTP.
5+
6+
function sha1(buffer: Uint8Array): ArrayBuffer {
7+
const rotl = (n: number, s: number) => (n << s) | (n >>> (32 - s));
8+
9+
let h0 = 0x67452301;
10+
let h1 = 0xefcdab89;
11+
let h2 = 0x98badcfe;
12+
let h3 = 0x10325476;
13+
let h4 = 0xc3d2e1f0;
14+
15+
const msgLen = buffer.length;
16+
const bitLen = msgLen * 8;
17+
const paddingLen = (((55 - (msgLen % 64)) + 64) % 64) + 1;
18+
const padded = new Uint8Array(msgLen + paddingLen + 8);
19+
padded.set(buffer);
20+
padded[msgLen] = 0x80;
21+
22+
const view = new DataView(padded.buffer);
23+
view.setUint32(padded.length - 4, bitLen, false);
24+
25+
const w = new Int32Array(80);
26+
for (let offset = 0; offset < padded.length; offset += 64) {
27+
for (let i = 0; i < 16; i++) {
28+
w[i] = view.getInt32(offset + i * 4, false);
29+
}
30+
for (let i = 16; i < 80; i++) {
31+
w[i] = rotl(w[i - 3]! ^ w[i - 8]! ^ w[i - 14]! ^ w[i - 16]!, 1);
32+
}
33+
34+
let a = h0,
35+
b = h1,
36+
c = h2,
37+
d = h3,
38+
e = h4;
39+
40+
for (let i = 0; i < 80; i++) {
41+
let f: number, k: number;
42+
if (i < 20) {
43+
f = (b & c) | (~b & d);
44+
k = 0x5a827999;
45+
} else if (i < 40) {
46+
f = b ^ c ^ d;
47+
k = 0x6ed9eba1;
48+
} else if (i < 60) {
49+
f = (b & c) | (b & d) | (c & d);
50+
k = 0x8f1bbcdc;
51+
} else {
52+
f = b ^ c ^ d;
53+
k = 0xca62c1d6;
54+
}
55+
56+
const temp = (rotl(a, 5) + f + e + k + w[i]!) | 0;
57+
e = d;
58+
d = c;
59+
c = rotl(b, 30);
60+
b = a;
61+
a = temp;
62+
}
63+
64+
h0 = (h0 + a) | 0;
65+
h1 = (h1 + b) | 0;
66+
h2 = (h2 + c) | 0;
67+
h3 = (h3 + d) | 0;
68+
h4 = (h4 + e) | 0;
69+
}
70+
71+
const result = new ArrayBuffer(20);
72+
const resultView = new DataView(result);
73+
resultView.setUint32(0, h0, false);
74+
resultView.setUint32(4, h1, false);
75+
resultView.setUint32(8, h2, false);
76+
resultView.setUint32(12, h3, false);
77+
resultView.setUint32(16, h4, false);
78+
return result;
79+
}
80+
81+
if (typeof globalThis.crypto !== 'undefined' && !globalThis.crypto.subtle) {
82+
(globalThis.crypto as any).subtle = {
83+
async digest(_algorithm: string, data: BufferSource): Promise<ArrayBuffer> {
84+
const buffer =
85+
data instanceof ArrayBuffer
86+
? new Uint8Array(data)
87+
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
88+
return sha1(buffer);
89+
},
90+
};
91+
}

src/lib/static-function-middleware.ts

Lines changed: 0 additions & 192 deletions
This file was deleted.

src/routes/$lang/$.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import browserCollections from 'fumadocs-mdx:collections/browser';
66
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
77
import defaultMdxComponents from 'fumadocs-ui/mdx';
88
import { baseOptions } from '@/lib/layout.shared';
9-
import { staticFunctionMiddleware } from '@/lib/static-function-middleware';
9+
import '@/lib/crypto-polyfill';
10+
import { staticFunctionMiddleware } from '@tanstack/start-static-server-functions';
1011
import { useFumadocsLoader } from 'fumadocs-core/source/client';
1112
import { Suspense } from 'react';
1213
import { ServerUrl, ApiKeyLink, InlineCode, ConfigCode, CodeKeyword, CodeString, CodeComment, CodeLine } from '@/components/mdx';

src/routes/$lang/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import browserCollections from 'fumadocs-mdx:collections/browser';
66
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
77
import defaultMdxComponents from 'fumadocs-ui/mdx';
88
import { baseOptions } from '@/lib/layout.shared';
9-
import { staticFunctionMiddleware } from '@/lib/static-function-middleware';
9+
import '@/lib/crypto-polyfill';
10+
import { staticFunctionMiddleware } from '@tanstack/start-static-server-functions';
1011
import { useFumadocsLoader } from 'fumadocs-core/source/client';
1112
import { Suspense } from 'react';
1213
import { ServerUrl, ApiKeyLink, InlineCode } from '@/components/mdx';

0 commit comments

Comments
 (0)