@zappdev/cli 0.1.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 (209) hide show
  1. package/README.md +55 -0
  2. package/dist/zapp-cli.js +9471 -0
  3. package/native/src/app/app.zc +490 -0
  4. package/native/src/event/event.zc +24 -0
  5. package/native/src/event/events.zc +70 -0
  6. package/native/src/platform/darwin/backend.zc +923 -0
  7. package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
  8. package/native/src/platform/darwin/bootstrap.zc +9 -0
  9. package/native/src/platform/darwin/engine_jsc.zc +86 -0
  10. package/native/src/platform/darwin/engine_qjs.zc +92 -0
  11. package/native/src/platform/darwin/platform.zc +156 -0
  12. package/native/src/platform/darwin/webview.zc +550 -0
  13. package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
  14. package/native/src/platform/darwin/window.zc +1223 -0
  15. package/native/src/platform/darwin/worker/common.zc +223 -0
  16. package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
  17. package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
  18. package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
  19. package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
  20. package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
  21. package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
  22. package/native/src/platform/darwin/worker/dispatch.zc +55 -0
  23. package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
  24. package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
  25. package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
  26. package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
  27. package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
  28. package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
  29. package/native/src/platform/darwin/worker/jsc.zc +670 -0
  30. package/native/src/platform/darwin/worker/mod.zc +30 -0
  31. package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
  32. package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
  33. package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
  34. package/native/src/platform/darwin/worker/qjs.zc +1053 -0
  35. package/native/src/platform/darwin/worker/timers.zc +149 -0
  36. package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
  37. package/native/src/platform/platform.zc +64 -0
  38. package/native/src/platform/shared/log.zc +156 -0
  39. package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
  40. package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
  41. package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
  42. package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
  43. package/native/src/platform/shared/worker_registry.zc +206 -0
  44. package/native/src/platform/window.zc +446 -0
  45. package/native/src/platform/windows/backend.zc +452 -0
  46. package/native/src/platform/windows/backend_bootstrap.zc +9 -0
  47. package/native/src/platform/windows/bootstrap.zc +9 -0
  48. package/native/src/platform/windows/engine_qjs.zc +60 -0
  49. package/native/src/platform/windows/platform.zc +387 -0
  50. package/native/src/platform/windows/webview.zc +1175 -0
  51. package/native/src/platform/windows/webview_bootstrap.zc +9 -0
  52. package/native/src/platform/windows/window.zc +1271 -0
  53. package/native/src/platform/windows/worker/common.zc +409 -0
  54. package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
  55. package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
  56. package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
  57. package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
  58. package/native/src/platform/windows/worker/core/url_core.zc +216 -0
  59. package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
  60. package/native/src/platform/windows/worker/dispatch.zc +34 -0
  61. package/native/src/platform/windows/worker/mod.zc +46 -0
  62. package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
  63. package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
  64. package/native/src/platform/windows/worker/qjs.zc +1049 -0
  65. package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
  66. package/native/src/platform/worker.zc +8 -0
  67. package/native/src/service/service.zc +228 -0
  68. package/native/vendor/quickjs-ng/.gitattributes +4 -0
  69. package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
  70. package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
  71. package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
  72. package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
  73. package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
  74. package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
  75. package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
  76. package/native/vendor/quickjs-ng/.gitmodules +5 -0
  77. package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
  78. package/native/vendor/quickjs-ng/LICENSE +24 -0
  79. package/native/vendor/quickjs-ng/Makefile +149 -0
  80. package/native/vendor/quickjs-ng/amalgam.js +53 -0
  81. package/native/vendor/quickjs-ng/api-test.c +927 -0
  82. package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
  83. package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
  84. package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
  85. package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
  86. package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
  87. package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
  88. package/native/vendor/quickjs-ng/ctest.c +17 -0
  89. package/native/vendor/quickjs-ng/cutils.h +2013 -0
  90. package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
  91. package/native/vendor/quickjs-ng/dtoa.c +1619 -0
  92. package/native/vendor/quickjs-ng/dtoa.h +87 -0
  93. package/native/vendor/quickjs-ng/examples/fib.c +67 -0
  94. package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
  95. package/native/vendor/quickjs-ng/examples/hello.js +1 -0
  96. package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
  97. package/native/vendor/quickjs-ng/examples/meson.build +17 -0
  98. package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
  99. package/native/vendor/quickjs-ng/examples/point.c +154 -0
  100. package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
  101. package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
  102. package/native/vendor/quickjs-ng/fuzz.c +51 -0
  103. package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
  104. package/native/vendor/quickjs-ng/gen/hello.c +53 -0
  105. package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
  106. package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
  107. package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
  108. package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
  109. package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
  110. package/native/vendor/quickjs-ng/libregexp.c +2687 -0
  111. package/native/vendor/quickjs-ng/libregexp.h +98 -0
  112. package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
  113. package/native/vendor/quickjs-ng/libunicode.c +1746 -0
  114. package/native/vendor/quickjs-ng/libunicode.h +126 -0
  115. package/native/vendor/quickjs-ng/list.h +107 -0
  116. package/native/vendor/quickjs-ng/lre-test.c +73 -0
  117. package/native/vendor/quickjs-ng/meson.build +684 -0
  118. package/native/vendor/quickjs-ng/meson_options.txt +6 -0
  119. package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
  120. package/native/vendor/quickjs-ng/qjs.c +748 -0
  121. package/native/vendor/quickjs-ng/qjsc.c +673 -0
  122. package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
  123. package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
  124. package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
  125. package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
  126. package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
  127. package/native/vendor/quickjs-ng/quickjs.c +60259 -0
  128. package/native/vendor/quickjs-ng/quickjs.h +1419 -0
  129. package/native/vendor/quickjs-ng/repl.js +1927 -0
  130. package/native/vendor/quickjs-ng/run-test262.c +2417 -0
  131. package/native/vendor/quickjs-ng/standalone.js +129 -0
  132. package/native/vendor/quickjs-ng/tests/assert.js +49 -0
  133. package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
  134. package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
  135. package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
  136. package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
  137. package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
  138. package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
  139. package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
  140. package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
  141. package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
  142. package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
  143. package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
  144. package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
  145. package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
  146. package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
  147. package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
  148. package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
  149. package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
  150. package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
  151. package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
  152. package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
  153. package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
  154. package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
  155. package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
  156. package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
  157. package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
  158. package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
  159. package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
  160. package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
  161. package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
  162. package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
  163. package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
  164. package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
  165. package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
  166. package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
  167. package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
  168. package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
  169. package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
  170. package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
  171. package/native/vendor/quickjs-ng/tests/empty.js +0 -0
  172. package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
  173. package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
  174. package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
  175. package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
  176. package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
  177. package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
  178. package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
  179. package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
  180. package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
  181. package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
  182. package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
  183. package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
  184. package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
  185. package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
  186. package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
  187. package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
  188. package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
  189. package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
  190. package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
  191. package/native/vendor/quickjs-ng/tests.conf +14 -0
  192. package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
  193. package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
  194. package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
  195. package/native/vendor/quickjs-ng/update-version.sh +32 -0
  196. package/native/vendor/webview2/include/WebView2.h +60636 -0
  197. package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
  198. package/package.json +33 -0
  199. package/src/backend.ts +139 -0
  200. package/src/build-config.ts +87 -0
  201. package/src/build.ts +276 -0
  202. package/src/common.ts +195 -0
  203. package/src/config.ts +89 -0
  204. package/src/dev.ts +164 -0
  205. package/src/generate.ts +200 -0
  206. package/src/icons.ts +116 -0
  207. package/src/init.ts +190 -0
  208. package/src/package.ts +150 -0
  209. package/src/zapp-cli.ts +263 -0
