import * as os from 'os'
import './url.js'
import './text-codec.js'
declare global {
interface Console {
error: (...args: unknown[]) => void
}
var window: typeof globalThis
type TimerId = os.TimerId
function setTimeout
(fn: (...argsf: P) => void, ms?: number, ...argsr: P): TimerId
function clearTimeout(id: TimerId): void
function btoa(data: string): string
function atob(data: string): string
interface SubtleCrypto {
digest(algorithm: 'SHA-1', data: ArrayBuffer | Uint8Array): Promise
}
interface Crypto {
getRandomValues(array: T): T
subtle: SubtleCrypto
}
var crypto: Crypto
}
// 1. window — triggers Emscripten browser path
if (typeof globalThis.window === 'undefined')
globalThis.window = globalThis
// 2. setTimeout polyfill — bridge to os.setTimeout
if (typeof globalThis.setTimeout === 'undefined') {
globalThis.setTimeout = ((fn, ms, ...args) => {
return os.setTimeout(() => fn(...args), ms ?? 0)
}) satisfies typeof setTimeout
}
// 2b. clearTimeout polyfill — bridge to os.clearTimeout
if (typeof globalThis.clearTimeout === 'undefined') {
globalThis.clearTimeout = os.clearTimeout
}
// 3. console.error polyfill — QuickJS only has console.log
if (typeof console.error === 'undefined') {
console.error = (...args: unknown[]) => { console.log(...args) }
}
// ── SHA-1 ──
function sha1Bytes(bytes: number[]): ArrayBuffer {
const len = bytes.length
const ml = len * 8
bytes.push(0x80)
while (bytes.length % 64 !== 56) { bytes.push(0) }
bytes.push(0)
bytes.push(0)
bytes.push(0)
bytes.push(0)
bytes.push((ml >>> 24) & 0xFF)
bytes.push((ml >>> 16) & 0xFF)
bytes.push((ml >>> 8) & 0xFF)
bytes.push(ml & 0xFF)
let h0 = 0x67452301, h1 = 0xEFCDAB89
let h2 = 0x98BADCFE, h3 = 0x10325476, h4 = 0xC3D2E1F0
const rotl = (x: number, n: number): number => ((x << n) | (x >>> (32 - n))) >>> 0
for (let i = 0; i < bytes.length; i += 64) {
const w: number[] = []
for (let t = 0; t < 16; t++) {
w[t] = (bytes[i + 4 * t]! << 24) | (bytes[i + 4 * t + 1]! << 16) |
(bytes[i + 4 * t + 2]! << 8) | bytes[i + 4 * t + 3]!
}
for (let t = 16; t < 80; t++) {
w[t] = rotl(w[t - 3]! ^ w[t - 8]! ^ w[t - 14]! ^ w[t - 16]!, 1)
}
let a = h0, b = h1, c = h2, d = h3, e = h4
for (let t = 0; t < 80; t++) {
let f: number, k: number
if (t < 20) { f = (b & c) | (~b & d); k = 0x5A827999 }
else if (t < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1 }
else if (t < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC }
else { f = b ^ c ^ d; k = 0xCA62C1D6 }
const temp = (rotl(a, 5) + f + e + k + w[t]!) >>> 0
e = d; d = c; c = rotl(b, 30); b = a; a = temp
}
h0 = (h0 + a) >>> 0; h1 = (h1 + b) >>> 0
h2 = (h2 + c) >>> 0; h3 = (h3 + d) >>> 0; h4 = (h4 + e) >>> 0
}
const result = new Uint8Array(20)
const w32 = (off: number, v: number) => {
result[off] = (v >>> 24) & 0xFF; result[off + 1] = (v >>> 16) & 0xFF
result[off + 2] = (v >>> 8) & 0xFF; result[off + 3] = v & 0xFF
}
w32(0, h0); w32(4, h1); w32(8, h2); w32(12, h3); w32(16, h4)
return result.buffer
}
// ── Base64 ──
const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function b64Encode(data: Uint8Array): string {
let r = ''
for (let i = 0; i < data.length; i += 3) {
const b0 = data[i]!, b1 = i + 1 < data.length ? data[i + 1]! : 0, b2 = i + 2 < data.length ? data[i + 2]! : 0
r += B64[b0 >> 2]! + B64[((b0 & 3) << 4) | (b1 >> 4)]!
r += i + 1 < data.length ? B64[((b1 & 15) << 2) | (b2 >> 6)]! : '='
r += i + 2 < data.length ? B64[b2 & 63]! : '='
}
return r
}
function b64Decode(str: string): Uint8Array {
str = str.replace(/[^A-Za-z0-9+/=]/g, '')
const bytes: number[] = []
for (let i = 0; i < str.length; i += 4) {
const c0 = B64.indexOf(str[i]!), c1 = B64.indexOf(str[i + 1]!)
const c2 = B64.indexOf(str[i + 2]!), c3 = B64.indexOf(str[i + 3]!)
bytes.push((c0 << 2) | (c1 >> 4))
if (c2 >= 0) bytes.push(((c1 & 15) << 4) | (c2 >> 2))
if (c3 >= 0) bytes.push(((c2 & 3) << 6) | c3)
}
return new Uint8Array(bytes)
}
// ── btoa / atob ──
if (typeof globalThis.btoa === 'undefined') {
globalThis.btoa = (data: string): string => {
const bytes = new Uint8Array(data.length)
for (let i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i) & 0xFF
return b64Encode(bytes)
}
}
if (typeof globalThis.atob === 'undefined') {
globalThis.atob = (data: string): string => {
const bytes = b64Decode(data)
let r = ''
for (let i = 0; i < bytes.length; i++) r += String.fromCharCode(bytes[i]!)
return r
}
}
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = {
getRandomValues: (array: T): T => {
const view = new Uint8Array(array.buffer, array.byteOffset, array.byteLength)
for (let i = 0; i < view.length; i++) view[i] = (Math.random() * 256) | 0
return array
},
subtle: {
digest: (algorithm: string, data: ArrayBuffer | Uint8Array): Promise => {
if (algorithm.toUpperCase() !== 'SHA-1')
return Promise.reject(new Error('Digest: ' + algorithm + ' not supported'))
const bytes = data instanceof Uint8Array ? Array.from(data) : Array.from(new Uint8Array(data))
return Promise.resolve(sha1Bytes(bytes))
}
}
}
}