@zappdev/runtime 0.5.0-alpha.0 → 0.6.0-alpha.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/dock.ts +21 -0
- package/notification.ts +46 -0
- package/package.json +1 -1
- package/window.ts +7 -0
package/dock.ts
CHANGED
|
@@ -13,24 +13,39 @@
|
|
|
13
13
|
|
|
14
14
|
import { getBridge } from "./bridge";
|
|
15
15
|
|
|
16
|
+
// In worker contexts, __zappBridge.dock is a sync host dispatcher that
|
|
17
|
+
// calls darwin_dock_* directly. Webview fallback uses IPC-style post.
|
|
18
|
+
function dockHost(): ((action: string, args?: unknown) => void) | null {
|
|
19
|
+
const host = (globalThis as any).__zappBridge;
|
|
20
|
+
return host?.dock ?? null;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
export const Dock = {
|
|
17
24
|
/** Show the app icon in the dock/taskbar. */
|
|
18
25
|
showIcon(): void {
|
|
26
|
+
const host = dockHost();
|
|
27
|
+
if (host) { host("showIcon"); return; }
|
|
19
28
|
(getBridge() as any).post(JSON.stringify({ t: 4, m: "dock:showIcon", a: {} }));
|
|
20
29
|
},
|
|
21
30
|
|
|
22
31
|
/** Hide the app icon from the dock/taskbar. */
|
|
23
32
|
hideIcon(): void {
|
|
33
|
+
const host = dockHost();
|
|
34
|
+
if (host) { host("hideIcon"); return; }
|
|
24
35
|
(getBridge() as any).post(JSON.stringify({ t: 4, m: "dock:hideIcon", a: {} }));
|
|
25
36
|
},
|
|
26
37
|
|
|
27
38
|
/** Set a text badge on the dock icon (e.g. "5", "new"). */
|
|
28
39
|
setBadge(label: string): void {
|
|
40
|
+
const host = dockHost();
|
|
41
|
+
if (host) { host("setBadge", { label }); return; }
|
|
29
42
|
(getBridge() as any).post(JSON.stringify({ t: 4, m: "dock:setBadge", a: { label } }));
|
|
30
43
|
},
|
|
31
44
|
|
|
32
45
|
/** Remove the badge from the dock icon. */
|
|
33
46
|
removeBadge(): void {
|
|
47
|
+
const host = dockHost();
|
|
48
|
+
if (host) { host("removeBadge"); return; }
|
|
34
49
|
(getBridge() as any).post(JSON.stringify({ t: 4, m: "dock:removeBadge", a: {} }));
|
|
35
50
|
},
|
|
36
51
|
|
|
@@ -38,6 +53,8 @@ export const Dock = {
|
|
|
38
53
|
* @param type "informational" (bounces once) or "critical" (bounces until activated). Default: "informational"
|
|
39
54
|
*/
|
|
40
55
|
bounce(type: "informational" | "critical" = "informational"): void {
|
|
56
|
+
const host = dockHost();
|
|
57
|
+
if (host) { host("bounce", { type: type === "critical" ? 1 : 0 }); return; }
|
|
41
58
|
(getBridge() as any).post(JSON.stringify({
|
|
42
59
|
t: 4, m: "dock:bounce", a: { type: type === "critical" ? 1 : 0 },
|
|
43
60
|
}));
|
|
@@ -45,11 +62,15 @@ export const Dock = {
|
|
|
45
62
|
|
|
46
63
|
/** Set a custom dock icon from a file path. */
|
|
47
64
|
setIcon(path: string): void {
|
|
65
|
+
const host = dockHost();
|
|
66
|
+
if (host) { host("setIcon", { path }); return; }
|
|
48
67
|
(getBridge() as any).post(JSON.stringify({ t: 4, m: "dock:setIcon", a: { path } }));
|
|
49
68
|
},
|
|
50
69
|
|
|
51
70
|
/** Reset the dock icon to the app bundle default. */
|
|
52
71
|
resetIcon(): void {
|
|
72
|
+
const host = dockHost();
|
|
73
|
+
if (host) { host("resetIcon"); return; }
|
|
53
74
|
(getBridge() as any).post(JSON.stringify({ t: 4, m: "dock:resetIcon", a: {} }));
|
|
54
75
|
},
|
|
55
76
|
};
|
package/notification.ts
CHANGED
|
@@ -20,6 +20,16 @@
|
|
|
20
20
|
import { getBridge } from "./bridge";
|
|
21
21
|
import { Events } from "./events";
|
|
22
22
|
|
|
23
|
+
// In worker contexts, __zappBridge.notif is a dispatcher host object that
|
|
24
|
+
// routes directly to darwin_notification_* C functions. We prefer it when
|
|
25
|
+
// available to avoid the webview IPC roundtrip (bridge.invoke sends JSON
|
|
26
|
+
// over WKWebView's userContentController). The webview path is the
|
|
27
|
+
// fallback — it's the only option there.
|
|
28
|
+
function notifHost(): ((action: string, args?: unknown) => unknown) | null {
|
|
29
|
+
const host = (globalThis as any).__zappBridge;
|
|
30
|
+
return host?.notif ?? null;
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
export interface NotificationAction {
|
|
24
34
|
id: string;
|
|
25
35
|
title: string;
|
|
@@ -72,26 +82,52 @@ export type PermissionStatus = "granted" | "denied" | "not-determined" | "provis
|
|
|
72
82
|
|
|
73
83
|
export const Notification = {
|
|
74
84
|
async requestPermission(): Promise<PermissionStatus> {
|
|
85
|
+
const host = notifHost();
|
|
86
|
+
if (host) {
|
|
87
|
+
// In workers we can't easily wait on an async permission prompt — fall
|
|
88
|
+
// back to returning the current status. Users of headless workers
|
|
89
|
+
// typically request permission from a webview first anyway.
|
|
90
|
+
const r = host("getPermission") as { status: string };
|
|
91
|
+
return r.status as PermissionStatus;
|
|
92
|
+
}
|
|
75
93
|
const result = await getBridge().invoke("__notif:requestPermission") as { status: string };
|
|
76
94
|
return result.status as PermissionStatus;
|
|
77
95
|
},
|
|
78
96
|
|
|
79
97
|
async getPermissionStatus(): Promise<PermissionStatus> {
|
|
98
|
+
const host = notifHost();
|
|
99
|
+
if (host) {
|
|
100
|
+
const r = host("getPermission") as { status: string };
|
|
101
|
+
return r.status as PermissionStatus;
|
|
102
|
+
}
|
|
80
103
|
const result = await getBridge().invoke("__notif:getPermission") as { status: string };
|
|
81
104
|
return result.status as PermissionStatus;
|
|
82
105
|
},
|
|
83
106
|
|
|
84
107
|
async show(options: NotificationOptions): Promise<string> {
|
|
108
|
+
const host = notifHost();
|
|
109
|
+
if (host) {
|
|
110
|
+
const r = host("show", options) as { id: string };
|
|
111
|
+
return r.id;
|
|
112
|
+
}
|
|
85
113
|
const result = await getBridge().invoke("__notif:show", options as any) as { id: string };
|
|
86
114
|
return result.id;
|
|
87
115
|
},
|
|
88
116
|
|
|
89
117
|
async schedule(options: ScheduleOptions): Promise<string> {
|
|
118
|
+
const host = notifHost();
|
|
119
|
+
if (host) {
|
|
120
|
+
const delaySeconds = "seconds" in options.trigger ? options.trigger.seconds : 0;
|
|
121
|
+
const r = host("schedule", { ...options, delaySeconds }) as { id: string };
|
|
122
|
+
return r.id;
|
|
123
|
+
}
|
|
90
124
|
const result = await getBridge().invoke("__notif:schedule", options as any) as { id: string };
|
|
91
125
|
return result.id;
|
|
92
126
|
},
|
|
93
127
|
|
|
94
128
|
async registerCategory(category: NotificationCategory): Promise<void> {
|
|
129
|
+
// Worker path not wired — registerCategory needs typed-struct args that
|
|
130
|
+
// don't fit the simple dispatcher. Fall back to webview IPC.
|
|
95
131
|
await getBridge().invoke("__notif:registerCategory", category as any);
|
|
96
132
|
},
|
|
97
133
|
|
|
@@ -100,20 +136,28 @@ export const Notification = {
|
|
|
100
136
|
},
|
|
101
137
|
|
|
102
138
|
async cancel(id: string): Promise<void> {
|
|
139
|
+
const host = notifHost();
|
|
140
|
+
if (host) { host("cancel", { id }); return; }
|
|
103
141
|
await getBridge().invoke("__notif:cancel", { id } as any);
|
|
104
142
|
},
|
|
105
143
|
|
|
106
144
|
async cancelAll(): Promise<void> {
|
|
145
|
+
const host = notifHost();
|
|
146
|
+
if (host) { host("cancelAll"); return; }
|
|
107
147
|
await getBridge().invoke("__notif:cancelAll");
|
|
108
148
|
},
|
|
109
149
|
|
|
110
150
|
/** Remove a specific delivered notification from notification center. */
|
|
111
151
|
async removeDelivered(id: string): Promise<void> {
|
|
152
|
+
const host = notifHost();
|
|
153
|
+
if (host) { host("removeDelivered", { id }); return; }
|
|
112
154
|
await getBridge().invoke("__notif:removeDelivered", { id } as any);
|
|
113
155
|
},
|
|
114
156
|
|
|
115
157
|
/** Remove all delivered notifications from notification center. */
|
|
116
158
|
async removeAllDelivered(): Promise<void> {
|
|
159
|
+
const host = notifHost();
|
|
160
|
+
if (host) { host("removeAllDelivered"); return; }
|
|
117
161
|
await getBridge().invoke("__notif:removeAllDelivered");
|
|
118
162
|
},
|
|
119
163
|
|
|
@@ -122,6 +166,8 @@ export const Notification = {
|
|
|
122
166
|
* The notification must have been shown with an explicit `id`.
|
|
123
167
|
*/
|
|
124
168
|
async update(id: string, options: Partial<NotificationOptions>): Promise<void> {
|
|
169
|
+
const host = notifHost();
|
|
170
|
+
if (host) { host("update", { id, ...options }); return; }
|
|
125
171
|
await getBridge().invoke("__notif:update", { id, ...options } as any);
|
|
126
172
|
},
|
|
127
173
|
|
package/package.json
CHANGED
package/window.ts
CHANGED
|
@@ -112,6 +112,13 @@ export const Window = {
|
|
|
112
112
|
|
|
113
113
|
/** Create a new window. Returns a handle for the new window. */
|
|
114
114
|
async create(opts?: Partial<WindowOptions>): Promise<WindowHandle> {
|
|
115
|
+
// Worker context: call the createWindow host directly (sync C call).
|
|
116
|
+
const host = (globalThis as any).__zappBridge;
|
|
117
|
+
if (host?.createWindow) {
|
|
118
|
+
const r = host.createWindow(opts ?? {}) as { windowId: string };
|
|
119
|
+
return createWindowHandle(r.windowId);
|
|
120
|
+
}
|
|
121
|
+
// Webview context: async IPC roundtrip through the WKWebView bridge.
|
|
115
122
|
const result = await getBridge().invoke("__window:create", opts ?? {}) as { windowId: string };
|
|
116
123
|
return createWindowHandle(result.windowId);
|
|
117
124
|
},
|