@@ -0,0 +1,343 @@
1
+ // Win32-native WebSocket using WinHTTP WebSocket APIs.
2
+ // Mirrors the interface of darwin/worker/core/websocket_core.zc.
3
+
4
+ //> windows: link: -lwinhttp
5
+
6
+ raw {
7
+ #ifdef _WIN32
8
+ #include <windows.h>
9
+ #include <winhttp.h>
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+
14
+ typedef void (*zapp_ws_event_fn)(
15
+ const char* ws_id,
16
+ const char* event_type,
17
+ const char* json_payload,
18
+ void* user_data
19
+ );
20
+
21
+ // Per-connection state
22
+ typedef struct {
23
+ char ws_id[64];
24
+ HINTERNET session;
25
+ HINTERNET connection;
26
+ HINTERNET websocket;
27
+ zapp_ws_event_fn callback;
28
+ void* user_data;
29
+ HANDLE thread;
30
+ volatile int closed;
31
+ } ZappWsConn;
32
+
33
+ #define ZAPP_WS_MAX 64
34
+ static ZappWsConn zapp_ws_conns[ZAPP_WS_MAX] = {0};
35
+ static int zapp_ws_id_counter = 1;
36
+ static CRITICAL_SECTION zapp_ws_lock;
37
+ static int zapp_ws_lock_init = 0;
38
+
39
+ static void zapp_ws_ensure_init(void) {
40
+ if (!zapp_ws_lock_init) {
41
+ InitializeCriticalSection(&zapp_ws_lock);
42
+ zapp_ws_lock_init = 1;
43
+ }
44
+ }
45
+
46
+ static ZappWsConn* zapp_ws_find(const char* ws_id) {
47
+ if (!ws_id) return NULL;
48
+ for (int i = 0; i < ZAPP_WS_MAX; i++) {
49
+ if (zapp_ws_conns[i].ws_id[0] && strcmp(zapp_ws_conns[i].ws_id, ws_id) == 0)
50
+ return &zapp_ws_conns[i];
51
+ }
52
+ return NULL;
53
+ }
54
+
55
+ static ZappWsConn* zapp_ws_alloc(void) {
56
+ for (int i = 0; i < ZAPP_WS_MAX; i++) {
57
+ if (!zapp_ws_conns[i].ws_id[0]) return &zapp_ws_conns[i];
58
+ }
59
+ return NULL;
60
+ }
61
+
62
+ static void zapp_ws_fire(ZappWsConn* c, const char* event_type, const char* json_payload) {
63
+ if (!c || !c->callback) return;
64
+ c->callback(c->ws_id, event_type, json_payload ? json_payload : "{}", c->user_data);
65
+ }
66
+
67
+ static char* zapp_ws_escape_json_string(const char* s) {
68
+ if (!s) return _strdup("");
69
+ size_t slen = strlen(s);
70
+ size_t cap = slen * 2 + 1;
71
+ char* out = (char*)malloc(cap);
72
+ size_t j = 0;
73
+ for (size_t i = 0; i < slen; i++) {
74
+ if (j + 6 >= cap) { cap *= 2; out = (char*)realloc(out, cap); }
75
+ char ch = s[i];
76
+ if (ch == '"') { out[j++] = '\\'; out[j++] = '"'; }
77
+ else if (ch == '\\') { out[j++] = '\\'; out[j++] = '\\'; }
78
+ else if (ch == '\n') { out[j++] = '\\'; out[j++] = 'n'; }
79
+ else if (ch == '\r') { out[j++] = '\\'; out[j++] = 'r'; }
80
+ else if (ch == '\t') { out[j++] = '\\'; out[j++] = 't'; }
81
+ else out[j++] = ch;
82
+ }
83
+ out[j] = '\0';
84
+ return out;
85
+ }
86
+
87
+ // Receive loop running on a dedicated thread
88
+ static DWORD WINAPI zapp_ws_receive_thread(LPVOID param) {
89
+ ZappWsConn* c = (ZappWsConn*)param;
90
+ BYTE buf[65536];
91
+ DWORD bytesRead = 0;
92
+ WINHTTP_WEB_SOCKET_BUFFER_TYPE bufType;
93
+
94
+ while (!c->closed && c->websocket) {
95
+ DWORD err = WinHttpWebSocketReceive(c->websocket, buf, sizeof(buf) - 1, &bytesRead, &bufType);
96
+ if (err != NO_ERROR) {
97
+ if (!c->closed) {
98
+ char errJson[256];
99
+ snprintf(errJson, sizeof(errJson),
100
+ "{\"type\":\"error\",\"wsId\":\"%s\",\"message\":\"Receive error: %lu\"}",
101
+ c->ws_id, err);
102
+ zapp_ws_fire(c, "error", errJson);
103
+ }
104
+ break;
105
+ }
106
+
107
+ if (bufType == WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE) {
108
+ USHORT statusCode = 0;
109
+ BYTE reasonBuf[256] = {0};
110
+ DWORD reasonLen = 0;
111
+ WinHttpWebSocketQueryCloseStatus(c->websocket, &statusCode, reasonBuf, sizeof(reasonBuf) - 1, &reasonLen);
112
+ reasonBuf[reasonLen] = '\0';
113
+
114
+ char* escapedReason = zapp_ws_escape_json_string((const char*)reasonBuf);
115
+ char closeJson[512];
116
+ snprintf(closeJson, sizeof(closeJson),
117
+ "{\"type\":\"close\",\"wsId\":\"%s\",\"code\":%d,\"reason\":\"%s\",\"wasClean\":true}",
118
+ c->ws_id, (int)statusCode, escapedReason);
119
+ free(escapedReason);
120
+ zapp_ws_fire(c, "close", closeJson);
121
+ break;
122
+ }
123
+
124
+ if (bufType == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE ||
125
+ bufType == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE) {
126
+ buf[bytesRead] = '\0';
127
+ char* escaped = zapp_ws_escape_json_string((const char*)buf);
128
+ size_t jsonLen = strlen(escaped) + 128 + strlen(c->ws_id);
129
+ char* msgJson = (char*)malloc(jsonLen);
130
+ snprintf(msgJson, jsonLen,
131
+ "{\"type\":\"message\",\"wsId\":\"%s\",\"data\":\"%s\",\"binary\":false}",
132
+ c->ws_id, escaped);
133
+ free(escaped);
134
+ zapp_ws_fire(c, "message", msgJson);
135
+ free(msgJson);
136
+ } else if (bufType == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE ||
137
+ bufType == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE) {
138
+ // Build a JSON array of bytes
139
+ size_t arrCap = bytesRead * 4 + 64 + strlen(c->ws_id) + 64;
140
+ char* msgJson = (char*)malloc(arrCap);
141
+ int off = snprintf(msgJson, arrCap,
142
+ "{\"type\":\"message\",\"wsId\":\"%s\",\"data\":[", c->ws_id);
143
+ for (DWORD i = 0; i < bytesRead; i++) {
144
+ if (i > 0) off += snprintf(msgJson + off, arrCap - off, ",");
145
+ off += snprintf(msgJson + off, arrCap - off, "%u", (unsigned)buf[i]);
146
+ }
147
+ off += snprintf(msgJson + off, arrCap - off, "],\"binary\":true}");
148
+ zapp_ws_fire(c, "message", msgJson);
149
+ free(msgJson);
150
+ }
151
+ }
152
+ return 0;
153
+ }
154
+
155
+ // Connect. Returns wsId C string (caller must free), or NULL on failure.
156
+ static char* zapp_core_ws_connect(const char* url_str, const char** protocols, int protocol_count,
157
+ zapp_ws_event_fn callback, void* user_data) {
158
+ zapp_ws_ensure_init();
159
+ if (!url_str || !callback) return NULL;
160
+
161
+ // Parse URL: ws://host:port/path or wss://host:port/path
162
+ int secure = 0;
163
+ const char* hostStart = url_str;
164
+ if (strncmp(url_str, "wss://", 6) == 0) { hostStart = url_str + 6; secure = 1; }
165
+ else if (strncmp(url_str, "ws://", 5) == 0) { hostStart = url_str + 5; }
166
+ else return NULL;
167
+
168
+ char host[256] = {0};
169
+ INTERNET_PORT port = secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
170
+ const char* slash = strchr(hostStart, '/');
171
+ const char* colon = strchr(hostStart, ':');
172
+ if (colon && (!slash || colon < slash)) {
173
+ size_t hlen = (size_t)(colon - hostStart);
174
+ if (hlen >= sizeof(host)) return NULL;
175
+ memcpy(host, hostStart, hlen);
176
+ port = (INTERNET_PORT)atoi(colon + 1);
177
+ } else if (slash) {
178
+ size_t hlen = (size_t)(slash - hostStart);
179
+ if (hlen >= sizeof(host)) return NULL;
180
+ memcpy(host, hostStart, hlen);
181
+ } else {
182
+ strncpy(host, hostStart, sizeof(host) - 1);
183
+ }
184
+
185
+ const char* pathStr = slash ? slash : "/";
186
+ wchar_t wHost[256], wPath[1024];
187
+ MultiByteToWideChar(CP_UTF8, 0, host, -1, wHost, 256);
188
+ MultiByteToWideChar(CP_UTF8, 0, pathStr, -1, wPath, 1024);
189
+
190
+ HINTERNET session = WinHttpOpen(L"Zapp/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);
191
+ if (!session) return NULL;
192
+
193
+ HINTERNET connection = WinHttpConnect(session, wHost, port, 0);
194
+ if (!connection) { WinHttpCloseHandle(session); return NULL; }
195
+
196
+ DWORD flags = secure ? WINHTTP_FLAG_SECURE : 0;
197
+ HINTERNET request = WinHttpOpenRequest(connection, L"GET", wPath, NULL, NULL, NULL, flags);
198
+ if (!request) { WinHttpCloseHandle(connection); WinHttpCloseHandle(session); return NULL; }
199
+
200
+ // Add subprotocol header if requested
201
+ if (protocols && protocol_count > 0) {
202
+ size_t headerLen = 64;
203
+ for (int i = 0; i < protocol_count; i++) {
204
+ if (protocols[i]) headerLen += strlen(protocols[i]) + 2;
205
+ }
206
+ char* header = (char*)malloc(headerLen);
207
+ int off = snprintf(header, headerLen, "Sec-WebSocket-Protocol: ");
208
+ for (int i = 0; i < protocol_count; i++) {
209
+ if (protocols[i]) {
210
+ if (i > 0) off += snprintf(header + off, headerLen - off, ", ");
211
+ off += snprintf(header + off, headerLen - off, "%s", protocols[i]);
212
+ }
213
+ }
214
+ wchar_t wHeader[1024];
215
+ MultiByteToWideChar(CP_UTF8, 0, header, -1, wHeader, 1024);
216
+ WinHttpAddRequestHeaders(request, wHeader, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD);
217
+ free(header);
218
+ }
219
+
220
+ // Upgrade to WebSocket
221
+ if (!WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0)) {
222
+ WinHttpCloseHandle(request); WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
223
+ return NULL;
224
+ }
225
+
226
+ if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0) ||
227
+ !WinHttpReceiveResponse(request, NULL)) {
228
+ WinHttpCloseHandle(request); WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
229
+ return NULL;
230
+ }
231
+
232
+ HINTERNET websocket = WinHttpWebSocketCompleteUpgrade(request, 0);
233
+ WinHttpCloseHandle(request);
234
+ if (!websocket) {
235
+ WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
236
+ return NULL;
237
+ }
238
+
239
+ EnterCriticalSection(&zapp_ws_lock);
240
+ ZappWsConn* c = zapp_ws_alloc();
241
+ if (!c) {
242
+ LeaveCriticalSection(&zapp_ws_lock);
243
+ WinHttpWebSocketClose(websocket, WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS, NULL, 0);
244
+ WinHttpCloseHandle(websocket); WinHttpCloseHandle(connection); WinHttpCloseHandle(session);
245
+ return NULL;
246
+ }
247
+
248
+ snprintf(c->ws_id, sizeof(c->ws_id), "ws-%d", zapp_ws_id_counter++);
249
+ c->session = session;
250
+ c->connection = connection;
251
+ c->websocket = websocket;
252
+ c->callback = callback;
253
+ c->user_data = user_data;
254
+ c->closed = 0;
255
+ c->thread = CreateThread(NULL, 0, zapp_ws_receive_thread, c, 0, NULL);
256
+ LeaveCriticalSection(&zapp_ws_lock);
257
+
258
+ // Fire open event
259
+ char openJson[128];
260
+ snprintf(openJson, sizeof(openJson), "{\"type\":\"open\",\"wsId\":\"%s\"}", c->ws_id);
261
+ zapp_ws_fire(c, "open", openJson);
262
+
263
+ return _strdup(c->ws_id);
264
+ }
265
+
266
+ static void zapp_core_ws_send_text(const char* ws_id, const char* text) {
267
+ if (!ws_id || !text) return;
268
+ EnterCriticalSection(&zapp_ws_lock);
269
+ ZappWsConn* c = zapp_ws_find(ws_id);
270
+ LeaveCriticalSection(&zapp_ws_lock);
271
+ if (!c || c->closed || !c->websocket) return;
272
+
273
+ DWORD len = (DWORD)strlen(text);
274
+ DWORD err = WinHttpWebSocketSend(c->websocket,
275
+ WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, (PVOID)text, len);
276
+ if (err != NO_ERROR) {
277
+ char errJson[256];
278
+ snprintf(errJson, sizeof(errJson),
279
+ "{\"type\":\"error\",\"wsId\":\"%s\",\"message\":\"Send failed: %lu\"}",
280
+ ws_id, err);
281
+ zapp_ws_fire(c, "error", errJson);
282
+ }
283
+ }
284
+
285
+ static void zapp_core_ws_send_binary(const char* ws_id, const uint8_t* bytes, size_t len) {
286
+ if (!ws_id || !bytes || len == 0) return;
287
+ EnterCriticalSection(&zapp_ws_lock);
288
+ ZappWsConn* c = zapp_ws_find(ws_id);
289
+ LeaveCriticalSection(&zapp_ws_lock);
290
+ if (!c || c->closed || !c->websocket) return;
291
+
292
+ DWORD err = WinHttpWebSocketSend(c->websocket,
293
+ WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, (PVOID)bytes, (DWORD)len);
294
+ if (err != NO_ERROR) {
295
+ char errJson[256];
296
+ snprintf(errJson, sizeof(errJson),
297
+ "{\"type\":\"error\",\"wsId\":\"%s\",\"message\":\"Binary send failed: %lu\"}",
298
+ ws_id, err);
299
+ zapp_ws_fire(c, "error", errJson);
300
+ }
301
+ }
302
+
303
+ static void zapp_core_ws_close(const char* ws_id, int code, const char* reason) {
304
+ if (!ws_id) return;
305
+
306
+ EnterCriticalSection(&zapp_ws_lock);
307
+ ZappWsConn* c = zapp_ws_find(ws_id);
308
+ if (!c || c->closed) {
309
+ LeaveCriticalSection(&zapp_ws_lock);
310
+ return;
311
+ }
312
+ c->closed = 1;
313
+ LeaveCriticalSection(&zapp_ws_lock);
314
+
315
+ if (c->websocket) {
316
+ DWORD reasonLen = reason ? (DWORD)strlen(reason) : 0;
317
+ WinHttpWebSocketClose(c->websocket, (USHORT)code, reason ? (PVOID)reason : NULL, reasonLen);
318
+ }
319
+
320
+ // Fire close event
321
+ char* escapedReason = zapp_ws_escape_json_string(reason ? reason : "");
322
+ char closeJson[512];
323
+ snprintf(closeJson, sizeof(closeJson),
324
+ "{\"type\":\"close\",\"wsId\":\"%s\",\"code\":%d,\"reason\":\"%s\",\"wasClean\":true}",
325
+ ws_id, code, escapedReason);
326
+ free(escapedReason);
327
+ zapp_ws_fire(c, "close", closeJson);
328
+
329
+ // Wait for receive thread to exit
330
+ if (c->thread) {
331
+ WaitForSingleObject(c->thread, 2000);
332
+ CloseHandle(c->thread);
333
+ }
334
+
335
+ // Cleanup handles
336
+ if (c->websocket) WinHttpCloseHandle(c->websocket);
337
+ if (c->connection) WinHttpCloseHandle(c->connection);
338
+ if (c->session) WinHttpCloseHandle(c->session);
339
+
340
+ memset(c, 0, sizeof(ZappWsConn));
341
+ }
342
+ #endif
343
+ }
@@ -0,0 +1,34 @@
1
+ raw {
2
+ #if defined(_WIN32) && defined(ZAPP_WORKER_ENGINE_QJS)
3
+ #include <windows.h>
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+
8
+ extern void zapp_windows_webview_eval_all(const char* js_utf8);
9
+ extern char* zapp_escape_js_string(const char* raw);
10
+
11
+ void zapp_dispatch_worker_to_webviews(const char* kind, const char* worker_id, const char* payload_json) {
12
+ if (kind == NULL || worker_id == NULL) return;
13
+ if (payload_json == NULL) payload_json = "null";
14
+
15
+ char* escaped_kind = zapp_escape_js_string(kind);
16
+ char* escaped_wid = zapp_escape_js_string(worker_id);
17
+
18
+ size_t jsLen = strlen(escaped_kind) + strlen(escaped_wid) + strlen(payload_json) + 256;
19
+ char* js = (char*)malloc(jsLen);
20
+ snprintf(js, jsLen,
21
+ "(function(){var b=globalThis[Symbol.for('zapp.bridge')];"
22
+ "if(b&&typeof b.dispatchWorkerBridge==='function'){"
23
+ "b.dispatchWorkerBridge('%s','%s',%s);}})();",
24
+ escaped_kind, escaped_wid, payload_json
25
+ );
26
+
27
+ zapp_windows_webview_eval_all(js);
28
+
29
+ free(js);
30
+ free(escaped_kind);
31
+ free(escaped_wid);
32
+ }
33
+ #endif
34
+ }
@@ -0,0 +1,46 @@
1
+ // Windows worker: QuickJS engine, opt-in via ZAPP_WORKER_ENGINE_QJS define.
2
+
3
+ import "../../worker.zc";
4
+
5
+ @cfg(ZAPP_WORKER_ENGINE_QJS)
6
+ import "./qjs.zc";
7
+
8
+ @cfg(ZAPP_WORKER_ENGINE_QJS)
9
+ fn windows_platform_bind_runtime(app: App*) -> void {
10
+ raw {
11
+ #ifdef _WIN32
12
+ zapp_ui_thread_id = GetCurrentThreadId();
13
+ #endif
14
+ }
15
+ (WindowsWorkerQjs{}).bind_runtime(app);
16
+ }
17
+
18
+ @cfg(ZAPP_WORKER_ENGINE_QJS)
19
+ fn windows_platform_handle_worker_bridge(app: App*, action: string, payload: string) -> void {
20
+ (WindowsWorkerQjs{}).handle_bridge(app, action, payload);
21
+ }
22
+
23
+ // No-op stubs when QJS workers are disabled
24
+ @cfg(not(ZAPP_WORKER_ENGINE_QJS))
25
+ fn windows_platform_bind_runtime(app: App*) -> void {
26
+ let _a = app;
27
+ }
28
+
29
+ @cfg(not(ZAPP_WORKER_ENGINE_QJS))
30
+ fn windows_platform_handle_worker_bridge(app: App*, action: string, payload: string) -> void {
31
+ let _a = app; let _b = action; let _c = payload;
32
+ }
33
+
34
+ raw {
35
+ #if defined(_WIN32) && !defined(ZAPP_WORKER_ENGINE_QJS)
36
+ // Stubs for worker functions referenced outside the worker module
37
+ void zapp_windows_reset_owner_workers(const char* owner_id) { (void)owner_id; }
38
+ void zapp_windows_reset_all_workers(void) {}
39
+ void zapp_windows_send_event_to_js(void* app_ptr, char* name, char* payload) {
40
+ (void)app_ptr; (void)name; (void)payload;
41
+ }
42
+ void zapp_windows_worker_dispatch_sync_result(const char* worker_id, const char* payload_json) {
43
+ (void)worker_id; (void)payload_json;
44
+ }
45
+ #endif
46
+ }
@@ -0,0 +1,255 @@
1
+ // QJS wrapper for fetch on Windows. Delegates to core/fetch_core.zc.
2
+
3
+ raw {
4
+ #if defined(_WIN32) && defined(ZAPP_WORKER_ENGINE_QJS)
5
+ #include "quickjs.h"
6
+ #include "quickjs-libc.h"
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+
10
+ extern void* zapp_windows_qjs_get_context(const char* workerId);
11
+ extern void zapp_windows_qjs_dispatch(void (*func)(void*), void* data);
12
+ extern void zapp_windows_qjs_drain_jobs(void* ctx, const char* label);
13
+ extern void zapp_log_worker(int level, int window_id, int worker_id, const char* message);
14
+ #ifndef ZAPP_LOG_ERROR
15
+ #define ZAPP_LOG_ERROR 0
16
+ #define ZAPP_LOG_WARN 1
17
+ #define ZAPP_LOG_INFO 2
18
+ #define ZAPP_LOG_DEBUG 3
19
+ #define ZAPP_LOG_TRACE 4
20
+ #endif
21
+
22
+
23
+ typedef struct {
24
+ char workerId[128];
25
+ JSContext* creatingCtx;
26
+ JSValue savedResolve;
27
+ JSValue savedReject;
28
+ zapp_fetch_response_t* response;
29
+ char* error;
30
+ } ZappFetchResultData;
31
+
32
+ static void zapp_fetch_deliver_on_qjs(void* data) {
33
+ ZappFetchResultData* d = (ZappFetchResultData*)data;
34
+
35
+ void* ctx_ptr = zapp_windows_qjs_get_context(d->workerId);
36
+ if (!ctx_ptr || (JSContext*)ctx_ptr != d->creatingCtx) {
37
+ JS_FreeValue(d->creatingCtx, d->savedResolve);
38
+ JS_FreeValue(d->creatingCtx, d->savedReject);
39
+ if (d->error) free(d->error);
40
+ if (d->response) {
41
+ free(d->response->status_text);
42
+ for (int i = 0; i < d->response->header_count; i++) {
43
+ free(d->response->header_keys[i]);
44
+ free(d->response->header_values[i]);
45
+ }
46
+ free(d->response->header_keys);
47
+ free(d->response->header_values);
48
+ free(d->response->body);
49
+ free(d->response->body_base64);
50
+ free(d->response);
51
+ }
52
+ free(d);
53
+ return;
54
+ }
55
+
56
+ JSContext* ctx = (JSContext*)ctx_ptr;
57
+
58
+ if (d->error) {
59
+ JSValue args[1] = { JS_NewString(ctx, d->error) };
60
+ JSValue ret = JS_Call(ctx, d->savedReject, JS_UNDEFINED, 1, args);
61
+ if (JS_IsException(ret)) {
62
+ JSValue exc = JS_GetException(ctx);
63
+ const char* s = JS_ToCString(ctx, exc);
64
+ if (s) { zapp_log_worker(ZAPP_LOG_ERROR, -1, -1, s); JS_FreeCString(ctx, s); }
65
+ JS_FreeValue(ctx, exc);
66
+ }
67
+ JS_FreeValue(ctx, ret);
68
+ JS_FreeValue(ctx, args[0]);
69
+ } else if (d->response) {
70
+ zapp_fetch_response_t* r = d->response;
71
+ JSValue resObj = JS_NewObject(ctx);
72
+ JS_SetPropertyStr(ctx, resObj, "status", JS_NewInt32(ctx, r->status));
73
+ JS_SetPropertyStr(ctx, resObj, "statusText",
74
+ JS_NewString(ctx, r->status_text ? r->status_text : ""));
75
+
76
+ JSValue headersObj = JS_NewObject(ctx);
77
+ for (int i = 0; i < r->header_count; i++) {
78
+ if (r->header_keys[i] && r->header_values[i]) {
79
+ JS_SetPropertyStr(ctx, headersObj, r->header_keys[i],
80
+ JS_NewString(ctx, r->header_values[i]));
81
+ }
82
+ }
83
+ JS_SetPropertyStr(ctx, resObj, "headers", headersObj);
84
+
85
+ if (r->body)
86
+ JS_SetPropertyStr(ctx, resObj, "body", JS_NewString(ctx, r->body));
87
+ else if (r->body_base64)
88
+ JS_SetPropertyStr(ctx, resObj, "body_base64", JS_NewString(ctx, r->body_base64));
89
+ else
90
+ JS_SetPropertyStr(ctx, resObj, "body", JS_NewString(ctx, ""));
91
+
92
+ JSValue args[1] = { resObj };
93
+ JSValue ret = JS_Call(ctx, d->savedResolve, JS_UNDEFINED, 1, args);
94
+ if (JS_IsException(ret)) {
95
+ JSValue exc = JS_GetException(ctx);
96
+ const char* s = JS_ToCString(ctx, exc);
97
+ if (s) { zapp_log_worker(ZAPP_LOG_ERROR, -1, -1, s); JS_FreeCString(ctx, s); }
98
+ JS_FreeValue(ctx, exc);
99
+ }
100
+ JS_FreeValue(ctx, ret);
101
+ JS_FreeValue(ctx, resObj);
102
+ }
103
+
104
+ JS_FreeValue(ctx, d->savedResolve);
105
+ JS_FreeValue(ctx, d->savedReject);
106
+ zapp_windows_qjs_drain_jobs(ctx, "fetch");
107
+
108
+ if (d->error) free(d->error);
109
+ if (d->response) {
110
+ free(d->response->status_text);
111
+ for (int i = 0; i < d->response->header_count; i++) {
112
+ free(d->response->header_keys[i]);
113
+ free(d->response->header_values[i]);
114
+ }
115
+ free(d->response->header_keys);
116
+ free(d->response->header_values);
117
+ free(d->response->body);
118
+ free(d->response->body_base64);
119
+ free(d->response);
120
+ }
121
+ free(d);
122
+ }
123
+
124
+ static void zapp_fetch_completion_handler(zapp_fetch_response_t* response, const char* error, void* userdata) {
125
+ ZappFetchResultData* d = (ZappFetchResultData*)userdata;
126
+
127
+ if (error) {
128
+ d->error = _strdup(error);
129
+ d->response = NULL;
130
+ } else if (response) {
131
+ // Deep copy the response since it's freed after callback returns
132
+ zapp_fetch_response_t* copy = (zapp_fetch_response_t*)calloc(1, sizeof(zapp_fetch_response_t));
133
+ copy->status = response->status;
134
+ copy->status_text = response->status_text ? _strdup(response->status_text) : NULL;
135
+ copy->header_count = response->header_count;
136
+ if (copy->header_count > 0) {
137
+ copy->header_keys = (char**)calloc(copy->header_count, sizeof(char*));
138
+ copy->header_values = (char**)calloc(copy->header_count, sizeof(char*));
139
+ for (int i = 0; i < copy->header_count; i++) {
140
+ copy->header_keys[i] = response->header_keys[i] ? _strdup(response->header_keys[i]) : NULL;
141
+ copy->header_values[i] = response->header_values[i] ? _strdup(response->header_values[i]) : NULL;
142
+ }
143
+ }
144
+ copy->body = response->body ? _strdup(response->body) : NULL;
145
+ copy->body_base64 = response->body_base64 ? _strdup(response->body_base64) : NULL;
146
+ d->response = copy;
147
+ }
148
+
149
+ zapp_windows_qjs_dispatch(zapp_fetch_deliver_on_qjs, d);
150
+ }
151
+
152
+ static JSValue qjs_bridge_fetch(JSContext* ctx, JSValue this_val, int argc, JSValue* argv, int magic, JSValue* func_data) {
153
+ (void)this_val; (void)magic;
154
+ if (argc < 4) return JS_UNDEFINED;
155
+
156
+ const char* worker_id = JS_ToCString(ctx, func_data[0]);
157
+ if (!worker_id) return JS_UNDEFINED;
158
+
159
+ const char* urlStr = JS_ToCString(ctx, argv[0]);
160
+ if (!urlStr) { JS_FreeCString(ctx, worker_id); return JS_UNDEFINED; }
161
+
162
+ JSValue optionsVal = argv[1];
163
+ JSValue resolveVal = argv[2];
164
+ JSValue rejectVal = argv[3];
165
+
166
+ // Extract method
167
+ char* method_copy = NULL;
168
+ if (!JS_IsUndefined(optionsVal) && !JS_IsNull(optionsVal)) {
169
+ JSValue m = JS_GetPropertyStr(ctx, optionsVal, "method");
170
+ if (!JS_IsUndefined(m)) {
171
+ const char* ms = JS_ToCString(ctx, m);
172
+ if (ms) { method_copy = _strdup(ms); JS_FreeCString(ctx, ms); }
173
+ }
174
+ JS_FreeValue(ctx, m);
175
+ }
176
+
177
+ // Extract headers
178
+ char** hKeys = NULL;
179
+ char** hVals = NULL;
180
+ int hCount = 0;
181
+ if (!JS_IsUndefined(optionsVal) && !JS_IsNull(optionsVal)) {
182
+ JSValue headersVal = JS_GetPropertyStr(ctx, optionsVal, "headers");
183
+ if (JS_IsObject(headersVal)) {
184
+ JSPropertyEnum* tab = NULL;
185
+ uint32_t len = 0;
186
+ if (JS_GetOwnPropertyNames(ctx, &tab, &len, headersVal, JS_GPN_STRING_MASK) == 0 && len > 0) {
187
+ hCount = (int)len;
188
+ hKeys = (char**)calloc(hCount, sizeof(char*));
189
+ hVals = (char**)calloc(hCount, sizeof(char*));
190
+ for (uint32_t i = 0; i < len; i++) {
191
+ const char* key = JS_AtomToCString(ctx, tab[i].atom);
192
+ JSValue val = JS_GetProperty(ctx, headersVal, tab[i].atom);
193
+ const char* valStr = JS_ToCString(ctx, val);
194
+ hKeys[i] = key ? _strdup(key) : NULL;
195
+ hVals[i] = valStr ? _strdup(valStr) : NULL;
196
+ if (key) JS_FreeCString(ctx, key);
197
+ if (valStr) JS_FreeCString(ctx, valStr);
198
+ JS_FreeValue(ctx, val);
199
+ JS_FreeAtom(ctx, tab[i].atom);
200
+ }
201
+ js_free(ctx, tab);
202
+ }
203
+ }
204
+ JS_FreeValue(ctx, headersVal);
205
+ }
206
+
207
+ // Extract body
208
+ char* body_copy = NULL;
209
+ size_t body_len = 0;
210
+ if (!JS_IsUndefined(optionsVal) && !JS_IsNull(optionsVal)) {
211
+ JSValue bodyVal = JS_GetPropertyStr(ctx, optionsVal, "body");
212
+ if (!JS_IsUndefined(bodyVal) && !JS_IsNull(bodyVal) && JS_IsString(bodyVal)) {
213
+ const char* bs = JS_ToCString(ctx, bodyVal);
214
+ if (bs) { body_copy = _strdup(bs); body_len = strlen(body_copy); JS_FreeCString(ctx, bs); }
215
+ }
216
+ JS_FreeValue(ctx, bodyVal);
217
+ }
218
+
219
+ // Create result data with saved JS callbacks
220
+ ZappFetchResultData* resultData = (ZappFetchResultData*)calloc(1, sizeof(ZappFetchResultData));
221
+ strncpy(resultData->workerId, worker_id, sizeof(resultData->workerId) - 1);
222
+ resultData->creatingCtx = ctx;
223
+ resultData->savedResolve = JS_DupValue(ctx, resolveVal);
224
+ resultData->savedReject = JS_DupValue(ctx, rejectVal);
225
+
226
+ char* urlCopy = _strdup(urlStr);
227
+ JS_FreeCString(ctx, urlStr);
228
+ JS_FreeCString(ctx, worker_id);
229
+
230
+ zapp_core_fetch_execute(
231
+ urlCopy, method_copy,
232
+ (const char**)hKeys, (const char**)hVals, hCount,
233
+ body_copy, body_len,
234
+ resultData->workerId,
235
+ zapp_fetch_completion_handler, resultData
236
+ );
237
+
238
+ free(urlCopy);
239
+ free(method_copy);
240
+ for (int i = 0; i < hCount; i++) { free(hKeys[i]); free(hVals[i]); }
241
+ free(hKeys); free(hVals);
242
+ free(body_copy);
243
+
244
+ return JS_UNDEFINED;
245
+ }
246
+
247
+ void zapp_windows_qjs_fetch_install(JSContext* ctx, JSValue bridge, const char* worker_id) {
248
+ JSValue wIdVal = JS_NewString(ctx, worker_id);
249
+ JSValue funcData[1] = { wIdVal };
250
+ JS_SetPropertyStr(ctx, bridge, "fetch",
251
+ JS_NewCFunctionData(ctx, qjs_bridge_fetch, 4, 0, 1, funcData));
252
+ JS_FreeValue(ctx, wIdVal);
253
+ }
254
+ #endif
255
+ }