@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.
- package/README.md +55 -0
- package/dist/zapp-cli.js +9471 -0
- package/native/src/app/app.zc +490 -0
- package/native/src/event/event.zc +24 -0
- package/native/src/event/events.zc +70 -0
- package/native/src/platform/darwin/backend.zc +923 -0
- package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
- package/native/src/platform/darwin/bootstrap.zc +9 -0
- package/native/src/platform/darwin/engine_jsc.zc +86 -0
- package/native/src/platform/darwin/engine_qjs.zc +92 -0
- package/native/src/platform/darwin/platform.zc +156 -0
- package/native/src/platform/darwin/webview.zc +550 -0
- package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
- package/native/src/platform/darwin/window.zc +1223 -0
- package/native/src/platform/darwin/worker/common.zc +223 -0
- package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
- package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
- package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
- package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
- package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
- package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
- package/native/src/platform/darwin/worker/dispatch.zc +55 -0
- package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
- package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
- package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
- package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
- package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
- package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
- package/native/src/platform/darwin/worker/jsc.zc +670 -0
- package/native/src/platform/darwin/worker/mod.zc +30 -0
- package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
- package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
- package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
- package/native/src/platform/darwin/worker/qjs.zc +1053 -0
- package/native/src/platform/darwin/worker/timers.zc +149 -0
- package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
- package/native/src/platform/platform.zc +64 -0
- package/native/src/platform/shared/log.zc +156 -0
- package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
- package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
- package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
- package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
- package/native/src/platform/shared/worker_registry.zc +206 -0
- package/native/src/platform/window.zc +446 -0
- package/native/src/platform/windows/backend.zc +452 -0
- package/native/src/platform/windows/backend_bootstrap.zc +9 -0
- package/native/src/platform/windows/bootstrap.zc +9 -0
- package/native/src/platform/windows/engine_qjs.zc +60 -0
- package/native/src/platform/windows/platform.zc +387 -0
- package/native/src/platform/windows/webview.zc +1175 -0
- package/native/src/platform/windows/webview_bootstrap.zc +9 -0
- package/native/src/platform/windows/window.zc +1271 -0
- package/native/src/platform/windows/worker/common.zc +409 -0
- package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
- package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
- package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
- package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
- package/native/src/platform/windows/worker/core/url_core.zc +216 -0
- package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
- package/native/src/platform/windows/worker/dispatch.zc +34 -0
- package/native/src/platform/windows/worker/mod.zc +46 -0
- package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
- package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
- package/native/src/platform/windows/worker/qjs.zc +1049 -0
- package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
- package/native/src/platform/worker.zc +8 -0
- package/native/src/service/service.zc +228 -0
- package/native/vendor/quickjs-ng/.gitattributes +4 -0
- package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
- package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
- package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
- package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
- package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
- package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
- package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
- package/native/vendor/quickjs-ng/.gitmodules +5 -0
- package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
- package/native/vendor/quickjs-ng/LICENSE +24 -0
- package/native/vendor/quickjs-ng/Makefile +149 -0
- package/native/vendor/quickjs-ng/amalgam.js +53 -0
- package/native/vendor/quickjs-ng/api-test.c +927 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
- package/native/vendor/quickjs-ng/ctest.c +17 -0
- package/native/vendor/quickjs-ng/cutils.h +2013 -0
- package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
- package/native/vendor/quickjs-ng/dtoa.c +1619 -0
- package/native/vendor/quickjs-ng/dtoa.h +87 -0
- package/native/vendor/quickjs-ng/examples/fib.c +67 -0
- package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
- package/native/vendor/quickjs-ng/examples/hello.js +1 -0
- package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
- package/native/vendor/quickjs-ng/examples/meson.build +17 -0
- package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
- package/native/vendor/quickjs-ng/examples/point.c +154 -0
- package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
- package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
- package/native/vendor/quickjs-ng/fuzz.c +51 -0
- package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/native/vendor/quickjs-ng/gen/hello.c +53 -0
- package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
- package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
- package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
- package/native/vendor/quickjs-ng/libregexp.c +2687 -0
- package/native/vendor/quickjs-ng/libregexp.h +98 -0
- package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
- package/native/vendor/quickjs-ng/libunicode.c +1746 -0
- package/native/vendor/quickjs-ng/libunicode.h +126 -0
- package/native/vendor/quickjs-ng/list.h +107 -0
- package/native/vendor/quickjs-ng/lre-test.c +73 -0
- package/native/vendor/quickjs-ng/meson.build +684 -0
- package/native/vendor/quickjs-ng/meson_options.txt +6 -0
- package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
- package/native/vendor/quickjs-ng/qjs.c +748 -0
- package/native/vendor/quickjs-ng/qjsc.c +673 -0
- package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
- package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
- package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
- package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
- package/native/vendor/quickjs-ng/quickjs.c +60259 -0
- package/native/vendor/quickjs-ng/quickjs.h +1419 -0
- package/native/vendor/quickjs-ng/repl.js +1927 -0
- package/native/vendor/quickjs-ng/run-test262.c +2417 -0
- package/native/vendor/quickjs-ng/standalone.js +129 -0
- package/native/vendor/quickjs-ng/tests/assert.js +49 -0
- package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
- package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
- package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
- package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
- package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
- package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
- package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
- package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
- package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
- package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
- package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
- package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
- package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
- package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
- package/native/vendor/quickjs-ng/tests/empty.js +0 -0
- package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
- package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
- package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
- package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
- package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
- package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
- package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
- package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
- package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
- package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
- package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
- package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
- package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
- package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
- package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
- package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
- package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
- package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
- package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
- package/native/vendor/quickjs-ng/tests.conf +14 -0
- package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
- package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
- package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/native/vendor/quickjs-ng/update-version.sh +32 -0
- package/native/vendor/webview2/include/WebView2.h +60636 -0
- package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
- package/package.json +33 -0
- package/src/backend.ts +139 -0
- package/src/build-config.ts +87 -0
- package/src/build.ts +276 -0
- package/src/common.ts +195 -0
- package/src/config.ts +89 -0
- package/src/dev.ts +164 -0
- package/src/generate.ts +200 -0
- package/src/icons.ts +116 -0
- package/src/init.ts +190 -0
- package/src/package.ts +150 -0
- package/src/zapp-cli.ts +263 -0
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
//> macos: framework: WebKit
|
|
2
|
+
//> macos: framework: Cocoa
|
|
3
|
+
//> macos: framework: Security
|
|
4
|
+
//> macos: link: -lcompression
|
|
5
|
+
|
|
6
|
+
import "./window.zc";
|
|
7
|
+
import "./webview_bootstrap.zc";
|
|
8
|
+
|
|
9
|
+
include <stdlib.h>
|
|
10
|
+
include <string.h>
|
|
11
|
+
include <stdbool.h>
|
|
12
|
+
|
|
13
|
+
raw {
|
|
14
|
+
#ifdef __APPLE__
|
|
15
|
+
#include <Cocoa/Cocoa.h>
|
|
16
|
+
#include <WebKit/WebKit.h>
|
|
17
|
+
#include <dispatch/dispatch.h>
|
|
18
|
+
#include <compression.h>
|
|
19
|
+
#ifndef ZAPP_EMBEDDED_ASSET_STRUCT_DEFINED
|
|
20
|
+
#define ZAPP_EMBEDDED_ASSET_STRUCT_DEFINED 1
|
|
21
|
+
struct ZappEmbeddedAsset {
|
|
22
|
+
char* path;
|
|
23
|
+
uint8_t* data;
|
|
24
|
+
int len;
|
|
25
|
+
bool is_brotli;
|
|
26
|
+
int uncompressed_len;
|
|
27
|
+
};
|
|
28
|
+
#endif
|
|
29
|
+
extern struct ZappEmbeddedAsset zapp_embedded_assets[];
|
|
30
|
+
extern int zapp_embedded_assets_count;
|
|
31
|
+
|
|
32
|
+
extern void* app_get_active(void);
|
|
33
|
+
extern char* app_get_bootstrap_name(void);
|
|
34
|
+
extern bool app_get_bootstrap_application_should_terminate_after_last_window_closed(void);
|
|
35
|
+
extern bool app_get_bootstrap_web_content_inspectable(void);
|
|
36
|
+
extern int app_get_bootstrap_max_workers(void);
|
|
37
|
+
extern void zapp_handle_message(void* app_ptr, char* msg_c);
|
|
38
|
+
extern const char* zapp_darwin_webview_bootstrap_script(void);
|
|
39
|
+
extern char* service_get_bindings_manifest_json(void);
|
|
40
|
+
extern const char* zapp_build_asset_root(void);
|
|
41
|
+
extern const char* zapp_build_initial_url(void);
|
|
42
|
+
extern int zapp_build_is_dev_mode(void);
|
|
43
|
+
extern int zapp_build_use_embedded_assets(void);
|
|
44
|
+
|
|
45
|
+
static NSString* zapp_escape_js_string(const char* raw) {
|
|
46
|
+
if (!raw) return @"";
|
|
47
|
+
NSString* s = [NSString stringWithUTF8String:raw];
|
|
48
|
+
s = [s stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
|
|
49
|
+
s = [s stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
|
|
50
|
+
s = [s stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
|
|
51
|
+
s = [s stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
|
|
52
|
+
return s;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static NSString* zapp_mime_for_path(NSString* path) {
|
|
56
|
+
NSString* lower = [path lowercaseString];
|
|
57
|
+
if ([lower hasSuffix:@".html"]) return @"text/html; charset=utf-8";
|
|
58
|
+
if ([lower hasSuffix:@".js"] || [lower hasSuffix:@".mjs"]) return @"application/javascript; charset=utf-8";
|
|
59
|
+
if ([lower hasSuffix:@".css"]) return @"text/css; charset=utf-8";
|
|
60
|
+
if ([lower hasSuffix:@".json"]) return @"application/json; charset=utf-8";
|
|
61
|
+
if ([lower hasSuffix:@".svg"]) return @"image/svg+xml";
|
|
62
|
+
if ([lower hasSuffix:@".png"]) return @"image/png";
|
|
63
|
+
if ([lower hasSuffix:@".jpg"] || [lower hasSuffix:@".jpeg"]) return @"image/jpeg";
|
|
64
|
+
if ([lower hasSuffix:@".woff2"]) return @"font/woff2";
|
|
65
|
+
if ([lower hasSuffix:@".map"]) return @"application/json; charset=utf-8";
|
|
66
|
+
return @"application/octet-stream";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static NSString* zapp_asset_root_path(void) {
|
|
70
|
+
const char* configuredRoot = zapp_build_asset_root();
|
|
71
|
+
if (configuredRoot && configuredRoot[0] != '\0') {
|
|
72
|
+
return [NSString stringWithUTF8String:configuredRoot];
|
|
73
|
+
}
|
|
74
|
+
return [[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:@"example/frontend/dist"];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static NSMutableDictionary<NSString*, NSMutableDictionary*>* zapp_sync_waits = nil;
|
|
78
|
+
static NSMutableDictionary<NSString*, NSMutableArray<NSString*>*>* zapp_sync_queues = nil;
|
|
79
|
+
extern void zapp_darwin_worker_dispatch_sync_result(const char* worker_id, const char* payload_json);
|
|
80
|
+
|
|
81
|
+
static void zapp_sync_ensure_state(void) {
|
|
82
|
+
if (zapp_sync_waits == nil) {
|
|
83
|
+
zapp_sync_waits = [NSMutableDictionary dictionary];
|
|
84
|
+
}
|
|
85
|
+
if (zapp_sync_queues == nil) {
|
|
86
|
+
zapp_sync_queues = [NSMutableDictionary dictionary];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static void zapp_sync_remove_wait_from_queue(NSString* key, NSString* requestId) {
|
|
91
|
+
if (key == nil || requestId == nil) return;
|
|
92
|
+
NSMutableArray<NSString*>* queue = [zapp_sync_queues objectForKey:key];
|
|
93
|
+
if (queue == nil) return;
|
|
94
|
+
[queue removeObject:requestId];
|
|
95
|
+
if ([queue count] == 0) {
|
|
96
|
+
[zapp_sync_queues removeObjectForKey:key];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static void zapp_dispatch_sync_result_to_webviews(const char* payload_json) {
|
|
101
|
+
NSString* payload = zapp_escape_js_string(payload_json);
|
|
102
|
+
NSString* js = [NSString stringWithFormat:
|
|
103
|
+
@"(function(){const b=globalThis[Symbol.for('zapp.bridge')];if(b&&typeof b.dispatchSyncResult==='function'){b.dispatchSyncResult('%@');}})();",
|
|
104
|
+
payload
|
|
105
|
+
];
|
|
106
|
+
for (NSWindow* window in [NSApp windows]) {
|
|
107
|
+
NSView* content = [window contentView];
|
|
108
|
+
if ([content isKindOfClass:[WKWebView class]]) {
|
|
109
|
+
WKWebView* webview = (WKWebView*)content;
|
|
110
|
+
[webview evaluateJavaScript:js completionHandler:nil];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static void zapp_sync_dispatch_result(NSString* requestId, BOOL ok, NSString* status, NSString* targetWorkerId) {
|
|
116
|
+
if (requestId == nil || [requestId length] == 0) return;
|
|
117
|
+
NSString* safeStatus = ([status isKindOfClass:[NSString class]] && [status length] > 0) ? status : @"notified";
|
|
118
|
+
NSString* payload = [NSString stringWithFormat:
|
|
119
|
+
@"{\"id\":\"%@\",\"ok\":%@,\"status\":\"%@\"}",
|
|
120
|
+
requestId,
|
|
121
|
+
ok ? @"true" : @"false",
|
|
122
|
+
safeStatus
|
|
123
|
+
];
|
|
124
|
+
if ([targetWorkerId isKindOfClass:[NSString class]] && [targetWorkerId length] > 0) {
|
|
125
|
+
zapp_darwin_worker_dispatch_sync_result([targetWorkerId UTF8String], [payload UTF8String]);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
zapp_dispatch_sync_result_to_webviews([payload UTF8String]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static NSURL* zapp_initial_url(void) {
|
|
132
|
+
const char* configuredUrl = zapp_build_initial_url();
|
|
133
|
+
if (configuredUrl && configuredUrl[0] != '\0') {
|
|
134
|
+
return [NSURL URLWithString:[NSString stringWithUTF8String:configuredUrl]];
|
|
135
|
+
}
|
|
136
|
+
return [NSURL URLWithString:@"zapp://index.html"];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@interface ZappAssetSchemeHandler : NSObject <WKURLSchemeHandler>
|
|
140
|
+
@end
|
|
141
|
+
|
|
142
|
+
@implementation ZappAssetSchemeHandler
|
|
143
|
+
- (void)webView:(WKWebView*)webView startURLSchemeTask:(id<WKURLSchemeTask>)task {
|
|
144
|
+
(void)webView;
|
|
145
|
+
NSURL* url = [task request].URL;
|
|
146
|
+
NSString* host = url.host ?: @"";
|
|
147
|
+
NSString* path = url.path ?: @"/";
|
|
148
|
+
NSString* assetRoot = zapp_asset_root_path();
|
|
149
|
+
|
|
150
|
+
// Map custom scheme URLs to dist files:
|
|
151
|
+
// - zapp://index.html -> index.html
|
|
152
|
+
// - zapp://index.html/assets/a.css -> assets/a.css
|
|
153
|
+
// - zapp://app/index.html -> index.html
|
|
154
|
+
// - zapp://app/assets/a.css -> assets/a.css
|
|
155
|
+
NSString* rel = path;
|
|
156
|
+
if ((rel.length == 0 || [rel isEqualToString:@"/"]) && host.length > 0) {
|
|
157
|
+
rel = [@"/" stringByAppendingString:host];
|
|
158
|
+
} else if (host.length > 0 && ![host isEqualToString:@"app"]) {
|
|
159
|
+
// Some URLs encode the html file in host and real path in pathname.
|
|
160
|
+
// For asset paths, ignore host and keep only pathname.
|
|
161
|
+
if ([path hasPrefix:@"/assets/"]) {
|
|
162
|
+
rel = path;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if ([rel isEqualToString:@"/"] || rel.length == 0) {
|
|
166
|
+
rel = @"/index.html";
|
|
167
|
+
}
|
|
168
|
+
while ([rel hasPrefix:@"/"]) rel = [rel substringFromIndex:1];
|
|
169
|
+
|
|
170
|
+
NSString* lookupPath = [@"/" stringByAppendingString:rel];
|
|
171
|
+
if (zapp_build_use_embedded_assets() != 0 && zapp_embedded_assets_count > 0) {
|
|
172
|
+
bool foundEmbedded = false;
|
|
173
|
+
for (int i = 0; i < zapp_embedded_assets_count; i++) {
|
|
174
|
+
NSString* assetPath = [NSString stringWithUTF8String:zapp_embedded_assets[i].path];
|
|
175
|
+
if ([assetPath isEqualToString:lookupPath]) {
|
|
176
|
+
NSData* data = nil;
|
|
177
|
+
if (zapp_embedded_assets[i].is_brotli) {
|
|
178
|
+
uint8_t* out_buf = malloc(zapp_embedded_assets[i].uncompressed_len);
|
|
179
|
+
size_t decoded_size = compression_decode_buffer(out_buf, zapp_embedded_assets[i].uncompressed_len,
|
|
180
|
+
zapp_embedded_assets[i].data, zapp_embedded_assets[i].len,
|
|
181
|
+
NULL, COMPRESSION_BROTLI);
|
|
182
|
+
if (decoded_size > 0) {
|
|
183
|
+
data = [NSData dataWithBytesNoCopy:out_buf length:decoded_size freeWhenDone:YES];
|
|
184
|
+
} else {
|
|
185
|
+
free(out_buf);
|
|
186
|
+
data = [NSData data];
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
data = [NSData dataWithBytesNoCopy:(void*)zapp_embedded_assets[i].data length:zapp_embedded_assets[i].len freeWhenDone:NO];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
NSMutableDictionary* headers = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
193
|
+
@"Content-Type": zapp_mime_for_path(lookupPath),
|
|
194
|
+
@"Cross-Origin-Opener-Policy": @"same-origin",
|
|
195
|
+
@"Cross-Origin-Embedder-Policy": @"require-corp",
|
|
196
|
+
@"Cross-Origin-Resource-Policy": @"same-origin",
|
|
197
|
+
@"Cache-Control": @"no-cache"
|
|
198
|
+
}];
|
|
199
|
+
|
|
200
|
+
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
|
|
201
|
+
initWithURL:url
|
|
202
|
+
statusCode:200
|
|
203
|
+
HTTPVersion:@"HTTP/1.1"
|
|
204
|
+
headerFields:headers];
|
|
205
|
+
[task didReceiveResponse:response];
|
|
206
|
+
[task didReceiveData:data];
|
|
207
|
+
[task didFinish];
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
BOOL isAssetRequest = [rel hasPrefix:@"assets/"] || [rel hasPrefix:@"zapp-workers/"];
|
|
212
|
+
if (!isAssetRequest && !foundEmbedded) {
|
|
213
|
+
for (int i = 0; i < zapp_embedded_assets_count; i++) {
|
|
214
|
+
NSString* assetPath = [NSString stringWithUTF8String:zapp_embedded_assets[i].path];
|
|
215
|
+
if ([assetPath isEqualToString:@"/index.html"]) {
|
|
216
|
+
NSData* data = nil;
|
|
217
|
+
if (zapp_embedded_assets[i].is_brotli) {
|
|
218
|
+
uint8_t* out_buf = malloc(zapp_embedded_assets[i].uncompressed_len);
|
|
219
|
+
size_t decoded_size = compression_decode_buffer(out_buf, zapp_embedded_assets[i].uncompressed_len,
|
|
220
|
+
zapp_embedded_assets[i].data, zapp_embedded_assets[i].len,
|
|
221
|
+
NULL, COMPRESSION_BROTLI);
|
|
222
|
+
if (decoded_size > 0) {
|
|
223
|
+
data = [NSData dataWithBytesNoCopy:out_buf length:decoded_size freeWhenDone:YES];
|
|
224
|
+
} else {
|
|
225
|
+
free(out_buf);
|
|
226
|
+
data = [NSData data];
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
data = [NSData dataWithBytesNoCopy:(void*)zapp_embedded_assets[i].data length:zapp_embedded_assets[i].len freeWhenDone:NO];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
NSMutableDictionary* headers = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
233
|
+
@"Content-Type": zapp_mime_for_path(@"/index.html"),
|
|
234
|
+
@"Cross-Origin-Opener-Policy": @"same-origin",
|
|
235
|
+
@"Cross-Origin-Embedder-Policy": @"require-corp",
|
|
236
|
+
@"Cross-Origin-Resource-Policy": @"same-origin",
|
|
237
|
+
@"Cache-Control": @"no-cache"
|
|
238
|
+
}];
|
|
239
|
+
|
|
240
|
+
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
|
|
241
|
+
initWithURL:url
|
|
242
|
+
statusCode:200
|
|
243
|
+
HTTPVersion:@"HTTP/1.1"
|
|
244
|
+
headerFields:headers];
|
|
245
|
+
[task didReceiveResponse:response];
|
|
246
|
+
[task didReceiveData:data];
|
|
247
|
+
[task didFinish];
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
NSString* full = [assetRoot stringByAppendingPathComponent:rel];
|
|
255
|
+
if ([[NSFileManager defaultManager] fileExistsAtPath:full] == NO) {
|
|
256
|
+
BOOL isAssetRequest = [rel hasPrefix:@"assets/"] || [rel hasPrefix:@"zapp-workers/"];
|
|
257
|
+
if (!isAssetRequest) {
|
|
258
|
+
NSString* fallback = [assetRoot stringByAppendingPathComponent:@"index.html"];
|
|
259
|
+
if ([[NSFileManager defaultManager] fileExistsAtPath:fallback]) {
|
|
260
|
+
full = fallback;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if ([[NSFileManager defaultManager] fileExistsAtPath:full] == NO) {
|
|
264
|
+
NSData* empty = [NSData data];
|
|
265
|
+
NSHTTPURLResponse* notFound = [[NSHTTPURLResponse alloc]
|
|
266
|
+
initWithURL:url
|
|
267
|
+
statusCode:404
|
|
268
|
+
HTTPVersion:@"HTTP/1.1"
|
|
269
|
+
headerFields:@{ @"Content-Type": @"text/plain; charset=utf-8" }];
|
|
270
|
+
[task didReceiveResponse:notFound];
|
|
271
|
+
[task didReceiveData:empty];
|
|
272
|
+
[task didFinish];
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
NSData* data = [NSData dataWithContentsOfFile:full];
|
|
278
|
+
if (!data) data = [NSData data];
|
|
279
|
+
NSDictionary* headers = @{
|
|
280
|
+
@"Content-Type": zapp_mime_for_path(full),
|
|
281
|
+
@"Cross-Origin-Opener-Policy": @"same-origin",
|
|
282
|
+
@"Cross-Origin-Embedder-Policy": @"require-corp",
|
|
283
|
+
@"Cross-Origin-Resource-Policy": @"same-origin",
|
|
284
|
+
@"Cache-Control": @"no-cache"
|
|
285
|
+
};
|
|
286
|
+
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
|
|
287
|
+
initWithURL:url
|
|
288
|
+
statusCode:200
|
|
289
|
+
HTTPVersion:@"HTTP/1.1"
|
|
290
|
+
headerFields:headers];
|
|
291
|
+
[task didReceiveResponse:response];
|
|
292
|
+
[task didReceiveData:data];
|
|
293
|
+
[task didFinish];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
- (void)webView:(WKWebView*)webView stopURLSchemeTask:(id<WKURLSchemeTask>)task {
|
|
297
|
+
(void)webView;
|
|
298
|
+
(void)task;
|
|
299
|
+
}
|
|
300
|
+
@end
|
|
301
|
+
|
|
302
|
+
@interface ZappMsgHandler : NSObject <WKScriptMessageHandler>
|
|
303
|
+
@end
|
|
304
|
+
|
|
305
|
+
@implementation ZappMsgHandler
|
|
306
|
+
- (void)userContentController:(WKUserContentController*)ucc didReceiveScriptMessage:(WKScriptMessage*)msg {
|
|
307
|
+
(void)ucc;
|
|
308
|
+
id body = [msg body];
|
|
309
|
+
if (![body isKindOfClass:[NSString class]]) return;
|
|
310
|
+
const char* raw_msg = [(NSString*)body UTF8String];
|
|
311
|
+
if (!raw_msg) return;
|
|
312
|
+
char* msg_copy = strdup(raw_msg);
|
|
313
|
+
if (!msg_copy) return;
|
|
314
|
+
void* app_ptr = app_get_active();
|
|
315
|
+
if (app_ptr != NULL) {
|
|
316
|
+
zapp_handle_message(app_ptr, msg_copy);
|
|
317
|
+
}
|
|
318
|
+
free(msg_copy);
|
|
319
|
+
}
|
|
320
|
+
@end
|
|
321
|
+
|
|
322
|
+
void zapp_dispatch_invoke_result(char* request_id, char* payload_json) {
|
|
323
|
+
(void)request_id;
|
|
324
|
+
NSString* payload = zapp_escape_js_string(payload_json);
|
|
325
|
+
NSString* js = [NSString stringWithFormat:
|
|
326
|
+
@"(function(){const b=globalThis[Symbol.for('zapp.bridge')];if(b&&typeof b.dispatchInvokeResult==='function'){b.dispatchInvokeResult('%@');}})();",
|
|
327
|
+
payload];
|
|
328
|
+
for (NSWindow* window in [NSApp windows]) {
|
|
329
|
+
NSView* content = [window contentView];
|
|
330
|
+
if ([content isKindOfClass:[WKWebView class]]) {
|
|
331
|
+
WKWebView* webview = (WKWebView*)content;
|
|
332
|
+
[webview evaluateJavaScript:js completionHandler:nil];
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
void platform_sync_handle_bridge(char* action, char* payload_json) {
|
|
338
|
+
if (action == NULL || payload_json == NULL) return;
|
|
339
|
+
NSString* actionStr = [NSString stringWithUTF8String:action];
|
|
340
|
+
NSString* payload = [NSString stringWithUTF8String:payload_json];
|
|
341
|
+
if (![actionStr isKindOfClass:[NSString class]] || ![payload isKindOfClass:[NSString class]]) return;
|
|
342
|
+
|
|
343
|
+
NSData* payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
|
|
344
|
+
if (payloadData == nil) return;
|
|
345
|
+
id rawObj = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:nil];
|
|
346
|
+
if (![rawObj isKindOfClass:[NSDictionary class]]) return;
|
|
347
|
+
NSDictionary* body = (NSDictionary*)rawObj;
|
|
348
|
+
|
|
349
|
+
zapp_sync_ensure_state();
|
|
350
|
+
|
|
351
|
+
if ([actionStr isEqualToString:@"wait"]) {
|
|
352
|
+
NSString* requestId = [body objectForKey:@"id"];
|
|
353
|
+
NSString* key = [body objectForKey:@"key"];
|
|
354
|
+
NSNumber* timeoutNumber = [body objectForKey:@"timeoutMs"];
|
|
355
|
+
NSString* targetWorkerId = [body objectForKey:@"targetWorkerId"];
|
|
356
|
+
if (![requestId isKindOfClass:[NSString class]] || [requestId length] == 0) return;
|
|
357
|
+
if (![key isKindOfClass:[NSString class]] || [key length] == 0) return;
|
|
358
|
+
if ([zapp_sync_waits objectForKey:requestId] != nil) return;
|
|
359
|
+
|
|
360
|
+
NSInteger timeoutMs = 30000;
|
|
361
|
+
if ([timeoutNumber respondsToSelector:@selector(integerValue)]) {
|
|
362
|
+
timeoutMs = [timeoutNumber integerValue];
|
|
363
|
+
}
|
|
364
|
+
if (timeoutMs < 1) timeoutMs = 1;
|
|
365
|
+
if (timeoutMs > 300000) timeoutMs = 300000;
|
|
366
|
+
|
|
367
|
+
NSMutableDictionary* waitObj = [NSMutableDictionary dictionary];
|
|
368
|
+
[waitObj setObject:key forKey:@"key"];
|
|
369
|
+
if ([targetWorkerId isKindOfClass:[NSString class]] && [targetWorkerId length] > 0) {
|
|
370
|
+
[waitObj setObject:targetWorkerId forKey:@"targetWorkerId"];
|
|
371
|
+
}
|
|
372
|
+
[zapp_sync_waits setObject:waitObj forKey:requestId];
|
|
373
|
+
|
|
374
|
+
NSMutableArray<NSString*>* queue = [zapp_sync_queues objectForKey:key];
|
|
375
|
+
if (queue == nil) {
|
|
376
|
+
queue = [NSMutableArray array];
|
|
377
|
+
[zapp_sync_queues setObject:queue forKey:key];
|
|
378
|
+
}
|
|
379
|
+
[queue addObject:requestId];
|
|
380
|
+
|
|
381
|
+
if ([timeoutNumber respondsToSelector:@selector(integerValue)]) {
|
|
382
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeoutMs * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
|
383
|
+
NSDictionary* existing = [zapp_sync_waits objectForKey:requestId];
|
|
384
|
+
if (existing == nil) return;
|
|
385
|
+
NSString* existingKey = [existing objectForKey:@"key"];
|
|
386
|
+
NSString* existingTargetWorkerId = [existing objectForKey:@"targetWorkerId"];
|
|
387
|
+
[zapp_sync_waits removeObjectForKey:requestId];
|
|
388
|
+
zapp_sync_remove_wait_from_queue(existingKey, requestId);
|
|
389
|
+
zapp_sync_dispatch_result(requestId, YES, @"timed-out", existingTargetWorkerId);
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if ([actionStr isEqualToString:@"notify"]) {
|
|
396
|
+
NSString* key = [body objectForKey:@"key"];
|
|
397
|
+
NSNumber* countNumber = [body objectForKey:@"count"];
|
|
398
|
+
if (![key isKindOfClass:[NSString class]] || [key length] == 0) return;
|
|
399
|
+
NSInteger count = 1;
|
|
400
|
+
if ([countNumber respondsToSelector:@selector(integerValue)]) {
|
|
401
|
+
count = [countNumber integerValue];
|
|
402
|
+
}
|
|
403
|
+
if (count < 1) count = 1;
|
|
404
|
+
if (count > 65535) count = 65535;
|
|
405
|
+
|
|
406
|
+
NSMutableArray<NSString*>* queue = [zapp_sync_queues objectForKey:key];
|
|
407
|
+
if (queue == nil || [queue count] == 0) return;
|
|
408
|
+
|
|
409
|
+
NSInteger delivered = 0;
|
|
410
|
+
while (delivered < count && [queue count] > 0) {
|
|
411
|
+
NSString* requestId = queue[0];
|
|
412
|
+
[queue removeObjectAtIndex:0];
|
|
413
|
+
NSDictionary* existing = [zapp_sync_waits objectForKey:requestId];
|
|
414
|
+
if (existing == nil) continue;
|
|
415
|
+
NSString* existingTargetWorkerId = [existing objectForKey:@"targetWorkerId"];
|
|
416
|
+
[zapp_sync_waits removeObjectForKey:requestId];
|
|
417
|
+
zapp_sync_dispatch_result(requestId, YES, @"notified", existingTargetWorkerId);
|
|
418
|
+
delivered += 1;
|
|
419
|
+
}
|
|
420
|
+
if ([queue count] == 0) {
|
|
421
|
+
[zapp_sync_queues removeObjectForKey:key];
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if ([actionStr isEqualToString:@"cancel"]) {
|
|
427
|
+
NSString* requestId = [body objectForKey:@"id"];
|
|
428
|
+
if (![requestId isKindOfClass:[NSString class]] || [requestId length] == 0) return;
|
|
429
|
+
NSDictionary* existing = [zapp_sync_waits objectForKey:requestId];
|
|
430
|
+
if (existing == nil) return;
|
|
431
|
+
NSString* existingKey = [existing objectForKey:@"key"];
|
|
432
|
+
NSString* existingTargetWorkerId = [existing objectForKey:@"targetWorkerId"];
|
|
433
|
+
[zapp_sync_waits removeObjectForKey:requestId];
|
|
434
|
+
zapp_sync_remove_wait_from_queue(existingKey, requestId);
|
|
435
|
+
zapp_sync_dispatch_result(requestId, YES, @"cancelled", existingTargetWorkerId);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Custom WKWebView subclass for drag region support
|
|
440
|
+
@interface ZappWebView : WKWebView
|
|
441
|
+
@property (nonatomic, assign) BOOL inDragRegion;
|
|
442
|
+
@end
|
|
443
|
+
|
|
444
|
+
@implementation ZappWebView
|
|
445
|
+
- (instancetype)initWithFrame:(NSRect)frame configuration:(WKWebViewConfiguration*)config {
|
|
446
|
+
self = [super initWithFrame:frame configuration:config];
|
|
447
|
+
if (self) { _inDragRegion = NO; }
|
|
448
|
+
return self;
|
|
449
|
+
}
|
|
450
|
+
- (void)mouseDown:(NSEvent*)event {
|
|
451
|
+
if (self.inDragRegion) {
|
|
452
|
+
[self.window performWindowDragWithEvent:event];
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
[super mouseDown:event];
|
|
456
|
+
}
|
|
457
|
+
// Allow the window to be moved when clicking drag regions
|
|
458
|
+
- (BOOL)mouseDownCanMoveWindow {
|
|
459
|
+
return self.inDragRegion;
|
|
460
|
+
}
|
|
461
|
+
@end
|
|
462
|
+
|
|
463
|
+
void zapp_darwin_webview_create(void* window_ptr, bool inspectable) {
|
|
464
|
+
NSWindow* window = (__bridge NSWindow*)window_ptr;
|
|
465
|
+
NSView* hostView = [window contentView];
|
|
466
|
+
NSRect bounds = [hostView bounds];
|
|
467
|
+
WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init];
|
|
468
|
+
ZappAssetSchemeHandler* schemeHandler = [[ZappAssetSchemeHandler alloc] init];
|
|
469
|
+
[config setURLSchemeHandler:schemeHandler forURLScheme:@"zapp"];
|
|
470
|
+
WKUserContentController* ucc = [[WKUserContentController alloc] init];
|
|
471
|
+
NSString* ownerId = [NSString stringWithFormat:@"owner-%p", window];
|
|
472
|
+
NSString* windowId = [NSString stringWithFormat:@"win-%p", window];
|
|
473
|
+
const char* bindingsRaw = service_get_bindings_manifest_json();
|
|
474
|
+
NSString* bindingsJson = zapp_escape_js_string(bindingsRaw);
|
|
475
|
+
|
|
476
|
+
const char* bootstrapName = app_get_bootstrap_name();
|
|
477
|
+
NSString* appName = bootstrapName != NULL
|
|
478
|
+
? [NSString stringWithUTF8String:bootstrapName]
|
|
479
|
+
: @"Zapp App";
|
|
480
|
+
BOOL applicationShouldTerminateAfterLastWindowClosed =
|
|
481
|
+
app_get_bootstrap_application_should_terminate_after_last_window_closed() ? YES : NO;
|
|
482
|
+
BOOL webContentInspectable =
|
|
483
|
+
app_get_bootstrap_web_content_inspectable() ? YES : NO;
|
|
484
|
+
int maxWorkers = app_get_bootstrap_max_workers();
|
|
485
|
+
appName = [appName stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
|
|
486
|
+
appName = [appName stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];
|
|
487
|
+
NSString* appConfigScript = [NSString stringWithFormat:
|
|
488
|
+
@"(function(){globalThis[Symbol.for('zapp.bootstrapConfig')]={name:'%@',applicationShouldTerminateAfterLastWindowClosed:%@,webContentInspectable:%@,maxWorkers:%d};})();",
|
|
489
|
+
appName,
|
|
490
|
+
applicationShouldTerminateAfterLastWindowClosed ? @"true" : @"false",
|
|
491
|
+
webContentInspectable ? @"true" : @"false",
|
|
492
|
+
maxWorkers
|
|
493
|
+
];
|
|
494
|
+
WKUserScript* appConfigUserScript = [[WKUserScript alloc]
|
|
495
|
+
initWithSource:appConfigScript
|
|
496
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
|
|
497
|
+
forMainFrameOnly:NO];
|
|
498
|
+
[ucc addUserScript:appConfigUserScript];
|
|
499
|
+
|
|
500
|
+
NSString* bindingsScript = [NSString stringWithFormat:
|
|
501
|
+
@"(function(){globalThis[Symbol.for('zapp.bindingsManifest')]='%@';})();",
|
|
502
|
+
bindingsJson
|
|
503
|
+
];
|
|
504
|
+
WKUserScript* bindingsUserScript = [[WKUserScript alloc]
|
|
505
|
+
initWithSource:bindingsScript
|
|
506
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
|
|
507
|
+
forMainFrameOnly:NO];
|
|
508
|
+
[ucc addUserScript:bindingsUserScript];
|
|
509
|
+
|
|
510
|
+
NSString* ownerScript = [NSString stringWithFormat:
|
|
511
|
+
@"(function(){globalThis[Symbol.for('zapp.ownerId')]='%@';})();",
|
|
512
|
+
ownerId
|
|
513
|
+
];
|
|
514
|
+
WKUserScript* ownerUserScript = [[WKUserScript alloc]
|
|
515
|
+
initWithSource:ownerScript
|
|
516
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
|
|
517
|
+
forMainFrameOnly:NO];
|
|
518
|
+
[ucc addUserScript:ownerUserScript];
|
|
519
|
+
|
|
520
|
+
NSString* windowIdScript = [NSString stringWithFormat:
|
|
521
|
+
@"(function(){globalThis[Symbol.for('zapp.windowId')]='%@';})();",
|
|
522
|
+
windowId
|
|
523
|
+
];
|
|
524
|
+
WKUserScript* windowIdUserScript = [[WKUserScript alloc]
|
|
525
|
+
initWithSource:windowIdScript
|
|
526
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
|
|
527
|
+
forMainFrameOnly:NO];
|
|
528
|
+
[ucc addUserScript:windowIdUserScript];
|
|
529
|
+
|
|
530
|
+
NSString* bootstrap = [NSString stringWithUTF8String:zapp_darwin_webview_bootstrap_script()];
|
|
531
|
+
WKUserScript* userScript = [[WKUserScript alloc]
|
|
532
|
+
initWithSource:bootstrap
|
|
533
|
+
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
|
|
534
|
+
forMainFrameOnly:NO];
|
|
535
|
+
[ucc addUserScript:userScript];
|
|
536
|
+
|
|
537
|
+
ZappMsgHandler* handler = [[ZappMsgHandler alloc] init];
|
|
538
|
+
[ucc addScriptMessageHandler:handler name:@"zapp"];
|
|
539
|
+
[config setUserContentController:ucc];
|
|
540
|
+
[[config preferences] setValue:@YES forKey:@"developerExtrasEnabled"];
|
|
541
|
+
ZappWebView* webview = [[ZappWebView alloc] initWithFrame:bounds configuration:config];
|
|
542
|
+
[webview setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
|
|
543
|
+
[webview setInspectable:inspectable ? YES : NO];
|
|
544
|
+
NSURL* url = zapp_initial_url();
|
|
545
|
+
[webview loadRequest:[NSURLRequest requestWithURL:url]];
|
|
546
|
+
|
|
547
|
+
[window setContentView:webview];
|
|
548
|
+
}
|
|
549
|
+
#endif
|
|
550
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// AUTO-GENERATED FILE. DO NOT EDIT.
|
|
2
|
+
// Source of truth: `packages/bootstrap/src/webview.ts`
|
|
3
|
+
// Generated: `2026-03-22T07:58:05.467Z`
|
|
4
|
+
|
|
5
|
+
raw {
|
|
6
|
+
const char* zapp_darwin_webview_bootstrap_script(void) {
|
|
7
|
+
return "(()=>{var{defineProperty:_,getOwnPropertyNames:o,getOwnPropertyDescriptor:s}=Object,d=Object.prototype.hasOwnProperty;var S=new WeakMap,n=(H)=>{var Q=S.get(H),$;if(Q)return Q;if(Q=_({},\"__esModule\",{value:!0}),H&&typeof H===\"object\"||typeof H===\"function\")o(H).map((K)=>!d.call(Q,K)&&_(Q,K,{get:()=>H[K],enumerable:!($=s(H,K))||$.enumerable}));return S.set(H,Q),Q};var GH={},L=globalThis,h=L.__zapp,W=h&&typeof h===\"object\"?h:{},v=()=>{if(L.__zapp===W)return;L.__zapp=W;try{Object.defineProperty(L,\"__zapp\",{value:W,enumerable:!0,configurable:!1,writable:!1})}catch{}},k=Symbol.for(\"zapp.bridge\"),M=Symbol.for(\"zapp.bootstrapConfig\"),w=Symbol.for(\"zapp.ownerId\"),x=L,B=(H)=>{let Q=x[k]?\?{},$=Object.assign({},Q,H);Object.defineProperty(x,k,{value:$,enumerable:!1,configurable:!0,writable:!1})},X={},Y={},O=0;B({_listeners:Y,_lastId:O});var D=X.__ctxId?\?=`ctx-${Date.now()}-${Math.random().toString(36).slice(2)}`,R=X.__pendingInvokes=X.__pendingInvokes?\?{},C=X.__pendingSyncWaits=X.__pendingSyncWaits?\?{},I=X.__invokeSeq?\?0,m=1,a=131072,y=x[M]==null?null:{name:x[M].name,applicationShouldTerminateAfterLastWindowClosed:x[M].applicationShouldTerminateAfterLastWindowClosed,webContentInspectable:x[M].webContentInspectable,maxWorkers:x[M].maxWorkers};try{delete x[M]}catch{}var u=(H)=>typeof H===\"string\"?H:JSON.stringify(H?\?{}),A=(H,Q,$)=>{v();let K=L.webkit?.messageHandlers?.zapp;if(!K?.postMessage)return!1;return K.postMessage(`${H}\n${Q}\n${u($)}`),!0};X.invoke=(H,Q)=>new Promise(($,K)=>{let J=typeof H===\"string\"?H.trim():\"\";if(!J){K(Error(\"Service method must be a non-empty string.\"));return}if(u(Q).length>a){K(Error(\"Service payload exceeds max size.\"));return}let G=`${D}:inv-${++I}`;X.__invokeSeq=I;let f={v:m,id:G,method:J,args:Q,meta:{sourceCtxId:D}},F=setTimeout(()=>{delete R[G],K(Error(\"Service invocation timed out.\"))},15000);if(R[G]={resolve:$,reject:K,timeout:F},!A(\"invoke_rpc\",J,f))clearTimeout(F),delete R[G],K(Error(\"Native invoke transport unavailable.\"))});var b=()=>{let H=Error(\"Sync wait aborted.\");return H.name=\"AbortError\",H};X.syncWait=(H,Q=30000,$)=>new Promise((K,J)=>{let V=typeof H===\"string\"?H.trim():\"\";if(!V){J(Error(\"Sync key must be a non-empty string.\"));return}if($?.aborted){J(b());return}let G=`${D}:sync-${Date.now()}-${Math.random().toString(36).slice(2)}`,f=Q==null||Number.isNaN(Number(Q))?null:Math.floor(Number(Q)),F=f==null?null:Math.max(1,Math.min(300000,f)),z={id:G,key:V,timeoutMs:F,meta:{sourceCtxId:D}},Z=F==null?void 0:setTimeout(()=>{delete C[G],J(Error(\"Sync wait transport timed out.\"))},F+5000);if(C[G]={resolve:K,reject:J,timeout:Z},!A(\"sync\",\"wait\",z)){if(Z)clearTimeout(Z);delete C[G],J(Error(\"Native sync transport unavailable.\"));return}if($){let N=()=>{let T=C[G];if(!T)return;if(T.timeout)clearTimeout(T.timeout);delete C[G],A(\"sync\",\"cancel\",{id:G,meta:{sourceCtxId:D}}),J(b())};$.addEventListener(\"abort\",N,{once:!0})}});X.syncNotify=(H,Q=1)=>{let $=typeof H===\"string\"?H.trim():\"\";if(!$)return!1;let K=Math.max(1,Math.min(65535,Math.floor(Q)));return A(\"sync\",\"notify\",{key:$,count:K,meta:{sourceCtxId:D}})};X.syncCancel=(H)=>{let Q=typeof H===\"string\"?H.trim():\"\";if(!Q)return!1;return A(\"sync\",\"cancel\",{id:Q,meta:{sourceCtxId:D}})};X.emit=(H,Q)=>A(\"emit\",H,{__zapp_internal_meta:{sourceCtxId:D},data:Q});X.onEvent=(H,Q)=>{let $=++O;return(Y[H]?\?=[]).push({id:$,fn:Q}),$};X.offEvent=(H,Q)=>{let $=Y[H]?\?[];Y[H]=$.filter((K)=>K.id!==Q)};X.onceEvent=(H,Q)=>{let $=++O;return(Y[H]?\?=[]).push({id:$,fn:Q,once:!0}),$};X.offAllEvents=(H)=>{if(H)delete Y[H];else Object.keys(Y).forEach((Q)=>delete Y[Q])};var t=(H)=>{let Q=H.pathname.split(\".\").pop()?.toLowerCase();if(Q!==\"ts\"&&Q!==\"tsx\")return H.toString();let $=(Z)=>{let U=Z.startsWith(\"/\")?Z:`/${Z}`;if(H.protocol===\"zapp:\")return`zapp://app${U}`;return new URL(U,H).toString()},K=x[Symbol.for(\"zapp.workerManifest\")],J=H.pathname.split(\"/\").pop()?\?\"worker.ts\",V=`./${J}`;if(K){let Z=K[V]?\?K[J];if(typeof Z===\"string\"&&Z.length>0)return $(Z)}let G=H.pathname.split(\"/\"),z=`/zapp-workers/${(G[G.length-1]?\?\"worker.ts\").replace(/\\.[^.]+$/,\"\")}.mjs`;return $(z)},r=(H)=>H instanceof URL?t(H):H;if(!X.workerBridge){let H={},Q=0,$=x[w],K=typeof $===\"string\"&&$.length>0?$:`owner-${Date.now()}-${Math.random().toString(36).slice(2)}`;try{delete x[w]}catch{}let J=[],V=(F)=>{return H[F]?\?={message:[],error:[],close:[]},H[F]},G=(F,z,Z)=>{let U=(E)=>{queueMicrotask(E)};if(F===\"close\"){let E=H[z];U(()=>{if(E)for(let i of E.close)try{i(Z)}catch{}X.workerBridge?.terminateWorker(z)});return}let N=H[z];if(!N)return;let T=Z;if(typeof Z===\"string\")try{T=JSON.parse(Z)}catch{}let j=F===\"error\"?N.error:N.message;U(()=>{for(let E of j)try{E(T)}catch{}})};X.__workerBridgeDispatch=G,B({dispatchWorkerBridge:G}),X.workerBridge={createWorker(F,z){let Z=Boolean(z?.shared),U=`${K}:${D}:zw-${++Q}`;return V(U),J.push(U),A(\"worker\",\"create\",{id:U,scriptUrl:F,ownerId:K,shared:Z}),U},postToWorker(F,z){A(\"worker\",\"post\",{id:F,data:z,ownerId:K})},terminateWorker(F){A(\"worker\",\"terminate\",{id:F,ownerId:K}),J=J.filter((z)=>z!==F),delete H[F]},subscribe(F,z,Z,U){let N=V(F);if(z)N.message.push(z);if(Z)N.error.push(Z);if(U)N.close.push(U);return()=>{let T=H[F];if(!T)return;if(z)T.message=T.message.filter((j)=>j!==z);if(Z)T.error=T.error.filter((j)=>j!==Z);if(U)T.close=T.close.filter((j)=>j!==U)}}};let f=()=>{if(!J.length)return;A(\"worker\",\"reset_owner\",{ownerId:K}),J=[];for(let F of Object.keys(H))delete H[F]};B({resetOwnerWorkers:f,createWorker:X.workerBridge.createWorker.bind(X.workerBridge),postToWorker:X.workerBridge.postToWorker.bind(X.workerBridge),terminateWorker:X.workerBridge.terminateWorker.bind(X.workerBridge),subscribeWorker:X.workerBridge.subscribe.bind(X.workerBridge),resolveWorkerScriptURL:r}),L.addEventListener(\"beforeunload\",f),L.addEventListener(\"pagehide\",f)}var q={},e=0,HH=(H)=>new Promise((Q,$)=>{let K=`${D}:win-${++e}`,J=setTimeout(()=>{delete q[K],$(Error(\"Window creation timed out.\"))},15000);q[K]={resolve:Q,reject:$,timeout:J},A(\"window\",\"create\",{requestId:K,options:H})}),QH=(H,Q,$)=>{A(\"window\",Q,{windowId:H,...$})},$H=(H,Q)=>{A(\"app\",H,Q?\?{})},KH=(H)=>{let Q=H;if(typeof H===\"string\")try{Q=JSON.parse(H)}catch{return}if(!Q||typeof Q!==\"object\")return;let $=Q;if(typeof $.requestId!==\"string\")return;let K=q[$.requestId];if(!K)return;if(clearTimeout(K.timeout),delete q[$.requestId],$.ok===!1)K.reject(Error($.error?\?\"Window creation failed.\"));else K.resolve({id:$.id?\?\"\"})},l=(H,Q,$)=>{v();let K={windowId:H,timestamp:Date.now()};if($)try{let V=JSON.parse($);if(V.width||V.height)K.size={width:V.width?\?0,height:V.height?\?0};if(V.x!==void 0||V.y!==void 0)K.position={x:V.x?\?0,y:V.y?\?0}}catch{}let J=(V)=>{let G=Y[V];if(!G||G.length===0)return;let f=[];for(let F of G){try{F.fn(K)}catch{}if(!F.once)f.push(F)}if(f.length>0)Y[V]=f;else delete Y[V]};J(`__zapp_window:${H}:${Q}`),J(`window:${Q}`)};B({windowCreate:HH,windowAction:QH,appAction:$H,dispatchWindowResult:KH,dispatchWindowEvent:l,_emit:X.emit,_onEvent:X.onEvent,_onceEvent:X.onceEvent,_offEvent:X.offEvent,_offAllEvents:X.offAllEvents});W.invoke=X.invoke;W.emit=X.emit;W.on=(H,Q)=>{let $=X.onEvent?.(H,Q)?\?0;return()=>X.offEvent?.(H,$)};var XH=(H,Q)=>{v();let $=Q;if(typeof Q===\"string\"){let V=Q.trim();if(V.startsWith(\"{\")&&V.endsWith(\"}\")||V.startsWith(\"[\")&&V.endsWith(\"]\"))try{$=JSON.parse(Q)}catch{}}if($&&typeof $===\"object\"){let V=$;if(V.__zapp_internal_meta?.sourceCtxId===D)return;if(Object.prototype.hasOwnProperty.call(V,\"data\"))$=V.data}let K=Y[H]?\?[],J=[];for(let V of K){try{V.fn($)}catch{}if(!V.once)J.push(V)}if(J.length>0)Y[H]=J;else delete Y[H]},JH=(H)=>{let Q=H;if(typeof H===\"string\")try{Q=JSON.parse(H)}catch{return}if(!Q||typeof Q!==\"object\")return;let $=Q;if(typeof $.id!==\"string\"||$.id.length===0)return;let K=R[$.id];if(!K)return;if(clearTimeout(K.timeout),delete R[$.id],$.ok){K.resolve($.result);return}let J=$.error?.code?\?\"INTERNAL_ERROR\",V=$.error?.message?\?\"Service invocation failed\";K.reject(Error(`${J}: ${V}`))},VH=(H)=>{let Q=H;if(typeof H===\"string\")try{Q=JSON.parse(H)}catch{return}if(!Q||typeof Q!==\"object\")return;let $=Q;if(typeof $.id!==\"string\"||$.id.length===0)return;let K=C[$.id];if(!K)return;if(K.timeout)clearTimeout(K.timeout);if(delete C[$.id],!$.ok){K.reject(Error(\"Sync wait failed.\"));return}if($.status===\"cancelled\"){K.reject(b());return}K.resolve($.status===\"timed-out\"?\"timed-out\":\"notified\")},FH=(H)=>{let Q=H;if(typeof H===\"string\")try{Q=JSON.parse(H)}catch{return}if(!Q||typeof Q!==\"object\")return;let $=Q;if(typeof $.requestId!==\"string\")return;let K=`__zapp:dialog:${$.requestId}`,J=Y[K];if(J){for(let V of J)try{V.fn($)}catch{}delete Y[K]}};B({dispatchInvokeResult:JH,dispatchSyncResult:VH,dispatchDialogResult:FH,deliverEvent:XH,getConfig:()=>y==null?null:{...y},invoke:async(H)=>{let Q=H;if(!Q||typeof Q!==\"object\")throw Error(\"Invalid invoke request\");if(typeof Q.method!==\"string\")throw Error(\"Invalid service method\");let $=await X.invoke?.(Q.method,Q.args);return{v:m,id:Q.id,ok:!0,result:$}},getServiceBindings:()=>{let H=x[Symbol.for(\"zapp.bindingsManifest\")];if(typeof H!==\"string\")return null;return H},syncWait:async(H)=>{let Q=H;return X.syncWait?.(Q?.key?\?\"\",Q?.timeoutMs===void 0?30000:Q.timeoutMs,Q?.signal)?\?Promise.reject(Error(\"Sync unavailable\"))},syncNotify:(H)=>{let Q=H;return X.syncNotify?.(Q?.key?\?\"\",Q?.count?\?1)?\?!1},syncCancel:(H)=>{let Q=H;return X.syncCancel?.(Q?.id?\?\"\")?\?!1}});Object.defineProperties(W,{invoke:{value:X.invoke,enumerable:!0,configurable:!1,writable:!1},syncWait:{value:X.syncWait,enumerable:!0,configurable:!1,writable:!1},syncNotify:{value:X.syncNotify,enumerable:!0,configurable:!1,writable:!1},syncCancel:{value:X.syncCancel,enumerable:!0,configurable:!1,writable:!1},emit:{value:X.emit,enumerable:!0,configurable:!1,writable:!1},on:{value:W.on,enumerable:!0,configurable:!1,writable:!1}});Object.freeze(W);if(typeof document<\"u\"){let H=()=>{if(!document.head)return;let Q=document.createElement(\"meta\");Q.httpEquiv=\"Content-Security-Policy\",Q.content=\"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; img-src 'self' data: blob:;\",document.head.insertBefore(Q,document.head.firstChild)};if(document.head)H();else document.addEventListener(\"DOMContentLoaded\",H,{once:!0})}v();var p=Symbol.for(\"zapp.windowId\"),c=Symbol.for(\"zapp.windowReady\"),P=L,g=()=>{if(P[c])return;P[c]=!0;let H=P[p],Q=L.webkit?.messageHandlers?.zapp;if(Q?.postMessage){let $=JSON.stringify({windowId:H?\?\"unknown\"});Q.postMessage(`window\nready\n${$}`)}l(H?\?\"unknown\",\"ready\")};if(typeof document<\"u\"){if(document.addEventListener(\"DOMContentLoaded\",g,{once:!0}),document.readyState!==\"loading\")g();let H=($)=>{let K=$;while(K){if(K.hasAttribute?.(\"data-zapp-drag-region\"))return!0;let J=K.tagName;if(J===\"BUTTON\"||J===\"INPUT\"||J===\"SELECT\"||J===\"TEXTAREA\"||J===\"A\")return!1;K=K.parentElement}return!1},Q=!1;document.addEventListener(\"mousemove\",($)=>{let K=H($.target);if(K!==Q)Q=K,A(\"window\",\"setDragRegion\",{windowId:P[p]?\?\"unknown\",drag:K})})}})();\n";
|
|
8
|
+
}
|
|
9
|
+
}
|