quickwin 1.2.1 → 2.0.0

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 (137) hide show
  1. package/README.en.md +3 -3
  2. package/README.md +21 -24
  3. package/examples/PdfCanvas.js +8 -37
  4. package/examples/PdfCanvas.tsx +11 -41
  5. package/examples/exec_server.js +20054 -1423
  6. package/examples/exec_server.tsx +489 -0
  7. package/examples/exec_server_worker.js +383 -33
  8. package/examples/exec_server_worker.ts +408 -30
  9. package/examples/pdf_preview2.js +31 -73
  10. package/examples/pdf_preview2.ts +33 -76
  11. package/examples/pdf_viewer.js +1496 -616
  12. package/examples/pdf_viewer.tsx +23 -64
  13. package/examples/setres.js +22 -47
  14. package/examples/setres.ts +23 -57
  15. package/examples/test_gallery.js +1491 -525
  16. package/examples/test_react_lazy.js +1455 -500
  17. package/examples/test_react_listbox.js +1454 -499
  18. package/examples/test_root_window.js +1450 -495
  19. package/examples/test_tab.js +1455 -500
  20. package/lib/abort.js +70 -0
  21. package/lib/abort.ts +69 -0
  22. package/lib/certs.js +214 -0
  23. package/lib/certs.ts +224 -0
  24. package/lib/exec-log.js +15 -0
  25. package/lib/exec-log.ts +30 -0
  26. package/lib/fetch.js +37 -4
  27. package/lib/fetch.ts +35 -4
  28. package/lib/ffi/bind.js +352 -0
  29. package/lib/ffi/bind.ts +442 -0
  30. package/lib/ffi/ctype.js +168 -0
  31. package/lib/ffi/ctype.ts +331 -0
  32. package/lib/ffi/index.js +6 -0
  33. package/lib/ffi/index.ts +6 -0
  34. package/lib/ffi/struct.js +412 -0
  35. package/lib/ffi/struct.ts +664 -0
  36. package/lib/http-common.js +43 -5
  37. package/lib/http-common.ts +48 -6
  38. package/lib/http-server.js +187 -29
  39. package/lib/http-server.ts +177 -26
  40. package/lib/react-qw/components/DateTimePicker.js +20 -33
  41. package/lib/react-qw/components/Input.js +3 -10
  42. package/lib/react-qw/components/Link.js +7 -22
  43. package/lib/react-qw/components/ListView.js +80 -141
  44. package/lib/react-qw/components/PathPicker.js +36 -80
  45. package/lib/react-qw/components/ScrollView.js +15 -8
  46. package/lib/react-qw/components/Slider.js +2 -1
  47. package/lib/react-qw/components/Tab.js +15 -20
  48. package/lib/react-qw/components/Tooltip.js +21 -20
  49. package/lib/react-qw/components/TreeView.js +14 -47
  50. package/lib/react-qw/index.js +4 -2
  51. package/lib/react-qw/index.ts +4 -2
  52. package/lib/react-qw/nmhdr.js +5 -0
  53. package/lib/react-qw/nmhdr.ts +7 -0
  54. package/lib/react-qw/props.js +7 -2
  55. package/lib/react-qw/props.ts +7 -3
  56. package/lib/react-qw/reconciler.js +23 -13
  57. package/lib/react-qw/reconciler.ts +22 -13
  58. package/lib/text-measure.js +18 -35
  59. package/lib/text-measure.ts +20 -37
  60. package/lib/websocket.js +12 -2
  61. package/lib/websocket.ts +15 -2
  62. package/lib/windows/comctl32.js +18 -0
  63. package/lib/windows/comctl32.ts +20 -0
  64. package/lib/windows/comdlg32.js +7 -0
  65. package/lib/windows/comdlg32.ts +9 -0
  66. package/lib/windows/gdi32.js +90 -0
  67. package/lib/windows/gdi32.ts +97 -0
  68. package/lib/windows/kernel32.js +66 -0
  69. package/lib/windows/kernel32.ts +76 -0
  70. package/lib/windows/ntdll.js +8 -0
  71. package/lib/windows/ntdll.ts +10 -0
  72. package/lib/windows/ole32.js +7 -0
  73. package/lib/windows/ole32.ts +9 -0
  74. package/lib/windows/shell32.js +11 -0
  75. package/lib/windows/shell32.ts +14 -0
  76. package/lib/windows/structs.js +384 -0
  77. package/lib/windows/structs.ts +422 -0
  78. package/lib/windows/user32.js +469 -0
  79. package/lib/windows/user32.ts +502 -0
  80. package/package.json +1 -1
  81. package/quickwin.d.ts +22 -33
  82. package/quickwin_const.d.ts +1 -0
  83. package/qwin-nowasm-x86.exe +0 -0
  84. package/qwin-nowasm.exe +0 -0
  85. package/qwin-x86.exe +0 -0
  86. package/qwin.exe +0 -0
  87. package/test/bench_ffi_callraw.js +236 -0
  88. package/test/bench_ffi_callraw.ts +236 -0
  89. package/test/bench_ffi_overhead.js +139 -0
  90. package/test/bench_ffi_overhead.ts +141 -0
  91. package/test/bench_sendmessage.js +104 -0
  92. package/test/bench_sendmessage.ts +100 -0
  93. package/test/bench_sendmessage_nonnull.js +187 -0
  94. package/test/bench_sendmessage_nonnull.ts +188 -0
  95. package/test/run.js +14 -4
  96. package/test/run.ts +15 -5
  97. package/test/test_basic_fetch.js +8 -0
  98. package/test/test_basic_fetch.ts +9 -0
  99. package/test/test_ffi.js +33 -47
  100. package/test/test_ffi.ts +41 -60
  101. package/test/test_ffi_abi.js +235 -0
  102. package/test/test_ffi_abi.ts +218 -0
  103. package/test/test_ffi_bind.js +572 -0
  104. package/test/test_ffi_bind.ts +597 -0
  105. package/test/test_ffi_struct.js +745 -0
  106. package/test/test_ffi_struct.ts +798 -0
  107. package/test/test_ffi_struct_layout.js +495 -0
  108. package/test/test_ffi_struct_layout.ts +543 -0
  109. package/test/test_ffi_user32.js +103 -0
  110. package/test/test_ffi_user32.ts +113 -0
  111. package/test/test_ffi_windows.js +101 -0
  112. package/test/test_ffi_windows.ts +113 -0
  113. package/test/test_helper.js +8 -1
  114. package/test/test_helper.ts +9 -1
  115. package/test/test_http_import.js +18 -0
  116. package/test/test_http_import.ts +19 -0
  117. package/test/test_http_server.js +73 -1
  118. package/test/test_http_server.ts +75 -1
  119. package/test/test_ipv6.js +2 -2
  120. package/test/test_ipv6.ts +2 -2
  121. package/test/test_net_fetch.js +70 -8
  122. package/test/test_net_fetch.ts +69 -7
  123. package/test/test_net_websocket.js +1 -1
  124. package/test/test_net_websocket.ts +1 -1
  125. package/test/test_react_complex.js +1465 -510
  126. package/test/test_react_counter.js +1455 -500
  127. package/test/test_react_flex.js +1475 -513
  128. package/test/test_react_hidden.js +1458 -503
  129. package/test/test_react_listview_link.js +1455 -500
  130. package/test/test_react_notify.js +18534 -0
  131. package/test/test_react_render.js +1455 -500
  132. package/test/test_wolfssl_read.js +3 -2
  133. package/test/test_wolfssl_read.ts +3 -1
  134. package/test/test_worker_net.js +35 -17
  135. package/test/test_worker_net.ts +27 -15
  136. package/tsconfig.json +1 -1
  137. package/examples/exec_server.ts +0 -80
