quickwin 2026.5.2-3.145209

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.
Files changed (83) hide show
  1. package/README.md +6 -0
  2. package/examples/pdf_preview.js +440 -0
  3. package/examples/pdf_preview.ts +470 -0
  4. package/examples/preact_demo.js +35 -0
  5. package/examples/preact_demo.tsx +49 -0
  6. package/examples/tray_demo.js +75 -0
  7. package/examples/tray_demo.tsx +79 -0
  8. package/lib/fetch.js +746 -0
  9. package/lib/fetch.ts +811 -0
  10. package/lib/polyfill.js +500 -0
  11. package/lib/polyfill.ts +454 -0
  12. package/lib/preact/hooks.js +287 -0
  13. package/lib/preact/hooks.ts +330 -0
  14. package/lib/preact/jsx-runtime.js +1 -0
  15. package/lib/preact/jsx-runtime.ts +2 -0
  16. package/lib/preact/jsx.d.ts +36 -0
  17. package/lib/preact/layout.js +153 -0
  18. package/lib/preact/layout.ts +183 -0
  19. package/lib/preact/preact.js +54 -0
  20. package/lib/preact/preact.ts +133 -0
  21. package/lib/preact/props.js +99 -0
  22. package/lib/preact/props.ts +119 -0
  23. package/lib/preact/render.js +320 -0
  24. package/lib/preact/render.ts +353 -0
  25. package/lib/websocket.js +540 -0
  26. package/lib/websocket.ts +574 -0
  27. package/package.json +32 -0
  28. package/quickwin.d.ts +657 -0
  29. package/test/add.wasm +0 -0
  30. package/test/complex.wasm +0 -0
  31. package/test/complex_imports.wasm +0 -0
  32. package/test/global_imports.wasm +0 -0
  33. package/test/import_func.wasm +0 -0
  34. package/test/imports.wasm +0 -0
  35. package/test/run.js +86 -0
  36. package/test/run.ts +90 -0
  37. package/test/sjlj.wasm +0 -0
  38. package/test/test_basic.js +7 -0
  39. package/test/test_basic.ts +9 -0
  40. package/test/test_brotli.js +48 -0
  41. package/test/test_brotli.ts +52 -0
  42. package/test/test_fetch_cache.js +131 -0
  43. package/test/test_fetch_cache.ts +141 -0
  44. package/test/test_ffi.js +157 -0
  45. package/test/test_ffi.ts +174 -0
  46. package/test/test_frame_encoding.js +128 -0
  47. package/test/test_frame_encoding.ts +132 -0
  48. package/test/test_helper.js +84 -0
  49. package/test/test_helper.ts +80 -0
  50. package/test/test_http_import.js +78 -0
  51. package/test/test_http_import.ts +74 -0
  52. package/test/test_mupdf_render.js +69 -0
  53. package/test/test_mupdf_render.ts +74 -0
  54. package/test/test_mupdf_twice.js +77 -0
  55. package/test/test_mupdf_twice.ts +81 -0
  56. package/test/test_mupdf_wasm.js +33 -0
  57. package/test/test_mupdf_wasm.ts +30 -0
  58. package/test/test_net_event.js +63 -0
  59. package/test/test_net_event.ts +59 -0
  60. package/test/test_net_fetch.js +153 -0
  61. package/test/test_net_fetch.ts +131 -0
  62. package/test/test_net_websocket.js +158 -0
  63. package/test/test_net_websocket.ts +144 -0
  64. package/test/test_polyfill.js +58 -0
  65. package/test/test_polyfill.ts +60 -0
  66. package/test/test_url.js +173 -0
  67. package/test/test_url.ts +183 -0
  68. package/test/test_wasm_basic.js +82 -0
  69. package/test/test_wasm_basic.ts +70 -0
  70. package/test/test_wasm_import_global.js +41 -0
  71. package/test/test_wasm_import_global.ts +39 -0
  72. package/test/test_wasm_sjlj.js +153 -0
  73. package/test/test_wasm_sjlj.ts +134 -0
  74. package/test/test_wasm_types.js +96 -0
  75. package/test/test_wasm_types.ts +108 -0
  76. package/test/types.wasm +0 -0
  77. package/tsconfig.json +18 -0
  78. package/vendor/mupdf-wasm/mupdf-wasm.d.ts +571 -0
  79. package/vendor/mupdf-wasm/mupdf-wasm.js +2749 -0
  80. package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
  81. package/vendor/mupdf-wasm/mupdf.d.ts +939 -0
  82. package/vendor/mupdf-wasm/mupdf.js +3317 -0
  83. package/win-mingw64.exe +0 -0
