@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,179 @@
1
+ // Engine-agnostic WebSocket connection management using NSURLSessionWebSocketTask.
2
+ // The JS engine callback is abstracted via a C function pointer.
3
+
4
+ raw {
5
+ #ifdef __APPLE__
6
+ #include <Foundation/Foundation.h>
7
+
8
+ static NSMutableDictionary<NSString*, NSMutableDictionary*>* zapp_ws_conns = nil;
9
+ static int zapp_ws_id_counter = 1;
10
+
11
+ static void zapp_core_ws_ensure_init(void) {
12
+ if (zapp_ws_conns == nil) zapp_ws_conns = [NSMutableDictionary new];
13
+ }
14
+
15
+ static NSString* zapp_core_ws_json_for_event(NSDictionary* dict) {
16
+ NSData* d = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil];
17
+ return d ? [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding] : @"{}";
18
+ }
19
+
20
+ static void zapp_core_ws_fire(NSString* wsId, NSString* eventType, NSDictionary* payload) {
21
+ NSMutableDictionary* conn = zapp_ws_conns[wsId];
22
+ if (conn == nil) return;
23
+
24
+ zapp_ws_event_fn cb = NULL;
25
+ NSValue* cbVal = conn[@"callback_fn"];
26
+ NSValue* udVal = conn[@"user_data"];
27
+ if (cbVal) cb = (zapp_ws_event_fn)[cbVal pointerValue];
28
+ void* ud = udVal ? [udVal pointerValue] : NULL;
29
+ if (!cb) return;
30
+
31
+ NSMutableDictionary* full = [NSMutableDictionary dictionaryWithDictionary:payload ?: @{}];
32
+ full[@"type"] = eventType;
33
+ full[@"wsId"] = wsId;
34
+ NSString* json = zapp_core_ws_json_for_event(full);
35
+
36
+ cb([wsId UTF8String], [eventType UTF8String], [json UTF8String], ud);
37
+ }
38
+
39
+ static void zapp_core_ws_receive_loop(NSURLSessionWebSocketTask* task, NSString* wsId);
40
+
41
+ static void zapp_core_ws_receive_loop(NSURLSessionWebSocketTask* task, NSString* wsId) {
42
+ [task receiveMessageWithCompletionHandler:^(NSURLSessionWebSocketMessage* message, NSError* error) {
43
+ if (error != nil) {
44
+ zapp_core_ws_fire(wsId, @"error", @{@"message": [error localizedDescription] ?: @"WebSocket error"});
45
+ return;
46
+ }
47
+ if (message == nil) return;
48
+
49
+ if (message.type == NSURLSessionWebSocketMessageTypeString) {
50
+ NSString* text = message.string ?: @"";
51
+ zapp_core_ws_fire(wsId, @"message", @{@"data": text, @"binary": @NO});
52
+ } else if (message.type == NSURLSessionWebSocketMessageTypeData) {
53
+ NSData* data = message.data;
54
+ if (data != nil) {
55
+ NSMutableArray* byteArray = [NSMutableArray arrayWithCapacity:[data length]];
56
+ const uint8_t* bytes = (const uint8_t*)[data bytes];
57
+ for (NSUInteger i = 0; i < [data length]; i++) {
58
+ [byteArray addObject:@(bytes[i])];
59
+ }
60
+ zapp_core_ws_fire(wsId, @"message", @{@"data": byteArray, @"binary": @YES});
61
+ }
62
+ }
63
+
64
+ NSMutableDictionary* conn = zapp_ws_conns[wsId];
65
+ if (conn != nil && task.state == NSURLSessionTaskStateRunning) {
66
+ zapp_core_ws_receive_loop(task, wsId);
67
+ }
68
+ }];
69
+ }
70
+
71
+ // Connect. Returns wsId C string (caller must free), or NULL on failure.
72
+ static char* zapp_core_ws_connect(const char* url_str, const char** protocols, int protocol_count,
73
+ zapp_ws_event_fn callback, void* user_data) {
74
+ zapp_core_ws_ensure_init();
75
+ if (url_str == NULL) return NULL;
76
+
77
+ NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:url_str]];
78
+ if (url == nil) return NULL;
79
+
80
+ NSString* wsId = [NSString stringWithFormat:@"ws-%d", zapp_ws_id_counter++];
81
+
82
+ NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
83
+ NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
84
+ NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
85
+
86
+ if (protocols && protocol_count > 0) {
87
+ NSMutableArray* protos = [NSMutableArray arrayWithCapacity:protocol_count];
88
+ for (int i = 0; i < protocol_count; i++) {
89
+ if (protocols[i]) [protos addObject:[NSString stringWithUTF8String:protocols[i]]];
90
+ }
91
+ if ([protos count] > 0) {
92
+ [request setValue:[protos componentsJoinedByString:@", "] forHTTPHeaderField:@"Sec-WebSocket-Protocol"];
93
+ }
94
+ }
95
+
96
+ NSURLSessionWebSocketTask* task = [session webSocketTaskWithRequest:request];
97
+
98
+ NSMutableDictionary* conn = [NSMutableDictionary dictionary];
99
+ conn[@"task"] = task;
100
+ conn[@"session"] = session;
101
+ conn[@"callback_fn"] = [NSValue valueWithPointer:(void*)callback];
102
+ if (user_data) conn[@"user_data"] = [NSValue valueWithPointer:user_data];
103
+ zapp_ws_conns[wsId] = conn;
104
+
105
+ [task resume];
106
+ zapp_core_ws_receive_loop(task, wsId);
107
+
108
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
109
+ NSMutableDictionary* c = zapp_ws_conns[wsId];
110
+ if (c != nil) {
111
+ NSURLSessionWebSocketTask* t = c[@"task"];
112
+ if (t && t.state == NSURLSessionTaskStateRunning) {
113
+ zapp_core_ws_fire(wsId, @"open", @{});
114
+ } else {
115
+ zapp_core_ws_fire(wsId, @"error", @{@"message": @"Connection failed"});
116
+ }
117
+ }
118
+ });
119
+
120
+ return strdup([wsId UTF8String]);
121
+ }
122
+
123
+ // Send text or binary data on an existing WebSocket.
124
+ static void zapp_core_ws_send_text(const char* ws_id, const char* text) {
125
+ if (!ws_id || !text) return;
126
+ NSString* wsId = [NSString stringWithUTF8String:ws_id];
127
+ NSMutableDictionary* conn = zapp_ws_conns[wsId];
128
+ if (!conn) return;
129
+ NSURLSessionWebSocketTask* task = conn[@"task"];
130
+ if (!task || task.state != NSURLSessionTaskStateRunning) return;
131
+
132
+ NSURLSessionWebSocketMessage* msg = [[NSURLSessionWebSocketMessage alloc] initWithString:[NSString stringWithUTF8String:text]];
133
+ [task sendMessage:msg completionHandler:^(NSError* error) {
134
+ if (error) {
135
+ zapp_core_ws_fire(wsId, @"error", @{@"message": [error localizedDescription] ?: @"Send failed"});
136
+ }
137
+ }];
138
+ }
139
+
140
+ static void zapp_core_ws_send_binary(const char* ws_id, const uint8_t* bytes, size_t len) {
141
+ if (!ws_id || !bytes || len == 0) return;
142
+ NSString* wsId = [NSString stringWithUTF8String:ws_id];
143
+ NSMutableDictionary* conn = zapp_ws_conns[wsId];
144
+ if (!conn) return;
145
+ NSURLSessionWebSocketTask* task = conn[@"task"];
146
+ if (!task || task.state != NSURLSessionTaskStateRunning) return;
147
+
148
+ NSData* data = [NSData dataWithBytes:bytes length:len];
149
+ NSURLSessionWebSocketMessage* msg = [[NSURLSessionWebSocketMessage alloc] initWithData:data];
150
+ [task sendMessage:msg completionHandler:^(NSError* error) {
151
+ if (error) {
152
+ zapp_core_ws_fire(wsId, @"error", @{@"message": [error localizedDescription] ?: @"Send failed"});
153
+ }
154
+ }];
155
+ }
156
+
157
+ // Close an existing WebSocket.
158
+ static void zapp_core_ws_close(const char* ws_id, int code, const char* reason) {
159
+ if (!ws_id) return;
160
+ NSString* wsId = [NSString stringWithUTF8String:ws_id];
161
+ NSMutableDictionary* conn = zapp_ws_conns[wsId];
162
+ if (!conn) return;
163
+
164
+ NSURLSessionWebSocketTask* task = conn[@"task"];
165
+ if (task) {
166
+ NSData* reasonData = reason ? [[NSString stringWithUTF8String:reason] dataUsingEncoding:NSUTF8StringEncoding] : nil;
167
+ [task cancelWithCloseCode:(NSURLSessionWebSocketCloseCode)code reason:reasonData];
168
+ }
169
+
170
+ zapp_core_ws_fire(wsId, @"close", @{
171
+ @"code": @(code),
172
+ @"reason": reason ? [NSString stringWithUTF8String:reason] : @"",
173
+ @"wasClean": @YES,
174
+ });
175
+
176
+ [zapp_ws_conns removeObjectForKey:wsId];
177
+ }
178
+ #endif
179
+ }
@@ -0,0 +1,55 @@
1
+ raw {
2
+ #ifdef __APPLE__
3
+ #include <Cocoa/Cocoa.h>
4
+ #include <WebKit/WebKit.h>
5
+ #include <dispatch/dispatch.h>
6
+
7
+ void zapp_dispatch_worker_to_webviews(const char* kind, const char* worker_id, const char* payload_json) {
8
+ if (kind == NULL || worker_id == NULL) return;
9
+ if (payload_json == NULL) payload_json = "null";
10
+
11
+ NSString* k = [NSString stringWithUTF8String:kind];
12
+ NSString* wid = [NSString stringWithUTF8String:worker_id];
13
+ NSString* payload = [NSString stringWithUTF8String:payload_json];
14
+
15
+ k = [k stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
16
+ k = [k stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
17
+ wid = [wid stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
18
+ wid = [wid stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
19
+
20
+ NSString* js = [NSString stringWithFormat:
21
+ @"(function(){var b=globalThis[Symbol.for('zapp.bridge')];if(b&&typeof b.dispatchWorkerBridge==='function'){b.dispatchWorkerBridge('%@','%@',%@);}})();",
22
+ k, wid, payload
23
+ ];
24
+
25
+ dispatch_async(dispatch_get_main_queue(), ^{
26
+ for (NSWindow* window in [NSApp windows]) {
27
+ NSView* content = [window contentView];
28
+ if ([content isKindOfClass:[WKWebView class]]) {
29
+ WKWebView* webview = (WKWebView*)content;
30
+ [webview evaluateJavaScript:js completionHandler:nil];
31
+ }
32
+ }
33
+ });
34
+ }
35
+
36
+ NSString* zapp_json_stringify_obj(id obj) {
37
+ if (obj == nil || obj == [NSNull null]) return @"null";
38
+ if (![NSJSONSerialization isValidJSONObject:obj]) {
39
+ if ([obj isKindOfClass:[NSString class]]) {
40
+ NSData* data = [NSJSONSerialization dataWithJSONObject:@[(NSString*)obj] options:0 error:nil];
41
+ if (!data) return @"null";
42
+ NSString* arr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
43
+ if ([arr length] >= 2) {
44
+ return [arr substringWithRange:NSMakeRange(1, [arr length] - 2)];
45
+ }
46
+ return @"null";
47
+ }
48
+ return @"null";
49
+ }
50
+ NSData* jsonData = [NSJSONSerialization dataWithJSONObject:obj options:0 error:nil];
51
+ if (!jsonData) return @"null";
52
+ return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
53
+ }
54
+ #endif
55
+ }
@@ -0,0 +1,39 @@
1
+ // JSC wrapper for btoa/atob. Delegates to core/base64_core.zc.
2
+
3
+ //> macos: framework: JavaScriptCore
4
+
5
+ raw {
6
+ #ifdef __APPLE__
7
+ #include <Foundation/Foundation.h>
8
+ #include <JavaScriptCore/JavaScriptCore.h>
9
+
10
+ static char* zapp_core_btoa(const char* input);
11
+ static char* zapp_core_atob(const char* input);
12
+
13
+ void zapp_darwin_worker_base64_init(JSContext* ctx) {
14
+ JSValue* bridge = ctx[@"__zappBridge"];
15
+ if (bridge == nil || bridge.isUndefined) {
16
+ ctx[@"__zappBridge"] = [JSValue valueWithNewObjectInContext:ctx];
17
+ bridge = ctx[@"__zappBridge"];
18
+ }
19
+
20
+ bridge[@"btoa"] = ^NSString*(JSValue* strVal) {
21
+ if (strVal == nil || [strVal isUndefined] || [strVal isNull]) return @"";
22
+ const char* input = [[strVal toString] UTF8String];
23
+ char* result = zapp_core_btoa(input);
24
+ NSString* ns = [NSString stringWithUTF8String:result];
25
+ free(result);
26
+ return ns ?: @"";
27
+ };
28
+
29
+ bridge[@"atob"] = ^NSString*(JSValue* strVal) {
30
+ if (strVal == nil || [strVal isUndefined] || [strVal isNull]) return @"";
31
+ const char* input = [[strVal toString] UTF8String];
32
+ char* result = zapp_core_atob(input);
33
+ NSString* ns = [NSString stringWithUTF8String:result];
34
+ free(result);
35
+ return ns ?: @"";
36
+ };
37
+ }
38
+ #endif
39
+ }
@@ -0,0 +1,49 @@
1
+ // JSC wrapper for crypto. Delegates to core/crypto_core.zc.
2
+
3
+ //> macos: framework: JavaScriptCore
4
+
5
+ raw {
6
+ #ifdef __APPLE__
7
+ #include <Foundation/Foundation.h>
8
+ #include <JavaScriptCore/JavaScriptCore.h>
9
+
10
+ static void zapp_core_crypto_random_bytes(uint8_t* buf, size_t len);
11
+ static char* zapp_core_crypto_random_uuid(void);
12
+
13
+ void zapp_darwin_worker_crypto_init(JSContext* ctx) {
14
+ JSValue* bridge = ctx[@"__zappBridge"];
15
+ if (bridge == nil || bridge.isUndefined) {
16
+ ctx[@"__zappBridge"] = [JSValue valueWithNewObjectInContext:ctx];
17
+ bridge = ctx[@"__zappBridge"];
18
+ }
19
+
20
+ bridge[@"getRandomValues"] = ^(JSValue* arrayVal) {
21
+ if (arrayVal == nil || [arrayVal isUndefined] || [arrayVal isNull]) return arrayVal;
22
+
23
+ JSContextRef ctxRef = ctx.JSGlobalContextRef;
24
+ JSValueRef valRef = arrayVal.JSValueRef;
25
+ if (!ctxRef || !valRef) return arrayVal;
26
+
27
+ JSValueRef exception = NULL;
28
+ JSTypedArrayType type = JSValueGetTypedArrayType(ctxRef, valRef, &exception);
29
+ if (type == kJSTypedArrayTypeNone) return arrayVal;
30
+
31
+ size_t len = JSObjectGetTypedArrayByteLength(ctxRef, valRef, &exception);
32
+ if (len == 0 || exception) return arrayVal;
33
+
34
+ void* bytes = JSObjectGetTypedArrayBytesPtr(ctxRef, valRef, &exception);
35
+ if (!bytes || exception) return arrayVal;
36
+
37
+ zapp_core_crypto_random_bytes((uint8_t*)bytes, len);
38
+ return arrayVal;
39
+ };
40
+
41
+ bridge[@"randomUUID"] = ^NSString*() {
42
+ char* uuid = zapp_core_crypto_random_uuid();
43
+ NSString* result = [NSString stringWithUTF8String:uuid];
44
+ free(uuid);
45
+ return result;
46
+ };
47
+ }
48
+ #endif
49
+ }
@@ -0,0 +1,86 @@
1
+ // JSC wrapper for TextEncoder/TextDecoder. Delegates to core/encoding_core.zc.
2
+
3
+ //> macos: framework: JavaScriptCore
4
+
5
+ raw {
6
+ #ifdef __APPLE__
7
+ #include <Foundation/Foundation.h>
8
+ #include <JavaScriptCore/JavaScriptCore.h>
9
+
10
+ static uint8_t* zapp_core_text_encode(const char* input, size_t* out_len);
11
+ static char* zapp_core_text_decode(const uint8_t* bytes, size_t len);
12
+
13
+ static JSValue* zapp_jsc_create_uint8array(JSContext* ctx, const uint8_t* bytes, size_t len) {
14
+ JSContextRef ctxRef = ctx.JSGlobalContextRef;
15
+ JSValueRef exception = NULL;
16
+
17
+ JSStringRef u8Name = JSStringCreateWithUTF8CString("Uint8Array");
18
+ JSValueRef u8Ctor = JSObjectGetProperty(ctxRef, JSContextGetGlobalObject(ctxRef), u8Name, NULL);
19
+ JSStringRelease(u8Name);
20
+
21
+ if (len == 0 || bytes == NULL) {
22
+ JSValueRef args[1] = { JSValueMakeNumber(ctxRef, 0) };
23
+ JSObjectRef result = JSObjectCallAsConstructor(ctxRef, (JSObjectRef)u8Ctor, 1, args, &exception);
24
+ if (result && !exception) return [JSValue valueWithJSValueRef:result inContext:ctx];
25
+ return [JSValue valueWithUndefinedInContext:ctx];
26
+ }
27
+
28
+ JSValueRef args[1] = { JSValueMakeNumber(ctxRef, (double)len) };
29
+ JSObjectRef u8Arr = JSObjectCallAsConstructor(ctxRef, (JSObjectRef)u8Ctor, 1, args, &exception);
30
+ if (!u8Arr || exception) return [JSValue valueWithUndefinedInContext:ctx];
31
+
32
+ void* ptr = JSObjectGetTypedArrayBytesPtr(ctxRef, u8Arr, &exception);
33
+ if (ptr && !exception) memcpy(ptr, bytes, len);
34
+
35
+ return [JSValue valueWithJSValueRef:u8Arr inContext:ctx];
36
+ }
37
+
38
+ void zapp_darwin_worker_encoding_init(JSContext* ctx) {
39
+ JSValue* bridge = ctx[@"__zappBridge"];
40
+ if (bridge == nil || bridge.isUndefined) {
41
+ ctx[@"__zappBridge"] = [JSValue valueWithNewObjectInContext:ctx];
42
+ bridge = ctx[@"__zappBridge"];
43
+ }
44
+
45
+ bridge[@"textEncode"] = ^JSValue*(JSValue* strVal) {
46
+ if (strVal == nil || [strVal isUndefined] || [strVal isNull]) {
47
+ return zapp_jsc_create_uint8array(ctx, NULL, 0);
48
+ }
49
+ NSString* str = [strVal toString];
50
+ if (str == nil) return zapp_jsc_create_uint8array(ctx, NULL, 0);
51
+ size_t len = 0;
52
+ uint8_t* bytes = zapp_core_text_encode([str UTF8String], &len);
53
+ JSValue* result = zapp_jsc_create_uint8array(ctx, bytes, len);
54
+ free(bytes);
55
+ return result;
56
+ };
57
+
58
+ bridge[@"textDecode"] = ^NSString*(JSValue* bufVal) {
59
+ if (bufVal == nil || [bufVal isUndefined] || [bufVal isNull]) return @"";
60
+
61
+ JSContextRef ctxRef = ctx.JSGlobalContextRef;
62
+ JSValueRef valRef = bufVal.JSValueRef;
63
+ JSValueRef exception = NULL;
64
+ const uint8_t* bytes = NULL;
65
+ size_t len = 0;
66
+
67
+ JSTypedArrayType type = JSValueGetTypedArrayType(ctxRef, valRef, &exception);
68
+ if (type != kJSTypedArrayTypeNone && exception == NULL) {
69
+ bytes = (const uint8_t*)JSObjectGetTypedArrayBytesPtr(ctxRef, valRef, &exception);
70
+ size_t byteOffset = JSObjectGetTypedArrayByteOffset(ctxRef, valRef, &exception);
71
+ len = JSObjectGetTypedArrayByteLength(ctxRef, valRef, &exception);
72
+ if (bytes) bytes += byteOffset;
73
+ } else {
74
+ exception = NULL;
75
+ bytes = (const uint8_t*)JSObjectGetArrayBufferBytesPtr(ctxRef, valRef, &exception);
76
+ if (bytes && exception == NULL) len = JSObjectGetArrayBufferByteLength(ctxRef, valRef, &exception);
77
+ }
78
+
79
+ char* decoded = zapp_core_text_decode(bytes, len);
80
+ NSString* result = [NSString stringWithUTF8String:decoded];
81
+ free(decoded);
82
+ return result ?: @"";
83
+ };
84
+ }
85
+ #endif
86
+ }
@@ -0,0 +1,149 @@
1
+ // JSC wrapper for fetch. Delegates to core/fetch_core.zc.
2
+
3
+ //> macos: framework: JavaScriptCore
4
+
5
+ raw {
6
+ #ifdef __APPLE__
7
+ #include <Foundation/Foundation.h>
8
+ #include <JavaScriptCore/JavaScriptCore.h>
9
+
10
+ extern void zapp_darwin_worker_js_sync(dispatch_block_t block);
11
+ static void zapp_core_fetch_ensure_init(void);
12
+ static void zapp_core_fetch_execute(NSMutableURLRequest*, NSString*, zapp_fetch_completion_t);
13
+ static NSMutableURLRequest* zapp_core_fetch_build_request(const char*, const char*, const char**, const char**, int, const char*, size_t);
14
+ static void zapp_core_fetch_cancel(NSString*);
15
+ static void zapp_core_fetch_cancel_all(void);
16
+
17
+ void zapp_darwin_worker_fetch_init(JSContext* ctx, NSString* workerId) {
18
+ zapp_core_fetch_ensure_init();
19
+
20
+ __weak JSContext* weakCtx = ctx;
21
+
22
+ JSValue* bridge = ctx[@"__zappBridge"];
23
+ if (bridge == nil || bridge.isUndefined) {
24
+ ctx[@"__zappBridge"] = [JSValue valueWithNewObjectInContext:ctx];
25
+ bridge = ctx[@"__zappBridge"];
26
+ }
27
+
28
+ bridge[@"fetch"] = ^(JSValue* urlVal, JSValue* optionsVal, JSValue* resolveVal, JSValue* rejectVal) {
29
+ JSContext* strongCtx = weakCtx;
30
+ if (!strongCtx) return;
31
+
32
+ NSString* wId = [strongCtx[@"__zappWorkerDispatchId"] toString];
33
+ if (![wId isKindOfClass:[NSString class]] || [wId length] == 0) wId = workerId;
34
+ if (!wId) return;
35
+
36
+ const char* urlStr = [[urlVal toString] UTF8String];
37
+
38
+ // Extract method
39
+ const char* method = NULL;
40
+ NSString* methodNS = nil;
41
+ if (optionsVal && ![optionsVal isUndefined] && ![optionsVal isNull]) {
42
+ JSValue* m = optionsVal[@"method"];
43
+ if (m && ![m isUndefined]) { methodNS = [m toString]; method = [methodNS UTF8String]; }
44
+ }
45
+
46
+ // Extract headers
47
+ const char** hKeys = NULL;
48
+ const char** hVals = NULL;
49
+ int hCount = 0;
50
+ NSMutableArray* hKeysNS = nil;
51
+ NSMutableArray* hValsNS = nil;
52
+ if (optionsVal && ![optionsVal isUndefined] && ![optionsVal isNull]) {
53
+ JSValue* headersVal = optionsVal[@"headers"];
54
+ if (headersVal && ![headersVal isUndefined] && [headersVal isObject]) {
55
+ NSDictionary* hDict = [headersVal toDictionary];
56
+ hCount = (int)[hDict count];
57
+ if (hCount > 0) {
58
+ hKeysNS = [NSMutableArray arrayWithCapacity:hCount];
59
+ hValsNS = [NSMutableArray arrayWithCapacity:hCount];
60
+ hKeys = (const char**)calloc(hCount, sizeof(char*));
61
+ hVals = (const char**)calloc(hCount, sizeof(char*));
62
+ int i = 0;
63
+ for (NSString* k in hDict) {
64
+ NSString* v = [NSString stringWithFormat:@"%@", hDict[k]];
65
+ [hKeysNS addObject:k];
66
+ [hValsNS addObject:v];
67
+ hKeys[i] = [k UTF8String];
68
+ hVals[i] = [v UTF8String];
69
+ i++;
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ // Extract body
76
+ const char* body = NULL;
77
+ size_t bodyLen = 0;
78
+ NSString* bodyNS = nil;
79
+ if (optionsVal && ![optionsVal isUndefined] && ![optionsVal isNull]) {
80
+ JSValue* bodyVal = optionsVal[@"body"];
81
+ if (bodyVal && ![bodyVal isUndefined] && ![bodyVal isNull] && [bodyVal isString]) {
82
+ bodyNS = [bodyVal toString];
83
+ body = [bodyNS UTF8String];
84
+ bodyLen = [bodyNS lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
85
+ }
86
+ }
87
+
88
+ NSMutableURLRequest* request = zapp_core_fetch_build_request(urlStr, method, hKeys, hVals, hCount, body, bodyLen);
89
+ free(hKeys);
90
+ free(hVals);
91
+
92
+ if (!request) {
93
+ if (rejectVal && ![rejectVal isUndefined]) [rejectVal callWithArguments:@[@"Invalid URL"]];
94
+ return;
95
+ }
96
+
97
+ __block JSValue* blockResolve = resolveVal;
98
+ __block JSValue* blockReject = rejectVal;
99
+
100
+ zapp_core_fetch_execute(request, wId, ^(zapp_fetch_response_t* response, NSString* error) {
101
+ zapp_darwin_worker_js_sync(^{
102
+ JSContext* ctx2 = weakCtx;
103
+ if (!ctx2) return;
104
+
105
+ if (error) {
106
+ if (blockReject && ![blockReject isUndefined]) {
107
+ [blockReject callWithArguments:@[error]];
108
+ }
109
+ blockResolve = nil; blockReject = nil;
110
+ return;
111
+ }
112
+
113
+ if (!response) { blockResolve = nil; blockReject = nil; return; }
114
+
115
+ NSMutableDictionary* resDict = [NSMutableDictionary dictionary];
116
+ resDict[@"status"] = @(response->status);
117
+ resDict[@"statusText"] = response->status_text ? [NSString stringWithUTF8String:response->status_text] : @"";
118
+
119
+ NSMutableDictionary* headers = [NSMutableDictionary dictionary];
120
+ for (int i = 0; i < response->header_count; i++) {
121
+ if (response->header_keys[i] && response->header_values[i]) {
122
+ headers[[NSString stringWithUTF8String:response->header_keys[i]]] =
123
+ [NSString stringWithUTF8String:response->header_values[i]];
124
+ }
125
+ }
126
+ resDict[@"headers"] = headers;
127
+
128
+ if (response->body) resDict[@"body"] = [NSString stringWithUTF8String:response->body];
129
+ else if (response->body_base64) resDict[@"body_base64"] = [NSString stringWithUTF8String:response->body_base64];
130
+ else resDict[@"body"] = @"";
131
+
132
+ if (blockResolve && ![blockResolve isUndefined]) {
133
+ [blockResolve callWithArguments:@[resDict]];
134
+ }
135
+ blockResolve = nil; blockReject = nil;
136
+ });
137
+ });
138
+ };
139
+ }
140
+
141
+ void zapp_darwin_worker_fetch_cancel(NSString* workerId) {
142
+ zapp_core_fetch_cancel(workerId);
143
+ }
144
+
145
+ void zapp_darwin_worker_fetch_cancel_all(void) {
146
+ zapp_core_fetch_cancel_all();
147
+ }
148
+ #endif
149
+ }
@@ -0,0 +1,54 @@
1
+ // JSC wrapper for URL parsing. Delegates to core/url_core.zc.
2
+
3
+ //> macos: framework: JavaScriptCore
4
+
5
+ raw {
6
+ #ifdef __APPLE__
7
+ #include <Foundation/Foundation.h>
8
+ #include <JavaScriptCore/JavaScriptCore.h>
9
+
10
+ static int zapp_core_url_parse(const char* url_str, const char* base_str, zapp_url_parsed_t* out);
11
+ static void zapp_core_url_free(zapp_url_parsed_t* c);
12
+
13
+ void zapp_darwin_worker_url_init(JSContext* ctx) {
14
+ JSValue* bridge = ctx[@"__zappBridge"];
15
+ if (bridge == nil || bridge.isUndefined) {
16
+ ctx[@"__zappBridge"] = [JSValue valueWithNewObjectInContext:ctx];
17
+ bridge = ctx[@"__zappBridge"];
18
+ }
19
+
20
+ bridge[@"urlParse"] = ^(JSValue* urlVal, JSValue* baseVal) {
21
+ if (urlVal == nil || [urlVal isUndefined] || [urlVal isNull]) {
22
+ return [JSValue valueWithNullInContext:ctx];
23
+ }
24
+
25
+ const char* urlStr = [[urlVal toString] UTF8String];
26
+ const char* baseStr = NULL;
27
+ if (baseVal != nil && ![baseVal isUndefined] && ![baseVal isNull]) {
28
+ baseStr = [[baseVal toString] UTF8String];
29
+ }
30
+
31
+ zapp_url_parsed_t c;
32
+ if (zapp_core_url_parse(urlStr, baseStr, &c) != 0) {
33
+ return [JSValue valueWithNullInContext:ctx];
34
+ }
35
+
36
+ NSDictionary* result = @{
37
+ @"href": [NSString stringWithUTF8String:c.href],
38
+ @"protocol": [NSString stringWithUTF8String:c.protocol],
39
+ @"host": [NSString stringWithUTF8String:c.host],
40
+ @"hostname": [NSString stringWithUTF8String:c.hostname],
41
+ @"port": [NSString stringWithUTF8String:c.port],
42
+ @"pathname": [NSString stringWithUTF8String:c.pathname],
43
+ @"search": [NSString stringWithUTF8String:c.search],
44
+ @"hash": [NSString stringWithUTF8String:c.hash],
45
+ @"origin": [NSString stringWithUTF8String:c.origin],
46
+ @"username": [NSString stringWithUTF8String:c.username],
47
+ @"password": [NSString stringWithUTF8String:c.password],
48
+ };
49
+ zapp_core_url_free(&c);
50
+ return [JSValue valueWithObject:result inContext:ctx];
51
+ };
52
+ }
53
+ #endif
54
+ }