@@ -104,8 +104,9 @@ export const suite = {
104
104
  if (d instanceof ArrayBuffer) {
105
105
  sawArray = true;
106
106
  total += d.byteLength;
107
- if (total >= EXPECTED)
108
- break;
107
+ // Keep draining after the body is complete: the point of
108
+ // this suite is the no-data/EOF contract, so a full body
109
+ // must not short-circuit the read that would observe null.
109
110
  }
110
111
  }
111
112
  if (total >= EXPECTED)
@@ -99,7 +99,9 @@ export const suite = {
99
99
  if (d instanceof ArrayBuffer) {
100
100
  sawArray = true
101
101
  total += d.byteLength
102
- if (total >= EXPECTED) break
102
+ // Keep draining after the body is complete: the point of
103
+ // this suite is the no-data/EOF contract, so a full body
104
+ // must not short-circuit the read that would observe null.
103
105
  }
104
106
  }
105
107
  if (total >= EXPECTED) finish()
@@ -27,25 +27,43 @@ export const suite = {
27
27
  catch (e) {
28
28
  t.checkTrue('worker creation failed: ' + e, false);
29
29
  }
30
+ // Retry across jsdelivr's official CDN hosts: a dropped connection
31
+ // on a slow CI network must not be reported as a TLS regression.
30
32
  t.section('npm-package');
31
33
  let worker3;
32
- try {
33
- const { data: r3 } = await new Promise((resolve, reject) => {
34
- worker3 = new os.Worker('https://cdn.jsdelivr.net/npm/quickwin/test/worker_module.js');
35
- const timer = os.setTimeout(() => reject(new Error('timeout')), 15000);
36
- worker3.onmessage = (e) => {
37
- os.clearTimeout(timer);
38
- resolve({ worker: worker3, data: e.data });
39
- };
40
- worker3.postMessage({ type: 'start' });
41
- });
42
- t.check('npm worker message type', 'result', r3.type);
43
- t.check('npm worker imported value', 42, r3.value);
44
- worker3.postMessage({ type: 'done' });
45
- worker3.onmessage = null;
46
- }
47
- catch (e) {
48
- t.checkTrue('npm worker failed: ' + e, false);
34
+ const NPM_HOSTS = ['cdn.jsdelivr.net', 'fastly.jsdelivr.net', 'gcore.jsdelivr.net'];
35
+ let workerOk = false;
36
+ for (const host of NPM_HOSTS) {
37
+ for (let attempt = 0; attempt < 3 && !workerOk; attempt++) {
38
+ try {
39
+ const { data: r3 } = await new Promise((resolve, reject) => {
40
+ worker3 = new os.Worker('https://' + host + '/npm/quickwin/test/worker_module.js');
41
+ const timer = os.setTimeout(() => reject(new Error('timeout')), 15000);
42
+ worker3.onmessage = (e) => {
43
+ os.clearTimeout(timer);
44
+ resolve({ worker: worker3, data: e.data });
45
+ };
46
+ worker3.postMessage({ type: 'start' });
47
+ });
48
+ t.check('npm worker message type', 'result', r3.type);
49
+ t.check('npm worker imported value', 42, r3.value);
50
+ worker3.postMessage({ type: 'done' });
51
+ worker3.onmessage = null;
52
+ workerOk = true;
53
+ }
54
+ catch (e) {
55
+ if (worker3) {
56
+ worker3.onmessage = null;
57
+ worker3 = null;
58
+ }
59
+ if (attempt === 2 && host === NPM_HOSTS[NPM_HOSTS.length - 1])
60
+ t.checkTrue('npm worker failed: ' + e, false);
61
+ else
62
+ os.sleep(500);
63
+ }
64
+ }
65
+ if (workerOk)
66
+ break;
49
67
  }
50
68
  }
51
69
  };