@@ -0,0 +1,454 @@
1
+ import * as os from 'os'
2
+
3
+ declare global {
4
+ interface Console {
5
+ error: (...args: any) => void
6
+ }
7
+
8
+ var window: typeof globalThis
9
+
10
+ interface TextDecoder {
11
+ encoding: string
12
+ decode(buffer?: ArrayBuffer | Uint8Array): string
13
+ }
14
+ var TextDecoder: { new(): TextDecoder }
15
+
16
+ interface TextEncoder {
17
+ encoding: string
18
+ encode(input?: string): Uint8Array
19
+ }
20
+ var TextEncoder: { new(): TextEncoder }
21
+
22
+ function setTimeout(fn: (...args: any[]) => void, ms: number, ...args: any[]): number
23
+
24
+ function btoa(data: string): string
25
+ function atob(data: string): string
26
+
27
+ interface SubtleCrypto {
28
+ digest(algorithm: 'SHA-1', data: ArrayBuffer | Uint8Array): Promise<ArrayBuffer>
29
+ }
30
+
31
+ interface Crypto {
32
+ getRandomValues<T extends ArrayBufferView>(array: T): T
33
+ subtle: SubtleCrypto
34
+ }
35
+
36
+ var crypto: Crypto
37
+
38
+ interface URLSearchParams {
39
+ append(key: string, value: string): void
40
+ delete(key: string): void
41
+ get(key: string): string | null
42
+ getAll(key: string): string[]
43
+ has(key: string): boolean
44
+ set(key: string, value: string): void
45
+ sort(): void
46
+ forEach(fn: (value: string, key: string) => void): void
47
+ keys(): IterableIterator<string>
48
+ values(): IterableIterator<string>
49
+ entries(): IterableIterator<[string, string]>
50
+ toString(): string
51
+ readonly size: number
52
+ [Symbol.iterator](): IterableIterator<[string, string]>
53
+ }
54
+
55
+ var URLSearchParams: {
56
+ new(init?: string | [string, string][] | Record<string, string>): URLSearchParams
57
+ prototype: URLSearchParams
58
+ }
59
+
60
+ interface URL {
61
+ href: string
62
+ protocol: string
63
+ hostname: string
64
+ port: string
65
+ pathname: string
66
+ search: string
67
+ hash: string
68
+ host: string
69
+ origin: string
70
+ username: string
71
+ password: string
72
+ searchParams: URLSearchParams
73
+ toString(): string
74
+ toJSON(): string
75
+ }
76
+
77
+ var URL: {
78
+ new(url: string, base?: string): URL
79
+ prototype: URL
80
+ }
81
+ }
82
+
83
+ // 1. window — triggers Emscripten browser path
84
+ if (typeof globalThis.window === 'undefined')
85
+ globalThis.window = globalThis
86
+
87
+ // 2. TextDecoder polyfill
88
+ if (typeof globalThis.TextDecoder === 'undefined') {
89
+ globalThis.TextDecoder = class TextDecoder {
90
+ encoding: string = 'utf-8'
91
+ decode(buffer?: ArrayBuffer | Uint8Array): string {
92
+ if (!buffer) return ''
93
+ const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer)
94
+ let out = ''
95
+ for (let i = 0; i < bytes.length; ) {
96
+ const b = bytes[i++]
97
+ if (b < 0x80) { out += String.fromCharCode(b); continue }
98
+ let c: number
99
+ if (b < 0xE0) { c = b & 0x1F; c = (c << 6) | (bytes[i++] & 0x3F) }
100
+ else if (b < 0xF0) { c = b & 0x0F; c = (c << 6) | (bytes[i++] & 0x3F); c = (c << 6) | (bytes[i++] & 0x3F) }
101
+ else { c = b & 0x07; c = (c << 6) | (bytes[i++] & 0x3F); c = (c << 6) | (bytes[i++] & 0x3F); c = (c << 6) | (bytes[i++] & 0x3F) }
102
+ if (c <= 0xFFFF) out += String.fromCharCode(c)
103
+ else { c -= 0x10000; out += String.fromCharCode(0xD800 | (c >> 10), 0xDC00 | (c & 0x3FF)) }
104
+ }
105
+ return out
106
+ }
107
+ }
108
+ }
109
+
110
+ // 3. setTimeout polyfill — bridge to os.setTimeout
111
+ if (typeof globalThis.setTimeout === 'undefined') {
112
+ globalThis.setTimeout = (fn: (...args: unknown[]) => void, ms: number, ...args: unknown[]) => {
113
+ return os.setTimeout(() => fn(...args), ms)
114
+ }
115
+ }
116
+
117
+ // 4. TextEncoder polyfill
118
+ if (typeof globalThis.TextEncoder === 'undefined') {
119
+ globalThis.TextEncoder = class TextEncoder {
120
+ encoding: string = 'utf-8'
121
+ encode(input?: string): Uint8Array {
122
+ if (!input) return new Uint8Array(0)
123
+ const bytes: number[] = []
124
+ for (let i = 0; i < input.length; i++) {
125
+ let c = input.charCodeAt(i)
126
+ if (c < 0x80) { bytes.push(c) }
127
+ else if (c < 0x800) { bytes.push(0xC0 | (c >> 6), 0x80 | (c & 0x3F)) }
128
+ else if (c < 0xD800 || c >= 0xE000) { bytes.push(0xE0 | (c >> 12), 0x80 | ((c >> 6) & 0x3F), 0x80 | (c & 0x3F)) }
129
+ else { i++; const c2 = input.charCodeAt(i); c = 0x10000 + ((c & 0x3FF) << 10) | (c2 & 0x3FF); bytes.push(0xF0 | (c >> 18), 0x80 | ((c >> 12) & 0x3F), 0x80 | ((c >> 6) & 0x3F), 0x80 | (c & 0x3F)) }
130
+ }
131
+ return new Uint8Array(bytes)
132
+ }
133
+ }
134
+ }
135
+
136
+ // 5. console.error polyfill — QuickJS only has console.log
137
+ if (typeof console.error === 'undefined') {
138
+ console.error = (...args: unknown[]) => { console.log(...args) }
139
+ }
140
+
141
+
142
+ // ── SHA-1 ──
143
+
144
+ function sha1Bytes(bytes: number[]): Uint8Array {
145
+ const len = bytes.length
146
+ const ml = len * 8
147
+
148
+ bytes.push(0x80)
149
+ while (bytes.length % 64 !== 56) { bytes.push(0) }
150
+ bytes.push(0)
151
+ bytes.push(0)
152
+ bytes.push(0)
153
+ bytes.push(0)
154
+ bytes.push((ml >>> 24) & 0xFF)
155
+ bytes.push((ml >>> 16) & 0xFF)
156
+ bytes.push((ml >>> 8) & 0xFF)
157
+ bytes.push(ml & 0xFF)
158
+
159
+ let h0 = 0x67452301, h1 = 0xEFCDAB89
160
+ let h2 = 0x98BADCFE, h3 = 0x10325476, h4 = 0xC3D2E1F0
161
+ const rotl = (x: number, n: number): number => ((x << n) | (x >>> (32 - n))) >>> 0
162
+
163
+ for (let i = 0; i < bytes.length; i += 64) {
164
+ const w: number[] = []
165
+ for (let t = 0; t < 16; t++) {
166
+ w[t] = (bytes[i + 4 * t] << 24) | (bytes[i + 4 * t + 1] << 16) |
167
+ (bytes[i + 4 * t + 2] << 8) | bytes[i + 4 * t + 3]
168
+ }
169
+ for (let t = 16; t < 80; t++) {
170
+ w[t] = rotl(w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16], 1)
171
+ }
172
+
173
+ let a = h0, b = h1, c = h2, d = h3, e = h4
174
+ for (let t = 0; t < 80; t++) {
175
+ let f: number, k: number
176
+ if (t < 20) { f = (b & c) | (~b & d); k = 0x5A827999 }
177
+ else if (t < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1 }
178
+ else if (t < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC }
179
+ else { f = b ^ c ^ d; k = 0xCA62C1D6 }
180
+ const temp = (rotl(a, 5) + f + e + k + w[t]) >>> 0
181
+ e = d; d = c; c = rotl(b, 30); b = a; a = temp
182
+ }
183
+ h0 = (h0 + a) >>> 0; h1 = (h1 + b) >>> 0
184
+ h2 = (h2 + c) >>> 0; h3 = (h3 + d) >>> 0; h4 = (h4 + e) >>> 0
185
+ }
186
+
187
+ const result = new Uint8Array(20)
188
+ const w32 = (off: number, v: number) => {
189
+ result[off] = (v >>> 24) & 0xFF; result[off + 1] = (v >>> 16) & 0xFF
190
+ result[off + 2] = (v >>> 8) & 0xFF; result[off + 3] = v & 0xFF
191
+ }
192
+ w32(0, h0); w32(4, h1); w32(8, h2); w32(12, h3); w32(16, h4)
193
+ return result
194
+ }
195
+
196
+ // ── Base64 ──
197
+
198
+ const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
199
+
200
+ function b64Encode(data: Uint8Array): string {
201
+ let r = ''
202
+ for (let i = 0; i < data.length; i += 3) {
203
+ const b0 = data[i], b1 = i + 1 < data.length ? data[i + 1] : 0, b2 = i + 2 < data.length ? data[i + 2] : 0
204
+ r += B64[b0 >> 2] + B64[((b0 & 3) << 4) | (b1 >> 4)]
205
+ r += i + 1 < data.length ? B64[((b1 & 15) << 2) | (b2 >> 6)] : '='
206
+ r += i + 2 < data.length ? B64[b2 & 63] : '='
207
+ }
208
+ return r
209
+ }
210
+
211
+ function b64Decode(str: string): Uint8Array {
212
+ str = str.replace(/[^A-Za-z0-9+/=]/g, '')
213
+ const bytes: number[] = []
214
+ for (let i = 0; i < str.length; i += 4) {
215
+ const c0 = B64.indexOf(str[i]), c1 = B64.indexOf(str[i + 1])
216
+ const c2 = B64.indexOf(str[i + 2]), c3 = B64.indexOf(str[i + 3])
217
+ bytes.push((c0 << 2) | (c1 >> 4))
218
+ if (c2 >= 0) bytes.push(((c1 & 15) << 4) | (c2 >> 2))
219
+ if (c3 >= 0) bytes.push(((c2 & 3) << 6) | c3)
220
+ }
221
+ return new Uint8Array(bytes)
222
+ }
223
+
224
+ // ── btoa / atob ──
225
+
226
+ if (typeof globalThis.btoa === 'undefined') {
227
+ globalThis.btoa = (data: string): string => {
228
+ const bytes = new Uint8Array(data.length)
229
+ for (let i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i) & 0xFF
230
+ return b64Encode(bytes)
231
+ }
232
+ }
233
+
234
+ if (typeof globalThis.atob === 'undefined') {
235
+ globalThis.atob = (data: string): string => {
236
+ const bytes = b64Decode(data)
237
+ let r = ''
238
+ for (let i = 0; i < bytes.length; i++) r += String.fromCharCode(bytes[i])
239
+ return r
240
+ }
241
+ }
242
+
243
+ function _encode(s: string): string { return encodeURIComponent(s) }
244
+ function _decode(s: string): string {
245
+ try { return decodeURIComponent(s.replace(/\+/g, ' ')) }
246
+ catch { return s }
247
+ }
248
+
249
+ function _normalizePath(path: string): string {
250
+ if (!path) return '/'
251
+ const parts = path.split('/')
252
+ const out: string[] = []
253
+ let hasRoot = path[0] === '/'
254
+ if (hasRoot) out.push('')
255
+ for (const p of parts) {
256
+ if (p === '' || p === '.') continue
257
+ if (p === '..') {
258
+ const last = out[out.length - 1]
259
+ if (last !== undefined && last !== '') out.pop()
260
+ } else {
261
+ out.push(p)
262
+ }
263
+ }
264
+ if (path.endsWith('/') && out[out.length - 1] !== '') out.push('')
265
+ const result = out.join('/')
266
+ if (hasRoot && !result.startsWith('/')) return '/' + result
267
+ return result || '/'
268
+ }
269
+
270
+ function _parseURL(url: string): { scheme: string; user: string; pass: string; host: string; port: string; path: string; query: string; fragment: string } {
271
+ const r = { scheme: '', user: '', pass: '', host: '', port: '', path: '/', query: '', fragment: '' }
272
+ const fi = url.indexOf('#')
273
+ if (fi >= 0) { r.fragment = url.slice(fi + 1); url = url.slice(0, fi) }
274
+ const qi = url.indexOf('?')
275
+ if (qi >= 0) { r.query = url.slice(qi + 1); url = url.slice(0, qi) }
276
+ const sm = url.match(/^([a-zA-Z][a-zA-Z0-9+\-.]*):(.*)$/)
277
+ if (sm) { r.scheme = sm[1].toLowerCase(); url = sm[2] }
278
+ if (url.startsWith('//')) {
279
+ url = url.slice(2)
280
+ const si = url.indexOf('/')
281
+ let auth: string
282
+ if (si < 0) { auth = url; url = '' } else { auth = url.slice(0, si); url = url.slice(si) }
283
+ const ai = auth.lastIndexOf('@')
284
+ if (ai >= 0) {
285
+ const ui = auth.slice(0, ai); auth = auth.slice(ai + 1)
286
+ const ci = ui.indexOf(':')
287
+ if (ci >= 0) { r.user = _decode(ui.slice(0, ci)); r.pass = _decode(ui.slice(ci + 1)) }
288
+ else r.user = _decode(ui)
289
+ }
290
+ if (auth.startsWith('[')) {
291
+ const cb = auth.indexOf(']')
292
+ r.host = auth.slice(1, cb).toLowerCase()
293
+ const pp = auth.slice(cb + 1)
294
+ if (pp.startsWith(':')) r.port = pp.slice(1)
295
+ } else {
296
+ const ci = auth.lastIndexOf(':')
297
+ if (ci >= 0 && ci === auth.lastIndexOf(':')) { r.host = auth.slice(0, ci).toLowerCase(); r.port = auth.slice(ci + 1) }
298
+ else r.host = auth.toLowerCase()
299
+ }
300
+ }
301
+ r.path = url
302
+ if (r.host && !r.path.startsWith('/')) r.path = '/' + r.path
303
+ return r
304
+ }
305
+
306
+ class URLSearchParamsImpl {
307
+ private _list: [string, string][] = []
308
+
309
+ constructor(init?: string | [string, string][] | Record<string, string>) {
310
+ if (typeof init === 'string') {
311
+ const s = init.startsWith('?') ? init.slice(1) : init
312
+ if (!s) return
313
+ for (const p of s.split('&')) {
314
+ const eq = p.indexOf('=')
315
+ if (eq < 0) { this._list.push([_decode(p), '']); continue }
316
+ this._list.push([_decode(p.slice(0, eq)), _decode(p.slice(eq + 1))])
317
+ }
318
+ } else if (init) {
319
+ if (Array.isArray(init)) for (const [k, v] of init) this._list.push([String(k), String(v)])
320
+ else for (const k of Object.keys(init)) this._list.push([k, String(init[k])])
321
+ }
322
+ }
323
+
324
+ append(key: string, value: string): void { this._list.push([key, value]) }
325
+ delete(key: string): void { this._list = this._list.filter(([k]) => k !== key) }
326
+ get(key: string): string | null { for (const [k, v] of this._list) if (k === key) return v; return null }
327
+ getAll(key: string): string[] { return this._list.filter(([k]) => k === key).map(([, v]) => v) }
328
+ has(key: string): boolean { return this._list.some(([k]) => k === key) }
329
+ set(key: string, value: string): void {
330
+ let f = false
331
+ for (let i = 0; i < this._list.length; i++) {
332
+ if (this._list[i][0] === key) { if (!f) { this._list[i][1] = value; f = true } else { this._list.splice(i, 1); i-- } }
333
+ }
334
+ if (!f) this._list.push([key, value])
335
+ }
336
+ sort(): void { this._list.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) }
337
+ forEach(fn: (v: string, k: string) => void): void { for (const [k, v] of this._list) fn(v, k) }
338
+
339
+ *keys(): IterableIterator<string> { for (const [k] of this._list) yield k }
340
+ *values(): IterableIterator<string> { for (const [, v] of this._list) yield v }
341
+ *entries(): IterableIterator<[string, string]> { for (const item of this._list) yield [item[0], item[1]] }
342
+ *[Symbol.iterator](): IterableIterator<[string, string]> { for (const item of this._list) yield item }
343
+
344
+ toString(): string { return this._list.map(([k, v]) => _encode(k) + '=' + _encode(v)).join('&') }
345
+ get size(): number { return this._list.length }
346
+ }
347
+
348
+ if (typeof globalThis.URLSearchParams === 'undefined') {
349
+ globalThis.URLSearchParams = URLSearchParamsImpl as any
350
+ }
351
+
352
+ class URLImpl {
353
+ private _scheme = ''
354
+ private _username = ''
355
+ private _password = ''
356
+ private _hostname = ''
357
+ private _port = ''
358
+ private _pathname = '/'
359
+ private _query = ''
360
+ private _fragment = ''
361
+ private _searchParams: URLSearchParams = new URLSearchParamsImpl()
362
+
363
+ constructor(url: string, base?: string) {
364
+ let p = _parseURL(url)
365
+ if (p.scheme) { this._apply(p); return }
366
+ if (base === undefined) throw new TypeError('Invalid URL')
367
+
368
+ const b = new URLImpl(base)
369
+ if (p.host) { p.scheme = b._scheme; this._apply(p); return }
370
+ if (!p.path && !p.query) {
371
+ this._apply({
372
+ scheme: b._scheme, user: b._username, pass: b._password,
373
+ host: b._hostname, port: b._port,
374
+ path: b._pathname, query: b._query, fragment: p.fragment || ''
375
+ }); return
376
+ }
377
+ p.scheme = b._scheme; if (!p.user) p.user = b._username; if (!p.pass) p.pass = b._password
378
+ if (!p.host) p.host = b._hostname; if (!p.port) p.port = b._port; if (!p.fragment) p.fragment = ''
379
+ if (p.path && !p.path.startsWith('/')) {
380
+ const bd = b._pathname.substring(0, b._pathname.lastIndexOf('/') + 1)
381
+ p.path = _normalizePath(bd + p.path)
382
+ } else if (!p.path) { p.path = b._pathname; if (!p.query) p.query = b._query }
383
+ this._apply(p)
384
+ }
385
+
386
+ private _apply(p: { scheme: string; user: string; pass: string; host: string; port: string; path: string; query: string; fragment: string }): void {
387
+ this._scheme = p.scheme; this._username = p.user; this._password = p.pass
388
+ this._hostname = p.host; this._port = p.port
389
+ this._pathname = _normalizePath(p.path || '/')
390
+ this._query = p.query; this._fragment = p.fragment
391
+ this._searchParams = new URLSearchParamsImpl(this._query)
392
+ }
393
+
394
+ get href(): string { return this.toString() }
395
+ get protocol(): string { return this._scheme + ':' }
396
+ get hostname(): string { return this._hostname }
397
+ get port(): string { return this._port }
398
+ get pathname(): string { return this._pathname }
399
+ get search(): string { return this._query ? '?' + this._query : '' }
400
+ get hash(): string { return this._fragment ? '#' + this._fragment : '' }
401
+ get host(): string {
402
+ const h = this._hostname
403
+ const ipv6 = h.includes(':')
404
+ return (ipv6 ? '[' + h + ']' : h) + (this._port ? ':' + this._port : '')
405
+ }
406
+ get origin(): string {
407
+ const h = this._hostname
408
+ const ipv6 = h.includes(':')
409
+ return this._scheme + '://' + (ipv6 ? '[' + h + ']' : h) + (this._port ? ':' + this._port : '')
410
+ }
411
+ get username(): string { return this._username }
412
+ get password(): string { return this._password }
413
+ get searchParams(): URLSearchParams { return this._searchParams }
414
+
415
+ toString(): string {
416
+ let s = this._scheme + ':'
417
+ const special = ['http', 'https', 'ws', 'wss', 'ftp', 'file']
418
+ if (this._hostname || (special.includes(this._scheme) && this._pathname.startsWith('/'))) {
419
+ s += '//'
420
+ if (this._username) { s += _encode(this._username); if (this._password) s += ':' + _encode(this._password); s += '@' }
421
+ s += this._hostname
422
+ if (this._port) s += ':' + this._port
423
+ }
424
+ s += this._pathname
425
+ if (this._query) s += '?' + this._query
426
+ if (this._fragment) s += '#' + this._fragment
427
+ return s
428
+ }
429
+
430
+ toJSON(): string { return this.toString() }
431
+ }
432
+
433
+ if (typeof globalThis.URL === 'undefined') {
434
+ globalThis.URL = URLImpl as any
435
+ }
436
+
437
+ if (typeof globalThis.crypto === 'undefined') {
438
+ globalThis.crypto = {
439
+ getRandomValues: <T extends ArrayBufferView>(array: T): T => {
440
+ const view = new Uint8Array(array.buffer, array.byteOffset, array.byteLength)
441
+ for (let i = 0; i < view.length; i++) view[i] = (Math.random() * 256) | 0
442
+ return array
443
+ },
444
+ subtle: {
445
+ digest: (algorithm: string, data: ArrayBuffer | Uint8Array): Promise<ArrayBuffer> => {
446
+ if (algorithm.toUpperCase() !== 'SHA-1')
447
+ return Promise.reject(new Error('Digest: ' + algorithm + ' not supported'))
448
+ const bytes = data instanceof Uint8Array ? Array.from(data) : Array.from(new Uint8Array(data))
449
+ const hash = sha1Bytes(bytes)
450
+ return Promise.resolve(hash.buffer as ArrayBuffer)
451
+ }
452
+ }
453
+ }
454
+ }