@@ -31,24 +31,36 @@ export const suite = {
31
31
  t.checkTrue('worker creation failed: ' + e, false)
32
32
  }
33
33
 
34
+ // Retry across jsdelivr's official CDN hosts: a dropped connection
35
+ // on a slow CI network must not be reported as a TLS regression.
34
36
  t.section('npm-package')
35
37
  let worker3: any
36
- try {
37
- const { data: r3 } = await new Promise<any>((resolve, reject) => {
38
- worker3 = new os.Worker('https://cdn.jsdelivr.net/npm/quickwin/test/worker_module.js')
39
- const timer = os.setTimeout(() => reject(new Error('timeout')), 15000)
40
- worker3.onmessage = (e: any) => {
41
- os.clearTimeout(timer)
42
- resolve({ worker: worker3, data: e.data })
38
+ const NPM_HOSTS = ['cdn.jsdelivr.net', 'fastly.jsdelivr.net', 'gcore.jsdelivr.net']
39
+ let workerOk = false
40
+ for (const host of NPM_HOSTS) {
41
+ for (let attempt = 0; attempt < 3 && !workerOk; attempt++) {
42
+ try {
43
+ const { data: r3 } = await new Promise<any>((resolve, reject) => {
44
+ worker3 = new os.Worker('https://' + host + '/npm/quickwin/test/worker_module.js')
45
+ const timer = os.setTimeout(() => reject(new Error('timeout')), 15000)
46
+ worker3.onmessage = (e: any) => {
47
+ os.clearTimeout(timer)
48
+ resolve({ worker: worker3, data: e.data })
49
+ }
50
+ worker3.postMessage({ type: 'start' })
51
+ })
52
+ t.check('npm worker message type', 'result', r3.type)
53
+ t.check('npm worker imported value', 42, r3.value)
54
+ worker3.postMessage({ type: 'done' })
55
+ worker3.onmessage = null
56
+ workerOk = true
57
+ } catch (e) {
58
+ if (worker3) { worker3.onmessage = null; worker3 = null }
59
+ if (attempt === 2 && host === NPM_HOSTS[NPM_HOSTS.length - 1]) t.checkTrue('npm worker failed: ' + e, false)
60
+ else os.sleep(500)
43
61
  }
44
- worker3.postMessage({ type: 'start' })
45
- })
46
- t.check('npm worker message type', 'result', r3.type)
47
- t.check('npm worker imported value', 42, r3.value)
48
- worker3.postMessage({ type: 'done' })
49
- worker3.onmessage = null
50
- } catch (e) {
51
- t.checkTrue('npm worker failed: ' + e, false)
62
+ }
63
+ if (workerOk) break
52
64
  }
53
65
  }
54
66
  }
package/tsconfig.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "esModuleInterop": true,
16
16
  // "skipLibCheck": true,
17
17
  "allowJs": false,
18
- "lib": ["ES2020"],
18
+ "lib": ["ES2025"],
19
19
  "types": ["./quickwin.d.ts"],
20
20
  "rootDir": ".",
21
21
  "outDir": "_build",
@@ -1,80 +0,0 @@
1
- import { createServer } from '../lib/http-server.js'
2
- import * as os from 'os'
3
-
4
- // WORKER_DATA_URL 由 esbuild --define 在 build.ts 中注入(base64 data: URL)
5
- declare const WORKER_DATA_URL: string
6
-
7
- const EXEC_TIMEOUT_MS = 60_000
8
-
9
- interface ExecResult {
10
- out: Uint8Array
11
- code: number
12
- error: string | null
13
- }
14
-
15
- function runInWorker(cmd: string): Promise<ExecResult> {
16
- return new Promise((resolve, reject) => {
17
- const worker = new os.Worker(WORKER_DATA_URL)
18
- const id = 1
19
- let settled = false
20
- let timer: ReturnType<typeof os.setTimeout>
21
-
22
- const finish = (fn: () => void) => {
23
- if (settled) return
24
- settled = true
25
- os.clearTimeout(timer)
26
- worker.onmessage = null
27
- fn()
28
- }
29
-
30
- timer = os.setTimeout(() => {
31
- finish(() => reject(new Error('exec timeout')))
32
- }, EXEC_TIMEOUT_MS)
33
-
34
- worker.onmessage = (e) => {
35
- const msg = e.data as { type: string; id: number; out?: Uint8Array; code?: number; error?: string | null }
36
- if (msg.type !== 'result' || msg.id !== id) return
37
- finish(() => resolve({ out: msg.out ?? new Uint8Array(0), code: msg.code ?? -1, error: msg.error ?? null }))
38
- }
39
-
40
- try {
41
- worker.postMessage({ type: 'run', id, cmd })
42
- } catch (ex) {
43
- finish(() => reject(ex instanceof Error ? ex : new Error(String(ex))))
44
- }
45
- })
46
- }
47
-
48
- const server = createServer(async (req) => {
49
- const path = new URL(req.url).pathname
50
- if (req.method === 'GET' && (path === '/' || path === '/health')) {
51
- return new Response('ok', { headers: { 'Content-Type': 'text/plain' } })
52
- }
53
- if (req.method === 'POST' && path === '/exec') {
54
- const body = await req.json() as { cmd: string }
55
- try {
56
- const { out, code, error } = await runInWorker(body.cmd)
57
- if (error) {
58
- return new Response(JSON.stringify({ error }), {
59
- status: 500,
60
- headers: { 'Content-Type': 'application/json' }
61
- })
62
- }
63
- return new Response(out, {
64
- headers: {
65
- 'Content-Type': 'application/octet-stream',
66
- 'X-Exit-Code': String(code),
67
- }
68
- })
69
- } catch (ex) {
70
- return new Response(JSON.stringify({ error: String(ex) }), {
71
- status: 504,
72
- headers: { 'Content-Type': 'application/json' }
73
- })
74
- }
75
- }
76
- return new Response('Not Found', { status: 404 })
77
- })
78
-
79
- const rc = server.listen(8080, '0.0.0.0')
80
- console.log('listen rc=' + rc + ' addr=' + JSON.stringify(server.address()))