@stacksjs/desktop 0.2.196 → 0.2.198
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/dist/browser.js +115 -3911
- package/dist/chunk-2mx7fq49.js +4 -0
- package/dist/chunk-ys4frvmj.js +3960 -0
- package/dist/index.js +247 -4040
- package/dist/test-utils.js +1 -3
- package/package.json +1 -1
- package/dist/browser.js.map +0 -64
- package/dist/index.js.map +0 -72
- package/dist/test-utils.js.map +0 -10
package/dist/index.js
CHANGED
|
@@ -1,332 +1,124 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
};
|
|
118
|
-
if (duration > 0) {
|
|
119
|
-
state.timeout = setTimeout(() => {
|
|
120
|
-
notification.close();
|
|
121
|
-
activeAlerts.delete(id);
|
|
122
|
-
}, duration);
|
|
123
|
-
}
|
|
124
|
-
return;
|
|
125
|
-
} catch {}
|
|
126
|
-
}
|
|
127
|
-
if (isBrowser()) {
|
|
128
|
-
try {
|
|
129
|
-
const container = getToastContainer(options.position);
|
|
130
|
-
const wrapper = document.createElement("div");
|
|
131
|
-
wrapper.innerHTML = createToastHTML(state);
|
|
132
|
-
const toast = wrapper.firstElementChild;
|
|
133
|
-
if (!toast) {
|
|
134
|
-
const typeLabel = (options.type || "info").toUpperCase();
|
|
135
|
-
console.log(`[stx-alert] ${typeLabel}: ${options.title || ""}`);
|
|
136
|
-
console.log(`[stx-alert] ${options.message}`);
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
state.element = toast;
|
|
140
|
-
try {
|
|
141
|
-
container.appendChild(toast);
|
|
142
|
-
} catch {
|
|
143
|
-
const typeLabel = (options.type || "info").toUpperCase();
|
|
144
|
-
console.log(`[stx-alert] ${typeLabel}: ${options.title || ""}`);
|
|
145
|
-
console.log(`[stx-alert] ${options.message}`);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (typeof requestAnimationFrame === "function") {
|
|
149
|
-
requestAnimationFrame(() => {
|
|
150
|
-
try {
|
|
151
|
-
toast.classList.add("visible");
|
|
152
|
-
} catch {}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
try {
|
|
156
|
-
toast.addEventListener("click", (e) => {
|
|
157
|
-
if (e.target.classList?.contains("stx-toast-close")) {
|
|
158
|
-
dismissAlert(state);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
if (options.onClick) {
|
|
162
|
-
options.onClick();
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
} catch {}
|
|
166
|
-
if (duration > 0) {
|
|
167
|
-
state.timeout = setTimeout(() => {
|
|
168
|
-
dismissAlert(state);
|
|
169
|
-
}, duration);
|
|
170
|
-
}
|
|
171
|
-
} catch {
|
|
172
|
-
const typeLabel = (options.type || "info").toUpperCase();
|
|
173
|
-
console.log(`[stx-alert] ${typeLabel}: ${options.title || ""}`);
|
|
174
|
-
console.log(`[stx-alert] ${options.message}`);
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
const typeLabel = (options.type || "info").toUpperCase();
|
|
178
|
-
console.log(`[stx-alert] ${typeLabel}: ${options.title || ""}`);
|
|
179
|
-
console.log(`[stx-alert] ${options.message}`);
|
|
180
|
-
if (duration > 0) {
|
|
181
|
-
state.timeout = setTimeout(() => {
|
|
182
|
-
activeAlerts.delete(id);
|
|
183
|
-
}, duration);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
async function showToast(options) {
|
|
188
|
-
return showAlert({
|
|
189
|
-
...options,
|
|
190
|
-
position: options.position || "top-right"
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
async function showInfoToast(message, duration = 3000) {
|
|
194
|
-
return showToast({ message, type: "info", duration });
|
|
195
|
-
}
|
|
196
|
-
async function showSuccessToast(message, duration = 3000) {
|
|
197
|
-
return showToast({ message, type: "success", duration });
|
|
198
|
-
}
|
|
199
|
-
async function showWarningToast(message, duration = 3000) {
|
|
200
|
-
return showToast({ message, type: "warning", duration });
|
|
201
|
-
}
|
|
202
|
-
async function showErrorToast(message, duration = 5000) {
|
|
203
|
-
return showToast({ message, type: "error", duration });
|
|
204
|
-
}
|
|
205
|
-
async function notify(title, message, type = "info") {
|
|
206
|
-
return showAlert({ title, message, type });
|
|
207
|
-
}
|
|
208
|
-
function dismissAlertById(id) {
|
|
209
|
-
const state = activeAlerts.get(id);
|
|
210
|
-
if (state) {
|
|
211
|
-
dismissAlert(state);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
function dismissAllAlerts() {
|
|
215
|
-
for (const state of activeAlerts.values()) {
|
|
216
|
-
dismissAlert(state);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
function getActiveAlertCount() {
|
|
220
|
-
return activeAlerts.size;
|
|
221
|
-
}
|
|
222
|
-
var TOAST_STYLES = `
|
|
223
|
-
.stx-toast-container {
|
|
224
|
-
position: fixed;
|
|
225
|
-
z-index: 10001;
|
|
226
|
-
display: flex;
|
|
227
|
-
flex-direction: column;
|
|
228
|
-
gap: 8px;
|
|
229
|
-
max-width: 400px;
|
|
230
|
-
pointer-events: none;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.stx-toast-container.top-left { top: 16px; left: 16px; }
|
|
234
|
-
.stx-toast-container.top-center { top: 16px; left: 50%; transform: translateX(-50%); }
|
|
235
|
-
.stx-toast-container.top-right { top: 16px; right: 16px; }
|
|
236
|
-
.stx-toast-container.bottom-left { bottom: 16px; left: 16px; }
|
|
237
|
-
.stx-toast-container.bottom-center { bottom: 16px; left: 50%; transform: translateX(-50%); }
|
|
238
|
-
.stx-toast-container.bottom-right { bottom: 16px; right: 16px; }
|
|
239
|
-
|
|
240
|
-
.stx-toast {
|
|
241
|
-
display: flex;
|
|
242
|
-
align-items: flex-start;
|
|
243
|
-
gap: 12px;
|
|
244
|
-
padding: 12px 16px;
|
|
245
|
-
background: #fff;
|
|
246
|
-
border-radius: 8px;
|
|
247
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
248
|
-
pointer-events: auto;
|
|
249
|
-
cursor: pointer;
|
|
250
|
-
opacity: 0;
|
|
251
|
-
transform: translateY(-10px);
|
|
252
|
-
transition: opacity 0.2s, transform 0.2s;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.stx-toast.visible {
|
|
256
|
-
opacity: 1;
|
|
257
|
-
transform: translateY(0);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
.stx-toast.dismissing {
|
|
261
|
-
opacity: 0;
|
|
262
|
-
transform: translateX(100%);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
@media (prefers-color-scheme: dark) {
|
|
266
|
-
.stx-toast {
|
|
267
|
-
background: #2d2d2d;
|
|
268
|
-
color: #fff;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
.stx-toast-icon {
|
|
273
|
-
font-size: 20px;
|
|
274
|
-
flex-shrink: 0;
|
|
275
|
-
margin-top: 2px;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
.stx-toast.info .stx-toast-icon { color: #3498db; }
|
|
279
|
-
.stx-toast.success .stx-toast-icon { color: #27ae60; }
|
|
280
|
-
.stx-toast.warning .stx-toast-icon { color: #f39c12; }
|
|
281
|
-
.stx-toast.error .stx-toast-icon { color: #e74c3c; }
|
|
282
|
-
|
|
283
|
-
.stx-toast-content {
|
|
284
|
-
flex: 1;
|
|
285
|
-
min-width: 0;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
.stx-toast-title {
|
|
289
|
-
font-weight: 600;
|
|
290
|
-
margin-bottom: 4px;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.stx-toast-message {
|
|
294
|
-
color: #666;
|
|
295
|
-
font-size: 14px;
|
|
296
|
-
line-height: 1.4;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
@media (prefers-color-scheme: dark) {
|
|
300
|
-
.stx-toast-message { color: #aaa; }
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
.stx-toast-close {
|
|
304
|
-
background: none;
|
|
305
|
-
border: none;
|
|
306
|
-
font-size: 20px;
|
|
307
|
-
cursor: pointer;
|
|
308
|
-
opacity: 0.5;
|
|
309
|
-
padding: 0;
|
|
310
|
-
line-height: 1;
|
|
311
|
-
color: inherit;
|
|
312
|
-
transition: opacity 0.15s;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
.stx-toast-close:hover {
|
|
316
|
-
opacity: 1;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/* Border accent for different types */
|
|
320
|
-
.stx-toast.info { border-left: 4px solid #3498db; }
|
|
321
|
-
.stx-toast.success { border-left: 4px solid #27ae60; }
|
|
322
|
-
.stx-toast.warning { border-left: 4px solid #f39c12; }
|
|
323
|
-
.stx-toast.error { border-left: 4px solid #e74c3c; }
|
|
324
|
-
`;
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_WATCH_INTERVAL_MS,
|
|
4
|
+
MAX_WATCH_INTERVAL_MS,
|
|
5
|
+
MIN_WATCH_INTERVAL_MS,
|
|
6
|
+
MODAL_STYLES,
|
|
7
|
+
TOAST_STYLES,
|
|
8
|
+
alert,
|
|
9
|
+
app,
|
|
10
|
+
appleScript,
|
|
11
|
+
audio,
|
|
12
|
+
battery,
|
|
13
|
+
biometric,
|
|
14
|
+
bluetooth,
|
|
15
|
+
bonjour,
|
|
16
|
+
caffeinate,
|
|
17
|
+
clipboard,
|
|
18
|
+
closeAllModals,
|
|
19
|
+
confirm,
|
|
20
|
+
continuityCamera,
|
|
21
|
+
coreml,
|
|
22
|
+
crashReporter,
|
|
23
|
+
createInterval,
|
|
24
|
+
createTimer,
|
|
25
|
+
decaffeinate,
|
|
26
|
+
deepLinks,
|
|
27
|
+
delay,
|
|
28
|
+
dismissAlertById,
|
|
29
|
+
dismissAllAlerts,
|
|
30
|
+
dragOut,
|
|
31
|
+
fileAssociations,
|
|
32
|
+
focus,
|
|
33
|
+
focusShortcutsReady,
|
|
34
|
+
formatCompact,
|
|
35
|
+
formatDuration,
|
|
36
|
+
formatRemainingTime,
|
|
37
|
+
formatShortcut,
|
|
38
|
+
formatTime,
|
|
39
|
+
fs,
|
|
40
|
+
getActiveAlertCount,
|
|
41
|
+
getActiveModalCount,
|
|
42
|
+
getCaffeinateStatus,
|
|
43
|
+
getCapabilities,
|
|
44
|
+
getCapability,
|
|
45
|
+
getDialogBridgeScript,
|
|
46
|
+
getRegisteredHotkeys,
|
|
47
|
+
globalShortcuts,
|
|
48
|
+
handoff,
|
|
49
|
+
hasBridge,
|
|
50
|
+
hasFocusShortcuts,
|
|
51
|
+
iap,
|
|
52
|
+
isAvailable,
|
|
53
|
+
isCaffeinated,
|
|
54
|
+
isDragOutAvailable,
|
|
55
|
+
keychain,
|
|
56
|
+
liveActivities,
|
|
57
|
+
localServer,
|
|
58
|
+
location,
|
|
59
|
+
log,
|
|
60
|
+
menu,
|
|
61
|
+
midi,
|
|
62
|
+
nativeAutoLaunch,
|
|
63
|
+
network,
|
|
64
|
+
notifications,
|
|
65
|
+
notify,
|
|
66
|
+
parseShortcut,
|
|
67
|
+
pdf,
|
|
68
|
+
permissions,
|
|
69
|
+
printing,
|
|
70
|
+
prompt,
|
|
71
|
+
redactPII,
|
|
72
|
+
registerHotkey,
|
|
73
|
+
requestNotificationPermission,
|
|
74
|
+
screen,
|
|
75
|
+
screenCapture,
|
|
76
|
+
screenSharing,
|
|
77
|
+
serial,
|
|
78
|
+
serviceMenu,
|
|
79
|
+
shell,
|
|
80
|
+
showAlert,
|
|
81
|
+
showAlertDialog,
|
|
82
|
+
showColorPicker,
|
|
83
|
+
showConfirmDialog,
|
|
84
|
+
showErrorDialog,
|
|
85
|
+
showErrorModal,
|
|
86
|
+
showErrorToast,
|
|
87
|
+
showInfoModal,
|
|
88
|
+
showInfoToast,
|
|
89
|
+
showMessageBox,
|
|
90
|
+
showModal,
|
|
91
|
+
showOpenDialog,
|
|
92
|
+
showQuestionModal,
|
|
93
|
+
showSaveDialog,
|
|
94
|
+
showSuccessModal,
|
|
95
|
+
showSuccessToast,
|
|
96
|
+
showToast,
|
|
97
|
+
showWarningDialog,
|
|
98
|
+
showWarningModal,
|
|
99
|
+
showWarningToast,
|
|
100
|
+
signPayload,
|
|
101
|
+
speech,
|
|
102
|
+
speechRecognition,
|
|
103
|
+
spotlight,
|
|
104
|
+
tags,
|
|
105
|
+
theme,
|
|
106
|
+
touchbar,
|
|
107
|
+
unregisterAllHotkeys,
|
|
108
|
+
unregisterHotkey,
|
|
109
|
+
updater,
|
|
110
|
+
vision,
|
|
111
|
+
watchScreenSharing,
|
|
112
|
+
windowEvents
|
|
113
|
+
} from "./chunk-ys4frvmj.js";
|
|
114
|
+
import {
|
|
115
|
+
__require
|
|
116
|
+
} from "./chunk-2mx7fq49.js";
|
|
325
117
|
// src/components.ts
|
|
326
118
|
function generateId(prefix = "stx") {
|
|
327
119
|
return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
328
120
|
}
|
|
329
|
-
function
|
|
121
|
+
function escapeHtml(str) {
|
|
330
122
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
331
123
|
}
|
|
332
124
|
function buildClasses(...classes) {
|
|
@@ -354,7 +146,7 @@ function createButton(props) {
|
|
|
354
146
|
const styleStr = buildStyles(style);
|
|
355
147
|
const iconHtml = icon ? `<span class="stx-button-icon">${icon}</span>` : "";
|
|
356
148
|
const loadingHtml = loading ? '<span class="stx-button-spinner"></span>' : "";
|
|
357
|
-
const content = iconPosition === "left" ? `${iconHtml}${loadingHtml}<span class="stx-button-text">${
|
|
149
|
+
const content = iconPosition === "left" ? `${iconHtml}${loadingHtml}<span class="stx-button-text">${escapeHtml(text)}</span>` : `<span class="stx-button-text">${escapeHtml(text)}</span>${iconHtml}${loadingHtml}`;
|
|
358
150
|
return `<button id="${id}" class="${classes}" ${disabled || loading ? "disabled" : ""} ${styleStr ? `style='${styleStr}'` : ""}>${content}</button>`;
|
|
359
151
|
}
|
|
360
152
|
function createTextInput(props) {
|
|
@@ -382,26 +174,26 @@ function createTextInput(props) {
|
|
|
382
174
|
`type="${type}"`,
|
|
383
175
|
`id="${id}"`,
|
|
384
176
|
`class="${classes}"`,
|
|
385
|
-
value && `value="${
|
|
386
|
-
placeholder && `placeholder="${
|
|
177
|
+
value && `value="${escapeHtml(value)}"`,
|
|
178
|
+
placeholder && `placeholder="${escapeHtml(placeholder)}"`,
|
|
387
179
|
disabled && "disabled",
|
|
388
180
|
readonly && "readonly",
|
|
389
181
|
required && "required",
|
|
390
182
|
maxLength && `maxlength="${maxLength}"`,
|
|
391
183
|
minLength && `minlength="${minLength}"`,
|
|
392
|
-
pattern && `pattern="${
|
|
184
|
+
pattern && `pattern="${escapeHtml(pattern)}"`,
|
|
393
185
|
autocomplete && `autocomplete="${autocomplete}"`,
|
|
394
186
|
styleStr && `style="${styleStr}"`
|
|
395
187
|
].filter(Boolean).join(" ");
|
|
396
188
|
let html = "";
|
|
397
189
|
if (label) {
|
|
398
|
-
html += `<label class="stx-input-label" for="${id}">${
|
|
190
|
+
html += `<label class="stx-input-label" for="${id}">${escapeHtml(label)}</label>`;
|
|
399
191
|
}
|
|
400
192
|
html += `<input ${attrs} />`;
|
|
401
193
|
if (error) {
|
|
402
|
-
html += `<div class="stx-input-error">${
|
|
194
|
+
html += `<div class="stx-input-error">${escapeHtml(error)}</div>`;
|
|
403
195
|
} else if (hint) {
|
|
404
|
-
html += `<div class="stx-input-hint">${
|
|
196
|
+
html += `<div class="stx-input-hint">${escapeHtml(hint)}</div>`;
|
|
405
197
|
}
|
|
406
198
|
return `<div class="stx-input-wrapper">${html}</div>`;
|
|
407
199
|
}
|
|
@@ -428,7 +220,7 @@ function createCheckbox(props) {
|
|
|
428
220
|
<label class="${classes}" ${styleStr ? `style="${styleStr}"` : ""}>
|
|
429
221
|
<input ${inputAttrs} />
|
|
430
222
|
<span class="stx-checkbox-box"></span>
|
|
431
|
-
${label ? `<span class="stx-checkbox-label">${
|
|
223
|
+
${label ? `<span class="stx-checkbox-label">${escapeHtml(label)}</span>` : ""}
|
|
432
224
|
</label>
|
|
433
225
|
`;
|
|
434
226
|
}
|
|
@@ -458,7 +250,7 @@ function createSlider(props) {
|
|
|
458
250
|
].filter(Boolean).join(" ");
|
|
459
251
|
let html = "";
|
|
460
252
|
if (label) {
|
|
461
|
-
html += `<label class="stx-slider-label" for="${id}">${
|
|
253
|
+
html += `<label class="stx-slider-label" for="${id}">${escapeHtml(label)}</label>`;
|
|
462
254
|
}
|
|
463
255
|
html += `<div class="stx-slider-track"><input ${inputAttrs} /></div>`;
|
|
464
256
|
if (showValue) {
|
|
@@ -499,7 +291,7 @@ function createBadge(props) {
|
|
|
499
291
|
} = props;
|
|
500
292
|
const classes = buildClasses("stx-badge", `stx-badge--${variant}`, `stx-badge--${size}`, className);
|
|
501
293
|
const styleStr = buildStyles(style);
|
|
502
|
-
return `<span id="${id}" class="${classes}" ${styleStr ? `style='${styleStr}'` : ""}>${
|
|
294
|
+
return `<span id="${id}" class="${classes}" ${styleStr ? `style='${styleStr}'` : ""}>${escapeHtml(text)}</span>`;
|
|
503
295
|
}
|
|
504
296
|
function createAvatar(props) {
|
|
505
297
|
const {
|
|
@@ -519,7 +311,7 @@ function createAvatar(props) {
|
|
|
519
311
|
const initials = name ? name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : "";
|
|
520
312
|
if (src) {
|
|
521
313
|
return `<div id="${id}" class="${classes}" ${combinedStyle ? `style="${combinedStyle}"` : ""}>
|
|
522
|
-
<img src="${
|
|
314
|
+
<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" class="stx-avatar-img" />
|
|
523
315
|
</div>`;
|
|
524
316
|
}
|
|
525
317
|
return `<div id="${id}" class="${classes}" ${combinedStyle ? `style="${combinedStyle}"` : ""}>
|
|
@@ -542,21 +334,21 @@ function createCard(props) {
|
|
|
542
334
|
const styleStr = buildStyles(style);
|
|
543
335
|
let html = "";
|
|
544
336
|
if (image) {
|
|
545
|
-
html += `<div class="stx-card-image"><img src="${
|
|
337
|
+
html += `<div class="stx-card-image"><img src="${escapeHtml(image)}" alt="" /></div>`;
|
|
546
338
|
}
|
|
547
339
|
html += '<div class="stx-card-body">';
|
|
548
340
|
if (title) {
|
|
549
|
-
html += `<h3 class="stx-card-title">${
|
|
341
|
+
html += `<h3 class="stx-card-title">${escapeHtml(title)}</h3>`;
|
|
550
342
|
}
|
|
551
343
|
if (subtitle) {
|
|
552
|
-
html += `<p class="stx-card-subtitle">${
|
|
344
|
+
html += `<p class="stx-card-subtitle">${escapeHtml(subtitle)}</p>`;
|
|
553
345
|
}
|
|
554
346
|
if (content) {
|
|
555
|
-
html += `<div class="stx-card-content">${
|
|
347
|
+
html += `<div class="stx-card-content">${escapeHtml(content)}</div>`;
|
|
556
348
|
}
|
|
557
349
|
html += "</div>";
|
|
558
350
|
if (footer) {
|
|
559
|
-
html += `<div class="stx-card-footer">${
|
|
351
|
+
html += `<div class="stx-card-footer">${escapeHtml(footer)}</div>`;
|
|
560
352
|
}
|
|
561
353
|
return `<div id="${id}" class="${classes}" ${styleStr ? `style='${styleStr}'` : ""}>${html}</div>`;
|
|
562
354
|
}
|
|
@@ -574,7 +366,7 @@ function createTabs(props) {
|
|
|
574
366
|
const tabsHtml = tabs.map((tab, index) => {
|
|
575
367
|
const isActive = activeTab ? tab.value === activeTab : index === 0;
|
|
576
368
|
const tabClasses = buildClasses("stx-tab", isActive && "stx-tab--active", tab.disabled && "stx-tab--disabled");
|
|
577
|
-
return `<button class="${tabClasses}" data-value="${
|
|
369
|
+
return `<button class="${tabClasses}" data-value="${escapeHtml(tab.value)}" ${tab.disabled ? "disabled" : ""} role="tab" aria-selected="${isActive}">${escapeHtml(tab.label)}</button>`;
|
|
578
370
|
}).join("");
|
|
579
371
|
return `<div id="${id}" class="${classes}" role="tablist" ${styleStr ? `style='${styleStr}'` : ""}>${tabsHtml}</div>`;
|
|
580
372
|
}
|
|
@@ -593,9 +385,9 @@ function createDropdown(props) {
|
|
|
593
385
|
const optionsHtml = options.map((opt) => {
|
|
594
386
|
const selected = opt.value === value ? "selected" : "";
|
|
595
387
|
const disabledAttr = opt.disabled ? "disabled" : "";
|
|
596
|
-
return `<option value="${
|
|
388
|
+
return `<option value="${escapeHtml(opt.value)}" ${selected} ${disabledAttr}>${escapeHtml(opt.label)}</option>`;
|
|
597
389
|
}).join("");
|
|
598
|
-
const placeholderOption = value ? "" : `<option value="" disabled selected>${
|
|
390
|
+
const placeholderOption = value ? "" : `<option value="" disabled selected>${escapeHtml(placeholder)}</option>`;
|
|
599
391
|
return `<select id="${id}" class="${classes}" ${disabled ? "disabled" : ""} ${styleStr ? `style='${styleStr}'` : ""}>${placeholderOption}${optionsHtml}</select>`;
|
|
600
392
|
}
|
|
601
393
|
function createRating(props) {
|
|
@@ -636,8 +428,8 @@ function createRadioButton(props) {
|
|
|
636
428
|
const inputAttrs = [
|
|
637
429
|
'type="radio"',
|
|
638
430
|
`id="${id}"`,
|
|
639
|
-
`name="${
|
|
640
|
-
`value="${
|
|
431
|
+
`name="${escapeHtml(name)}"`,
|
|
432
|
+
`value="${escapeHtml(value)}"`,
|
|
641
433
|
checked && "checked",
|
|
642
434
|
disabled && "disabled"
|
|
643
435
|
].filter(Boolean).join(" ");
|
|
@@ -645,7 +437,7 @@ function createRadioButton(props) {
|
|
|
645
437
|
<label class="${classes}" ${styleStr ? `style="${styleStr}"` : ""}>
|
|
646
438
|
<input ${inputAttrs} />
|
|
647
439
|
<span class="stx-radio-circle"></span>
|
|
648
|
-
${label ? `<span class="stx-radio-label">${
|
|
440
|
+
${label ? `<span class="stx-radio-label">${escapeHtml(label)}</span>` : ""}
|
|
649
441
|
</label>
|
|
650
442
|
`;
|
|
651
443
|
}
|
|
@@ -663,16 +455,16 @@ function createColorPicker(props) {
|
|
|
663
455
|
const styleStr = buildStyles(style);
|
|
664
456
|
let html = "";
|
|
665
457
|
if (label) {
|
|
666
|
-
html += `<label class="stx-color-picker-label" for="${id}">${
|
|
458
|
+
html += `<label class="stx-color-picker-label" for="${id}">${escapeHtml(label)}</label>`;
|
|
667
459
|
}
|
|
668
460
|
html += `<div class="stx-color-picker-input">
|
|
669
|
-
<input type="color" id="${id}" value="${
|
|
670
|
-
<span class="stx-color-picker-value">${
|
|
461
|
+
<input type="color" id="${id}" value="${escapeHtml(value)}" ${disabled ? "disabled" : ""} />
|
|
462
|
+
<span class="stx-color-picker-value">${escapeHtml(value)}</span>
|
|
671
463
|
</div>`;
|
|
672
464
|
if (presetColors.length > 0) {
|
|
673
465
|
html += '<div class="stx-color-picker-presets">';
|
|
674
466
|
for (const color of presetColors) {
|
|
675
|
-
html += `<button class="stx-color-preset" style="background: ${
|
|
467
|
+
html += `<button class="stx-color-preset" style="background: ${escapeHtml(color)}" data-color="${escapeHtml(color)}" ${disabled ? "disabled" : ""}></button>`;
|
|
676
468
|
}
|
|
677
469
|
html += "</div>";
|
|
678
470
|
}
|
|
@@ -703,11 +495,11 @@ function createDatePicker(props) {
|
|
|
703
495
|
minValue && `min="${minValue}"`,
|
|
704
496
|
maxValue && `max="${maxValue}"`,
|
|
705
497
|
disabled && "disabled",
|
|
706
|
-
`placeholder="${
|
|
498
|
+
`placeholder="${escapeHtml(placeholder)}"`
|
|
707
499
|
].filter(Boolean).join(" ");
|
|
708
500
|
let html = "";
|
|
709
501
|
if (label) {
|
|
710
|
-
html += `<label class="stx-date-picker-label" for="${id}">${
|
|
502
|
+
html += `<label class="stx-date-picker-label" for="${id}">${escapeHtml(label)}</label>`;
|
|
711
503
|
}
|
|
712
504
|
html += `<div class="stx-date-picker-input">
|
|
713
505
|
<input ${inputAttrs} />
|
|
@@ -732,15 +524,15 @@ function createTimePicker(props) {
|
|
|
732
524
|
const inputAttrs = [
|
|
733
525
|
'type="time"',
|
|
734
526
|
`id="${id}"`,
|
|
735
|
-
value && `value="${
|
|
527
|
+
value && `value="${escapeHtml(value)}"`,
|
|
736
528
|
`step="${step}"`,
|
|
737
|
-
min && `min="${
|
|
738
|
-
max && `max="${
|
|
529
|
+
min && `min="${escapeHtml(min)}"`,
|
|
530
|
+
max && `max="${escapeHtml(max)}"`,
|
|
739
531
|
disabled && "disabled"
|
|
740
532
|
].filter(Boolean).join(" ");
|
|
741
533
|
let html = "";
|
|
742
534
|
if (label) {
|
|
743
|
-
html += `<label class="stx-time-picker-label" for="${id}">${
|
|
535
|
+
html += `<label class="stx-time-picker-label" for="${id}">${escapeHtml(label)}</label>`;
|
|
744
536
|
}
|
|
745
537
|
html += `<input ${inputAttrs} class="stx-time-picker-input" />`;
|
|
746
538
|
return `<div class="${classes}" ${styleStr ? `style='${styleStr}'` : ""}>${html}</div>`;
|
|
@@ -763,15 +555,15 @@ function createAutocomplete(props) {
|
|
|
763
555
|
const displayValue = selectedOption ? selectedOption.label : value;
|
|
764
556
|
let html = "";
|
|
765
557
|
if (label) {
|
|
766
|
-
html += `<label class="stx-autocomplete-label" for="${id}">${
|
|
558
|
+
html += `<label class="stx-autocomplete-label" for="${id}">${escapeHtml(label)}</label>`;
|
|
767
559
|
}
|
|
768
560
|
html += `<div class="stx-autocomplete-input-wrapper">
|
|
769
|
-
<input type="text" id="${id}" value="${
|
|
561
|
+
<input type="text" id="${id}" value="${escapeHtml(displayValue)}" placeholder="${escapeHtml(placeholder)}" ${disabled ? "disabled" : ""} autocomplete="off" class="stx-autocomplete-input" />
|
|
770
562
|
${loading ? '<span class="stx-autocomplete-spinner"></span>' : ""}
|
|
771
563
|
</div>`;
|
|
772
564
|
html += '<ul class="stx-autocomplete-list">';
|
|
773
565
|
for (const opt of options) {
|
|
774
|
-
html += `<li class="stx-autocomplete-item ${opt.value === value ? "stx-autocomplete-item--selected" : ""}" data-value="${
|
|
566
|
+
html += `<li class="stx-autocomplete-item ${opt.value === value ? "stx-autocomplete-item--selected" : ""}" data-value="${escapeHtml(opt.value)}">${escapeHtml(opt.label)}</li>`;
|
|
775
567
|
}
|
|
776
568
|
html += "</ul>";
|
|
777
569
|
return `<div class="${classes}" ${styleStr ? `style='${styleStr}'` : ""}>${html}</div>`;
|
|
@@ -788,7 +580,7 @@ function createLabel(props) {
|
|
|
788
580
|
} = props;
|
|
789
581
|
const classes = buildClasses("stx-label", `stx-label--${size}`, className);
|
|
790
582
|
const styleStr = buildStyles(style);
|
|
791
|
-
return `<label id="${id}" class="${classes}" ${htmlFor ? `for='${
|
|
583
|
+
return `<label id="${id}" class="${classes}" ${htmlFor ? `for='${escapeHtml(htmlFor)}'` : ""} ${styleStr ? `style='${styleStr}'` : ""}>${escapeHtml(text)}${required ? '<span class="stx-label-required">*</span>' : ""}</label>`;
|
|
792
584
|
}
|
|
793
585
|
function createImageView(props) {
|
|
794
586
|
const {
|
|
@@ -810,8 +602,8 @@ function createImageView(props) {
|
|
|
810
602
|
if (height)
|
|
811
603
|
imageStyles.height = typeof height === "number" ? `${height}px` : height;
|
|
812
604
|
const combinedStyle = [buildStyles(imageStyles), buildStyles(style)].filter(Boolean).join("; ");
|
|
813
|
-
const fallbackAttr = fallback ? `onerror="this.src='${
|
|
814
|
-
return `<img id="${id}" class="${classes}" src="${
|
|
605
|
+
const fallbackAttr = fallback ? `onerror="this.src='${escapeHtml(fallback)}'"` : "";
|
|
606
|
+
return `<img id="${id}" class="${classes}" src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" loading="${loading}" ${combinedStyle ? `style='${combinedStyle}'` : ""} ${fallbackAttr} />`;
|
|
815
607
|
}
|
|
816
608
|
function createChip(props) {
|
|
817
609
|
const {
|
|
@@ -830,7 +622,7 @@ function createChip(props) {
|
|
|
830
622
|
if (icon) {
|
|
831
623
|
html += `<span class="stx-chip-icon">${icon}</span>`;
|
|
832
624
|
}
|
|
833
|
-
html += `<span class="stx-chip-text">${
|
|
625
|
+
html += `<span class="stx-chip-text">${escapeHtml(text)}</span>`;
|
|
834
626
|
if (removable) {
|
|
835
627
|
html += '<button class="stx-chip-remove" type="button">×</button>';
|
|
836
628
|
}
|
|
@@ -840,7 +632,7 @@ function createTooltip(props) {
|
|
|
840
632
|
const {
|
|
841
633
|
text,
|
|
842
634
|
position = "top",
|
|
843
|
-
delay = 200,
|
|
635
|
+
delay: delay2 = 200,
|
|
844
636
|
children,
|
|
845
637
|
id = generateId("tooltip"),
|
|
846
638
|
className,
|
|
@@ -848,9 +640,9 @@ function createTooltip(props) {
|
|
|
848
640
|
} = props;
|
|
849
641
|
const classes = buildClasses("stx-tooltip-wrapper", className);
|
|
850
642
|
const styleStr = buildStyles(style);
|
|
851
|
-
return `<div id="${id}" class="${classes}" ${styleStr ? `style="${styleStr}"` : ""} data-tooltip="${
|
|
643
|
+
return `<div id="${id}" class="${classes}" ${styleStr ? `style="${styleStr}"` : ""} data-tooltip="${escapeHtml(text)}" data-position="${position}" data-delay="${delay2}">
|
|
852
644
|
${children}
|
|
853
|
-
<span class="stx-tooltip stx-tooltip--${position}">${
|
|
645
|
+
<span class="stx-tooltip stx-tooltip--${position}">${escapeHtml(text)}</span>
|
|
854
646
|
</div>`;
|
|
855
647
|
}
|
|
856
648
|
function createScrollView(props) {
|
|
@@ -910,11 +702,11 @@ function createAccordion(props) {
|
|
|
910
702
|
const itemClasses = buildClasses("stx-accordion-item", isOpen && "stx-accordion-item--open", item.disabled && "stx-accordion-item--disabled");
|
|
911
703
|
html += `<div class="${itemClasses}" data-index="${index}">
|
|
912
704
|
<button class="stx-accordion-header" ${item.disabled ? "disabled" : ""} aria-expanded="${isOpen}" data-multiple="${multiple}">
|
|
913
|
-
<span class="stx-accordion-title">${
|
|
705
|
+
<span class="stx-accordion-title">${escapeHtml(item.title)}</span>
|
|
914
706
|
<span class="stx-accordion-icon">\u25BC</span>
|
|
915
707
|
</button>
|
|
916
708
|
<div class="stx-accordion-content" ${isOpen ? "" : "hidden"}>
|
|
917
|
-
${
|
|
709
|
+
${escapeHtml(item.content)}
|
|
918
710
|
</div>
|
|
919
711
|
</div>`;
|
|
920
712
|
});
|
|
@@ -939,8 +731,8 @@ function createStepper(props) {
|
|
|
939
731
|
${index < currentStep ? "\u2713" : index + 1}
|
|
940
732
|
</div>
|
|
941
733
|
<div class="stx-step-content">
|
|
942
|
-
<div class="stx-step-label">${
|
|
943
|
-
${step.description ? `<div class="stx-step-description">${
|
|
734
|
+
<div class="stx-step-label">${escapeHtml(step.label)}</div>
|
|
735
|
+
${step.description ? `<div class="stx-step-description">${escapeHtml(step.description)}</div>` : ""}
|
|
944
736
|
</div>
|
|
945
737
|
</div>`;
|
|
946
738
|
if (index < steps.length - 1) {
|
|
@@ -971,7 +763,7 @@ function createModalComponent(props) {
|
|
|
971
763
|
if (title || closable) {
|
|
972
764
|
html += '<div class="stx-modal-component-header">';
|
|
973
765
|
if (title) {
|
|
974
|
-
html += `<h3 class="stx-modal-component-title">${
|
|
766
|
+
html += `<h3 class="stx-modal-component-title">${escapeHtml(title)}</h3>`;
|
|
975
767
|
}
|
|
976
768
|
if (closable) {
|
|
977
769
|
html += '<button class="stx-modal-component-close">×</button>';
|
|
@@ -999,13 +791,13 @@ function createListView(props) {
|
|
|
999
791
|
const styleStr = buildStyles(style);
|
|
1000
792
|
if (items.length === 0) {
|
|
1001
793
|
return `<div id="${id}" class="${classes}" ${styleStr ? `style="${styleStr}"` : ""}>
|
|
1002
|
-
<div class="stx-list-view-empty">${
|
|
794
|
+
<div class="stx-list-view-empty">${escapeHtml(emptyMessage)}</div>
|
|
1003
795
|
</div>`;
|
|
1004
796
|
}
|
|
1005
797
|
let html = '<ul class="stx-list-view-items">';
|
|
1006
798
|
for (const item of items) {
|
|
1007
799
|
const itemClasses = buildClasses("stx-list-view-item", item.selected && "stx-list-view-item--selected");
|
|
1008
|
-
html += `<li class="${itemClasses}" data-id="${
|
|
800
|
+
html += `<li class="${itemClasses}" data-id="${escapeHtml(item.id)}" ${selectable ? 'tabindex="0"' : ""}>${item.content}</li>`;
|
|
1009
801
|
}
|
|
1010
802
|
html += "</ul>";
|
|
1011
803
|
return `<div id="${id}" class="${classes}" ${styleStr ? `style='${styleStr}'` : ""}>${html}</div>`;
|
|
@@ -1032,7 +824,7 @@ function createTable(props) {
|
|
|
1032
824
|
const sortClass = isSorted ? `stx-table-sorted stx-table-sorted--${sortOrder}` : "";
|
|
1033
825
|
const sortable = col.sortable ? 'data-sortable="true"' : "";
|
|
1034
826
|
const widthStyle = col.width ? `style="width: ${col.width}"` : "";
|
|
1035
|
-
html += `<th class="${sortClass}" ${sortable} ${widthStyle} data-key="${
|
|
827
|
+
html += `<th class="${sortClass}" ${sortable} ${widthStyle} data-key="${escapeHtml(col.key)}">${escapeHtml(col.label)}${col.sortable ? '<span class="stx-table-sort-icon"></span>' : ""}</th>`;
|
|
1036
828
|
}
|
|
1037
829
|
html += "</tr></thead>";
|
|
1038
830
|
html += "<tbody>";
|
|
@@ -1040,7 +832,7 @@ function createTable(props) {
|
|
|
1040
832
|
html += "<tr>";
|
|
1041
833
|
for (const col of columns) {
|
|
1042
834
|
const cellValue = row[col.key];
|
|
1043
|
-
html += `<td>${cellValue != null ?
|
|
835
|
+
html += `<td>${cellValue != null ? escapeHtml(String(cellValue)) : ""}</td>`;
|
|
1044
836
|
}
|
|
1045
837
|
html += "</tr>";
|
|
1046
838
|
}
|
|
@@ -1052,7 +844,7 @@ function renderTreeNode(node, expandedKeys, selectedKeys, checkable) {
|
|
|
1052
844
|
const isSelected = selectedKeys.includes(node.key);
|
|
1053
845
|
const hasChildren = node.children && node.children.length > 0;
|
|
1054
846
|
const nodeClasses = buildClasses("stx-tree-node", isSelected && "stx-tree-node--selected", node.disabled && "stx-tree-node--disabled");
|
|
1055
|
-
let html = `<div class="${nodeClasses}" data-key="${
|
|
847
|
+
let html = `<div class="${nodeClasses}" data-key="${escapeHtml(node.key)}">`;
|
|
1056
848
|
html += '<div class="stx-tree-node-content">';
|
|
1057
849
|
if (hasChildren) {
|
|
1058
850
|
html += `<span class="stx-tree-toggle ${isExpanded ? "stx-tree-toggle--expanded" : ""}">\u25B6</span>`;
|
|
@@ -1065,7 +857,7 @@ function renderTreeNode(node, expandedKeys, selectedKeys, checkable) {
|
|
|
1065
857
|
if (node.icon) {
|
|
1066
858
|
html += `<span class="stx-tree-icon">${node.icon}</span>`;
|
|
1067
859
|
}
|
|
1068
|
-
html += `<span class="stx-tree-label">${
|
|
860
|
+
html += `<span class="stx-tree-label">${escapeHtml(node.label)}</span>`;
|
|
1069
861
|
html += "</div>";
|
|
1070
862
|
if (hasChildren && isExpanded) {
|
|
1071
863
|
html += '<div class="stx-tree-children">';
|
|
@@ -1117,7 +909,7 @@ function createDataGrid(props) {
|
|
|
1117
909
|
const widthStyle = col.width ? `style="width: ${col.width}"` : "";
|
|
1118
910
|
html += `<th ${widthStyle}>
|
|
1119
911
|
<div class="stx-data-grid-header-cell">
|
|
1120
|
-
<span>${
|
|
912
|
+
<span>${escapeHtml(col.label)}</span>
|
|
1121
913
|
${col.sortable ? '<button class="stx-data-grid-sort">\u21C5</button>' : ""}
|
|
1122
914
|
${col.filterable ? '<button class="stx-data-grid-filter">\u22BB</button>' : ""}
|
|
1123
915
|
</div>
|
|
@@ -1132,7 +924,7 @@ function createDataGrid(props) {
|
|
|
1132
924
|
}
|
|
1133
925
|
for (const col of columns) {
|
|
1134
926
|
const cellValue = row[col.key];
|
|
1135
|
-
html += `<td>${cellValue != null ?
|
|
927
|
+
html += `<td>${cellValue != null ? escapeHtml(String(cellValue)) : ""}</td>`;
|
|
1136
928
|
}
|
|
1137
929
|
html += "</tr>";
|
|
1138
930
|
}
|
|
@@ -1167,9 +959,9 @@ function createChart(props) {
|
|
|
1167
959
|
};
|
|
1168
960
|
const combinedStyle = [buildStyles(chartStyles), buildStyles(style)].filter(Boolean).join("; ");
|
|
1169
961
|
const chartData = JSON.stringify({ type, data, options });
|
|
1170
|
-
return `<div id="${id}" class="${classes}" style="${combinedStyle}" data-chart='${
|
|
962
|
+
return `<div id="${id}" class="${classes}" style="${combinedStyle}" data-chart='${escapeHtml(chartData)}'>
|
|
1171
963
|
<div class="stx-chart-placeholder">
|
|
1172
|
-
${options.title ? `<div class="stx-chart-title">${
|
|
964
|
+
${options.title ? `<div class="stx-chart-title">${escapeHtml(options.title)}</div>` : ""}
|
|
1173
965
|
<div class="stx-chart-type">${type.charAt(0).toUpperCase() + type.slice(1)} Chart</div>
|
|
1174
966
|
<div class="stx-chart-info">${data.datasets.length} dataset(s), ${data.labels.length} labels</div>
|
|
1175
967
|
</div>
|
|
@@ -1179,7 +971,7 @@ function createCodeEditor(props) {
|
|
|
1179
971
|
const {
|
|
1180
972
|
value = "",
|
|
1181
973
|
language = "plaintext",
|
|
1182
|
-
theme = "dark",
|
|
974
|
+
theme: theme2 = "dark",
|
|
1183
975
|
lineNumbers = true,
|
|
1184
976
|
readOnly = false,
|
|
1185
977
|
height = 300,
|
|
@@ -1189,7 +981,7 @@ function createCodeEditor(props) {
|
|
|
1189
981
|
className,
|
|
1190
982
|
style
|
|
1191
983
|
} = props;
|
|
1192
|
-
const classes = buildClasses("stx-code-editor", `stx-code-editor--${
|
|
984
|
+
const classes = buildClasses("stx-code-editor", `stx-code-editor--${theme2}`, lineNumbers && "stx-code-editor--line-numbers", readOnly && "stx-code-editor--readonly", wordWrap && "stx-code-editor--wrap", className);
|
|
1193
985
|
const editorStyles = {
|
|
1194
986
|
height: typeof height === "number" ? `${height}px` : height
|
|
1195
987
|
};
|
|
@@ -1204,8 +996,8 @@ function createCodeEditor(props) {
|
|
|
1204
996
|
}
|
|
1205
997
|
codeHtml += "</div>";
|
|
1206
998
|
}
|
|
1207
|
-
codeHtml += `<pre class="stx-code-editor-content"><code class="language-${
|
|
1208
|
-
return `<div id="${id}" class="${classes}" style="${combinedStyle}" data-language="${
|
|
999
|
+
codeHtml += `<pre class="stx-code-editor-content"><code class="language-${escapeHtml(language)}">${escapeHtml(value)}</code></pre>`;
|
|
1000
|
+
return `<div id="${id}" class="${classes}" style="${combinedStyle}" data-language="${escapeHtml(language)}" data-tab-size="${tabSize}">${codeHtml}</div>`;
|
|
1209
1001
|
}
|
|
1210
1002
|
function createMediaPlayer(props) {
|
|
1211
1003
|
const {
|
|
@@ -1231,12 +1023,12 @@ function createMediaPlayer(props) {
|
|
|
1231
1023
|
const combinedStyle = [buildStyles(mediaStyles), buildStyles(style)].filter(Boolean).join("; ");
|
|
1232
1024
|
const mediaAttrs = [
|
|
1233
1025
|
`id="${id}-media"`,
|
|
1234
|
-
`src="${
|
|
1026
|
+
`src="${escapeHtml(src)}"`,
|
|
1235
1027
|
controls && "controls",
|
|
1236
1028
|
autoplay && "autoplay",
|
|
1237
1029
|
loop && "loop",
|
|
1238
1030
|
muted && "muted",
|
|
1239
|
-
type === "video" && poster && `poster="${
|
|
1031
|
+
type === "video" && poster && `poster="${escapeHtml(poster)}"`
|
|
1240
1032
|
].filter(Boolean).join(" ");
|
|
1241
1033
|
const mediaElement = type === "video" ? `<video ${mediaAttrs}>Your browser does not support the video tag.</video>` : `<audio ${mediaAttrs}>Your browser does not support the audio tag.</audio>`;
|
|
1242
1034
|
return `<div id="${id}" class="${classes}" ${combinedStyle ? `style='${combinedStyle}'` : ""}>${mediaElement}</div>`;
|
|
@@ -1273,8 +1065,8 @@ function createFileExplorer(props) {
|
|
|
1273
1065
|
const icon = file.icon || (file.type === "folder" ? "\uD83D\uDCC1" : "\uD83D\uDCC4");
|
|
1274
1066
|
const size = file.type === "file" ? formatFileSize(file.size) : "";
|
|
1275
1067
|
const modified = file.modified ? file.modified.toLocaleDateString() : "";
|
|
1276
|
-
html += `<tr class="stx-file-explorer-item ${selectable ? "stx-file-explorer-item--selectable" : ""}" data-path="${
|
|
1277
|
-
<td><span class="stx-file-explorer-icon">${icon}</span>${
|
|
1068
|
+
html += `<tr class="stx-file-explorer-item ${selectable ? "stx-file-explorer-item--selectable" : ""}" data-path="${escapeHtml(file.path)}" data-type="${file.type}">
|
|
1069
|
+
<td><span class="stx-file-explorer-icon">${icon}</span>${escapeHtml(file.name)}</td>
|
|
1278
1070
|
<td>${size}</td>
|
|
1279
1071
|
<td>${modified}</td>
|
|
1280
1072
|
</tr>`;
|
|
@@ -1284,9 +1076,9 @@ function createFileExplorer(props) {
|
|
|
1284
1076
|
html = '<div class="stx-file-explorer-grid">';
|
|
1285
1077
|
for (const file of filteredFiles) {
|
|
1286
1078
|
const icon = file.icon || (file.type === "folder" ? "\uD83D\uDCC1" : "\uD83D\uDCC4");
|
|
1287
|
-
html += `<div class="stx-file-explorer-item ${selectable ? "stx-file-explorer-item--selectable" : ""}" data-path="${
|
|
1079
|
+
html += `<div class="stx-file-explorer-item ${selectable ? "stx-file-explorer-item--selectable" : ""}" data-path="${escapeHtml(file.path)}" data-type="${file.type}">
|
|
1288
1080
|
<div class="stx-file-explorer-icon">${icon}</div>
|
|
1289
|
-
<div class="stx-file-explorer-name">${
|
|
1081
|
+
<div class="stx-file-explorer-name">${escapeHtml(file.name)}</div>
|
|
1290
1082
|
</div>`;
|
|
1291
1083
|
}
|
|
1292
1084
|
html += "</div>";
|
|
@@ -1318,7 +1110,7 @@ function createWebView(props) {
|
|
|
1318
1110
|
}
|
|
1319
1111
|
}
|
|
1320
1112
|
const sandboxAttr = sandbox ? `sandbox="${sandboxAttrs.join(" ")}"` : "";
|
|
1321
|
-
return `<iframe id="${id}" class="${classes}" src="${
|
|
1113
|
+
return `<iframe id="${id}" class="${classes}" src="${escapeHtml(url)}" style="${combinedStyle}" ${sandboxAttr} loading="lazy" frameborder="0"></iframe>`;
|
|
1322
1114
|
}
|
|
1323
1115
|
var AVAILABLE_COMPONENTS = [
|
|
1324
1116
|
"Button",
|
|
@@ -1715,385 +1507,26 @@ var COMPONENT_STYLES = `
|
|
|
1715
1507
|
.stx-chip--error { background: #3a1a1a; }
|
|
1716
1508
|
}
|
|
1717
1509
|
`;
|
|
1718
|
-
// src/
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
1724
|
-
}
|
|
1725
|
-
var activeModals = [];
|
|
1726
|
-
function generateModalId() {
|
|
1727
|
-
return `modal-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
1728
|
-
}
|
|
1729
|
-
function getModalIcon(type) {
|
|
1730
|
-
switch (type) {
|
|
1731
|
-
case "info":
|
|
1732
|
-
return "ℹ";
|
|
1733
|
-
case "warning":
|
|
1734
|
-
return "⚠";
|
|
1735
|
-
case "error":
|
|
1736
|
-
return "✖";
|
|
1737
|
-
case "success":
|
|
1738
|
-
return "✔";
|
|
1739
|
-
case "question":
|
|
1740
|
-
return "❓";
|
|
1741
|
-
default:
|
|
1742
|
-
return "ℹ";
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
function getDefaultButtons(type) {
|
|
1746
|
-
if (type === "question") {
|
|
1747
|
-
return [
|
|
1748
|
-
{ label: "No", style: "default" },
|
|
1749
|
-
{ label: "Yes", style: "primary" }
|
|
1750
|
-
];
|
|
1510
|
+
// src/system-tray.ts
|
|
1511
|
+
import process2 from "process";
|
|
1512
|
+
function getPlatform() {
|
|
1513
|
+
if (process2.platform) {
|
|
1514
|
+
return process2.platform;
|
|
1751
1515
|
}
|
|
1752
|
-
return
|
|
1753
|
-
}
|
|
1754
|
-
function createModalHTML(state) {
|
|
1755
|
-
const { options } = state;
|
|
1756
|
-
const icon = getModalIcon(options.type);
|
|
1757
|
-
const buttons = options.buttons || getDefaultButtons(options.type);
|
|
1758
|
-
const typeClass = options.type || "info";
|
|
1759
|
-
let buttonsHtml = "";
|
|
1760
|
-
buttons.forEach((btn, index) => {
|
|
1761
|
-
const styleClass = btn.style === "destructive" ? "destructive" : btn.style === "primary" ? "primary" : "default";
|
|
1762
|
-
const autoFocus = index === (options.defaultButton ?? buttons.length - 1) ? "autofocus" : "";
|
|
1763
|
-
buttonsHtml += `<button class="stx-modal-btn ${styleClass}" data-index="${index}" ${autoFocus}>${btn.label}</button>`;
|
|
1764
|
-
});
|
|
1765
|
-
return `
|
|
1766
|
-
<div class="stx-modal-overlay" data-modal-id="${state.id}">
|
|
1767
|
-
<div class="stx-modal ${typeClass}" role="dialog" aria-modal="true" aria-labelledby="${state.id}-title">
|
|
1768
|
-
<div class="stx-modal-icon">${icon}</div>
|
|
1769
|
-
<div class="stx-modal-content">
|
|
1770
|
-
${options.title ? `<h2 id="${state.id}-title" class="stx-modal-title">${escapeHtml3(options.title)}</h2>` : ""}
|
|
1771
|
-
<p class="stx-modal-message">${escapeHtml3(options.message)}</p>
|
|
1772
|
-
</div>
|
|
1773
|
-
<div class="stx-modal-buttons">${buttonsHtml}</div>
|
|
1774
|
-
</div>
|
|
1775
|
-
</div>
|
|
1776
|
-
`;
|
|
1777
|
-
}
|
|
1778
|
-
function escapeHtml3(str) {
|
|
1779
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1516
|
+
return "unknown";
|
|
1780
1517
|
}
|
|
1781
|
-
function
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
activeModals.splice(index, 1);
|
|
1785
|
-
}
|
|
1786
|
-
if (state.element && isBrowser2()) {
|
|
1787
|
-
state.element.remove();
|
|
1788
|
-
}
|
|
1789
|
-
const buttons = state.options.buttons || getDefaultButtons(state.options.type);
|
|
1790
|
-
const button = buttons[buttonIndex];
|
|
1791
|
-
if (button?.action) {
|
|
1792
|
-
button.action();
|
|
1518
|
+
function isInCraftWindow() {
|
|
1519
|
+
if (typeof window !== "undefined" && window.craft?.tray) {
|
|
1520
|
+
return true;
|
|
1793
1521
|
}
|
|
1794
|
-
|
|
1522
|
+
return false;
|
|
1795
1523
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
options,
|
|
1803
|
-
resolve
|
|
1804
|
-
};
|
|
1805
|
-
activeModals.push(state);
|
|
1806
|
-
if (hasNative) {
|
|
1807
|
-
console.log(`[stx-modal] Showing native modal: ${options.title || "Modal"}`);
|
|
1808
|
-
setTimeout(() => {
|
|
1809
|
-
closeModal(state, options.defaultButton ?? 0, false);
|
|
1810
|
-
}, 0);
|
|
1811
|
-
} else if (isBrowser2()) {
|
|
1812
|
-
try {
|
|
1813
|
-
const container = document.createElement("div");
|
|
1814
|
-
container.innerHTML = createModalHTML(state);
|
|
1815
|
-
const overlay = container.firstElementChild;
|
|
1816
|
-
if (!overlay) {
|
|
1817
|
-
console.log(`[stx-modal] ${options.type?.toUpperCase() || "INFO"}: ${options.title || "Modal"}`);
|
|
1818
|
-
console.log(`[stx-modal] ${options.message}`);
|
|
1819
|
-
setTimeout(() => {
|
|
1820
|
-
closeModal(state, options.defaultButton ?? 0, false);
|
|
1821
|
-
}, 0);
|
|
1822
|
-
return;
|
|
1823
|
-
}
|
|
1824
|
-
state.element = overlay;
|
|
1825
|
-
try {
|
|
1826
|
-
document.body.appendChild(overlay);
|
|
1827
|
-
} catch {
|
|
1828
|
-
console.log(`[stx-modal] ${options.type?.toUpperCase() || "INFO"}: ${options.title || "Modal"}`);
|
|
1829
|
-
console.log(`[stx-modal] ${options.message}`);
|
|
1830
|
-
setTimeout(() => {
|
|
1831
|
-
closeModal(state, options.defaultButton ?? 0, false);
|
|
1832
|
-
}, 0);
|
|
1833
|
-
return;
|
|
1834
|
-
}
|
|
1835
|
-
try {
|
|
1836
|
-
overlay.querySelectorAll(".stx-modal-btn").forEach((btn) => {
|
|
1837
|
-
btn.addEventListener("click", () => {
|
|
1838
|
-
const index = Number.parseInt(btn.dataset.index || "0", 10);
|
|
1839
|
-
closeModal(state, index, false);
|
|
1840
|
-
});
|
|
1841
|
-
});
|
|
1842
|
-
} catch {}
|
|
1843
|
-
try {
|
|
1844
|
-
overlay.addEventListener("click", (e) => {
|
|
1845
|
-
if (e.target === overlay) {
|
|
1846
|
-
const cancelIndex = options.cancelButton ?? 0;
|
|
1847
|
-
closeModal(state, cancelIndex, true);
|
|
1848
|
-
}
|
|
1849
|
-
});
|
|
1850
|
-
} catch {}
|
|
1851
|
-
try {
|
|
1852
|
-
const handleKeydown = (e) => {
|
|
1853
|
-
if (e.key === "Escape") {
|
|
1854
|
-
const cancelIndex = options.cancelButton ?? 0;
|
|
1855
|
-
closeModal(state, cancelIndex, true);
|
|
1856
|
-
document.removeEventListener("keydown", handleKeydown);
|
|
1857
|
-
} else if (e.key === "Enter") {
|
|
1858
|
-
const defaultIndex = options.defaultButton ?? (options.buttons || getDefaultButtons(options.type)).length - 1;
|
|
1859
|
-
closeModal(state, defaultIndex, false);
|
|
1860
|
-
document.removeEventListener("keydown", handleKeydown);
|
|
1861
|
-
}
|
|
1862
|
-
};
|
|
1863
|
-
document.addEventListener("keydown", handleKeydown);
|
|
1864
|
-
} catch {}
|
|
1865
|
-
try {
|
|
1866
|
-
const firstButton = overlay.querySelector(".stx-modal-btn[autofocus]");
|
|
1867
|
-
if (firstButton) {
|
|
1868
|
-
firstButton.focus();
|
|
1869
|
-
}
|
|
1870
|
-
} catch {}
|
|
1871
|
-
if (typeof process !== "undefined" && process.env.BUN_TEST) {
|
|
1872
|
-
setTimeout(() => {
|
|
1873
|
-
closeModal(state, options.defaultButton ?? 0, false);
|
|
1874
|
-
}, 0);
|
|
1875
|
-
}
|
|
1876
|
-
} catch {
|
|
1877
|
-
console.log(`[stx-modal] ${options.type?.toUpperCase() || "INFO"}: ${options.title || "Modal"}`);
|
|
1878
|
-
console.log(`[stx-modal] ${options.message}`);
|
|
1879
|
-
setTimeout(() => {
|
|
1880
|
-
closeModal(state, options.defaultButton ?? 0, false);
|
|
1881
|
-
}, 0);
|
|
1882
|
-
}
|
|
1883
|
-
} else {
|
|
1884
|
-
console.log(`[stx-modal] ${options.type?.toUpperCase() || "INFO"}: ${options.title || "Modal"}`);
|
|
1885
|
-
console.log(`[stx-modal] ${options.message}`);
|
|
1886
|
-
const buttons = options.buttons || getDefaultButtons(options.type);
|
|
1887
|
-
console.log(`[stx-modal] Buttons: ${buttons.map((b) => b.label).join(", ")}`);
|
|
1888
|
-
setTimeout(() => {
|
|
1889
|
-
closeModal(state, options.defaultButton ?? 0, false);
|
|
1890
|
-
}, 0);
|
|
1891
|
-
}
|
|
1892
|
-
});
|
|
1893
|
-
}
|
|
1894
|
-
async function showInfoModal(title, message) {
|
|
1895
|
-
return showModal({ title, message, type: "info" });
|
|
1896
|
-
}
|
|
1897
|
-
async function showWarningModal(title, message) {
|
|
1898
|
-
return showModal({ title, message, type: "warning" });
|
|
1899
|
-
}
|
|
1900
|
-
async function showErrorModal(title, message) {
|
|
1901
|
-
return showModal({ title, message, type: "error" });
|
|
1902
|
-
}
|
|
1903
|
-
async function showSuccessModal(title, message) {
|
|
1904
|
-
return showModal({ title, message, type: "success" });
|
|
1905
|
-
}
|
|
1906
|
-
async function showQuestionModal(title, message) {
|
|
1907
|
-
return showModal({
|
|
1908
|
-
title,
|
|
1909
|
-
message,
|
|
1910
|
-
type: "question",
|
|
1911
|
-
buttons: [
|
|
1912
|
-
{ label: "No", style: "default" },
|
|
1913
|
-
{ label: "Yes", style: "primary" }
|
|
1914
|
-
],
|
|
1915
|
-
defaultButton: 1,
|
|
1916
|
-
cancelButton: 0
|
|
1917
|
-
});
|
|
1918
|
-
}
|
|
1919
|
-
async function confirm2(message, title = "Confirm") {
|
|
1920
|
-
const result = await showQuestionModal(title, message);
|
|
1921
|
-
return result.buttonIndex === 1;
|
|
1922
|
-
}
|
|
1923
|
-
async function alert2(message, title = "Alert") {
|
|
1924
|
-
await showInfoModal(title, message);
|
|
1925
|
-
}
|
|
1926
|
-
async function prompt2(message, defaultValue = "", title = "Input") {
|
|
1927
|
-
if (isBrowser2() && typeof window.prompt === "function") {
|
|
1928
|
-
return window.prompt(message, defaultValue);
|
|
1929
|
-
}
|
|
1930
|
-
console.log(`[stx-modal] PROMPT: ${title}`);
|
|
1931
|
-
console.log(`[stx-modal] ${message}`);
|
|
1932
|
-
console.log(`[stx-modal] Default: ${defaultValue}`);
|
|
1933
|
-
return defaultValue;
|
|
1934
|
-
}
|
|
1935
|
-
function getActiveModalCount() {
|
|
1936
|
-
return activeModals.length;
|
|
1937
|
-
}
|
|
1938
|
-
function closeAllModals() {
|
|
1939
|
-
while (activeModals.length > 0) {
|
|
1940
|
-
const state = activeModals[activeModals.length - 1];
|
|
1941
|
-
closeModal(state, 0, true);
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
var MODAL_STYLES = `
|
|
1945
|
-
.stx-modal-overlay {
|
|
1946
|
-
position: fixed;
|
|
1947
|
-
inset: 0;
|
|
1948
|
-
background: rgba(0, 0, 0, 0.5);
|
|
1949
|
-
display: flex;
|
|
1950
|
-
align-items: center;
|
|
1951
|
-
justify-content: center;
|
|
1952
|
-
z-index: 10000;
|
|
1953
|
-
animation: stx-modal-fade-in 0.15s ease-out;
|
|
1954
|
-
}
|
|
1955
|
-
|
|
1956
|
-
@keyframes stx-modal-fade-in {
|
|
1957
|
-
from { opacity: 0; }
|
|
1958
|
-
to { opacity: 1; }
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
.stx-modal {
|
|
1962
|
-
background: #fff;
|
|
1963
|
-
border-radius: 12px;
|
|
1964
|
-
padding: 24px;
|
|
1965
|
-
max-width: 400px;
|
|
1966
|
-
width: 90%;
|
|
1967
|
-
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
|
1968
|
-
animation: stx-modal-slide-up 0.2s ease-out;
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
@keyframes stx-modal-slide-up {
|
|
1972
|
-
from { transform: translateY(20px); opacity: 0; }
|
|
1973
|
-
to { transform: translateY(0); opacity: 1; }
|
|
1974
|
-
}
|
|
1975
|
-
|
|
1976
|
-
@media (prefers-color-scheme: dark) {
|
|
1977
|
-
.stx-modal {
|
|
1978
|
-
background: #2d2d2d;
|
|
1979
|
-
color: #fff;
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
|
-
.stx-modal-icon {
|
|
1984
|
-
font-size: 48px;
|
|
1985
|
-
text-align: center;
|
|
1986
|
-
margin-bottom: 16px;
|
|
1987
|
-
}
|
|
1988
|
-
|
|
1989
|
-
.stx-modal.info .stx-modal-icon { color: #3498db; }
|
|
1990
|
-
.stx-modal.warning .stx-modal-icon { color: #f39c12; }
|
|
1991
|
-
.stx-modal.error .stx-modal-icon { color: #e74c3c; }
|
|
1992
|
-
.stx-modal.success .stx-modal-icon { color: #27ae60; }
|
|
1993
|
-
.stx-modal.question .stx-modal-icon { color: #9b59b6; }
|
|
1994
|
-
|
|
1995
|
-
.stx-modal-content {
|
|
1996
|
-
text-align: center;
|
|
1997
|
-
margin-bottom: 24px;
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
.stx-modal-title {
|
|
2001
|
-
margin: 0 0 8px;
|
|
2002
|
-
font-size: 20px;
|
|
2003
|
-
font-weight: 600;
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
|
-
.stx-modal-message {
|
|
2007
|
-
margin: 0;
|
|
2008
|
-
color: #666;
|
|
2009
|
-
line-height: 1.5;
|
|
2010
|
-
}
|
|
2011
|
-
|
|
2012
|
-
@media (prefers-color-scheme: dark) {
|
|
2013
|
-
.stx-modal-message { color: #aaa; }
|
|
2014
|
-
}
|
|
2015
|
-
|
|
2016
|
-
.stx-modal-buttons {
|
|
2017
|
-
display: flex;
|
|
2018
|
-
gap: 8px;
|
|
2019
|
-
justify-content: center;
|
|
2020
|
-
}
|
|
2021
|
-
|
|
2022
|
-
.stx-modal-btn {
|
|
2023
|
-
padding: 10px 24px;
|
|
2024
|
-
border-radius: 6px;
|
|
2025
|
-
font-size: 14px;
|
|
2026
|
-
font-weight: 500;
|
|
2027
|
-
cursor: pointer;
|
|
2028
|
-
border: none;
|
|
2029
|
-
transition: background 0.15s, transform 0.1s;
|
|
2030
|
-
}
|
|
2031
|
-
|
|
2032
|
-
.stx-modal-btn:hover {
|
|
2033
|
-
transform: translateY(-1px);
|
|
2034
|
-
}
|
|
2035
|
-
|
|
2036
|
-
.stx-modal-btn:active {
|
|
2037
|
-
transform: translateY(0);
|
|
2038
|
-
}
|
|
2039
|
-
|
|
2040
|
-
.stx-modal-btn.default {
|
|
2041
|
-
background: #e0e0e0;
|
|
2042
|
-
color: #333;
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
.stx-modal-btn.default:hover {
|
|
2046
|
-
background: #d0d0d0;
|
|
2047
|
-
}
|
|
2048
|
-
|
|
2049
|
-
.stx-modal-btn.primary {
|
|
2050
|
-
background: #3498db;
|
|
2051
|
-
color: #fff;
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
.stx-modal-btn.primary:hover {
|
|
2055
|
-
background: #2980b9;
|
|
2056
|
-
}
|
|
2057
|
-
|
|
2058
|
-
.stx-modal-btn.destructive {
|
|
2059
|
-
background: #e74c3c;
|
|
2060
|
-
color: #fff;
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
|
-
.stx-modal-btn.destructive:hover {
|
|
2064
|
-
background: #c0392b;
|
|
2065
|
-
}
|
|
2066
|
-
|
|
2067
|
-
@media (prefers-color-scheme: dark) {
|
|
2068
|
-
.stx-modal-btn.default {
|
|
2069
|
-
background: #444;
|
|
2070
|
-
color: #fff;
|
|
2071
|
-
}
|
|
2072
|
-
.stx-modal-btn.default:hover {
|
|
2073
|
-
background: #555;
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
`;
|
|
2077
|
-
// src/system-tray.ts
|
|
2078
|
-
import process2 from "process";
|
|
2079
|
-
function getPlatform() {
|
|
2080
|
-
if (process2.platform) {
|
|
2081
|
-
return process2.platform;
|
|
2082
|
-
}
|
|
2083
|
-
return "unknown";
|
|
2084
|
-
}
|
|
2085
|
-
function isInCraftWindow() {
|
|
2086
|
-
if (typeof window !== "undefined" && window.craft?.tray) {
|
|
2087
|
-
return true;
|
|
2088
|
-
}
|
|
2089
|
-
return false;
|
|
2090
|
-
}
|
|
2091
|
-
function convertMenuItem(item, index) {
|
|
2092
|
-
if (item.type === "separator") {
|
|
2093
|
-
return {
|
|
2094
|
-
id: `sep-${index}`,
|
|
2095
|
-
label: "",
|
|
2096
|
-
type: "separator"
|
|
1524
|
+
function convertMenuItem(item, index) {
|
|
1525
|
+
if (item.type === "separator") {
|
|
1526
|
+
return {
|
|
1527
|
+
id: `sep-${index}`,
|
|
1528
|
+
label: "",
|
|
1529
|
+
type: "separator"
|
|
2097
1530
|
};
|
|
2098
1531
|
}
|
|
2099
1532
|
const menuItem = {
|
|
@@ -2137,9 +1570,9 @@ function renderMenuItem(item, level = 0) {
|
|
|
2137
1570
|
html += "</div>";
|
|
2138
1571
|
return html;
|
|
2139
1572
|
}
|
|
2140
|
-
function renderTrayMenu(
|
|
1573
|
+
function renderTrayMenu(menu2) {
|
|
2141
1574
|
let html = '<div class="stx-tray-menu">';
|
|
2142
|
-
for (const item of
|
|
1575
|
+
for (const item of menu2) {
|
|
2143
1576
|
html += renderMenuItem(item);
|
|
2144
1577
|
}
|
|
2145
1578
|
html += "</div>";
|
|
@@ -2234,10 +1667,10 @@ async function createSystemTray(options = {}) {
|
|
|
2234
1667
|
}
|
|
2235
1668
|
console.log(`[stx-tray:${id}] Tooltip: ${tooltip}`);
|
|
2236
1669
|
},
|
|
2237
|
-
setMenu: (
|
|
2238
|
-
state.menu =
|
|
1670
|
+
setMenu: (menu2) => {
|
|
1671
|
+
state.menu = menu2;
|
|
2239
1672
|
handlers.clear();
|
|
2240
|
-
for (const item of
|
|
1673
|
+
for (const item of menu2) {
|
|
2241
1674
|
if (item.type !== "separator" && item.onClick) {
|
|
2242
1675
|
handlers.set(item.label, item.onClick);
|
|
2243
1676
|
}
|
|
@@ -2251,12 +1684,12 @@ async function createSystemTray(options = {}) {
|
|
|
2251
1684
|
}
|
|
2252
1685
|
if (inCraft) {
|
|
2253
1686
|
const craftWindow = window;
|
|
2254
|
-
const craftMenu = convertMenuItems(
|
|
1687
|
+
const craftMenu = convertMenuItems(menu2);
|
|
2255
1688
|
craftWindow.craft.tray.setMenu({ items: craftMenu }).catch((e) => {
|
|
2256
1689
|
console.warn("[stx-tray] Failed to set menu:", e);
|
|
2257
1690
|
});
|
|
2258
1691
|
}
|
|
2259
|
-
console.log(`[stx-tray:${id}] Menu updated (${
|
|
1692
|
+
console.log(`[stx-tray:${id}] Menu updated (${menu2.length} items)`);
|
|
2260
1693
|
},
|
|
2261
1694
|
destroy: () => {
|
|
2262
1695
|
state.visible = false;
|
|
@@ -2297,11 +1730,11 @@ function getTrayInstance(id) {
|
|
|
2297
1730
|
craftWindow.craft.tray.setTooltip({ tooltip }).catch(() => {});
|
|
2298
1731
|
}
|
|
2299
1732
|
},
|
|
2300
|
-
setMenu: (
|
|
2301
|
-
instance.state.menu =
|
|
1733
|
+
setMenu: (menu2) => {
|
|
1734
|
+
instance.state.menu = menu2;
|
|
2302
1735
|
if (inCraft) {
|
|
2303
1736
|
const craftWindow = window;
|
|
2304
|
-
const craftMenu = convertMenuItems(
|
|
1737
|
+
const craftMenu = convertMenuItems(menu2);
|
|
2305
1738
|
craftWindow.craft.tray.setMenu({ items: craftMenu }).catch(() => {});
|
|
2306
1739
|
}
|
|
2307
1740
|
},
|
|
@@ -2414,222 +1847,6 @@ var TRAY_MENU_STYLES = `
|
|
|
2414
1847
|
display: block;
|
|
2415
1848
|
}
|
|
2416
1849
|
`;
|
|
2417
|
-
// src/dialogs.ts
|
|
2418
|
-
function isInCraftWindow2() {
|
|
2419
|
-
if (typeof window !== "undefined" && window.craft?.dialog) {
|
|
2420
|
-
return true;
|
|
2421
|
-
}
|
|
2422
|
-
return false;
|
|
2423
|
-
}
|
|
2424
|
-
async function showOpenDialog(options = {}) {
|
|
2425
|
-
if (isInCraftWindow2()) {
|
|
2426
|
-
const craftWindow = window;
|
|
2427
|
-
try {
|
|
2428
|
-
return await craftWindow.craft.dialog.showOpenDialog(options);
|
|
2429
|
-
} catch (error) {
|
|
2430
|
-
console.warn("[stx-dialog] Failed to show native open dialog:", error);
|
|
2431
|
-
}
|
|
2432
|
-
}
|
|
2433
|
-
return new Promise((resolve) => {
|
|
2434
|
-
if (typeof document === "undefined") {
|
|
2435
|
-
resolve({ canceled: true, filePaths: [] });
|
|
2436
|
-
return;
|
|
2437
|
-
}
|
|
2438
|
-
const input = document.createElement("input");
|
|
2439
|
-
input.type = "file";
|
|
2440
|
-
input.multiple = options.multiSelections ?? false;
|
|
2441
|
-
if (options.filters?.length) {
|
|
2442
|
-
const extensions = options.filters.flatMap((f) => f.extensions.map((e) => `.${e}`));
|
|
2443
|
-
input.accept = extensions.join(",");
|
|
2444
|
-
}
|
|
2445
|
-
if (options.canChooseDirectories && !options.canChooseFiles) {
|
|
2446
|
-
input.webkitdirectory = true;
|
|
2447
|
-
}
|
|
2448
|
-
input.onchange = () => {
|
|
2449
|
-
const files = Array.from(input.files || []);
|
|
2450
|
-
if (files.length === 0) {
|
|
2451
|
-
resolve({ canceled: true, filePaths: [] });
|
|
2452
|
-
} else {
|
|
2453
|
-
const filePaths = files.map((f) => f.name);
|
|
2454
|
-
resolve({ canceled: false, filePaths });
|
|
2455
|
-
}
|
|
2456
|
-
};
|
|
2457
|
-
input.oncancel = () => {
|
|
2458
|
-
resolve({ canceled: true, filePaths: [] });
|
|
2459
|
-
};
|
|
2460
|
-
input.click();
|
|
2461
|
-
});
|
|
2462
|
-
}
|
|
2463
|
-
async function showSaveDialog(options = {}) {
|
|
2464
|
-
if (isInCraftWindow2()) {
|
|
2465
|
-
const craftWindow = window;
|
|
2466
|
-
try {
|
|
2467
|
-
return await craftWindow.craft.dialog.showSaveDialog(options);
|
|
2468
|
-
} catch (error) {
|
|
2469
|
-
console.warn("[stx-dialog] Failed to show native save dialog:", error);
|
|
2470
|
-
}
|
|
2471
|
-
}
|
|
2472
|
-
if (typeof window !== "undefined" && "showSaveFilePicker" in window) {
|
|
2473
|
-
try {
|
|
2474
|
-
const fileTypes = options.filters?.map((f) => ({
|
|
2475
|
-
description: f.name,
|
|
2476
|
-
accept: {
|
|
2477
|
-
"*/*": f.extensions.map((e) => `.${e}`)
|
|
2478
|
-
}
|
|
2479
|
-
}));
|
|
2480
|
-
const handle = await window.showSaveFilePicker({
|
|
2481
|
-
suggestedName: options.defaultPath,
|
|
2482
|
-
types: fileTypes
|
|
2483
|
-
});
|
|
2484
|
-
return { canceled: false, filePath: handle.name };
|
|
2485
|
-
} catch (error) {
|
|
2486
|
-
return { canceled: true };
|
|
2487
|
-
}
|
|
2488
|
-
}
|
|
2489
|
-
console.warn("[stx-dialog] Save dialog not available, using prompt fallback");
|
|
2490
|
-
const filename = prompt("Enter filename:", options.defaultPath || "file.txt");
|
|
2491
|
-
if (filename) {
|
|
2492
|
-
return { canceled: false, filePath: filename };
|
|
2493
|
-
}
|
|
2494
|
-
return { canceled: true };
|
|
2495
|
-
}
|
|
2496
|
-
async function showMessageBox(options) {
|
|
2497
|
-
if (isInCraftWindow2()) {
|
|
2498
|
-
const craftWindow = window;
|
|
2499
|
-
try {
|
|
2500
|
-
return await craftWindow.craft.dialog.showMessageBox(options);
|
|
2501
|
-
} catch (error) {
|
|
2502
|
-
console.warn("[stx-dialog] Failed to show native message box:", error);
|
|
2503
|
-
}
|
|
2504
|
-
}
|
|
2505
|
-
const buttons = options.buttons || ["OK"];
|
|
2506
|
-
if (buttons.length === 1) {
|
|
2507
|
-
alert(options.message);
|
|
2508
|
-
return { response: 0 };
|
|
2509
|
-
}
|
|
2510
|
-
if (buttons.length === 2 && options.type === "question") {
|
|
2511
|
-
const confirmed2 = confirm(options.message);
|
|
2512
|
-
return { response: confirmed2 ? 1 : 0 };
|
|
2513
|
-
}
|
|
2514
|
-
console.warn("[stx-dialog] Complex message box not fully supported in browser, using confirm");
|
|
2515
|
-
const confirmed = confirm(`${options.message}
|
|
2516
|
-
|
|
2517
|
-
${buttons.join(" / ")}`);
|
|
2518
|
-
return { response: confirmed ? buttons.length - 1 : 0 };
|
|
2519
|
-
}
|
|
2520
|
-
async function showColorPicker(options = {}) {
|
|
2521
|
-
if (isInCraftWindow2()) {
|
|
2522
|
-
const craftWindow = window;
|
|
2523
|
-
try {
|
|
2524
|
-
return await craftWindow.craft.dialog.showColorPicker(options);
|
|
2525
|
-
} catch (error) {
|
|
2526
|
-
console.warn("[stx-dialog] Failed to show native color picker:", error);
|
|
2527
|
-
}
|
|
2528
|
-
}
|
|
2529
|
-
return new Promise((resolve) => {
|
|
2530
|
-
if (typeof document === "undefined") {
|
|
2531
|
-
resolve({ canceled: true });
|
|
2532
|
-
return;
|
|
2533
|
-
}
|
|
2534
|
-
const input = document.createElement("input");
|
|
2535
|
-
input.type = "color";
|
|
2536
|
-
input.value = options.color || "#000000";
|
|
2537
|
-
input.onchange = () => {
|
|
2538
|
-
resolve({ canceled: false, color: input.value });
|
|
2539
|
-
};
|
|
2540
|
-
input.oncancel = () => {
|
|
2541
|
-
resolve({ canceled: true });
|
|
2542
|
-
};
|
|
2543
|
-
input.click();
|
|
2544
|
-
});
|
|
2545
|
-
}
|
|
2546
|
-
async function showAlertDialog(message, title) {
|
|
2547
|
-
await showMessageBox({
|
|
2548
|
-
type: "info",
|
|
2549
|
-
title: title || "Alert",
|
|
2550
|
-
message,
|
|
2551
|
-
buttons: ["OK"]
|
|
2552
|
-
});
|
|
2553
|
-
}
|
|
2554
|
-
async function showConfirmDialog(message, title) {
|
|
2555
|
-
const result = await showMessageBox({
|
|
2556
|
-
type: "question",
|
|
2557
|
-
title: title || "Confirm",
|
|
2558
|
-
message,
|
|
2559
|
-
buttons: ["Cancel", "OK"],
|
|
2560
|
-
defaultButton: 1,
|
|
2561
|
-
cancelButton: 0
|
|
2562
|
-
});
|
|
2563
|
-
return result.response === 1;
|
|
2564
|
-
}
|
|
2565
|
-
async function showErrorDialog(message, title) {
|
|
2566
|
-
await showMessageBox({
|
|
2567
|
-
type: "error",
|
|
2568
|
-
title: title || "Error",
|
|
2569
|
-
message,
|
|
2570
|
-
buttons: ["OK"]
|
|
2571
|
-
});
|
|
2572
|
-
}
|
|
2573
|
-
async function showWarningDialog(message, title) {
|
|
2574
|
-
await showMessageBox({
|
|
2575
|
-
type: "warning",
|
|
2576
|
-
title: title || "Warning",
|
|
2577
|
-
message,
|
|
2578
|
-
buttons: ["OK"]
|
|
2579
|
-
});
|
|
2580
|
-
}
|
|
2581
|
-
function getDialogBridgeScript() {
|
|
2582
|
-
return `
|
|
2583
|
-
// STX Desktop Dialog Bridge
|
|
2584
|
-
// Provides convenient wrappers around window.craft.dialog APIs
|
|
2585
|
-
window.stxDialog = {
|
|
2586
|
-
// File dialogs
|
|
2587
|
-
showOpenDialog: (options) => window.craft?.dialog?.showOpenDialog(options),
|
|
2588
|
-
showSaveDialog: (options) => window.craft?.dialog?.showSaveDialog(options),
|
|
2589
|
-
|
|
2590
|
-
// Message dialogs
|
|
2591
|
-
showMessageBox: (options) => window.craft?.dialog?.showMessageBox(options),
|
|
2592
|
-
|
|
2593
|
-
// Color picker
|
|
2594
|
-
showColorPicker: (options) => window.craft?.dialog?.showColorPicker(options),
|
|
2595
|
-
|
|
2596
|
-
// Font picker
|
|
2597
|
-
showFontPicker: (options) => window.craft?.dialog?.showFontPicker(options),
|
|
2598
|
-
|
|
2599
|
-
// Convenience functions
|
|
2600
|
-
alert: async (message, title) => {
|
|
2601
|
-
return window.craft?.dialog?.showMessageBox({
|
|
2602
|
-
type: 'info',
|
|
2603
|
-
title: title || 'Alert',
|
|
2604
|
-
message,
|
|
2605
|
-
buttons: ['OK'],
|
|
2606
|
-
});
|
|
2607
|
-
},
|
|
2608
|
-
|
|
2609
|
-
confirm: async (message, title) => {
|
|
2610
|
-
const result = await window.craft?.dialog?.showMessageBox({
|
|
2611
|
-
type: 'question',
|
|
2612
|
-
title: title || 'Confirm',
|
|
2613
|
-
message,
|
|
2614
|
-
buttons: ['Cancel', 'OK'],
|
|
2615
|
-
});
|
|
2616
|
-
return result?.response === 1;
|
|
2617
|
-
},
|
|
2618
|
-
|
|
2619
|
-
error: async (message, title) => {
|
|
2620
|
-
return window.craft?.dialog?.showMessageBox({
|
|
2621
|
-
type: 'error',
|
|
2622
|
-
title: title || 'Error',
|
|
2623
|
-
message,
|
|
2624
|
-
buttons: ['OK'],
|
|
2625
|
-
});
|
|
2626
|
-
},
|
|
2627
|
-
|
|
2628
|
-
// Check if dialog is available
|
|
2629
|
-
isAvailable: () => typeof window.craft?.dialog !== 'undefined',
|
|
2630
|
-
};
|
|
2631
|
-
`;
|
|
2632
|
-
}
|
|
2633
1850
|
// src/window.ts
|
|
2634
1851
|
import process3 from "process";
|
|
2635
1852
|
import { existsSync } from "fs";
|
|
@@ -2689,7 +1906,7 @@ function closeAllWindows() {
|
|
|
2689
1906
|
}
|
|
2690
1907
|
activeWindows.clear();
|
|
2691
1908
|
}
|
|
2692
|
-
function createWindowInstance(id,
|
|
1909
|
+
function createWindowInstance(id, app2) {
|
|
2693
1910
|
return {
|
|
2694
1911
|
id,
|
|
2695
1912
|
show: () => {
|
|
@@ -2772,7 +1989,7 @@ async function createWindow(url, options = {}) {
|
|
|
2772
1989
|
const craftPath = getCraftBinaryPath();
|
|
2773
1990
|
try {
|
|
2774
1991
|
const { createApp } = await import("craft-native");
|
|
2775
|
-
const
|
|
1992
|
+
const app2 = createApp({
|
|
2776
1993
|
url,
|
|
2777
1994
|
craftPath,
|
|
2778
1995
|
window: {
|
|
@@ -2793,9 +2010,9 @@ async function createWindow(url, options = {}) {
|
|
|
2793
2010
|
sidebarConfig: prepareSidebarConfig(options)
|
|
2794
2011
|
}
|
|
2795
2012
|
});
|
|
2796
|
-
activeWindows.set(id, { app, url, options });
|
|
2797
|
-
await
|
|
2798
|
-
return createWindowInstance(id,
|
|
2013
|
+
activeWindows.set(id, { app: app2, url, options });
|
|
2014
|
+
await app2.show();
|
|
2015
|
+
return createWindowInstance(id, app2);
|
|
2799
2016
|
} catch {
|
|
2800
2017
|
try {
|
|
2801
2018
|
const { spawn } = await import("child_process");
|
|
@@ -2803,9 +2020,9 @@ async function createWindow(url, options = {}) {
|
|
|
2803
2020
|
child.on("error", (err) => {
|
|
2804
2021
|
console.error(err.code === "ENOENT" ? craftBinaryNotFoundMessage(craftPath) : `craft child error: ${err.message}`);
|
|
2805
2022
|
});
|
|
2806
|
-
const
|
|
2807
|
-
activeWindows.set(id, { app, url, options });
|
|
2808
|
-
return createWindowInstance(id,
|
|
2023
|
+
const app2 = { close: () => child.kill() };
|
|
2024
|
+
activeWindows.set(id, { app: app2, url, options });
|
|
2025
|
+
return createWindowInstance(id, app2);
|
|
2809
2026
|
} catch (binaryError) {
|
|
2810
2027
|
console.error("Failed to spawn craft binary:", binaryError.message);
|
|
2811
2028
|
return null;
|
|
@@ -2825,7 +2042,7 @@ async function openDevWindow(port, options = {}) {
|
|
|
2825
2042
|
console.log("\u26A1 Opening native window via craft-native\u2026");
|
|
2826
2043
|
const useSystemTray = !options.nativeSidebar;
|
|
2827
2044
|
const sidebarConfig = prepareSidebarConfig(options);
|
|
2828
|
-
const
|
|
2045
|
+
const app2 = createApp({
|
|
2829
2046
|
url,
|
|
2830
2047
|
craftPath: getCraftBinaryPath(),
|
|
2831
2048
|
window: {
|
|
@@ -2844,8 +2061,8 @@ async function openDevWindow(port, options = {}) {
|
|
|
2844
2061
|
}
|
|
2845
2062
|
});
|
|
2846
2063
|
const id = `dev-window-${port}`;
|
|
2847
|
-
activeWindows.set(id, { app, url, options });
|
|
2848
|
-
await
|
|
2064
|
+
activeWindows.set(id, { app: app2, url, options });
|
|
2065
|
+
await app2.show();
|
|
2849
2066
|
console.log(`\u2713 Native window opened at ${url}`);
|
|
2850
2067
|
return true;
|
|
2851
2068
|
} catch {
|
|
@@ -2905,7 +2122,7 @@ async function createWindowWithHTML(html, options = {}) {
|
|
|
2905
2122
|
try {
|
|
2906
2123
|
const { createApp } = await import("craft-native");
|
|
2907
2124
|
const craftPath = getCraftBinaryPath();
|
|
2908
|
-
const
|
|
2125
|
+
const app2 = createApp({
|
|
2909
2126
|
html,
|
|
2910
2127
|
craftPath,
|
|
2911
2128
|
window: {
|
|
@@ -2920,9 +2137,9 @@ async function createWindowWithHTML(html, options = {}) {
|
|
|
2920
2137
|
}
|
|
2921
2138
|
});
|
|
2922
2139
|
const id = `craft-window-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2923
|
-
activeWindows.set(id, { app, url: "html-content", options });
|
|
2924
|
-
await
|
|
2925
|
-
return createWindowInstance(id,
|
|
2140
|
+
activeWindows.set(id, { app: app2, url: "html-content", options });
|
|
2141
|
+
await app2.show();
|
|
2142
|
+
return createWindowInstance(id, app2);
|
|
2926
2143
|
} catch (error) {
|
|
2927
2144
|
console.error("Failed to create window with HTML:", error);
|
|
2928
2145
|
return null;
|
|
@@ -3016,179 +2233,6 @@ function createGitHubUpdateManifest(options) {
|
|
|
3016
2233
|
platforms
|
|
3017
2234
|
});
|
|
3018
2235
|
}
|
|
3019
|
-
// src/power.ts
|
|
3020
|
-
var currentProcess = null;
|
|
3021
|
-
var currentInstance = null;
|
|
3022
|
-
|
|
3023
|
-
class CaffeinateInstanceImpl {
|
|
3024
|
-
_process;
|
|
3025
|
-
_startedAt;
|
|
3026
|
-
_endsAt;
|
|
3027
|
-
_options;
|
|
3028
|
-
_expireHandlers = [];
|
|
3029
|
-
_expireTimer = null;
|
|
3030
|
-
_stopped = false;
|
|
3031
|
-
constructor(process4, options) {
|
|
3032
|
-
this._process = process4;
|
|
3033
|
-
this._options = options;
|
|
3034
|
-
this._startedAt = new Date;
|
|
3035
|
-
const duration = options.duration;
|
|
3036
|
-
if (duration && duration > 0) {
|
|
3037
|
-
const durationMs = duration * 60 * 1000;
|
|
3038
|
-
this._endsAt = new Date(this._startedAt.getTime() + durationMs);
|
|
3039
|
-
this._expireTimer = setTimeout(() => {
|
|
3040
|
-
this._stopped = true;
|
|
3041
|
-
for (const handler of this._expireHandlers) {
|
|
3042
|
-
try {
|
|
3043
|
-
handler();
|
|
3044
|
-
} catch {}
|
|
3045
|
-
}
|
|
3046
|
-
}, durationMs);
|
|
3047
|
-
} else {
|
|
3048
|
-
this._endsAt = null;
|
|
3049
|
-
}
|
|
3050
|
-
}
|
|
3051
|
-
get pid() {
|
|
3052
|
-
return this._process.pid;
|
|
3053
|
-
}
|
|
3054
|
-
get startedAt() {
|
|
3055
|
-
return this._startedAt;
|
|
3056
|
-
}
|
|
3057
|
-
get endsAt() {
|
|
3058
|
-
return this._endsAt;
|
|
3059
|
-
}
|
|
3060
|
-
get options() {
|
|
3061
|
-
return { ...this._options };
|
|
3062
|
-
}
|
|
3063
|
-
get isActive() {
|
|
3064
|
-
if (this._stopped)
|
|
3065
|
-
return false;
|
|
3066
|
-
return this._process.exitCode === null;
|
|
3067
|
-
}
|
|
3068
|
-
get remainingMs() {
|
|
3069
|
-
if (!this._endsAt)
|
|
3070
|
-
return null;
|
|
3071
|
-
const remaining = this._endsAt.getTime() - Date.now();
|
|
3072
|
-
return Math.max(0, remaining);
|
|
3073
|
-
}
|
|
3074
|
-
get elapsedMs() {
|
|
3075
|
-
return Date.now() - this._startedAt.getTime();
|
|
3076
|
-
}
|
|
3077
|
-
stop() {
|
|
3078
|
-
if (this._stopped)
|
|
3079
|
-
return;
|
|
3080
|
-
this._stopped = true;
|
|
3081
|
-
if (this._expireTimer) {
|
|
3082
|
-
clearTimeout(this._expireTimer);
|
|
3083
|
-
this._expireTimer = null;
|
|
3084
|
-
}
|
|
3085
|
-
try {
|
|
3086
|
-
this._process.kill();
|
|
3087
|
-
} catch {}
|
|
3088
|
-
}
|
|
3089
|
-
onExpire(handler) {
|
|
3090
|
-
this._expireHandlers.push(handler);
|
|
3091
|
-
}
|
|
3092
|
-
}
|
|
3093
|
-
function caffeinate(options = {}) {
|
|
3094
|
-
decaffeinate();
|
|
3095
|
-
const {
|
|
3096
|
-
duration,
|
|
3097
|
-
preventDisplaySleep = true,
|
|
3098
|
-
preventIdleSleep = true,
|
|
3099
|
-
preventSystemSleep = true,
|
|
3100
|
-
preventDiskSleep = false,
|
|
3101
|
-
assertUserActivity = true
|
|
3102
|
-
} = options;
|
|
3103
|
-
const flags = [];
|
|
3104
|
-
if (preventDisplaySleep)
|
|
3105
|
-
flags.push("-d");
|
|
3106
|
-
if (preventIdleSleep)
|
|
3107
|
-
flags.push("-i");
|
|
3108
|
-
if (preventSystemSleep)
|
|
3109
|
-
flags.push("-s");
|
|
3110
|
-
if (preventDiskSleep)
|
|
3111
|
-
flags.push("-m");
|
|
3112
|
-
if (assertUserActivity)
|
|
3113
|
-
flags.push("-u");
|
|
3114
|
-
const args = [...flags];
|
|
3115
|
-
if (duration && duration > 0) {
|
|
3116
|
-
args.push("-t", String(duration * 60));
|
|
3117
|
-
}
|
|
3118
|
-
const proc = Bun.spawn(["/usr/bin/caffeinate", ...args], {
|
|
3119
|
-
stdio: ["ignore", "ignore", "ignore"]
|
|
3120
|
-
});
|
|
3121
|
-
const instance = new CaffeinateInstanceImpl(proc, options);
|
|
3122
|
-
currentProcess = proc;
|
|
3123
|
-
currentInstance = instance;
|
|
3124
|
-
return instance;
|
|
3125
|
-
}
|
|
3126
|
-
function decaffeinate(instance) {
|
|
3127
|
-
if (instance) {
|
|
3128
|
-
instance.stop();
|
|
3129
|
-
if (currentInstance === instance) {
|
|
3130
|
-
currentProcess = null;
|
|
3131
|
-
currentInstance = null;
|
|
3132
|
-
}
|
|
3133
|
-
return;
|
|
3134
|
-
}
|
|
3135
|
-
if (currentInstance) {
|
|
3136
|
-
currentInstance.stop();
|
|
3137
|
-
}
|
|
3138
|
-
currentProcess = null;
|
|
3139
|
-
currentInstance = null;
|
|
3140
|
-
}
|
|
3141
|
-
function isCaffeinated() {
|
|
3142
|
-
return currentInstance !== null && currentInstance.isActive;
|
|
3143
|
-
}
|
|
3144
|
-
function getCaffeinateStatus() {
|
|
3145
|
-
if (!currentInstance || !currentInstance.isActive) {
|
|
3146
|
-
return {
|
|
3147
|
-
active: false,
|
|
3148
|
-
instance: null,
|
|
3149
|
-
startedAt: null,
|
|
3150
|
-
endsAt: null,
|
|
3151
|
-
durationMinutes: null
|
|
3152
|
-
};
|
|
3153
|
-
}
|
|
3154
|
-
const opts = currentInstance.options;
|
|
3155
|
-
const duration = opts.duration;
|
|
3156
|
-
return {
|
|
3157
|
-
active: true,
|
|
3158
|
-
instance: currentInstance,
|
|
3159
|
-
startedAt: currentInstance.startedAt,
|
|
3160
|
-
endsAt: currentInstance.endsAt,
|
|
3161
|
-
durationMinutes: duration && duration > 0 ? duration : -1
|
|
3162
|
-
};
|
|
3163
|
-
}
|
|
3164
|
-
function formatRemainingTime(instance) {
|
|
3165
|
-
const inst = instance || currentInstance;
|
|
3166
|
-
if (!inst || !inst.isActive)
|
|
3167
|
-
return "0:00";
|
|
3168
|
-
const remaining = inst.remainingMs;
|
|
3169
|
-
if (remaining === null)
|
|
3170
|
-
return "\u221E";
|
|
3171
|
-
const totalSeconds = Math.ceil(remaining / 1000);
|
|
3172
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
3173
|
-
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
3174
|
-
const seconds = totalSeconds % 60;
|
|
3175
|
-
if (hours > 0)
|
|
3176
|
-
return `${hours}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
|
|
3177
|
-
return `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
3178
|
-
}
|
|
3179
|
-
function formatDuration(minutes) {
|
|
3180
|
-
if (minutes <= 0 || minutes === -1)
|
|
3181
|
-
return "Indefinitely";
|
|
3182
|
-
if (minutes < 60)
|
|
3183
|
-
return `${minutes} minutes`;
|
|
3184
|
-
if (minutes === 60)
|
|
3185
|
-
return "1 hour";
|
|
3186
|
-
if (minutes % 60 === 0)
|
|
3187
|
-
return `${minutes / 60} hours`;
|
|
3188
|
-
const h = Math.floor(minutes / 60);
|
|
3189
|
-
const m = minutes % 60;
|
|
3190
|
-
return `${h}h ${m}m`;
|
|
3191
|
-
}
|
|
3192
2236
|
// src/preferences.ts
|
|
3193
2237
|
import { existsSync as existsSync2, mkdirSync, readFileSync, watch, writeFileSync } from "fs";
|
|
3194
2238
|
import { homedir, platform } from "os";
|
|
@@ -3486,1421 +2530,25 @@ async function isAutoLaunchEnabled(appName) {
|
|
|
3486
2530
|
return false;
|
|
3487
2531
|
}
|
|
3488
2532
|
}
|
|
3489
|
-
// src/
|
|
3490
|
-
var
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
case "\u2318":
|
|
3509
|
-
result.meta = true;
|
|
3510
|
-
break;
|
|
3511
|
-
case "ctrl":
|
|
3512
|
-
case "control":
|
|
3513
|
-
case "\u2303":
|
|
3514
|
-
result.ctrl = true;
|
|
3515
|
-
break;
|
|
3516
|
-
case "shift":
|
|
3517
|
-
case "\u21E7":
|
|
3518
|
-
result.shift = true;
|
|
3519
|
-
break;
|
|
3520
|
-
case "alt":
|
|
3521
|
-
case "option":
|
|
3522
|
-
case "opt":
|
|
3523
|
-
case "\u2325":
|
|
3524
|
-
result.alt = true;
|
|
3525
|
-
break;
|
|
3526
|
-
case "cmdorctrl":
|
|
3527
|
-
case "commandorcontrol":
|
|
3528
|
-
if (typeof process !== "undefined" && process.platform === "darwin") {
|
|
3529
|
-
result.meta = true;
|
|
3530
|
-
} else {
|
|
3531
|
-
result.ctrl = true;
|
|
3532
|
-
}
|
|
3533
|
-
break;
|
|
3534
|
-
default:
|
|
3535
|
-
result.key = lower;
|
|
3536
|
-
}
|
|
3537
|
-
}
|
|
3538
|
-
return result;
|
|
3539
|
-
}
|
|
3540
|
-
function formatShortcut(parsed) {
|
|
3541
|
-
const parts = [];
|
|
3542
|
-
if (parsed.ctrl)
|
|
3543
|
-
parts.push("\u2303");
|
|
3544
|
-
if (parsed.alt)
|
|
3545
|
-
parts.push("\u2325");
|
|
3546
|
-
if (parsed.shift)
|
|
3547
|
-
parts.push("\u21E7");
|
|
3548
|
-
if (parsed.meta)
|
|
3549
|
-
parts.push("\u2318");
|
|
3550
|
-
parts.push(parsed.key.toUpperCase());
|
|
3551
|
-
return parts.join("");
|
|
3552
|
-
}
|
|
3553
|
-
function matchesEvent(event, parsed) {
|
|
3554
|
-
if (parsed.meta !== event.metaKey)
|
|
3555
|
-
return false;
|
|
3556
|
-
if (parsed.ctrl !== event.ctrlKey)
|
|
3557
|
-
return false;
|
|
3558
|
-
if (parsed.shift !== event.shiftKey)
|
|
3559
|
-
return false;
|
|
3560
|
-
if (parsed.alt !== event.altKey)
|
|
3561
|
-
return false;
|
|
3562
|
-
const eventKey = event.key.toLowerCase();
|
|
3563
|
-
return eventKey === parsed.key || event.code.toLowerCase() === `key${parsed.key}`;
|
|
3564
|
-
}
|
|
3565
|
-
function handleKeyDown(event) {
|
|
3566
|
-
for (const [, reg] of registrations) {
|
|
3567
|
-
if (matchesEvent(event, reg.parsed)) {
|
|
3568
|
-
event.preventDefault();
|
|
3569
|
-
event.stopPropagation();
|
|
3570
|
-
try {
|
|
3571
|
-
reg.handler();
|
|
3572
|
-
} catch {}
|
|
3573
|
-
break;
|
|
3574
|
-
}
|
|
3575
|
-
}
|
|
3576
|
-
}
|
|
3577
|
-
function ensureDocumentListener() {
|
|
3578
|
-
if (documentListenerAttached)
|
|
3579
|
-
return;
|
|
3580
|
-
if (typeof document === "undefined")
|
|
3581
|
-
return;
|
|
3582
|
-
document.addEventListener("keydown", handleKeyDown, true);
|
|
3583
|
-
documentListenerAttached = true;
|
|
3584
|
-
}
|
|
3585
|
-
function removeDocumentListener() {
|
|
3586
|
-
if (!documentListenerAttached)
|
|
3587
|
-
return;
|
|
3588
|
-
if (typeof document === "undefined")
|
|
3589
|
-
return;
|
|
3590
|
-
document.removeEventListener("keydown", handleKeyDown, true);
|
|
3591
|
-
documentListenerAttached = false;
|
|
3592
|
-
}
|
|
3593
|
-
async function registerWithCraft(id, shortcut) {
|
|
3594
|
-
if (typeof window === "undefined")
|
|
3595
|
-
return false;
|
|
3596
|
-
const craft = window.craft;
|
|
3597
|
-
if (!craft?.hotkeys?.register)
|
|
3598
|
-
return false;
|
|
3599
|
-
try {
|
|
3600
|
-
await craft.hotkeys.register(id, shortcut);
|
|
3601
|
-
return true;
|
|
3602
|
-
} catch {
|
|
3603
|
-
return false;
|
|
3604
|
-
}
|
|
3605
|
-
}
|
|
3606
|
-
async function unregisterWithCraft(id) {
|
|
3607
|
-
if (typeof window === "undefined")
|
|
3608
|
-
return;
|
|
3609
|
-
const craft = window.craft;
|
|
3610
|
-
if (!craft?.hotkeys?.unregister)
|
|
3611
|
-
return;
|
|
3612
|
-
try {
|
|
3613
|
-
await craft.hotkeys.unregister(id);
|
|
3614
|
-
} catch {}
|
|
3615
|
-
}
|
|
3616
|
-
function registerHotkey(shortcut, handler) {
|
|
3617
|
-
const id = `hotkey_${++nextId}_${Date.now()}`;
|
|
3618
|
-
const parsed = parseShortcut(shortcut);
|
|
3619
|
-
registrations.set(id, { shortcut, handler, parsed });
|
|
3620
|
-
registerWithCraft(id, shortcut);
|
|
3621
|
-
ensureDocumentListener();
|
|
3622
|
-
const registration = {
|
|
3623
|
-
shortcut,
|
|
3624
|
-
id,
|
|
3625
|
-
unregister() {
|
|
3626
|
-
unregisterHotkey(registration);
|
|
3627
|
-
}
|
|
3628
|
-
};
|
|
3629
|
-
return registration;
|
|
3630
|
-
}
|
|
3631
|
-
function unregisterHotkey(registration) {
|
|
3632
|
-
registrations.delete(registration.id);
|
|
3633
|
-
unregisterWithCraft(registration.id);
|
|
3634
|
-
if (registrations.size === 0) {
|
|
3635
|
-
removeDocumentListener();
|
|
3636
|
-
}
|
|
3637
|
-
}
|
|
3638
|
-
function unregisterAllHotkeys() {
|
|
3639
|
-
for (const [id] of registrations) {
|
|
3640
|
-
unregisterWithCraft(id);
|
|
3641
|
-
}
|
|
3642
|
-
registrations.clear();
|
|
3643
|
-
removeDocumentListener();
|
|
3644
|
-
}
|
|
3645
|
-
function getRegisteredHotkeys() {
|
|
3646
|
-
return Array.from(registrations.entries()).map(([id, reg]) => ({
|
|
3647
|
-
shortcut: reg.shortcut,
|
|
3648
|
-
id,
|
|
3649
|
-
unregister() {
|
|
3650
|
-
registrations.delete(id);
|
|
3651
|
-
unregisterWithCraft(id);
|
|
3652
|
-
if (registrations.size === 0) {
|
|
3653
|
-
removeDocumentListener();
|
|
3654
|
-
}
|
|
3655
|
-
}
|
|
3656
|
-
}));
|
|
3657
|
-
}
|
|
3658
|
-
// src/timer.ts
|
|
3659
|
-
class TimerImpl {
|
|
3660
|
-
_duration;
|
|
3661
|
-
_tickInterval;
|
|
3662
|
-
_remaining;
|
|
3663
|
-
_running = false;
|
|
3664
|
-
_paused = false;
|
|
3665
|
-
_complete = false;
|
|
3666
|
-
_intervalId = null;
|
|
3667
|
-
_lastTick = 0;
|
|
3668
|
-
_completionHandlers = new Set;
|
|
3669
|
-
_tickHandlers = new Set;
|
|
3670
|
-
constructor(options) {
|
|
3671
|
-
this._duration = options.duration;
|
|
3672
|
-
this._tickInterval = options.tickInterval || 1000;
|
|
3673
|
-
this._remaining = options.duration;
|
|
3674
|
-
if (options.onComplete)
|
|
3675
|
-
this._completionHandlers.add(options.onComplete);
|
|
3676
|
-
if (options.onTick)
|
|
3677
|
-
this._tickHandlers.add(options.onTick);
|
|
3678
|
-
if (options.autoStart)
|
|
3679
|
-
this.start();
|
|
3680
|
-
}
|
|
3681
|
-
get isRunning() {
|
|
3682
|
-
return this._running && !this._paused;
|
|
3683
|
-
}
|
|
3684
|
-
get isPaused() {
|
|
3685
|
-
return this._paused;
|
|
3686
|
-
}
|
|
3687
|
-
get isComplete() {
|
|
3688
|
-
return this._complete;
|
|
3689
|
-
}
|
|
3690
|
-
get remaining() {
|
|
3691
|
-
if (this._running && !this._paused) {
|
|
3692
|
-
const elapsed = Date.now() - this._lastTick;
|
|
3693
|
-
return Math.max(0, this._remaining - elapsed);
|
|
3694
|
-
}
|
|
3695
|
-
return Math.max(0, this._remaining);
|
|
3696
|
-
}
|
|
3697
|
-
get elapsed() {
|
|
3698
|
-
return this._duration - this.remaining;
|
|
3699
|
-
}
|
|
3700
|
-
get duration() {
|
|
3701
|
-
return this._duration;
|
|
3702
|
-
}
|
|
3703
|
-
get progress() {
|
|
3704
|
-
if (this._duration === 0)
|
|
3705
|
-
return 1;
|
|
3706
|
-
return Math.min(1, this.elapsed / this._duration);
|
|
3707
|
-
}
|
|
3708
|
-
start() {
|
|
3709
|
-
if (this._running)
|
|
3710
|
-
return;
|
|
3711
|
-
this._running = true;
|
|
3712
|
-
this._paused = false;
|
|
3713
|
-
this._complete = false;
|
|
3714
|
-
this._lastTick = Date.now();
|
|
3715
|
-
this._startInterval();
|
|
3716
|
-
}
|
|
3717
|
-
stop() {
|
|
3718
|
-
this._clearInterval();
|
|
3719
|
-
this._running = false;
|
|
3720
|
-
this._paused = false;
|
|
3721
|
-
this._remaining = this._duration;
|
|
3722
|
-
}
|
|
3723
|
-
pause() {
|
|
3724
|
-
if (!this._running || this._paused)
|
|
3725
|
-
return;
|
|
3726
|
-
const elapsed = Date.now() - this._lastTick;
|
|
3727
|
-
this._remaining = Math.max(0, this._remaining - elapsed);
|
|
3728
|
-
this._clearInterval();
|
|
3729
|
-
this._paused = true;
|
|
3730
|
-
}
|
|
3731
|
-
resume() {
|
|
3732
|
-
if (!this._paused)
|
|
3733
|
-
return;
|
|
3734
|
-
this._paused = false;
|
|
3735
|
-
this._lastTick = Date.now();
|
|
3736
|
-
this._startInterval();
|
|
3737
|
-
}
|
|
3738
|
-
reset() {
|
|
3739
|
-
this._clearInterval();
|
|
3740
|
-
this._running = false;
|
|
3741
|
-
this._paused = false;
|
|
3742
|
-
this._complete = false;
|
|
3743
|
-
this._remaining = this._duration;
|
|
3744
|
-
}
|
|
3745
|
-
onComplete(handler) {
|
|
3746
|
-
this._completionHandlers.add(handler);
|
|
3747
|
-
return () => {
|
|
3748
|
-
this._completionHandlers.delete(handler);
|
|
3749
|
-
};
|
|
3750
|
-
}
|
|
3751
|
-
onTick(handler) {
|
|
3752
|
-
this._tickHandlers.add(handler);
|
|
3753
|
-
return () => {
|
|
3754
|
-
this._tickHandlers.delete(handler);
|
|
3755
|
-
};
|
|
3756
|
-
}
|
|
3757
|
-
_startInterval() {
|
|
3758
|
-
this._clearInterval();
|
|
3759
|
-
this._intervalId = setInterval(() => {
|
|
3760
|
-
const now = Date.now();
|
|
3761
|
-
const elapsed = now - this._lastTick;
|
|
3762
|
-
this._lastTick = now;
|
|
3763
|
-
this._remaining = Math.max(0, this._remaining - elapsed);
|
|
3764
|
-
for (const handler of this._tickHandlers) {
|
|
3765
|
-
try {
|
|
3766
|
-
handler(this._remaining);
|
|
3767
|
-
} catch {}
|
|
3768
|
-
}
|
|
3769
|
-
if (this._remaining <= 0) {
|
|
3770
|
-
this._clearInterval();
|
|
3771
|
-
this._running = false;
|
|
3772
|
-
this._complete = true;
|
|
3773
|
-
for (const handler of this._completionHandlers) {
|
|
3774
|
-
try {
|
|
3775
|
-
handler();
|
|
3776
|
-
} catch {}
|
|
3777
|
-
}
|
|
3778
|
-
}
|
|
3779
|
-
}, this._tickInterval);
|
|
3780
|
-
}
|
|
3781
|
-
_clearInterval() {
|
|
3782
|
-
if (this._intervalId !== null) {
|
|
3783
|
-
clearInterval(this._intervalId);
|
|
3784
|
-
this._intervalId = null;
|
|
3785
|
-
}
|
|
3786
|
-
}
|
|
3787
|
-
}
|
|
3788
|
-
|
|
3789
|
-
class IntervalImpl {
|
|
3790
|
-
_interval;
|
|
3791
|
-
_handler;
|
|
3792
|
-
_immediate;
|
|
3793
|
-
_running = false;
|
|
3794
|
-
_intervalId = null;
|
|
3795
|
-
constructor(options) {
|
|
3796
|
-
this._interval = options.interval;
|
|
3797
|
-
this._handler = options.handler;
|
|
3798
|
-
this._immediate = options.immediate !== false;
|
|
3799
|
-
if (this._immediate)
|
|
3800
|
-
this.start();
|
|
3801
|
-
}
|
|
3802
|
-
get isRunning() {
|
|
3803
|
-
return this._running;
|
|
3804
|
-
}
|
|
3805
|
-
start() {
|
|
3806
|
-
if (this._running)
|
|
3807
|
-
return;
|
|
3808
|
-
this._running = true;
|
|
3809
|
-
this._intervalId = setInterval(() => {
|
|
3810
|
-
try {
|
|
3811
|
-
this._handler();
|
|
3812
|
-
} catch {}
|
|
3813
|
-
}, this._interval);
|
|
3814
|
-
}
|
|
3815
|
-
stop() {
|
|
3816
|
-
if (this._intervalId !== null) {
|
|
3817
|
-
clearInterval(this._intervalId);
|
|
3818
|
-
this._intervalId = null;
|
|
3819
|
-
}
|
|
3820
|
-
this._running = false;
|
|
3821
|
-
}
|
|
3822
|
-
}
|
|
3823
|
-
function createTimer(options) {
|
|
3824
|
-
return new TimerImpl(options);
|
|
3825
|
-
}
|
|
3826
|
-
function createInterval(options) {
|
|
3827
|
-
return new IntervalImpl(options);
|
|
3828
|
-
}
|
|
3829
|
-
function delay(ms) {
|
|
3830
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3831
|
-
}
|
|
3832
|
-
function formatTime(ms) {
|
|
3833
|
-
const totalSeconds = Math.ceil(ms / 1000);
|
|
3834
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
3835
|
-
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
3836
|
-
const seconds = totalSeconds % 60;
|
|
3837
|
-
if (hours > 0)
|
|
3838
|
-
return `${hours}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
|
|
3839
|
-
return `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
3840
|
-
}
|
|
3841
|
-
function formatCompact(ms) {
|
|
3842
|
-
const totalSeconds = Math.ceil(ms / 1000);
|
|
3843
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
3844
|
-
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
3845
|
-
const seconds = totalSeconds % 60;
|
|
3846
|
-
if (hours > 0) {
|
|
3847
|
-
if (minutes > 0)
|
|
3848
|
-
return `${hours}h ${minutes}m`;
|
|
3849
|
-
return `${hours}h`;
|
|
3850
|
-
}
|
|
3851
|
-
if (minutes > 0) {
|
|
3852
|
-
if (seconds > 0)
|
|
3853
|
-
return `${minutes}m ${seconds}s`;
|
|
3854
|
-
return `${minutes}m`;
|
|
3855
|
-
}
|
|
3856
|
-
return `${seconds}s`;
|
|
3857
|
-
}
|
|
3858
|
-
// src/_bridge.ts
|
|
3859
|
-
function hasBridge(ns) {
|
|
3860
|
-
if (typeof window === "undefined")
|
|
3861
|
-
return false;
|
|
3862
|
-
const c = window.craft;
|
|
3863
|
-
return !!(c && c[ns]);
|
|
3864
|
-
}
|
|
3865
|
-
function requireBridge(ns) {
|
|
3866
|
-
if (!hasBridge(ns)) {
|
|
3867
|
-
throw new Error(`craft.${ns} is not available \u2014 this API requires a Craft native window`);
|
|
3868
|
-
}
|
|
3869
|
-
return window.craft[ns];
|
|
3870
|
-
}
|
|
3871
|
-
function onCraftEvent(name, cb) {
|
|
3872
|
-
if (typeof window === "undefined")
|
|
3873
|
-
return () => {};
|
|
3874
|
-
const h = (e) => cb(e.detail ?? {});
|
|
3875
|
-
window.addEventListener(name, h);
|
|
3876
|
-
return () => window.removeEventListener(name, h);
|
|
3877
|
-
}
|
|
3878
|
-
|
|
3879
|
-
// src/clipboard.ts
|
|
3880
|
-
var clipboard = {
|
|
3881
|
-
async writeText(text) {
|
|
3882
|
-
if (hasBridge("clipboard")) {
|
|
3883
|
-
await window.craft.clipboard.writeText(text);
|
|
3884
|
-
return;
|
|
3885
|
-
}
|
|
3886
|
-
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
3887
|
-
await navigator.clipboard.writeText(text);
|
|
3888
|
-
}
|
|
3889
|
-
},
|
|
3890
|
-
async readText() {
|
|
3891
|
-
if (hasBridge("clipboard")) {
|
|
3892
|
-
const v = await window.craft.clipboard.readText();
|
|
3893
|
-
return typeof v === "string" ? v : "";
|
|
3894
|
-
}
|
|
3895
|
-
if (typeof navigator !== "undefined" && navigator.clipboard?.readText) {
|
|
3896
|
-
try {
|
|
3897
|
-
return await navigator.clipboard.readText();
|
|
3898
|
-
} catch {
|
|
3899
|
-
return "";
|
|
3900
|
-
}
|
|
3901
|
-
}
|
|
3902
|
-
return "";
|
|
3903
|
-
},
|
|
3904
|
-
async writeHTML(html) {
|
|
3905
|
-
if (hasBridge("clipboard")) {
|
|
3906
|
-
await window.craft.clipboard.writeHTML(html);
|
|
3907
|
-
return;
|
|
3908
|
-
}
|
|
3909
|
-
if (typeof navigator !== "undefined" && navigator.clipboard?.write) {
|
|
3910
|
-
try {
|
|
3911
|
-
const item = new window.ClipboardItem({
|
|
3912
|
-
"text/html": new Blob([html], { type: "text/html" }),
|
|
3913
|
-
"text/plain": new Blob([stripHtml(html)], { type: "text/plain" })
|
|
3914
|
-
});
|
|
3915
|
-
await navigator.clipboard.write([item]);
|
|
3916
|
-
} catch {}
|
|
3917
|
-
}
|
|
3918
|
-
},
|
|
3919
|
-
async readHTML() {
|
|
3920
|
-
if (hasBridge("clipboard")) {
|
|
3921
|
-
const v = await window.craft.clipboard.readHTML();
|
|
3922
|
-
return typeof v === "string" ? v : "";
|
|
3923
|
-
}
|
|
3924
|
-
if (typeof navigator !== "undefined" && navigator.clipboard?.read) {
|
|
3925
|
-
try {
|
|
3926
|
-
const items = await navigator.clipboard.read();
|
|
3927
|
-
for (const item of items) {
|
|
3928
|
-
if (item.types.includes("text/html")) {
|
|
3929
|
-
const blob = await item.getType("text/html");
|
|
3930
|
-
return await blob.text();
|
|
3931
|
-
}
|
|
3932
|
-
}
|
|
3933
|
-
} catch {}
|
|
3934
|
-
}
|
|
3935
|
-
return "";
|
|
3936
|
-
},
|
|
3937
|
-
async clear() {
|
|
3938
|
-
if (hasBridge("clipboard")) {
|
|
3939
|
-
await window.craft.clipboard.clear();
|
|
3940
|
-
return;
|
|
3941
|
-
}
|
|
3942
|
-
if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
3943
|
-
try {
|
|
3944
|
-
await navigator.clipboard.writeText("");
|
|
3945
|
-
} catch {}
|
|
3946
|
-
}
|
|
3947
|
-
},
|
|
3948
|
-
async hasText() {
|
|
3949
|
-
if (hasBridge("clipboard")) {
|
|
3950
|
-
return await window.craft.clipboard.hasText();
|
|
3951
|
-
}
|
|
3952
|
-
return (await this.readText()).length > 0;
|
|
3953
|
-
},
|
|
3954
|
-
async hasHTML() {
|
|
3955
|
-
if (hasBridge("clipboard")) {
|
|
3956
|
-
return await window.craft.clipboard.hasHTML();
|
|
3957
|
-
}
|
|
3958
|
-
return (await this.readHTML()).length > 0;
|
|
3959
|
-
},
|
|
3960
|
-
async hasImage() {
|
|
3961
|
-
if (hasBridge("clipboard")) {
|
|
3962
|
-
return await window.craft.clipboard.hasImage();
|
|
3963
|
-
}
|
|
3964
|
-
return false;
|
|
3965
|
-
}
|
|
3966
|
-
};
|
|
3967
|
-
function stripHtml(html) {
|
|
3968
|
-
return html.replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/gi, "").replace(/<\/?(br|p|div|li|h[1-6])\b[^>]*>/gi, `
|
|
3969
|
-
`).replace(/<[^>]+>/g, "").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\n{3,}/g, `
|
|
3970
|
-
|
|
3971
|
-
`).trim();
|
|
3972
|
-
}
|
|
3973
|
-
// src/notifications.ts
|
|
3974
|
-
var notifications = {
|
|
3975
|
-
async show(options) {
|
|
3976
|
-
if (!options.title)
|
|
3977
|
-
throw new Error("notification title is required");
|
|
3978
|
-
if (hasBridge("notifications")) {
|
|
3979
|
-
await window.craft.notifications.show(options);
|
|
3980
|
-
return;
|
|
3981
|
-
}
|
|
3982
|
-
if (typeof window !== "undefined" && "Notification" in window) {
|
|
3983
|
-
const N = window.Notification;
|
|
3984
|
-
if (N.permission === "granted") {
|
|
3985
|
-
new N(options.title, { body: options.body, icon: options.icon });
|
|
3986
|
-
} else if (N.permission === "default") {
|
|
3987
|
-
const granted = await N.requestPermission() === "granted";
|
|
3988
|
-
if (granted)
|
|
3989
|
-
new N(options.title, { body: options.body, icon: options.icon });
|
|
3990
|
-
}
|
|
3991
|
-
}
|
|
3992
|
-
},
|
|
3993
|
-
async schedule(options) {
|
|
3994
|
-
if (hasBridge("notifications")) {
|
|
3995
|
-
const o = { ...options };
|
|
3996
|
-
if (o.triggerAt instanceof Date)
|
|
3997
|
-
o.triggerAt = o.triggerAt.toISOString();
|
|
3998
|
-
await window.craft.notifications.schedule(o);
|
|
3999
|
-
return;
|
|
4000
|
-
}
|
|
4001
|
-
const fireAt = toEpochMs(options.triggerAt);
|
|
4002
|
-
const delay2 = Math.max(0, fireAt - Date.now());
|
|
4003
|
-
setTimeout(() => {
|
|
4004
|
-
this.show(options).catch(() => {});
|
|
4005
|
-
}, delay2);
|
|
4006
|
-
},
|
|
4007
|
-
async cancel(id) {
|
|
4008
|
-
if (hasBridge("notifications")) {
|
|
4009
|
-
await window.craft.notifications.cancel(id);
|
|
4010
|
-
}
|
|
4011
|
-
},
|
|
4012
|
-
async cancelAll() {
|
|
4013
|
-
if (hasBridge("notifications")) {
|
|
4014
|
-
await window.craft.notifications.cancelAll();
|
|
4015
|
-
}
|
|
4016
|
-
},
|
|
4017
|
-
async setBadge(n) {
|
|
4018
|
-
const safe = Math.max(0, Math.round(Number.isFinite(n) ? n : 0));
|
|
4019
|
-
if (hasBridge("notifications")) {
|
|
4020
|
-
await window.craft.notifications.setBadge(safe);
|
|
4021
|
-
return;
|
|
4022
|
-
}
|
|
4023
|
-
if (typeof navigator !== "undefined" && navigator.setAppBadge) {
|
|
4024
|
-
try {
|
|
4025
|
-
await navigator.setAppBadge(safe);
|
|
4026
|
-
} catch {}
|
|
4027
|
-
}
|
|
4028
|
-
},
|
|
4029
|
-
async clearBadge() {
|
|
4030
|
-
if (hasBridge("notifications")) {
|
|
4031
|
-
await window.craft.notifications.clearBadge();
|
|
4032
|
-
return;
|
|
4033
|
-
}
|
|
4034
|
-
if (typeof navigator !== "undefined" && navigator.clearAppBadge) {
|
|
4035
|
-
try {
|
|
4036
|
-
await navigator.clearAppBadge();
|
|
4037
|
-
} catch {}
|
|
4038
|
-
}
|
|
4039
|
-
},
|
|
4040
|
-
async requestPermission() {
|
|
4041
|
-
if (hasBridge("notifications")) {
|
|
4042
|
-
return await window.craft.notifications.requestPermission();
|
|
4043
|
-
}
|
|
4044
|
-
if (typeof window !== "undefined" && "Notification" in window) {
|
|
4045
|
-
const N = window.Notification;
|
|
4046
|
-
if (N.permission === "granted")
|
|
4047
|
-
return true;
|
|
4048
|
-
if (N.permission === "denied")
|
|
4049
|
-
return false;
|
|
4050
|
-
const result = await N.requestPermission();
|
|
4051
|
-
return result === "granted";
|
|
4052
|
-
}
|
|
4053
|
-
return false;
|
|
4054
|
-
},
|
|
4055
|
-
async registerCategories(categories) {
|
|
4056
|
-
if (!Array.isArray(categories) || categories.length === 0)
|
|
4057
|
-
return;
|
|
4058
|
-
if (hasBridge("notifications")) {
|
|
4059
|
-
const fn = window.craft.notifications.registerCategories;
|
|
4060
|
-
if (typeof fn === "function")
|
|
4061
|
-
await fn(categories);
|
|
4062
|
-
}
|
|
4063
|
-
},
|
|
4064
|
-
onActionClicked(cb) {
|
|
4065
|
-
return onCraftEvent("craft:notification:actionClicked", cb);
|
|
4066
|
-
},
|
|
4067
|
-
onReply(cb) {
|
|
4068
|
-
return onCraftEvent("craft:notification:reply", cb);
|
|
4069
|
-
}
|
|
4070
|
-
};
|
|
4071
|
-
function toEpochMs(t) {
|
|
4072
|
-
if (t == null)
|
|
4073
|
-
return Date.now();
|
|
4074
|
-
if (t instanceof Date)
|
|
4075
|
-
return t.getTime();
|
|
4076
|
-
if (typeof t === "number")
|
|
4077
|
-
return t;
|
|
4078
|
-
const parsed = Date.parse(t);
|
|
4079
|
-
return Number.isNaN(parsed) ? Date.now() : parsed;
|
|
4080
|
-
}
|
|
4081
|
-
// src/fs.ts
|
|
4082
|
-
var fs = {
|
|
4083
|
-
async readFile(path) {
|
|
4084
|
-
const r = await requireBridge("fs").readFile(path);
|
|
4085
|
-
return r && r.data || "";
|
|
4086
|
-
},
|
|
4087
|
-
async readBuffer(path) {
|
|
4088
|
-
const r = await requireBridge("fs").readFile(path);
|
|
4089
|
-
const text = r && r.data || "";
|
|
4090
|
-
if (r && r.base64 === true) {
|
|
4091
|
-
return base64ToBytes(text);
|
|
4092
|
-
}
|
|
4093
|
-
return new TextEncoder().encode(text);
|
|
4094
|
-
},
|
|
4095
|
-
async writeFile(path, data) {
|
|
4096
|
-
await requireBridge("fs").writeFile(path, data);
|
|
4097
|
-
},
|
|
4098
|
-
async writeBuffer(path, data) {
|
|
4099
|
-
const b64 = bytesToBase64(data);
|
|
4100
|
-
const bridge = requireBridge("fs");
|
|
4101
|
-
if (typeof bridge.writeFileBytes === "function") {
|
|
4102
|
-
await bridge.writeFileBytes(path, b64);
|
|
4103
|
-
} else {
|
|
4104
|
-
await bridge.writeFile(path, b64);
|
|
4105
|
-
}
|
|
4106
|
-
},
|
|
4107
|
-
async copy(from, to) {
|
|
4108
|
-
if (from === to)
|
|
4109
|
-
throw new Error("fs.copy: source and destination must differ");
|
|
4110
|
-
await requireBridge("fs").copy(from, to);
|
|
4111
|
-
},
|
|
4112
|
-
async move(from, to) {
|
|
4113
|
-
if (from === to)
|
|
4114
|
-
throw new Error("fs.move: source and destination must differ");
|
|
4115
|
-
await requireBridge("fs").move(from, to);
|
|
4116
|
-
},
|
|
4117
|
-
async appendFile(path, data) {
|
|
4118
|
-
await requireBridge("fs").appendFile(path, data);
|
|
4119
|
-
},
|
|
4120
|
-
async deleteFile(path) {
|
|
4121
|
-
await requireBridge("fs").deleteFile(path);
|
|
4122
|
-
},
|
|
4123
|
-
async exists(path) {
|
|
4124
|
-
return await requireBridge("fs").exists(path);
|
|
4125
|
-
},
|
|
4126
|
-
async stat(path) {
|
|
4127
|
-
return normalizeStat(await requireBridge("fs").stat(path));
|
|
4128
|
-
},
|
|
4129
|
-
async readDir(path) {
|
|
4130
|
-
const r = await requireBridge("fs").readDir(path);
|
|
4131
|
-
const raw = r && r.entries || [];
|
|
4132
|
-
const base = path.endsWith("/") ? path.slice(0, -1) : path;
|
|
4133
|
-
return raw.map((e) => ({
|
|
4134
|
-
name: e.name,
|
|
4135
|
-
path: `${base}/${e.name}`,
|
|
4136
|
-
isDirectory: !!e.isDirectory
|
|
4137
|
-
}));
|
|
4138
|
-
},
|
|
4139
|
-
async mkdir(path, opts) {
|
|
4140
|
-
await requireBridge("fs").mkdir(path, opts);
|
|
4141
|
-
},
|
|
4142
|
-
async rmdir(path, opts) {
|
|
4143
|
-
await requireBridge("fs").rmdir(path, opts);
|
|
4144
|
-
},
|
|
4145
|
-
async watch(path, id) {
|
|
4146
|
-
await requireBridge("fs").watch(path, id);
|
|
4147
|
-
},
|
|
4148
|
-
async unwatch(id) {
|
|
4149
|
-
await requireBridge("fs").unwatch(id);
|
|
4150
|
-
},
|
|
4151
|
-
onChange(cb) {
|
|
4152
|
-
return onCraftEvent("craft:fs:change", cb);
|
|
4153
|
-
},
|
|
4154
|
-
async watchTree(path, options, cb) {
|
|
4155
|
-
const id = `watch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4156
|
-
const bridge = requireBridge("fs");
|
|
4157
|
-
await bridge.watch(path, id, { recursive: !!options.recursive });
|
|
4158
|
-
const allowed = options.kinds && options.kinds.length > 0 ? new Set(options.kinds) : null;
|
|
4159
|
-
const coalesceMs = Math.max(0, Math.floor(options.coalesceMs ?? 0));
|
|
4160
|
-
let buffer = [];
|
|
4161
|
-
let flushTimer = null;
|
|
4162
|
-
let stopped = false;
|
|
4163
|
-
const flush = () => {
|
|
4164
|
-
flushTimer = null;
|
|
4165
|
-
if (buffer.length === 0)
|
|
4166
|
-
return;
|
|
4167
|
-
const batch = buffer;
|
|
4168
|
-
buffer = [];
|
|
4169
|
-
try {
|
|
4170
|
-
cb(batch);
|
|
4171
|
-
} catch {}
|
|
4172
|
-
};
|
|
4173
|
-
const off = onCraftEvent("craft:fs:change", (e) => {
|
|
4174
|
-
if (stopped)
|
|
4175
|
-
return;
|
|
4176
|
-
if (e.id !== id)
|
|
4177
|
-
return;
|
|
4178
|
-
if (allowed && e.kind && !allowed.has(e.kind))
|
|
4179
|
-
return;
|
|
4180
|
-
buffer.push(e);
|
|
4181
|
-
if (coalesceMs === 0) {
|
|
4182
|
-
flush();
|
|
4183
|
-
return;
|
|
4184
|
-
}
|
|
4185
|
-
if (flushTimer == null) {
|
|
4186
|
-
flushTimer = setTimeout(flush, coalesceMs);
|
|
4187
|
-
}
|
|
4188
|
-
});
|
|
4189
|
-
return {
|
|
4190
|
-
id,
|
|
4191
|
-
async stop() {
|
|
4192
|
-
if (stopped)
|
|
4193
|
-
return;
|
|
4194
|
-
stopped = true;
|
|
4195
|
-
off();
|
|
4196
|
-
if (flushTimer) {
|
|
4197
|
-
clearTimeout(flushTimer);
|
|
4198
|
-
flushTimer = null;
|
|
4199
|
-
}
|
|
4200
|
-
if (buffer.length > 0)
|
|
4201
|
-
flush();
|
|
4202
|
-
try {
|
|
4203
|
-
await bridge.unwatch(id);
|
|
4204
|
-
} catch {}
|
|
4205
|
-
}
|
|
4206
|
-
};
|
|
4207
|
-
},
|
|
4208
|
-
async homeDir() {
|
|
4209
|
-
return await requireBridge("fs").homeDir();
|
|
4210
|
-
},
|
|
4211
|
-
async tempDir() {
|
|
4212
|
-
return await requireBridge("fs").tempDir();
|
|
4213
|
-
},
|
|
4214
|
-
async appDataDir() {
|
|
4215
|
-
return await requireBridge("fs").appDataDir();
|
|
4216
|
-
}
|
|
4217
|
-
};
|
|
4218
|
-
function bytesToBase64(bytes) {
|
|
4219
|
-
let s = "";
|
|
4220
|
-
for (let i = 0;i < bytes.length; i++)
|
|
4221
|
-
s += String.fromCharCode(bytes[i]);
|
|
4222
|
-
return typeof btoa === "function" ? btoa(s) : Buffer.from(bytes).toString("base64");
|
|
4223
|
-
}
|
|
4224
|
-
function base64ToBytes(b64) {
|
|
4225
|
-
const bin = typeof atob === "function" ? atob(b64) : Buffer.from(b64, "base64").toString("binary");
|
|
4226
|
-
const out = new Uint8Array(bin.length);
|
|
4227
|
-
for (let i = 0;i < bin.length; i++)
|
|
4228
|
-
out[i] = bin.charCodeAt(i);
|
|
4229
|
-
return out;
|
|
4230
|
-
}
|
|
4231
|
-
function normalizeStat(raw) {
|
|
4232
|
-
return {
|
|
4233
|
-
isFile: !!raw.isFile,
|
|
4234
|
-
isDirectory: !!raw.isDirectory,
|
|
4235
|
-
isSymlink: !!raw.isSymlink,
|
|
4236
|
-
size: Number(raw.size) || 0,
|
|
4237
|
-
modifiedAt: raw.modifiedAt != null ? raw.modifiedAt < 1000000000000 ? raw.modifiedAt * 1000 : raw.modifiedAt : 0
|
|
4238
|
-
};
|
|
4239
|
-
}
|
|
4240
|
-
// src/shell.ts
|
|
4241
|
-
var activeSpawnIds = new Set;
|
|
4242
|
-
var exitListenerAttached = false;
|
|
4243
|
-
function ensureExitListener() {
|
|
4244
|
-
if (exitListenerAttached)
|
|
4245
|
-
return;
|
|
4246
|
-
if (typeof window === "undefined" || typeof window.addEventListener !== "function")
|
|
4247
|
-
return;
|
|
4248
|
-
window.addEventListener("craft:shell:exit", (e) => {
|
|
4249
|
-
const detail = e.detail;
|
|
4250
|
-
if (detail?.id)
|
|
4251
|
-
activeSpawnIds.delete(detail.id);
|
|
4252
|
-
});
|
|
4253
|
-
exitListenerAttached = true;
|
|
4254
|
-
}
|
|
4255
|
-
var BLOCKED_SCHEMES = new Set(["javascript:", "data:", "file:", "vbscript:"]);
|
|
4256
|
-
var shell = {
|
|
4257
|
-
async openExternal(url) {
|
|
4258
|
-
const lc = url.trim().toLowerCase();
|
|
4259
|
-
for (const s of BLOCKED_SCHEMES) {
|
|
4260
|
-
if (lc.startsWith(s)) {
|
|
4261
|
-
throw new Error(`shell.openExternal: ${s} URLs are blocked for safety`);
|
|
4262
|
-
}
|
|
4263
|
-
}
|
|
4264
|
-
if (hasBridge("shell")) {
|
|
4265
|
-
await window.craft.shell.openExternal(url);
|
|
4266
|
-
return;
|
|
4267
|
-
}
|
|
4268
|
-
if (typeof window !== "undefined" && typeof window.open === "function") {
|
|
4269
|
-
window.open(url, "_blank", "noopener,noreferrer");
|
|
4270
|
-
}
|
|
4271
|
-
},
|
|
4272
|
-
async openPath(path) {
|
|
4273
|
-
await requireBridge("shell").openPath(path);
|
|
4274
|
-
},
|
|
4275
|
-
async showInFinder(path) {
|
|
4276
|
-
await requireBridge("shell").showInFinder(path);
|
|
4277
|
-
},
|
|
4278
|
-
async spawn(id, command, args = [], opts = {}) {
|
|
4279
|
-
ensureExitListener();
|
|
4280
|
-
if (!id || typeof id !== "string")
|
|
4281
|
-
throw new Error("shell.spawn: id must be a non-empty string");
|
|
4282
|
-
if (!command || typeof command !== "string")
|
|
4283
|
-
throw new Error("shell.spawn: command must be a non-empty string");
|
|
4284
|
-
if (!Array.isArray(args))
|
|
4285
|
-
throw new Error("shell.spawn: args must be an array");
|
|
4286
|
-
for (const a of args) {
|
|
4287
|
-
if (typeof a !== "string")
|
|
4288
|
-
throw new Error("shell.spawn: args entries must be strings");
|
|
4289
|
-
}
|
|
4290
|
-
if (activeSpawnIds.has(id)) {
|
|
4291
|
-
throw new Error(`shell.spawn: id "${id}" is already in use \u2014 call kill(id) first or pick a different id`);
|
|
4292
|
-
}
|
|
4293
|
-
activeSpawnIds.add(id);
|
|
4294
|
-
try {
|
|
4295
|
-
await requireBridge("shell").spawn(id, command, args, opts);
|
|
4296
|
-
} catch (e) {
|
|
4297
|
-
activeSpawnIds.delete(id);
|
|
4298
|
-
throw e;
|
|
4299
|
-
}
|
|
4300
|
-
},
|
|
4301
|
-
async kill(id) {
|
|
4302
|
-
await requireBridge("shell").kill(id);
|
|
4303
|
-
activeSpawnIds.delete(id);
|
|
4304
|
-
},
|
|
4305
|
-
async getEnv(name) {
|
|
4306
|
-
if (hasBridge("shell")) {
|
|
4307
|
-
const v = await window.craft.shell.getEnv(name);
|
|
4308
|
-
return v == null ? undefined : String(v);
|
|
4309
|
-
}
|
|
4310
|
-
return;
|
|
4311
|
-
},
|
|
4312
|
-
async setEnv(name, value) {
|
|
4313
|
-
await requireBridge("shell").setEnv(name, value);
|
|
4314
|
-
},
|
|
4315
|
-
onStdout(cb) {
|
|
4316
|
-
return onCraftEvent("craft:shell:stdout", cb);
|
|
4317
|
-
},
|
|
4318
|
-
onStderr(cb) {
|
|
4319
|
-
return onCraftEvent("craft:shell:stderr", cb);
|
|
4320
|
-
},
|
|
4321
|
-
onExit(cb) {
|
|
4322
|
-
return onCraftEvent("craft:shell:exit", cb);
|
|
4323
|
-
}
|
|
4324
|
-
};
|
|
4325
|
-
// src/global-shortcuts.ts
|
|
4326
|
-
var globalShortcuts = {
|
|
4327
|
-
async register(id, accelerator, opts) {
|
|
4328
|
-
if (!hasBridge("shortcuts"))
|
|
4329
|
-
return;
|
|
4330
|
-
await window.craft.shortcuts.register(id, accelerator, opts);
|
|
4331
|
-
},
|
|
4332
|
-
async unregister(id) {
|
|
4333
|
-
if (!hasBridge("shortcuts"))
|
|
4334
|
-
return;
|
|
4335
|
-
await window.craft.shortcuts.unregister(id);
|
|
4336
|
-
},
|
|
4337
|
-
async unregisterAll() {
|
|
4338
|
-
if (!hasBridge("shortcuts"))
|
|
4339
|
-
return;
|
|
4340
|
-
await window.craft.shortcuts.unregisterAll();
|
|
4341
|
-
},
|
|
4342
|
-
async enable(id) {
|
|
4343
|
-
if (!hasBridge("shortcuts"))
|
|
4344
|
-
return;
|
|
4345
|
-
await window.craft.shortcuts.enable(id);
|
|
4346
|
-
},
|
|
4347
|
-
async disable(id) {
|
|
4348
|
-
if (!hasBridge("shortcuts"))
|
|
4349
|
-
return;
|
|
4350
|
-
await window.craft.shortcuts.disable(id);
|
|
4351
|
-
},
|
|
4352
|
-
async isRegistered(id) {
|
|
4353
|
-
if (!hasBridge("shortcuts"))
|
|
4354
|
-
return false;
|
|
4355
|
-
return await window.craft.shortcuts.isRegistered(id);
|
|
4356
|
-
},
|
|
4357
|
-
async list() {
|
|
4358
|
-
if (!hasBridge("shortcuts"))
|
|
4359
|
-
return [];
|
|
4360
|
-
return await window.craft.shortcuts.list();
|
|
4361
|
-
},
|
|
4362
|
-
on(cb) {
|
|
4363
|
-
return onCraftEvent("craft:shortcut", cb);
|
|
4364
|
-
}
|
|
4365
|
-
};
|
|
4366
|
-
// src/theme.ts
|
|
4367
|
-
var theme = {
|
|
4368
|
-
get() {
|
|
4369
|
-
if (hasBridge("theme")) {
|
|
4370
|
-
try {
|
|
4371
|
-
return window.craft.theme.get();
|
|
4372
|
-
} catch {}
|
|
4373
|
-
}
|
|
4374
|
-
return { appearance: detectWebAppearance() };
|
|
4375
|
-
},
|
|
4376
|
-
onChange(cb) {
|
|
4377
|
-
cb(this.get());
|
|
4378
|
-
if (hasBridge("theme")) {
|
|
4379
|
-
return onCraftEvent("craft:theme", cb);
|
|
4380
|
-
}
|
|
4381
|
-
if (typeof window !== "undefined" && window.matchMedia) {
|
|
4382
|
-
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
4383
|
-
const handler = () => cb({ appearance: mq.matches ? "dark" : "light" });
|
|
4384
|
-
mq.addEventListener("change", handler);
|
|
4385
|
-
return () => mq.removeEventListener("change", handler);
|
|
4386
|
-
}
|
|
4387
|
-
return () => {};
|
|
4388
|
-
},
|
|
4389
|
-
async current() {
|
|
4390
|
-
return this.get();
|
|
4391
|
-
}
|
|
4392
|
-
};
|
|
4393
|
-
function detectWebAppearance() {
|
|
4394
|
-
if (typeof window === "undefined" || !window.matchMedia)
|
|
4395
|
-
return "light";
|
|
4396
|
-
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
4397
|
-
}
|
|
4398
|
-
// src/drag-out.ts
|
|
4399
|
-
async function dragOut(paths, options = {}) {
|
|
4400
|
-
if (!hasBridge("dragOut")) {
|
|
4401
|
-
throw new Error("dragOut requires a Craft native window");
|
|
4402
|
-
}
|
|
4403
|
-
const arr = Array.isArray(paths) ? paths : [paths];
|
|
4404
|
-
if (arr.length === 0)
|
|
4405
|
-
throw new Error("dragOut: at least one path required");
|
|
4406
|
-
await window.craft.dragOut.start(arr, options);
|
|
4407
|
-
}
|
|
4408
|
-
function isDragOutAvailable() {
|
|
4409
|
-
return hasBridge("dragOut");
|
|
4410
|
-
}
|
|
4411
|
-
// src/deep-link.ts
|
|
4412
|
-
var deepLinks = {
|
|
4413
|
-
onUrl(cb) {
|
|
4414
|
-
if (!hasBridge("deepLink"))
|
|
4415
|
-
return () => {};
|
|
4416
|
-
return onCraftEvent("craft:deepLink", cb);
|
|
4417
|
-
},
|
|
4418
|
-
getInitialUrl() {
|
|
4419
|
-
if (typeof window === "undefined")
|
|
4420
|
-
return null;
|
|
4421
|
-
if (hasBridge("deepLink")) {
|
|
4422
|
-
try {
|
|
4423
|
-
return window.craft.deepLink.getInitialUrl();
|
|
4424
|
-
} catch {
|
|
4425
|
-
return null;
|
|
4426
|
-
}
|
|
4427
|
-
}
|
|
4428
|
-
return window.__craftPendingDeepLink || null;
|
|
4429
|
-
},
|
|
4430
|
-
consumeInitialUrl() {
|
|
4431
|
-
const url = this.getInitialUrl();
|
|
4432
|
-
if (typeof window !== "undefined")
|
|
4433
|
-
window.__craftPendingDeepLink = undefined;
|
|
4434
|
-
return url;
|
|
4435
|
-
},
|
|
4436
|
-
isAvailable() {
|
|
4437
|
-
return hasBridge("deepLink");
|
|
4438
|
-
}
|
|
4439
|
-
};
|
|
4440
|
-
// src/battery.ts
|
|
4441
|
-
var battery = {
|
|
4442
|
-
async isCharging() {
|
|
4443
|
-
if (hasBridge("power"))
|
|
4444
|
-
return await window.craft.power.isCharging();
|
|
4445
|
-
const b = await getWebBatteryManager();
|
|
4446
|
-
return b ? !!b.charging : false;
|
|
4447
|
-
},
|
|
4448
|
-
async isPluggedIn() {
|
|
4449
|
-
if (hasBridge("power"))
|
|
4450
|
-
return await window.craft.power.isPluggedIn();
|
|
4451
|
-
const b = await getWebBatteryManager();
|
|
4452
|
-
return b ? !!b.charging || b.level >= 0.999 : false;
|
|
4453
|
-
},
|
|
4454
|
-
async isLowPowerMode() {
|
|
4455
|
-
if (hasBridge("power"))
|
|
4456
|
-
return await window.craft.power.isLowPowerMode();
|
|
4457
|
-
return false;
|
|
4458
|
-
},
|
|
4459
|
-
async level() {
|
|
4460
|
-
if (hasBridge("power")) {
|
|
4461
|
-
const v = await window.craft.power.batteryLevel();
|
|
4462
|
-
return typeof v === "number" ? v : null;
|
|
4463
|
-
}
|
|
4464
|
-
const b = await getWebBatteryManager();
|
|
4465
|
-
return b ? b.level : null;
|
|
4466
|
-
},
|
|
4467
|
-
async timeRemaining() {
|
|
4468
|
-
if (hasBridge("power")) {
|
|
4469
|
-
const r = await window.craft.power.timeRemaining();
|
|
4470
|
-
return typeof r === "number" ? r : null;
|
|
4471
|
-
}
|
|
4472
|
-
const b = await getWebBatteryManager();
|
|
4473
|
-
if (!b)
|
|
4474
|
-
return null;
|
|
4475
|
-
const sec = b.charging ? b.chargingTime : b.dischargingTime;
|
|
4476
|
-
return Number.isFinite(sec) ? Math.round(sec / 60) : null;
|
|
4477
|
-
},
|
|
4478
|
-
async thermalState() {
|
|
4479
|
-
if (hasBridge("power")) {
|
|
4480
|
-
const s = await window.craft.power.thermalState();
|
|
4481
|
-
return s || "unknown";
|
|
4482
|
-
}
|
|
4483
|
-
return "unknown";
|
|
4484
|
-
},
|
|
4485
|
-
async uptimeSeconds() {
|
|
4486
|
-
if (hasBridge("power"))
|
|
4487
|
-
return await window.craft.power.uptimeSeconds();
|
|
4488
|
-
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
4489
|
-
return Math.round(performance.now() / 1000);
|
|
4490
|
-
}
|
|
4491
|
-
return 0;
|
|
4492
|
-
},
|
|
4493
|
-
async preventSleep(reason = "app is busy") {
|
|
4494
|
-
if (hasBridge("power")) {
|
|
4495
|
-
await window.craft.power.preventSleep(reason);
|
|
4496
|
-
return;
|
|
4497
|
-
}
|
|
4498
|
-
if (typeof navigator === "undefined" || !navigator.wakeLock)
|
|
4499
|
-
return;
|
|
4500
|
-
const w = window;
|
|
4501
|
-
if (w.__craftWebWakeLock?.release) {
|
|
4502
|
-
try {
|
|
4503
|
-
await w.__craftWebWakeLock.release();
|
|
4504
|
-
} catch {}
|
|
4505
|
-
w.__craftWebWakeLock = null;
|
|
4506
|
-
}
|
|
4507
|
-
try {
|
|
4508
|
-
const sentinel = await navigator.wakeLock.request("screen");
|
|
4509
|
-
w.__craftWebWakeLock = sentinel;
|
|
4510
|
-
} catch {}
|
|
4511
|
-
},
|
|
4512
|
-
async allowSleep() {
|
|
4513
|
-
if (hasBridge("power")) {
|
|
4514
|
-
await window.craft.power.allowSleep();
|
|
4515
|
-
return;
|
|
4516
|
-
}
|
|
4517
|
-
const s = window.__craftWebWakeLock;
|
|
4518
|
-
if (s && typeof s.release === "function") {
|
|
4519
|
-
try {
|
|
4520
|
-
await s.release();
|
|
4521
|
-
} catch {}
|
|
4522
|
-
window.__craftWebWakeLock = null;
|
|
4523
|
-
}
|
|
4524
|
-
},
|
|
4525
|
-
onSleep(cb) {
|
|
4526
|
-
return onCraftEvent("craft:powerSleep", cb);
|
|
4527
|
-
},
|
|
4528
|
-
onWake(cb) {
|
|
4529
|
-
return onCraftEvent("craft:powerWake", cb);
|
|
4530
|
-
}
|
|
4531
|
-
};
|
|
4532
|
-
async function getWebBatteryManager() {
|
|
4533
|
-
if (typeof navigator === "undefined")
|
|
4534
|
-
return null;
|
|
4535
|
-
const nav = navigator;
|
|
4536
|
-
if (typeof nav.getBattery !== "function")
|
|
4537
|
-
return null;
|
|
4538
|
-
try {
|
|
4539
|
-
return await nav.getBattery();
|
|
4540
|
-
} catch {
|
|
4541
|
-
return null;
|
|
4542
|
-
}
|
|
4543
|
-
}
|
|
4544
|
-
// src/network.ts
|
|
4545
|
-
var network = {
|
|
4546
|
-
async connectionType() {
|
|
4547
|
-
if (hasBridge("network"))
|
|
4548
|
-
return await window.craft.network.connectionType();
|
|
4549
|
-
return webConnectionType();
|
|
4550
|
-
},
|
|
4551
|
-
async wifiSSID() {
|
|
4552
|
-
if (hasBridge("network")) {
|
|
4553
|
-
const v = await window.craft.network.wifiSSID();
|
|
4554
|
-
return v || undefined;
|
|
4555
|
-
}
|
|
4556
|
-
return;
|
|
4557
|
-
},
|
|
4558
|
-
async wifiSignalStrength() {
|
|
4559
|
-
if (hasBridge("network")) {
|
|
4560
|
-
const v = await window.craft.network.wifiSignalStrength();
|
|
4561
|
-
return typeof v === "number" ? v : undefined;
|
|
4562
|
-
}
|
|
4563
|
-
return;
|
|
4564
|
-
},
|
|
4565
|
-
async ipAddress() {
|
|
4566
|
-
if (hasBridge("network"))
|
|
4567
|
-
return await window.craft.network.ipAddress();
|
|
4568
|
-
return "";
|
|
4569
|
-
},
|
|
4570
|
-
async macAddress() {
|
|
4571
|
-
if (hasBridge("network"))
|
|
4572
|
-
return await window.craft.network.macAddress();
|
|
4573
|
-
return "";
|
|
4574
|
-
},
|
|
4575
|
-
async interfaces() {
|
|
4576
|
-
if (hasBridge("network"))
|
|
4577
|
-
return await window.craft.network.interfaces();
|
|
4578
|
-
return [];
|
|
4579
|
-
},
|
|
4580
|
-
async isVPNConnected() {
|
|
4581
|
-
if (hasBridge("network"))
|
|
4582
|
-
return await window.craft.network.isVPNConnected();
|
|
4583
|
-
return false;
|
|
4584
|
-
},
|
|
4585
|
-
async proxySettings() {
|
|
4586
|
-
if (hasBridge("network")) {
|
|
4587
|
-
const r = await window.craft.network.proxySettings();
|
|
4588
|
-
return r || {};
|
|
4589
|
-
}
|
|
4590
|
-
return {};
|
|
4591
|
-
},
|
|
4592
|
-
async openPreferences() {
|
|
4593
|
-
if (hasBridge("network"))
|
|
4594
|
-
await window.craft.network.openPreferences();
|
|
4595
|
-
},
|
|
4596
|
-
onChange(cb) {
|
|
4597
|
-
if (hasBridge("network")) {
|
|
4598
|
-
return onCraftEvent("craft:networkChange", cb);
|
|
4599
|
-
}
|
|
4600
|
-
if (typeof window === "undefined")
|
|
4601
|
-
return () => {};
|
|
4602
|
-
const onlineH = () => cb({ type: webConnectionType(), online: true });
|
|
4603
|
-
const offlineH = () => cb({ type: "none", online: false });
|
|
4604
|
-
window.addEventListener("online", onlineH);
|
|
4605
|
-
window.addEventListener("offline", offlineH);
|
|
4606
|
-
return () => {
|
|
4607
|
-
window.removeEventListener("online", onlineH);
|
|
4608
|
-
window.removeEventListener("offline", offlineH);
|
|
4609
|
-
};
|
|
4610
|
-
}
|
|
4611
|
-
};
|
|
4612
|
-
function webConnectionType() {
|
|
4613
|
-
if (typeof navigator === "undefined")
|
|
4614
|
-
return "unknown";
|
|
4615
|
-
if (navigator.onLine === false)
|
|
4616
|
-
return "none";
|
|
4617
|
-
const conn = navigator.connection;
|
|
4618
|
-
if (!conn)
|
|
4619
|
-
return "unknown";
|
|
4620
|
-
const t = String(conn.type || conn.effectiveType || "unknown").toLowerCase();
|
|
4621
|
-
if (t === "wifi" || t === "cellular" || t === "ethernet" || t === "bluetooth" || t === "none")
|
|
4622
|
-
return t;
|
|
4623
|
-
return "unknown";
|
|
4624
|
-
}
|
|
4625
|
-
// src/updater.ts
|
|
4626
|
-
var updater = {
|
|
4627
|
-
async checkForUpdates() {
|
|
4628
|
-
if (!hasBridge("updater"))
|
|
4629
|
-
return;
|
|
4630
|
-
await window.craft.updater.checkForUpdates();
|
|
4631
|
-
},
|
|
4632
|
-
async checkInBackground() {
|
|
4633
|
-
if (!hasBridge("updater"))
|
|
4634
|
-
return;
|
|
4635
|
-
await window.craft.updater.checkInBackground();
|
|
4636
|
-
},
|
|
4637
|
-
async setAutomaticChecks(on) {
|
|
4638
|
-
if (!hasBridge("updater"))
|
|
4639
|
-
return;
|
|
4640
|
-
await window.craft.updater.setAutomaticChecks(on);
|
|
4641
|
-
},
|
|
4642
|
-
async setCheckInterval(seconds) {
|
|
4643
|
-
if (!hasBridge("updater"))
|
|
4644
|
-
return;
|
|
4645
|
-
if (!Number.isFinite(seconds)) {
|
|
4646
|
-
throw new Error("setCheckInterval: must be a finite number");
|
|
4647
|
-
}
|
|
4648
|
-
const safe = seconds <= 0 ? 0 : Math.max(60, Math.round(seconds));
|
|
4649
|
-
await window.craft.updater.setCheckInterval(safe);
|
|
4650
|
-
},
|
|
4651
|
-
async setFeedURL(url) {
|
|
4652
|
-
if (!hasBridge("updater"))
|
|
4653
|
-
return;
|
|
4654
|
-
await window.craft.updater.setFeedURL(url);
|
|
4655
|
-
},
|
|
4656
|
-
async getLastUpdateCheckDate() {
|
|
4657
|
-
if (!hasBridge("updater"))
|
|
4658
|
-
return null;
|
|
4659
|
-
const v = await window.craft.updater.getLastUpdateCheckDate();
|
|
4660
|
-
return v || null;
|
|
4661
|
-
},
|
|
4662
|
-
async getUpdateInfo() {
|
|
4663
|
-
if (!hasBridge("updater"))
|
|
4664
|
-
return null;
|
|
4665
|
-
const v = await window.craft.updater.getUpdateInfo();
|
|
4666
|
-
if (!v || typeof v.version !== "string" || v.version.length === 0)
|
|
4667
|
-
return null;
|
|
4668
|
-
return v;
|
|
4669
|
-
},
|
|
4670
|
-
onAvailable(cb) {
|
|
4671
|
-
return onCraftEvent("craft:updateAvailable", cb);
|
|
4672
|
-
},
|
|
4673
|
-
onDownloaded(cb) {
|
|
4674
|
-
return onCraftEvent("craft:updateDownloaded", cb);
|
|
4675
|
-
},
|
|
4676
|
-
async verifySignature({ payload, signatureB64, publicKeyB64 }) {
|
|
4677
|
-
const data = toArrayBufferBytes(payload);
|
|
4678
|
-
let publicKey;
|
|
4679
|
-
try {
|
|
4680
|
-
publicKey = await crypto.subtle.importKey("raw", base64ToBytes2(publicKeyB64), { name: "Ed25519" }, false, ["verify"]);
|
|
4681
|
-
} catch {
|
|
4682
|
-
return false;
|
|
4683
|
-
}
|
|
4684
|
-
try {
|
|
4685
|
-
return await crypto.subtle.verify("Ed25519", publicKey, base64ToBytes2(signatureB64), data);
|
|
4686
|
-
} catch {
|
|
4687
|
-
return false;
|
|
4688
|
-
}
|
|
4689
|
-
},
|
|
4690
|
-
async verifyDownload({ url, signatureB64, publicKeyB64, fetchInit }) {
|
|
4691
|
-
let response;
|
|
4692
|
-
try {
|
|
4693
|
-
response = await fetch(url, fetchInit);
|
|
4694
|
-
} catch {
|
|
4695
|
-
return { ok: false, reason: "fetch-failed" };
|
|
4696
|
-
}
|
|
4697
|
-
if (!response.ok) {
|
|
4698
|
-
return { ok: false, reason: "http-error", status: response.status };
|
|
4699
|
-
}
|
|
4700
|
-
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
4701
|
-
let publicKey;
|
|
4702
|
-
try {
|
|
4703
|
-
publicKey = await crypto.subtle.importKey("raw", base64ToBytes2(publicKeyB64), { name: "Ed25519" }, false, ["verify"]);
|
|
4704
|
-
} catch {
|
|
4705
|
-
return { ok: false, reason: "bad-key" };
|
|
4706
|
-
}
|
|
4707
|
-
let valid = false;
|
|
4708
|
-
try {
|
|
4709
|
-
valid = await crypto.subtle.verify("Ed25519", publicKey, base64ToBytes2(signatureB64), toArrayBufferBytes(buffer));
|
|
4710
|
-
} catch {
|
|
4711
|
-
valid = false;
|
|
4712
|
-
}
|
|
4713
|
-
if (!valid)
|
|
4714
|
-
return { ok: false, reason: "bad-signature" };
|
|
4715
|
-
return { ok: true, payload: buffer };
|
|
4716
|
-
}
|
|
4717
|
-
};
|
|
4718
|
-
function toArrayBufferBytes(input) {
|
|
4719
|
-
if (input instanceof ArrayBuffer)
|
|
4720
|
-
return new Uint8Array(input);
|
|
4721
|
-
const out = new ArrayBuffer(input.byteLength);
|
|
4722
|
-
const view = new Uint8Array(out);
|
|
4723
|
-
view.set(input);
|
|
4724
|
-
return view;
|
|
4725
|
-
}
|
|
4726
|
-
function base64ToBytes2(b64) {
|
|
4727
|
-
if (typeof atob === "function") {
|
|
4728
|
-
const bin = atob(b64);
|
|
4729
|
-
const buffer = new ArrayBuffer(bin.length);
|
|
4730
|
-
const out = new Uint8Array(buffer);
|
|
4731
|
-
for (let i = 0;i < bin.length; i++)
|
|
4732
|
-
out[i] = bin.charCodeAt(i);
|
|
4733
|
-
return out;
|
|
4734
|
-
}
|
|
4735
|
-
const node = Buffer.from(b64, "base64");
|
|
4736
|
-
const buf = new ArrayBuffer(node.length);
|
|
4737
|
-
new Uint8Array(buf).set(node);
|
|
4738
|
-
return new Uint8Array(buf);
|
|
4739
|
-
}
|
|
4740
|
-
// src/window-events.ts
|
|
4741
|
-
var windowEvents = {
|
|
4742
|
-
onFocus(cb) {
|
|
4743
|
-
if (hasBridge("window"))
|
|
4744
|
-
return onCraftEvent("craft:window:focus", () => cb());
|
|
4745
|
-
return webEvent("focus", cb);
|
|
4746
|
-
},
|
|
4747
|
-
onBlur(cb) {
|
|
4748
|
-
if (hasBridge("window"))
|
|
4749
|
-
return onCraftEvent("craft:window:blur", () => cb());
|
|
4750
|
-
return webEvent("blur", cb);
|
|
4751
|
-
},
|
|
4752
|
-
onResize(cb) {
|
|
4753
|
-
if (hasBridge("window"))
|
|
4754
|
-
return onCraftEvent("craft:window:resize", cb);
|
|
4755
|
-
if (typeof window === "undefined")
|
|
4756
|
-
return () => {};
|
|
4757
|
-
const h = () => cb({ width: window.innerWidth, height: window.innerHeight });
|
|
4758
|
-
window.addEventListener("resize", h);
|
|
4759
|
-
return () => window.removeEventListener("resize", h);
|
|
4760
|
-
},
|
|
4761
|
-
onMove(cb) {
|
|
4762
|
-
if (hasBridge("window"))
|
|
4763
|
-
return onCraftEvent("craft:window:move", cb);
|
|
4764
|
-
return () => {};
|
|
4765
|
-
},
|
|
4766
|
-
onClose(cb) {
|
|
4767
|
-
if (hasBridge("window"))
|
|
4768
|
-
return onCraftEvent("craft:window:close", () => cb());
|
|
4769
|
-
return webEvent("beforeunload", cb);
|
|
4770
|
-
},
|
|
4771
|
-
onMinimize(cb) {
|
|
4772
|
-
if (hasBridge("window"))
|
|
4773
|
-
return onCraftEvent("craft:window:minimize", () => cb());
|
|
4774
|
-
if (typeof document === "undefined")
|
|
4775
|
-
return () => {};
|
|
4776
|
-
const h = () => {
|
|
4777
|
-
if (document.visibilityState === "hidden")
|
|
4778
|
-
cb();
|
|
4779
|
-
};
|
|
4780
|
-
document.addEventListener("visibilitychange", h);
|
|
4781
|
-
return () => document.removeEventListener("visibilitychange", h);
|
|
4782
|
-
},
|
|
4783
|
-
onRestore(cb) {
|
|
4784
|
-
if (hasBridge("window"))
|
|
4785
|
-
return onCraftEvent("craft:window:restore", () => cb());
|
|
4786
|
-
if (typeof document === "undefined")
|
|
4787
|
-
return () => {};
|
|
4788
|
-
const h = () => {
|
|
4789
|
-
if (document.visibilityState === "visible")
|
|
4790
|
-
cb();
|
|
4791
|
-
};
|
|
4792
|
-
document.addEventListener("visibilitychange", h);
|
|
4793
|
-
return () => document.removeEventListener("visibilitychange", h);
|
|
4794
|
-
}
|
|
4795
|
-
};
|
|
4796
|
-
function webEvent(name, cb) {
|
|
4797
|
-
if (typeof window === "undefined")
|
|
4798
|
-
return () => {};
|
|
4799
|
-
const h = () => cb();
|
|
4800
|
-
window.addEventListener(name, h);
|
|
4801
|
-
return () => window.removeEventListener(name, h);
|
|
4802
|
-
}
|
|
4803
|
-
// src/app-info.ts
|
|
4804
|
-
var DEFAULT_INFO = { name: "", version: "0.0.0" };
|
|
4805
|
-
var app = {
|
|
4806
|
-
async hideDockIcon() {
|
|
4807
|
-
if (hasBridge("app"))
|
|
4808
|
-
await window.craft.app.hideDockIcon();
|
|
4809
|
-
},
|
|
4810
|
-
async showDockIcon() {
|
|
4811
|
-
if (hasBridge("app"))
|
|
4812
|
-
await window.craft.app.showDockIcon();
|
|
4813
|
-
},
|
|
4814
|
-
async quit() {
|
|
4815
|
-
if (hasBridge("app"))
|
|
4816
|
-
await window.craft.app.quit();
|
|
4817
|
-
},
|
|
4818
|
-
async getInfo() {
|
|
4819
|
-
if (!hasBridge("app"))
|
|
4820
|
-
return DEFAULT_INFO;
|
|
4821
|
-
const r = await window.craft.app.getInfo();
|
|
4822
|
-
return { ...DEFAULT_INFO, ...r || {} };
|
|
4823
|
-
},
|
|
4824
|
-
async notify(options) {
|
|
4825
|
-
if (!options.title)
|
|
4826
|
-
throw new Error("notify: title is required");
|
|
4827
|
-
if (hasBridge("app"))
|
|
4828
|
-
await window.craft.app.notify(options);
|
|
4829
|
-
},
|
|
4830
|
-
async setBadge(count) {
|
|
4831
|
-
if (hasBridge("app"))
|
|
4832
|
-
await window.craft.app.setBadge(count);
|
|
4833
|
-
},
|
|
4834
|
-
async bounce(type = "informational") {
|
|
4835
|
-
if (hasBridge("app"))
|
|
4836
|
-
await window.craft.app.bounce(type);
|
|
4837
|
-
}
|
|
4838
|
-
};
|
|
4839
|
-
// src/menu.ts
|
|
4840
|
-
var menu = {
|
|
4841
|
-
async set(items) {
|
|
4842
|
-
if (hasBridge("menu"))
|
|
4843
|
-
await window.craft.menu.set(items);
|
|
4844
|
-
},
|
|
4845
|
-
async setDock(items) {
|
|
4846
|
-
if (hasBridge("menu"))
|
|
4847
|
-
await window.craft.menu.setDock(items);
|
|
4848
|
-
},
|
|
4849
|
-
async addItem(parent, item) {
|
|
4850
|
-
if (hasBridge("menu"))
|
|
4851
|
-
await window.craft.menu.addItem(parent, item);
|
|
4852
|
-
},
|
|
4853
|
-
async removeItem(id) {
|
|
4854
|
-
if (hasBridge("menu"))
|
|
4855
|
-
await window.craft.menu.removeItem(id);
|
|
4856
|
-
},
|
|
4857
|
-
async enableItem(id) {
|
|
4858
|
-
if (hasBridge("menu"))
|
|
4859
|
-
await window.craft.menu.enableItem(id);
|
|
4860
|
-
},
|
|
4861
|
-
async disableItem(id) {
|
|
4862
|
-
if (hasBridge("menu"))
|
|
4863
|
-
await window.craft.menu.disableItem(id);
|
|
4864
|
-
},
|
|
4865
|
-
async checkItem(id) {
|
|
4866
|
-
if (hasBridge("menu"))
|
|
4867
|
-
await window.craft.menu.checkItem(id);
|
|
4868
|
-
},
|
|
4869
|
-
async uncheckItem(id) {
|
|
4870
|
-
if (hasBridge("menu"))
|
|
4871
|
-
await window.craft.menu.uncheckItem(id);
|
|
4872
|
-
},
|
|
4873
|
-
async setItemLabel(id, lbl) {
|
|
4874
|
-
if (hasBridge("menu"))
|
|
4875
|
-
await window.craft.menu.setItemLabel(id, lbl);
|
|
4876
|
-
},
|
|
4877
|
-
async clearDock() {
|
|
4878
|
-
if (hasBridge("menu"))
|
|
4879
|
-
await window.craft.menu.clearDock();
|
|
4880
|
-
},
|
|
4881
|
-
onAction(cb) {
|
|
4882
|
-
return onCraftEvent("craft:menu:action", cb);
|
|
4883
|
-
}
|
|
4884
|
-
};
|
|
4885
|
-
// src/system.ts
|
|
4886
|
-
var system = {
|
|
4887
|
-
accentColor: () => bridgeOr("system", "accentColor", () => ""),
|
|
4888
|
-
highlightColor: () => bridgeOr("system", "highlightColor", () => ""),
|
|
4889
|
-
language: () => bridgeOr("system", "language", () => {
|
|
4890
|
-
if (typeof navigator === "undefined")
|
|
4891
|
-
return "";
|
|
4892
|
-
return navigator.language?.split("-")[0] || "";
|
|
4893
|
-
}),
|
|
4894
|
-
locale: () => bridgeOr("system", "locale", () => {
|
|
4895
|
-
if (typeof navigator === "undefined")
|
|
4896
|
-
return "";
|
|
4897
|
-
return navigator.language || "";
|
|
4898
|
-
}),
|
|
4899
|
-
timezone: () => bridgeOr("system", "timezone", () => {
|
|
4900
|
-
try {
|
|
4901
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone || "";
|
|
4902
|
-
} catch {
|
|
4903
|
-
return "";
|
|
2533
|
+
// src/system.ts
|
|
2534
|
+
var system = {
|
|
2535
|
+
accentColor: () => bridgeOr("system", "accentColor", () => ""),
|
|
2536
|
+
highlightColor: () => bridgeOr("system", "highlightColor", () => ""),
|
|
2537
|
+
language: () => bridgeOr("system", "language", () => {
|
|
2538
|
+
if (typeof navigator === "undefined")
|
|
2539
|
+
return "";
|
|
2540
|
+
return navigator.language?.split("-")[0] || "";
|
|
2541
|
+
}),
|
|
2542
|
+
locale: () => bridgeOr("system", "locale", () => {
|
|
2543
|
+
if (typeof navigator === "undefined")
|
|
2544
|
+
return "";
|
|
2545
|
+
return navigator.language || "";
|
|
2546
|
+
}),
|
|
2547
|
+
timezone: () => bridgeOr("system", "timezone", () => {
|
|
2548
|
+
try {
|
|
2549
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "";
|
|
2550
|
+
} catch {
|
|
2551
|
+
return "";
|
|
4904
2552
|
}
|
|
4905
2553
|
}),
|
|
4906
2554
|
is24HourTime: () => bridgeOr("system", "is24HourTime", () => {
|
|
@@ -4932,1445 +2580,6 @@ function mediaMatches(query) {
|
|
|
4932
2580
|
return false;
|
|
4933
2581
|
return window.matchMedia(query).matches;
|
|
4934
2582
|
}
|
|
4935
|
-
// src/screen.ts
|
|
4936
|
-
var screen = {
|
|
4937
|
-
async getDisplays() {
|
|
4938
|
-
if (hasBridge("screen"))
|
|
4939
|
-
return await window.craft.screen.getDisplays();
|
|
4940
|
-
return webDisplays();
|
|
4941
|
-
},
|
|
4942
|
-
async getPrimary() {
|
|
4943
|
-
if (hasBridge("screen")) {
|
|
4944
|
-
const r = await window.craft.screen.getPrimary();
|
|
4945
|
-
return r && typeof r.width === "number" ? r : null;
|
|
4946
|
-
}
|
|
4947
|
-
return webDisplays()[0] ?? null;
|
|
4948
|
-
},
|
|
4949
|
-
onChange(cb) {
|
|
4950
|
-
if (hasBridge("screen"))
|
|
4951
|
-
return onCraftEvent("craft:screen:change", () => cb());
|
|
4952
|
-
if (typeof window === "undefined")
|
|
4953
|
-
return () => {};
|
|
4954
|
-
const h = () => cb();
|
|
4955
|
-
window.addEventListener("resize", h);
|
|
4956
|
-
return () => window.removeEventListener("resize", h);
|
|
4957
|
-
}
|
|
4958
|
-
};
|
|
4959
|
-
function webDisplays() {
|
|
4960
|
-
if (typeof window === "undefined" || !window.screen)
|
|
4961
|
-
return [];
|
|
4962
|
-
const s = window.screen;
|
|
4963
|
-
return [{
|
|
4964
|
-
id: 0,
|
|
4965
|
-
x: s.left ?? 0,
|
|
4966
|
-
y: s.top ?? 0,
|
|
4967
|
-
width: s.width || 0,
|
|
4968
|
-
height: s.height || 0,
|
|
4969
|
-
workX: s.availLeft ?? 0,
|
|
4970
|
-
workY: s.availTop ?? 0,
|
|
4971
|
-
workWidth: s.availWidth ?? s.width ?? 0,
|
|
4972
|
-
workHeight: s.availHeight ?? s.height ?? 0,
|
|
4973
|
-
scaleFactor: window.devicePixelRatio || 1
|
|
4974
|
-
}];
|
|
4975
|
-
}
|
|
4976
|
-
// src/keychain.ts
|
|
4977
|
-
var keychain = {
|
|
4978
|
-
async set(service, account, password) {
|
|
4979
|
-
if (!service)
|
|
4980
|
-
throw new Error("keychain.set: service is required");
|
|
4981
|
-
if (!account)
|
|
4982
|
-
throw new Error("keychain.set: account is required");
|
|
4983
|
-
await requireBridge("keychain").set(service, account, password);
|
|
4984
|
-
},
|
|
4985
|
-
async get(service, account) {
|
|
4986
|
-
if (!service)
|
|
4987
|
-
throw new Error("keychain.get: service is required");
|
|
4988
|
-
if (!account)
|
|
4989
|
-
throw new Error("keychain.get: account is required");
|
|
4990
|
-
const v = await requireBridge("keychain").get(service, account);
|
|
4991
|
-
return typeof v === "string" ? v : null;
|
|
4992
|
-
},
|
|
4993
|
-
async delete(service, account) {
|
|
4994
|
-
if (!service)
|
|
4995
|
-
throw new Error("keychain.delete: service is required");
|
|
4996
|
-
if (!account)
|
|
4997
|
-
throw new Error("keychain.delete: account is required");
|
|
4998
|
-
await requireBridge("keychain").delete(service, account);
|
|
4999
|
-
},
|
|
5000
|
-
async has(service, account) {
|
|
5001
|
-
if (!service)
|
|
5002
|
-
throw new Error("keychain.has: service is required");
|
|
5003
|
-
if (!account)
|
|
5004
|
-
throw new Error("keychain.has: account is required");
|
|
5005
|
-
return await requireBridge("keychain").has(service, account);
|
|
5006
|
-
}
|
|
5007
|
-
};
|
|
5008
|
-
// src/permissions.ts
|
|
5009
|
-
var permissions = {
|
|
5010
|
-
async check(name) {
|
|
5011
|
-
if (hasBridge("permissions"))
|
|
5012
|
-
return await window.craft.permissions.check(name);
|
|
5013
|
-
return await webCheck(name);
|
|
5014
|
-
},
|
|
5015
|
-
async request(name) {
|
|
5016
|
-
if (hasBridge("permissions"))
|
|
5017
|
-
return await window.craft.permissions.request(name);
|
|
5018
|
-
return await webRequest(name);
|
|
5019
|
-
},
|
|
5020
|
-
async openSettings(name) {
|
|
5021
|
-
if (hasBridge("permissions"))
|
|
5022
|
-
await window.craft.permissions.openSettings(name);
|
|
5023
|
-
}
|
|
5024
|
-
};
|
|
5025
|
-
async function webCheck(name) {
|
|
5026
|
-
if (typeof navigator === "undefined" || !navigator.permissions?.query)
|
|
5027
|
-
return "not-supported";
|
|
5028
|
-
try {
|
|
5029
|
-
const result = await navigator.permissions.query({ name });
|
|
5030
|
-
return mapWebState(result.state);
|
|
5031
|
-
} catch {
|
|
5032
|
-
return "not-supported";
|
|
5033
|
-
}
|
|
5034
|
-
}
|
|
5035
|
-
async function webRequest(name) {
|
|
5036
|
-
if (name === "notifications" && typeof window !== "undefined" && "Notification" in window) {
|
|
5037
|
-
const r = await window.Notification.requestPermission();
|
|
5038
|
-
return r === "granted" ? "granted" : r === "denied" ? "denied" : "undetermined";
|
|
5039
|
-
}
|
|
5040
|
-
return await webCheck(name);
|
|
5041
|
-
}
|
|
5042
|
-
function mapWebState(s) {
|
|
5043
|
-
if (s === "granted")
|
|
5044
|
-
return "granted";
|
|
5045
|
-
if (s === "denied")
|
|
5046
|
-
return "denied";
|
|
5047
|
-
if (s === "prompt")
|
|
5048
|
-
return "undetermined";
|
|
5049
|
-
return "undetermined";
|
|
5050
|
-
}
|
|
5051
|
-
// src/printing.ts
|
|
5052
|
-
var printing = {
|
|
5053
|
-
async print() {
|
|
5054
|
-
if (hasBridge("printing")) {
|
|
5055
|
-
await window.craft.printing.print();
|
|
5056
|
-
return;
|
|
5057
|
-
}
|
|
5058
|
-
if (typeof window !== "undefined" && typeof window.print === "function") {
|
|
5059
|
-
window.print();
|
|
5060
|
-
}
|
|
5061
|
-
},
|
|
5062
|
-
async printToPDF(path) {
|
|
5063
|
-
if (!path)
|
|
5064
|
-
throw new Error("printToPDF: path is required");
|
|
5065
|
-
const isPosixAbs = path.startsWith("/");
|
|
5066
|
-
const isWinAbs = /^[a-zA-Z]:[\\/]/.test(path) || path.startsWith("\\\\");
|
|
5067
|
-
if (!isPosixAbs && !isWinAbs) {
|
|
5068
|
-
throw new Error("printToPDF: path must be absolute");
|
|
5069
|
-
}
|
|
5070
|
-
const r = await requireBridge("printing").printToPDF(path);
|
|
5071
|
-
return { ok: !!(r && r.ok), path: r?.path };
|
|
5072
|
-
}
|
|
5073
|
-
};
|
|
5074
|
-
// src/native-autolaunch.ts
|
|
5075
|
-
var nativeAutoLaunch = {
|
|
5076
|
-
async enable() {
|
|
5077
|
-
if (!hasBridge("autoLaunch"))
|
|
5078
|
-
return false;
|
|
5079
|
-
return await window.craft.autoLaunch.enable();
|
|
5080
|
-
},
|
|
5081
|
-
async disable() {
|
|
5082
|
-
if (!hasBridge("autoLaunch"))
|
|
5083
|
-
return false;
|
|
5084
|
-
return await window.craft.autoLaunch.disable();
|
|
5085
|
-
},
|
|
5086
|
-
async isEnabled() {
|
|
5087
|
-
if (!hasBridge("autoLaunch"))
|
|
5088
|
-
return false;
|
|
5089
|
-
return await window.craft.autoLaunch.isEnabled();
|
|
5090
|
-
}
|
|
5091
|
-
};
|
|
5092
|
-
// src/touchbar.ts
|
|
5093
|
-
var touchbar = {
|
|
5094
|
-
async addItem(item) {
|
|
5095
|
-
if (hasBridge("touchbar"))
|
|
5096
|
-
await window.craft.touchbar.addItem(item);
|
|
5097
|
-
},
|
|
5098
|
-
async removeItem(id) {
|
|
5099
|
-
if (hasBridge("touchbar"))
|
|
5100
|
-
await window.craft.touchbar.removeItem(id);
|
|
5101
|
-
},
|
|
5102
|
-
async updateItem(id, props) {
|
|
5103
|
-
if (hasBridge("touchbar"))
|
|
5104
|
-
await window.craft.touchbar.updateItem(id, props);
|
|
5105
|
-
},
|
|
5106
|
-
async setLabel(id, label) {
|
|
5107
|
-
if (hasBridge("touchbar"))
|
|
5108
|
-
await window.craft.touchbar.setLabel(id, label);
|
|
5109
|
-
},
|
|
5110
|
-
async setIcon(id, icon) {
|
|
5111
|
-
if (hasBridge("touchbar"))
|
|
5112
|
-
await window.craft.touchbar.setIcon(id, icon);
|
|
5113
|
-
},
|
|
5114
|
-
async setEnabled(id, enabled) {
|
|
5115
|
-
if (hasBridge("touchbar"))
|
|
5116
|
-
await window.craft.touchbar.setEnabled(id, enabled);
|
|
5117
|
-
},
|
|
5118
|
-
async setSliderValue(id, value) {
|
|
5119
|
-
if (hasBridge("touchbar"))
|
|
5120
|
-
await window.craft.touchbar.setSliderValue(id, value);
|
|
5121
|
-
},
|
|
5122
|
-
async clear() {
|
|
5123
|
-
if (hasBridge("touchbar"))
|
|
5124
|
-
await window.craft.touchbar.clear();
|
|
5125
|
-
},
|
|
5126
|
-
async show() {
|
|
5127
|
-
if (hasBridge("touchbar"))
|
|
5128
|
-
await window.craft.touchbar.show();
|
|
5129
|
-
},
|
|
5130
|
-
async hide() {
|
|
5131
|
-
if (hasBridge("touchbar"))
|
|
5132
|
-
await window.craft.touchbar.hide();
|
|
5133
|
-
},
|
|
5134
|
-
onAction(cb) {
|
|
5135
|
-
return onCraftEvent("craft:touchbar:action", cb);
|
|
5136
|
-
}
|
|
5137
|
-
};
|
|
5138
|
-
// src/bluetooth.ts
|
|
5139
|
-
var HEX_RE = /^[\da-f]*$/i;
|
|
5140
|
-
function assertHex(label, hex) {
|
|
5141
|
-
if (typeof hex !== "string" || !HEX_RE.test(hex) || hex.length % 2 !== 0) {
|
|
5142
|
-
throw new Error(`${label}: must be a hex string with even length, got ${JSON.stringify(hex)}`);
|
|
5143
|
-
}
|
|
5144
|
-
}
|
|
5145
|
-
var bluetooth = {
|
|
5146
|
-
async isEnabled() {
|
|
5147
|
-
return hasBridge("bluetooth") ? await window.craft.bluetooth.isEnabled() : false;
|
|
5148
|
-
},
|
|
5149
|
-
async powerState() {
|
|
5150
|
-
return hasBridge("bluetooth") ? await window.craft.bluetooth.powerState() : "unknown";
|
|
5151
|
-
},
|
|
5152
|
-
async connectedDevices() {
|
|
5153
|
-
return hasBridge("bluetooth") ? await window.craft.bluetooth.connectedDevices() : [];
|
|
5154
|
-
},
|
|
5155
|
-
async pairedDevices() {
|
|
5156
|
-
return hasBridge("bluetooth") ? await window.craft.bluetooth.pairedDevices() : [];
|
|
5157
|
-
},
|
|
5158
|
-
async startDiscovery() {
|
|
5159
|
-
if (hasBridge("bluetooth"))
|
|
5160
|
-
await window.craft.bluetooth.startDiscovery();
|
|
5161
|
-
},
|
|
5162
|
-
async stopDiscovery() {
|
|
5163
|
-
if (hasBridge("bluetooth"))
|
|
5164
|
-
await window.craft.bluetooth.stopDiscovery();
|
|
5165
|
-
},
|
|
5166
|
-
async isDiscovering() {
|
|
5167
|
-
return hasBridge("bluetooth") ? await window.craft.bluetooth.isDiscovering() : false;
|
|
5168
|
-
},
|
|
5169
|
-
async connect(id) {
|
|
5170
|
-
if (hasBridge("bluetooth"))
|
|
5171
|
-
await window.craft.bluetooth.connect(id);
|
|
5172
|
-
},
|
|
5173
|
-
async disconnect(id) {
|
|
5174
|
-
if (hasBridge("bluetooth"))
|
|
5175
|
-
await window.craft.bluetooth.disconnect(id);
|
|
5176
|
-
},
|
|
5177
|
-
async openPreferences() {
|
|
5178
|
-
if (hasBridge("bluetooth"))
|
|
5179
|
-
await window.craft.bluetooth.openPreferences();
|
|
5180
|
-
},
|
|
5181
|
-
async discoverServices(deviceId) {
|
|
5182
|
-
if (!deviceId)
|
|
5183
|
-
throw new Error("bluetooth.discoverServices: deviceId is required");
|
|
5184
|
-
if (!hasBridge("bluetooth"))
|
|
5185
|
-
return [];
|
|
5186
|
-
const r = await window.craft.bluetooth.discoverServices(deviceId);
|
|
5187
|
-
return Array.isArray(r) ? r : [];
|
|
5188
|
-
},
|
|
5189
|
-
async discoverCharacteristics(deviceId, serviceUuid) {
|
|
5190
|
-
if (!deviceId || !serviceUuid)
|
|
5191
|
-
throw new Error("bluetooth.discoverCharacteristics: deviceId and serviceUuid are required");
|
|
5192
|
-
if (!hasBridge("bluetooth"))
|
|
5193
|
-
return [];
|
|
5194
|
-
const r = await window.craft.bluetooth.discoverCharacteristics(deviceId, serviceUuid);
|
|
5195
|
-
return Array.isArray(r) ? r : [];
|
|
5196
|
-
},
|
|
5197
|
-
async readCharacteristic(deviceId, serviceUuid, characteristicUuid) {
|
|
5198
|
-
if (!deviceId || !serviceUuid || !characteristicUuid) {
|
|
5199
|
-
throw new Error("bluetooth.readCharacteristic: deviceId, serviceUuid, characteristicUuid are required");
|
|
5200
|
-
}
|
|
5201
|
-
if (!hasBridge("bluetooth"))
|
|
5202
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
5203
|
-
return await window.craft.bluetooth.readCharacteristic(deviceId, serviceUuid, characteristicUuid);
|
|
5204
|
-
},
|
|
5205
|
-
async writeCharacteristic(deviceId, serviceUuid, characteristicUuid, valueHex, mode = "with-response") {
|
|
5206
|
-
if (!deviceId || !serviceUuid || !characteristicUuid) {
|
|
5207
|
-
throw new Error("bluetooth.writeCharacteristic: deviceId, serviceUuid, characteristicUuid are required");
|
|
5208
|
-
}
|
|
5209
|
-
assertHex("bluetooth.writeCharacteristic.valueHex", valueHex);
|
|
5210
|
-
if (!hasBridge("bluetooth"))
|
|
5211
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
5212
|
-
return await window.craft.bluetooth.writeCharacteristic(deviceId, serviceUuid, characteristicUuid, valueHex, mode);
|
|
5213
|
-
},
|
|
5214
|
-
async setCharacteristicNotify(deviceId, serviceUuid, characteristicUuid, on) {
|
|
5215
|
-
if (!deviceId || !serviceUuid || !characteristicUuid) {
|
|
5216
|
-
throw new Error("bluetooth.setCharacteristicNotify: deviceId, serviceUuid, characteristicUuid are required");
|
|
5217
|
-
}
|
|
5218
|
-
if (!hasBridge("bluetooth"))
|
|
5219
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
5220
|
-
return await window.craft.bluetooth.setCharacteristicNotify(deviceId, serviceUuid, characteristicUuid, on);
|
|
5221
|
-
},
|
|
5222
|
-
onDeviceFound(cb) {
|
|
5223
|
-
return onCraftEvent("craft:bluetooth:deviceFound", cb);
|
|
5224
|
-
},
|
|
5225
|
-
onDeviceConnected(cb) {
|
|
5226
|
-
return onCraftEvent("craft:bluetooth:deviceConnected", cb);
|
|
5227
|
-
},
|
|
5228
|
-
onDeviceDisconnected(cb) {
|
|
5229
|
-
return onCraftEvent("craft:bluetooth:deviceDisconnected", cb);
|
|
5230
|
-
},
|
|
5231
|
-
onCharacteristicValue(cb) {
|
|
5232
|
-
return onCraftEvent("craft:bluetooth:characteristicValue", cb);
|
|
5233
|
-
}
|
|
5234
|
-
};
|
|
5235
|
-
// src/speech.ts
|
|
5236
|
-
var speech = {
|
|
5237
|
-
async speak(text, options) {
|
|
5238
|
-
if (!text)
|
|
5239
|
-
throw new Error("speech.speak: text is required");
|
|
5240
|
-
if (hasBridge("speech")) {
|
|
5241
|
-
await window.craft.speech.speak(text, options);
|
|
5242
|
-
return;
|
|
5243
|
-
}
|
|
5244
|
-
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5245
|
-
const u = new window.SpeechSynthesisUtterance(text);
|
|
5246
|
-
if (options) {
|
|
5247
|
-
if (options.rate != null)
|
|
5248
|
-
u.rate = options.rate;
|
|
5249
|
-
if (options.pitch != null)
|
|
5250
|
-
u.pitch = options.pitch;
|
|
5251
|
-
if (options.volume != null)
|
|
5252
|
-
u.volume = options.volume;
|
|
5253
|
-
if (options.voice) {
|
|
5254
|
-
const voices = window.speechSynthesis.getVoices();
|
|
5255
|
-
const match = voices.find((v) => v.voiceURI === options.voice || v.name === options.voice || v.lang === options.voice);
|
|
5256
|
-
if (match)
|
|
5257
|
-
u.voice = match;
|
|
5258
|
-
}
|
|
5259
|
-
}
|
|
5260
|
-
window.speechSynthesis.speak(u);
|
|
5261
|
-
}
|
|
5262
|
-
},
|
|
5263
|
-
async stop() {
|
|
5264
|
-
if (hasBridge("speech")) {
|
|
5265
|
-
await window.craft.speech.stop();
|
|
5266
|
-
return;
|
|
5267
|
-
}
|
|
5268
|
-
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5269
|
-
window.speechSynthesis.cancel();
|
|
5270
|
-
}
|
|
5271
|
-
},
|
|
5272
|
-
async pause() {
|
|
5273
|
-
if (hasBridge("speech")) {
|
|
5274
|
-
await window.craft.speech.pause();
|
|
5275
|
-
return;
|
|
5276
|
-
}
|
|
5277
|
-
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5278
|
-
window.speechSynthesis.pause();
|
|
5279
|
-
}
|
|
5280
|
-
},
|
|
5281
|
-
async resume() {
|
|
5282
|
-
if (hasBridge("speech")) {
|
|
5283
|
-
await window.craft.speech.resume();
|
|
5284
|
-
return;
|
|
5285
|
-
}
|
|
5286
|
-
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5287
|
-
window.speechSynthesis.resume();
|
|
5288
|
-
}
|
|
5289
|
-
},
|
|
5290
|
-
async isSpeaking() {
|
|
5291
|
-
if (hasBridge("speech"))
|
|
5292
|
-
return await window.craft.speech.isSpeaking();
|
|
5293
|
-
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5294
|
-
return !!window.speechSynthesis.speaking;
|
|
5295
|
-
}
|
|
5296
|
-
return false;
|
|
5297
|
-
},
|
|
5298
|
-
async getVoices() {
|
|
5299
|
-
if (hasBridge("speech"))
|
|
5300
|
-
return await window.craft.speech.getVoices();
|
|
5301
|
-
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5302
|
-
const raw = window.speechSynthesis.getVoices();
|
|
5303
|
-
return raw.map((v) => ({
|
|
5304
|
-
id: v.voiceURI || v.name,
|
|
5305
|
-
name: v.name,
|
|
5306
|
-
language: v.lang || "",
|
|
5307
|
-
quality: "default"
|
|
5308
|
-
}));
|
|
5309
|
-
}
|
|
5310
|
-
return [];
|
|
5311
|
-
}
|
|
5312
|
-
};
|
|
5313
|
-
// src/crash-reporter.ts
|
|
5314
|
-
var jsQueue = [];
|
|
5315
|
-
var jsEnabled = true;
|
|
5316
|
-
var jsUserId;
|
|
5317
|
-
var jsAppVersion;
|
|
5318
|
-
var crashReporter = {
|
|
5319
|
-
async report(entry) {
|
|
5320
|
-
if (hasBridge("crashReporter")) {
|
|
5321
|
-
await window.craft.crashReporter.report(entry);
|
|
5322
|
-
return;
|
|
5323
|
-
}
|
|
5324
|
-
if (!jsEnabled)
|
|
5325
|
-
return;
|
|
5326
|
-
const normalized = entry instanceof Error ? {
|
|
5327
|
-
timestamp: Date.now(),
|
|
5328
|
-
severity: "error",
|
|
5329
|
-
message: entry.message,
|
|
5330
|
-
source: "js",
|
|
5331
|
-
stack: entry.stack || "",
|
|
5332
|
-
userId: jsUserId,
|
|
5333
|
-
appVersion: jsAppVersion
|
|
5334
|
-
} : {
|
|
5335
|
-
timestamp: Date.now(),
|
|
5336
|
-
severity: entry.severity || "error",
|
|
5337
|
-
message: entry.message || "",
|
|
5338
|
-
source: entry.source || "js",
|
|
5339
|
-
stack: entry.stack || "",
|
|
5340
|
-
userId: jsUserId,
|
|
5341
|
-
appVersion: jsAppVersion
|
|
5342
|
-
};
|
|
5343
|
-
if (jsQueue.length >= 64)
|
|
5344
|
-
jsQueue.shift();
|
|
5345
|
-
jsQueue.push(normalized);
|
|
5346
|
-
},
|
|
5347
|
-
async flush() {
|
|
5348
|
-
if (hasBridge("crashReporter"))
|
|
5349
|
-
return await window.craft.crashReporter.flush();
|
|
5350
|
-
return [...jsQueue];
|
|
5351
|
-
},
|
|
5352
|
-
async clear() {
|
|
5353
|
-
if (hasBridge("crashReporter")) {
|
|
5354
|
-
await window.craft.crashReporter.clear();
|
|
5355
|
-
return;
|
|
5356
|
-
}
|
|
5357
|
-
jsQueue.length = 0;
|
|
5358
|
-
},
|
|
5359
|
-
async setEnabled(on) {
|
|
5360
|
-
if (hasBridge("crashReporter")) {
|
|
5361
|
-
await window.craft.crashReporter.setEnabled(on);
|
|
5362
|
-
return;
|
|
5363
|
-
}
|
|
5364
|
-
jsEnabled = on;
|
|
5365
|
-
},
|
|
5366
|
-
async isEnabled() {
|
|
5367
|
-
if (hasBridge("crashReporter"))
|
|
5368
|
-
return await window.craft.crashReporter.isEnabled();
|
|
5369
|
-
return jsEnabled;
|
|
5370
|
-
},
|
|
5371
|
-
async setUser(id) {
|
|
5372
|
-
if (hasBridge("crashReporter")) {
|
|
5373
|
-
await window.craft.crashReporter.setUser(id);
|
|
5374
|
-
return;
|
|
5375
|
-
}
|
|
5376
|
-
jsUserId = id || undefined;
|
|
5377
|
-
},
|
|
5378
|
-
async setAppVersion(version) {
|
|
5379
|
-
if (hasBridge("crashReporter")) {
|
|
5380
|
-
await window.craft.crashReporter.setAppVersion(version);
|
|
5381
|
-
return;
|
|
5382
|
-
}
|
|
5383
|
-
jsAppVersion = version || undefined;
|
|
5384
|
-
},
|
|
5385
|
-
attachGlobalHandlers() {
|
|
5386
|
-
if (hasBridge("crashReporter") && window.craft.crashReporter.attachGlobalHandlers) {
|
|
5387
|
-
return window.craft.crashReporter.attachGlobalHandlers();
|
|
5388
|
-
}
|
|
5389
|
-
if (typeof window === "undefined")
|
|
5390
|
-
return () => {};
|
|
5391
|
-
const errorH = (e) => {
|
|
5392
|
-
crashReporter.report({
|
|
5393
|
-
severity: "error",
|
|
5394
|
-
message: e.message,
|
|
5395
|
-
source: "js",
|
|
5396
|
-
stack: e.error?.stack || `${e.message}
|
|
5397
|
-
at ${e.filename}:${e.lineno}:${e.colno}`
|
|
5398
|
-
}).catch(() => {});
|
|
5399
|
-
};
|
|
5400
|
-
const rejectH = (e) => {
|
|
5401
|
-
const r = e.reason;
|
|
5402
|
-
crashReporter.report({
|
|
5403
|
-
severity: "error",
|
|
5404
|
-
message: r?.message || String(r),
|
|
5405
|
-
source: "js",
|
|
5406
|
-
stack: r?.stack || ""
|
|
5407
|
-
}).catch(() => {});
|
|
5408
|
-
};
|
|
5409
|
-
window.addEventListener("error", errorH);
|
|
5410
|
-
window.addEventListener("unhandledrejection", rejectH);
|
|
5411
|
-
return () => {
|
|
5412
|
-
window.removeEventListener("error", errorH);
|
|
5413
|
-
window.removeEventListener("unhandledrejection", rejectH);
|
|
5414
|
-
};
|
|
5415
|
-
},
|
|
5416
|
-
forwardTo(options) {
|
|
5417
|
-
return startForwarder(options);
|
|
5418
|
-
}
|
|
5419
|
-
};
|
|
5420
|
-
var DEFAULT_PERSIST_KEY = "craft:crashReporter:pending";
|
|
5421
|
-
var EMAIL_RE = /[\w.+-]+@[\w-]+\.[\w.-]+/g;
|
|
5422
|
-
var IPV4_RE = /\b(?:\d{1,3}\.){3}\d{1,3}\b/g;
|
|
5423
|
-
var HOME_PATH_RE = /\/(?:Users|home)\/[^\s/'"`]+/g;
|
|
5424
|
-
function redactPII(entry) {
|
|
5425
|
-
const scrub = (s) => s.replace(EMAIL_RE, "<email>").replace(IPV4_RE, "<ip>").replace(HOME_PATH_RE, "/<home>");
|
|
5426
|
-
return {
|
|
5427
|
-
...entry,
|
|
5428
|
-
message: scrub(entry.message),
|
|
5429
|
-
stack: scrub(entry.stack)
|
|
5430
|
-
};
|
|
5431
|
-
}
|
|
5432
|
-
async function signPayload(secret, body) {
|
|
5433
|
-
const enc = new TextEncoder;
|
|
5434
|
-
const key = await crypto.subtle.importKey("raw", enc.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
5435
|
-
const sig = await crypto.subtle.sign("HMAC", key, enc.encode(body));
|
|
5436
|
-
return [...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
5437
|
-
}
|
|
5438
|
-
function loadPersisted(key) {
|
|
5439
|
-
if (!key || typeof localStorage === "undefined")
|
|
5440
|
-
return [];
|
|
5441
|
-
try {
|
|
5442
|
-
const raw = localStorage.getItem(key);
|
|
5443
|
-
if (!raw)
|
|
5444
|
-
return [];
|
|
5445
|
-
const parsed = JSON.parse(raw);
|
|
5446
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
5447
|
-
} catch {
|
|
5448
|
-
return [];
|
|
5449
|
-
}
|
|
5450
|
-
}
|
|
5451
|
-
function savePersisted(key, entries) {
|
|
5452
|
-
if (!key || typeof localStorage === "undefined")
|
|
5453
|
-
return;
|
|
5454
|
-
try {
|
|
5455
|
-
if (entries.length === 0)
|
|
5456
|
-
localStorage.removeItem(key);
|
|
5457
|
-
else
|
|
5458
|
-
localStorage.setItem(key, JSON.stringify(entries));
|
|
5459
|
-
} catch {}
|
|
5460
|
-
}
|
|
5461
|
-
function startForwarder(options) {
|
|
5462
|
-
const {
|
|
5463
|
-
endpoint,
|
|
5464
|
-
intervalMs = 60000,
|
|
5465
|
-
signingSecret,
|
|
5466
|
-
redact = true,
|
|
5467
|
-
headers = {},
|
|
5468
|
-
maxRetries = 5,
|
|
5469
|
-
persistKey
|
|
5470
|
-
} = options;
|
|
5471
|
-
const storageKey = persistKey === null ? null : persistKey ?? DEFAULT_PERSIST_KEY;
|
|
5472
|
-
let pending = loadPersisted(storageKey);
|
|
5473
|
-
let stopped = false;
|
|
5474
|
-
let timer = null;
|
|
5475
|
-
let inFlight = null;
|
|
5476
|
-
const redactor = typeof redact === "function" ? redact : redact === false ? (e) => e : redactPII;
|
|
5477
|
-
async function postBatch(batch) {
|
|
5478
|
-
const body = JSON.stringify({ entries: batch });
|
|
5479
|
-
const requestHeaders = {
|
|
5480
|
-
"Content-Type": "application/json",
|
|
5481
|
-
...headers
|
|
5482
|
-
};
|
|
5483
|
-
if (signingSecret) {
|
|
5484
|
-
requestHeaders["X-Craft-Signature"] = await signPayload(signingSecret, body);
|
|
5485
|
-
}
|
|
5486
|
-
let attempt = 0;
|
|
5487
|
-
let delay2 = 1000;
|
|
5488
|
-
while (!stopped) {
|
|
5489
|
-
try {
|
|
5490
|
-
const res = await fetch(endpoint, { method: "POST", headers: requestHeaders, body });
|
|
5491
|
-
if (res.ok)
|
|
5492
|
-
return;
|
|
5493
|
-
if (res.status >= 400 && res.status < 500)
|
|
5494
|
-
return;
|
|
5495
|
-
throw new Error(`HTTP ${res.status}`);
|
|
5496
|
-
} catch (err) {
|
|
5497
|
-
attempt += 1;
|
|
5498
|
-
if (attempt > maxRetries) {
|
|
5499
|
-
pending = [...batch, ...pending];
|
|
5500
|
-
savePersisted(storageKey, pending);
|
|
5501
|
-
throw err;
|
|
5502
|
-
}
|
|
5503
|
-
await new Promise((r) => {
|
|
5504
|
-
setTimeout(r, delay2);
|
|
5505
|
-
});
|
|
5506
|
-
delay2 = Math.min(delay2 * 2, 60000);
|
|
5507
|
-
}
|
|
5508
|
-
}
|
|
5509
|
-
}
|
|
5510
|
-
async function drain() {
|
|
5511
|
-
if (stopped || inFlight)
|
|
5512
|
-
return inFlight ?? undefined;
|
|
5513
|
-
const fresh = await crashReporter.flush();
|
|
5514
|
-
if (fresh.length > 0)
|
|
5515
|
-
await crashReporter.clear();
|
|
5516
|
-
pending = [...pending, ...fresh.map((e) => redactor(e))];
|
|
5517
|
-
if (pending.length === 0)
|
|
5518
|
-
return;
|
|
5519
|
-
const batch = pending;
|
|
5520
|
-
pending = [];
|
|
5521
|
-
savePersisted(storageKey, pending);
|
|
5522
|
-
inFlight = postBatch(batch).catch(() => {}).finally(() => {
|
|
5523
|
-
inFlight = null;
|
|
5524
|
-
});
|
|
5525
|
-
return inFlight;
|
|
5526
|
-
}
|
|
5527
|
-
if (intervalMs > 0) {
|
|
5528
|
-
timer = setInterval(() => {
|
|
5529
|
-
drain().catch(() => {});
|
|
5530
|
-
}, intervalMs);
|
|
5531
|
-
}
|
|
5532
|
-
return {
|
|
5533
|
-
async flushNow() {
|
|
5534
|
-
await drain();
|
|
5535
|
-
},
|
|
5536
|
-
stop() {
|
|
5537
|
-
stopped = true;
|
|
5538
|
-
if (timer)
|
|
5539
|
-
clearInterval(timer);
|
|
5540
|
-
timer = null;
|
|
5541
|
-
},
|
|
5542
|
-
pending() {
|
|
5543
|
-
return [...pending];
|
|
5544
|
-
}
|
|
5545
|
-
};
|
|
5546
|
-
}
|
|
5547
|
-
// src/iap.ts
|
|
5548
|
-
var iap = {
|
|
5549
|
-
async isAvailable() {
|
|
5550
|
-
if (!hasBridge("iap"))
|
|
5551
|
-
return false;
|
|
5552
|
-
return await window.craft.iap.isAvailable();
|
|
5553
|
-
},
|
|
5554
|
-
async getProducts(ids) {
|
|
5555
|
-
if (!hasBridge("iap"))
|
|
5556
|
-
return [];
|
|
5557
|
-
const arr = Array.isArray(ids) ? ids : [String(ids)];
|
|
5558
|
-
return await window.craft.iap.getProducts(arr);
|
|
5559
|
-
},
|
|
5560
|
-
async purchase(productId) {
|
|
5561
|
-
if (!hasBridge("iap"))
|
|
5562
|
-
return { queued: false, productId, reason: "IAP bridge not available" };
|
|
5563
|
-
const r = await window.craft.iap.purchase(productId);
|
|
5564
|
-
return { queued: !!(r && r.queued), productId: r?.productId, reason: r?.reason };
|
|
5565
|
-
},
|
|
5566
|
-
async restorePurchases() {
|
|
5567
|
-
if (!hasBridge("iap"))
|
|
5568
|
-
return { ok: false };
|
|
5569
|
-
const r = await window.craft.iap.restorePurchases();
|
|
5570
|
-
return { ok: !!(r && r.ok) };
|
|
5571
|
-
},
|
|
5572
|
-
async finishTransaction(transactionId) {
|
|
5573
|
-
if (!hasBridge("iap"))
|
|
5574
|
-
return;
|
|
5575
|
-
await window.craft.iap.finishTransaction(transactionId);
|
|
5576
|
-
},
|
|
5577
|
-
async getReceiptData() {
|
|
5578
|
-
if (!hasBridge("iap"))
|
|
5579
|
-
return null;
|
|
5580
|
-
const r = await window.craft.iap.getReceiptData();
|
|
5581
|
-
return r ? String(r) : null;
|
|
5582
|
-
},
|
|
5583
|
-
onPurchased(cb) {
|
|
5584
|
-
return onCraftEvent("craft:iap:purchased", cb);
|
|
5585
|
-
},
|
|
5586
|
-
onFailed(cb) {
|
|
5587
|
-
return onCraftEvent("craft:iap:failed", cb);
|
|
5588
|
-
},
|
|
5589
|
-
onRestored(cb) {
|
|
5590
|
-
return onCraftEvent("craft:iap:restored", cb);
|
|
5591
|
-
},
|
|
5592
|
-
onProductsLoaded(cb) {
|
|
5593
|
-
return onCraftEvent("craft:iap:productsLoaded", (e) => cb(e.products || []));
|
|
5594
|
-
},
|
|
5595
|
-
onRefunded(cb) {
|
|
5596
|
-
return onCraftEvent("craft:iap:refunded", cb);
|
|
5597
|
-
},
|
|
5598
|
-
onSubscriptionStatusChanged(cb) {
|
|
5599
|
-
return onCraftEvent("craft:iap:subscriptionStatusChanged", cb);
|
|
5600
|
-
},
|
|
5601
|
-
async getActiveSubscriptions() {
|
|
5602
|
-
if (!hasBridge("iap"))
|
|
5603
|
-
return [];
|
|
5604
|
-
const fn = window.craft.iap.getActiveSubscriptions;
|
|
5605
|
-
if (typeof fn !== "function")
|
|
5606
|
-
return [];
|
|
5607
|
-
const r = await fn();
|
|
5608
|
-
return Array.isArray(r) ? r : [];
|
|
5609
|
-
},
|
|
5610
|
-
async isEligibleForIntroOffer(productId) {
|
|
5611
|
-
if (!hasBridge("iap"))
|
|
5612
|
-
return false;
|
|
5613
|
-
const fn = window.craft.iap.isEligibleForIntroOffer;
|
|
5614
|
-
if (typeof fn !== "function")
|
|
5615
|
-
return false;
|
|
5616
|
-
return !!await fn(productId);
|
|
5617
|
-
}
|
|
5618
|
-
};
|
|
5619
|
-
// src/handoff.ts
|
|
5620
|
-
var handoff = {
|
|
5621
|
-
async startActivity(type, options) {
|
|
5622
|
-
if (!type)
|
|
5623
|
-
throw new Error("handoff.startActivity: type is required");
|
|
5624
|
-
if (!hasBridge("handoff"))
|
|
5625
|
-
return false;
|
|
5626
|
-
const r = await window.craft.handoff.startActivity(type, options);
|
|
5627
|
-
return typeof r === "boolean" ? r : !!(r && r.ok);
|
|
5628
|
-
},
|
|
5629
|
-
async updateActivity(options) {
|
|
5630
|
-
if (!hasBridge("handoff"))
|
|
5631
|
-
return false;
|
|
5632
|
-
const r = await window.craft.handoff.updateActivity(options);
|
|
5633
|
-
return typeof r === "boolean" ? r : !!(r && r.ok);
|
|
5634
|
-
},
|
|
5635
|
-
async stopActivity() {
|
|
5636
|
-
if (!hasBridge("handoff"))
|
|
5637
|
-
return;
|
|
5638
|
-
await window.craft.handoff.stopActivity();
|
|
5639
|
-
},
|
|
5640
|
-
async getCurrentActivity() {
|
|
5641
|
-
if (!hasBridge("handoff"))
|
|
5642
|
-
return null;
|
|
5643
|
-
const r = await window.craft.handoff.getCurrentActivity();
|
|
5644
|
-
return r && typeof r.type === "string" ? r : null;
|
|
5645
|
-
},
|
|
5646
|
-
onIncoming(cb) {
|
|
5647
|
-
return onCraftEvent("craft:handoff:incoming", cb);
|
|
5648
|
-
}
|
|
5649
|
-
};
|
|
5650
|
-
// src/live-activities.ts
|
|
5651
|
-
var liveActivities = {
|
|
5652
|
-
async start(type, state) {
|
|
5653
|
-
return handoff.startActivity(type, {
|
|
5654
|
-
title: state?.title,
|
|
5655
|
-
webpageURL: state?.webpageURL,
|
|
5656
|
-
userInfo: state?.state
|
|
5657
|
-
});
|
|
5658
|
-
},
|
|
5659
|
-
async update(state) {
|
|
5660
|
-
return handoff.updateActivity({
|
|
5661
|
-
title: state.title,
|
|
5662
|
-
webpageURL: state.webpageURL,
|
|
5663
|
-
userInfo: state.state
|
|
5664
|
-
});
|
|
5665
|
-
},
|
|
5666
|
-
async stop() {
|
|
5667
|
-
await handoff.stopActivity();
|
|
5668
|
-
}
|
|
5669
|
-
};
|
|
5670
|
-
// src/location.ts
|
|
5671
|
-
var location = {
|
|
5672
|
-
async requestPermission(mode = "whenInUse") {
|
|
5673
|
-
if (hasBridge("location"))
|
|
5674
|
-
return await window.craft.location.requestPermission(mode);
|
|
5675
|
-
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5676
|
-
return "undetermined";
|
|
5677
|
-
}
|
|
5678
|
-
return "not-supported";
|
|
5679
|
-
},
|
|
5680
|
-
async getAuthorization() {
|
|
5681
|
-
if (hasBridge("location"))
|
|
5682
|
-
return await window.craft.location.getAuthorization();
|
|
5683
|
-
return "unknown";
|
|
5684
|
-
},
|
|
5685
|
-
async getCurrentLocation() {
|
|
5686
|
-
if (hasBridge("location"))
|
|
5687
|
-
return await window.craft.location.getCurrentLocation();
|
|
5688
|
-
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5689
|
-
navigator.geolocation.getCurrentPosition((pos) => {
|
|
5690
|
-
window.dispatchEvent(new CustomEvent("craft:location:update", {
|
|
5691
|
-
detail: {
|
|
5692
|
-
latitude: pos.coords.latitude,
|
|
5693
|
-
longitude: pos.coords.longitude,
|
|
5694
|
-
altitude: pos.coords.altitude,
|
|
5695
|
-
horizontalAccuracy: pos.coords.accuracy,
|
|
5696
|
-
verticalAccuracy: pos.coords.altitudeAccuracy,
|
|
5697
|
-
speed: pos.coords.speed
|
|
5698
|
-
}
|
|
5699
|
-
}));
|
|
5700
|
-
}, (err) => {
|
|
5701
|
-
window.dispatchEvent(new CustomEvent("craft:location:error", {
|
|
5702
|
-
detail: { message: err.message || String(err) }
|
|
5703
|
-
}));
|
|
5704
|
-
});
|
|
5705
|
-
return { requested: true };
|
|
5706
|
-
}
|
|
5707
|
-
return { requested: false };
|
|
5708
|
-
},
|
|
5709
|
-
async startWatching(options) {
|
|
5710
|
-
if (hasBridge("location"))
|
|
5711
|
-
return await window.craft.location.startWatching(options);
|
|
5712
|
-
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5713
|
-
const watchId = navigator.geolocation.watchPosition((pos) => {
|
|
5714
|
-
window.dispatchEvent(new CustomEvent("craft:location:update", {
|
|
5715
|
-
detail: {
|
|
5716
|
-
latitude: pos.coords.latitude,
|
|
5717
|
-
longitude: pos.coords.longitude,
|
|
5718
|
-
altitude: pos.coords.altitude,
|
|
5719
|
-
horizontalAccuracy: pos.coords.accuracy,
|
|
5720
|
-
verticalAccuracy: pos.coords.altitudeAccuracy,
|
|
5721
|
-
speed: pos.coords.speed
|
|
5722
|
-
}
|
|
5723
|
-
}));
|
|
5724
|
-
});
|
|
5725
|
-
window.__craftWebLocationWatchId = watchId;
|
|
5726
|
-
return true;
|
|
5727
|
-
}
|
|
5728
|
-
return false;
|
|
5729
|
-
},
|
|
5730
|
-
async stopWatching() {
|
|
5731
|
-
if (hasBridge("location")) {
|
|
5732
|
-
await window.craft.location.stopWatching();
|
|
5733
|
-
return;
|
|
5734
|
-
}
|
|
5735
|
-
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5736
|
-
const id = window.__craftWebLocationWatchId;
|
|
5737
|
-
if (id != null) {
|
|
5738
|
-
navigator.geolocation.clearWatch(id);
|
|
5739
|
-
window.__craftWebLocationWatchId = null;
|
|
5740
|
-
}
|
|
5741
|
-
}
|
|
5742
|
-
},
|
|
5743
|
-
onUpdate(cb) {
|
|
5744
|
-
return onCraftEvent("craft:location:update", cb);
|
|
5745
|
-
},
|
|
5746
|
-
onError(cb) {
|
|
5747
|
-
return onCraftEvent("craft:location:error", cb);
|
|
5748
|
-
},
|
|
5749
|
-
onAuthChanged(cb) {
|
|
5750
|
-
return onCraftEvent("craft:location:authChanged", cb);
|
|
5751
|
-
}
|
|
5752
|
-
};
|
|
5753
|
-
// src/screen-capture.ts
|
|
5754
|
-
var screenCapture = {
|
|
5755
|
-
async captureScreen() {
|
|
5756
|
-
if (!hasBridge("screenCapture"))
|
|
5757
|
-
return null;
|
|
5758
|
-
const r = await window.craft.screenCapture.captureScreen();
|
|
5759
|
-
return r ? String(r) : null;
|
|
5760
|
-
},
|
|
5761
|
-
async captureWindow(id) {
|
|
5762
|
-
if (!hasBridge("screenCapture"))
|
|
5763
|
-
return null;
|
|
5764
|
-
if (!Number.isFinite(id) || id <= 0)
|
|
5765
|
-
throw new Error("captureWindow: id must be a positive number");
|
|
5766
|
-
const r = await window.craft.screenCapture.captureWindow(id);
|
|
5767
|
-
return r ? String(r) : null;
|
|
5768
|
-
},
|
|
5769
|
-
async listWindows() {
|
|
5770
|
-
if (!hasBridge("screenCapture"))
|
|
5771
|
-
return [];
|
|
5772
|
-
return await window.craft.screenCapture.listWindows();
|
|
5773
|
-
}
|
|
5774
|
-
};
|
|
5775
|
-
// src/screen-sharing.ts
|
|
5776
|
-
var MIN_WATCH_INTERVAL_MS = 250;
|
|
5777
|
-
var MAX_WATCH_INTERVAL_MS = 60000;
|
|
5778
|
-
var DEFAULT_WATCH_INTERVAL_MS = 2000;
|
|
5779
|
-
var IDLE = {
|
|
5780
|
-
sharing: false,
|
|
5781
|
-
signals: {
|
|
5782
|
-
systemScreenShare: false,
|
|
5783
|
-
remoteSession: false,
|
|
5784
|
-
conferenceSharing: false,
|
|
5785
|
-
screenRecording: false
|
|
5786
|
-
},
|
|
5787
|
-
sources: []
|
|
5788
|
-
};
|
|
5789
|
-
function idleState() {
|
|
5790
|
-
return { ...IDLE, signals: { ...IDLE.signals }, sources: [] };
|
|
5791
|
-
}
|
|
5792
|
-
var screenSharing = {
|
|
5793
|
-
async getState() {
|
|
5794
|
-
if (!hasBridge("screenSharing"))
|
|
5795
|
-
return idleState();
|
|
5796
|
-
return await window.craft.screenSharing.getState();
|
|
5797
|
-
},
|
|
5798
|
-
async watch(intervalMs = DEFAULT_WATCH_INTERVAL_MS) {
|
|
5799
|
-
const clamped = Math.min(MAX_WATCH_INTERVAL_MS, Math.max(MIN_WATCH_INTERVAL_MS, Math.round(intervalMs)));
|
|
5800
|
-
if (!hasBridge("screenSharing"))
|
|
5801
|
-
return clamped;
|
|
5802
|
-
const r = await window.craft.screenSharing.watch(clamped);
|
|
5803
|
-
return r && r.intervalMs || clamped;
|
|
5804
|
-
},
|
|
5805
|
-
async stop() {
|
|
5806
|
-
if (!hasBridge("screenSharing"))
|
|
5807
|
-
return;
|
|
5808
|
-
await window.craft.screenSharing.unwatch();
|
|
5809
|
-
},
|
|
5810
|
-
onChange(cb) {
|
|
5811
|
-
return onCraftEvent("craft:screenSharing:change", cb);
|
|
5812
|
-
}
|
|
5813
|
-
};
|
|
5814
|
-
async function watchScreenSharing(cb, intervalMs = DEFAULT_WATCH_INTERVAL_MS) {
|
|
5815
|
-
const off = screenSharing.onChange(cb);
|
|
5816
|
-
await screenSharing.watch(intervalMs);
|
|
5817
|
-
return () => {
|
|
5818
|
-
off();
|
|
5819
|
-
screenSharing.stop();
|
|
5820
|
-
};
|
|
5821
|
-
}
|
|
5822
|
-
// src/focus.ts
|
|
5823
|
-
var UNSUPPORTED = { supported: false, isFocused: null, authorization: "unsupported" };
|
|
5824
|
-
function unavailable() {
|
|
5825
|
-
return { ok: false, error: "Focus control is only available in a Craft window on macOS" };
|
|
5826
|
-
}
|
|
5827
|
-
var focus = {
|
|
5828
|
-
async getStatus() {
|
|
5829
|
-
if (!hasBridge("focus"))
|
|
5830
|
-
return { ...UNSUPPORTED };
|
|
5831
|
-
return await window.craft.focus.getStatus();
|
|
5832
|
-
},
|
|
5833
|
-
async requestAuthorization() {
|
|
5834
|
-
if (!hasBridge("focus"))
|
|
5835
|
-
return "unsupported";
|
|
5836
|
-
return await window.craft.focus.requestAuthorization();
|
|
5837
|
-
},
|
|
5838
|
-
async setEnabled(enabled, options = {}) {
|
|
5839
|
-
if (!hasBridge("focus"))
|
|
5840
|
-
return unavailable();
|
|
5841
|
-
const name = enabled ? options.onShortcut : options.offShortcut;
|
|
5842
|
-
if (!name) {
|
|
5843
|
-
return {
|
|
5844
|
-
ok: false,
|
|
5845
|
-
error: `focus.setEnabled: no ${enabled ? "onShortcut" : "offShortcut"} configured`
|
|
5846
|
-
};
|
|
5847
|
-
}
|
|
5848
|
-
return await window.craft.focus.setEnabled(enabled, options);
|
|
5849
|
-
},
|
|
5850
|
-
async runShortcut(name) {
|
|
5851
|
-
if (!hasBridge("focus"))
|
|
5852
|
-
return unavailable();
|
|
5853
|
-
if (!name)
|
|
5854
|
-
throw new Error("focus.runShortcut: name is required");
|
|
5855
|
-
return await window.craft.focus.runShortcut(name);
|
|
5856
|
-
},
|
|
5857
|
-
async listShortcuts() {
|
|
5858
|
-
if (!hasBridge("focus"))
|
|
5859
|
-
return [];
|
|
5860
|
-
return await window.craft.focus.listShortcuts();
|
|
5861
|
-
},
|
|
5862
|
-
async listShortcutsResult() {
|
|
5863
|
-
if (!hasBridge("focus"))
|
|
5864
|
-
return { canList: false, shortcuts: [] };
|
|
5865
|
-
const r = await window.craft.focus.listShortcutsResult();
|
|
5866
|
-
return { canList: Boolean(r?.canList), shortcuts: r?.shortcuts || [] };
|
|
5867
|
-
}
|
|
5868
|
-
};
|
|
5869
|
-
async function hasFocusShortcuts(...names) {
|
|
5870
|
-
if (names.length === 0)
|
|
5871
|
-
return false;
|
|
5872
|
-
const installed = new Set(await focus.listShortcuts());
|
|
5873
|
-
return names.every((name) => installed.has(name));
|
|
5874
|
-
}
|
|
5875
|
-
async function focusShortcutsReady(...names) {
|
|
5876
|
-
if (names.length === 0)
|
|
5877
|
-
return false;
|
|
5878
|
-
const { canList, shortcuts } = await focus.listShortcutsResult();
|
|
5879
|
-
if (!canList)
|
|
5880
|
-
return "unknown";
|
|
5881
|
-
const installed = new Set(shortcuts);
|
|
5882
|
-
return names.every((name) => installed.has(name));
|
|
5883
|
-
}
|
|
5884
|
-
// src/local-server.ts
|
|
5885
|
-
var localServer = {
|
|
5886
|
-
async start(port = 0, host = "127.0.0.1") {
|
|
5887
|
-
if (!hasBridge("localServer"))
|
|
5888
|
-
return { port: 0, started: false, reason: "bridge unavailable" };
|
|
5889
|
-
return await window.craft.localServer.start(port, host);
|
|
5890
|
-
},
|
|
5891
|
-
async stop() {
|
|
5892
|
-
if (!hasBridge("localServer"))
|
|
5893
|
-
return;
|
|
5894
|
-
await window.craft.localServer.stop();
|
|
5895
|
-
},
|
|
5896
|
-
async respond(options) {
|
|
5897
|
-
if (!hasBridge("localServer"))
|
|
5898
|
-
return;
|
|
5899
|
-
await window.craft.localServer.respond(options || { status: 200, body: "OK" });
|
|
5900
|
-
},
|
|
5901
|
-
onRequest(cb) {
|
|
5902
|
-
return onCraftEvent("craft:localServer:request", cb);
|
|
5903
|
-
},
|
|
5904
|
-
async awaitOAuthCallback(options = {}) {
|
|
5905
|
-
requireBridge("localServer");
|
|
5906
|
-
const { port: requestedPort = 0, host = "127.0.0.1", timeoutMs = 5 * 60 * 1000, successHTML } = options;
|
|
5907
|
-
const start = await this.start(requestedPort, host);
|
|
5908
|
-
if (!start.started)
|
|
5909
|
-
throw new Error(`localServer: start failed${start.reason ? ` \u2014 ${start.reason}` : ""}`);
|
|
5910
|
-
return new Promise((resolve, reject) => {
|
|
5911
|
-
const timer = setTimeout(() => {
|
|
5912
|
-
off();
|
|
5913
|
-
this.stop().catch(() => {});
|
|
5914
|
-
reject(new Error("localServer: OAuth callback timed out"));
|
|
5915
|
-
}, timeoutMs);
|
|
5916
|
-
const off = this.onRequest(({ url }) => {
|
|
5917
|
-
clearTimeout(timer);
|
|
5918
|
-
off();
|
|
5919
|
-
const body = successHTML ?? `<!doctype html><meta charset="utf-8"><title>Done</title>
|
|
5920
|
-
<style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f5f5f7}</style>
|
|
5921
|
-
<div><h1>You can close this tab.</h1><p>Returning to the app\u2026</p></div>
|
|
5922
|
-
<script>setTimeout(()=>window.close(),1500)</script>`;
|
|
5923
|
-
this.respond({ status: 200, body, contentType: "text/html; charset=utf-8" }).catch(() => {}).finally(() => this.stop().catch(() => {}));
|
|
5924
|
-
resolve({ url, port: start.port });
|
|
5925
|
-
});
|
|
5926
|
-
});
|
|
5927
|
-
}
|
|
5928
|
-
};
|
|
5929
|
-
// src/biometric.ts
|
|
5930
|
-
var biometric = {
|
|
5931
|
-
async isAvailable() {
|
|
5932
|
-
if (!hasBridge("biometric"))
|
|
5933
|
-
return false;
|
|
5934
|
-
return await window.craft.biometric.isAvailable();
|
|
5935
|
-
},
|
|
5936
|
-
async getBiometryType() {
|
|
5937
|
-
if (!hasBridge("biometric"))
|
|
5938
|
-
return "none";
|
|
5939
|
-
return await window.craft.biometric.getBiometryType();
|
|
5940
|
-
},
|
|
5941
|
-
async evaluate(reason, options) {
|
|
5942
|
-
if (!reason)
|
|
5943
|
-
throw new Error("biometric.evaluate: reason is required");
|
|
5944
|
-
if (!hasBridge("biometric"))
|
|
5945
|
-
return { success: false, errorCode: -1 };
|
|
5946
|
-
return await window.craft.biometric.evaluate(reason, options);
|
|
5947
|
-
}
|
|
5948
|
-
};
|
|
5949
|
-
// src/audio.ts
|
|
5950
|
-
var webAudio = null;
|
|
5951
|
-
var audio = {
|
|
5952
|
-
async play(path, options) {
|
|
5953
|
-
if (hasBridge("audio")) {
|
|
5954
|
-
return await window.craft.audio.play(path, options);
|
|
5955
|
-
}
|
|
5956
|
-
if (typeof window === "undefined" || typeof Audio === "undefined")
|
|
5957
|
-
return false;
|
|
5958
|
-
if (webAudio) {
|
|
5959
|
-
webAudio.pause();
|
|
5960
|
-
webAudio = null;
|
|
5961
|
-
}
|
|
5962
|
-
webAudio = new Audio(path);
|
|
5963
|
-
if (options?.volume != null)
|
|
5964
|
-
webAudio.volume = options.volume;
|
|
5965
|
-
if (options?.loops)
|
|
5966
|
-
webAudio.loop = true;
|
|
5967
|
-
try {
|
|
5968
|
-
await webAudio.play();
|
|
5969
|
-
return true;
|
|
5970
|
-
} catch {
|
|
5971
|
-
return false;
|
|
5972
|
-
}
|
|
5973
|
-
},
|
|
5974
|
-
async playSystemSound(name) {
|
|
5975
|
-
if (hasBridge("audio"))
|
|
5976
|
-
return await window.craft.audio.playSystemSound(name);
|
|
5977
|
-
if (typeof window === "undefined" || typeof Audio === "undefined")
|
|
5978
|
-
return false;
|
|
5979
|
-
try {
|
|
5980
|
-
webAudio = new Audio(`/System/Library/Sounds/${name}.aiff`);
|
|
5981
|
-
await webAudio.play();
|
|
5982
|
-
return true;
|
|
5983
|
-
} catch {
|
|
5984
|
-
return false;
|
|
5985
|
-
}
|
|
5986
|
-
},
|
|
5987
|
-
async stop() {
|
|
5988
|
-
if (hasBridge("audio")) {
|
|
5989
|
-
await window.craft.audio.stop();
|
|
5990
|
-
return;
|
|
5991
|
-
}
|
|
5992
|
-
if (webAudio) {
|
|
5993
|
-
webAudio.pause();
|
|
5994
|
-
webAudio.currentTime = 0;
|
|
5995
|
-
webAudio = null;
|
|
5996
|
-
}
|
|
5997
|
-
},
|
|
5998
|
-
async isPlaying() {
|
|
5999
|
-
if (hasBridge("audio"))
|
|
6000
|
-
return await window.craft.audio.isPlaying();
|
|
6001
|
-
return !!(webAudio && !webAudio.paused);
|
|
6002
|
-
},
|
|
6003
|
-
async startRecording(path, options) {
|
|
6004
|
-
if (hasBridge("audio"))
|
|
6005
|
-
return await window.craft.audio.startRecording(path, options);
|
|
6006
|
-
return false;
|
|
6007
|
-
},
|
|
6008
|
-
async stopRecording() {
|
|
6009
|
-
if (hasBridge("audio"))
|
|
6010
|
-
await window.craft.audio.stopRecording();
|
|
6011
|
-
},
|
|
6012
|
-
async isRecording() {
|
|
6013
|
-
if (hasBridge("audio"))
|
|
6014
|
-
return await window.craft.audio.isRecording();
|
|
6015
|
-
return false;
|
|
6016
|
-
}
|
|
6017
|
-
};
|
|
6018
|
-
// src/apple-script.ts
|
|
6019
|
-
var appleScript = {
|
|
6020
|
-
async execute(source) {
|
|
6021
|
-
if (!source)
|
|
6022
|
-
throw new Error("appleScript.execute: source is required");
|
|
6023
|
-
if (!hasBridge("appleScript"))
|
|
6024
|
-
return { ok: false };
|
|
6025
|
-
return await window.craft.appleScript.execute(source);
|
|
6026
|
-
}
|
|
6027
|
-
};
|
|
6028
|
-
// src/file-associations.ts
|
|
6029
|
-
var fileAssociations = {
|
|
6030
|
-
async getDefault(uti) {
|
|
6031
|
-
if (!uti)
|
|
6032
|
-
throw new Error("fileAssociations.getDefault: uti is required");
|
|
6033
|
-
if (!hasBridge("fileAssociations"))
|
|
6034
|
-
return null;
|
|
6035
|
-
const v = await window.craft.fileAssociations.getDefault(uti);
|
|
6036
|
-
return v ? String(v) : null;
|
|
6037
|
-
},
|
|
6038
|
-
async setDefault(uti, bundleId) {
|
|
6039
|
-
if (!uti || !bundleId)
|
|
6040
|
-
throw new Error("fileAssociations.setDefault: uti and bundleId are required");
|
|
6041
|
-
if (!hasBridge("fileAssociations"))
|
|
6042
|
-
return false;
|
|
6043
|
-
return await window.craft.fileAssociations.setDefault(uti, bundleId);
|
|
6044
|
-
}
|
|
6045
|
-
};
|
|
6046
|
-
// src/tags.ts
|
|
6047
|
-
var tags = {
|
|
6048
|
-
async get(path) {
|
|
6049
|
-
if (!path)
|
|
6050
|
-
throw new Error("tags.get: path is required");
|
|
6051
|
-
if (!hasBridge("tags"))
|
|
6052
|
-
return [];
|
|
6053
|
-
return await window.craft.tags.get(path);
|
|
6054
|
-
},
|
|
6055
|
-
async set(path, t) {
|
|
6056
|
-
if (!path)
|
|
6057
|
-
throw new Error("tags.set: path is required");
|
|
6058
|
-
if (!hasBridge("tags"))
|
|
6059
|
-
return false;
|
|
6060
|
-
const arr = Array.isArray(t) ? t : [String(t)];
|
|
6061
|
-
return await window.craft.tags.set(path, arr);
|
|
6062
|
-
},
|
|
6063
|
-
async clear(path) {
|
|
6064
|
-
if (!path)
|
|
6065
|
-
throw new Error("tags.clear: path is required");
|
|
6066
|
-
if (!hasBridge("tags"))
|
|
6067
|
-
return false;
|
|
6068
|
-
return await window.craft.tags.clear(path);
|
|
6069
|
-
}
|
|
6070
|
-
};
|
|
6071
|
-
// src/pdf.ts
|
|
6072
|
-
var pdf = {
|
|
6073
|
-
async countPages(path) {
|
|
6074
|
-
if (!path)
|
|
6075
|
-
throw new Error("pdf.countPages: path is required");
|
|
6076
|
-
if (!hasBridge("pdf"))
|
|
6077
|
-
return 0;
|
|
6078
|
-
return await window.craft.pdf.countPages(path);
|
|
6079
|
-
},
|
|
6080
|
-
async extractText(path) {
|
|
6081
|
-
if (!path)
|
|
6082
|
-
throw new Error("pdf.extractText: path is required");
|
|
6083
|
-
if (!hasBridge("pdf"))
|
|
6084
|
-
return "";
|
|
6085
|
-
return await window.craft.pdf.extractText(path);
|
|
6086
|
-
}
|
|
6087
|
-
};
|
|
6088
|
-
// src/log.ts
|
|
6089
|
-
var log = {
|
|
6090
|
-
async debug(m) {
|
|
6091
|
-
if (hasBridge("log"))
|
|
6092
|
-
await window.craft.log.debug(m);
|
|
6093
|
-
else
|
|
6094
|
-
console.debug(m);
|
|
6095
|
-
},
|
|
6096
|
-
async info(m) {
|
|
6097
|
-
if (hasBridge("log"))
|
|
6098
|
-
await window.craft.log.info(m);
|
|
6099
|
-
else
|
|
6100
|
-
console.info(m);
|
|
6101
|
-
},
|
|
6102
|
-
async warn(m) {
|
|
6103
|
-
if (hasBridge("log"))
|
|
6104
|
-
await window.craft.log.warn(m);
|
|
6105
|
-
else
|
|
6106
|
-
console.warn(m);
|
|
6107
|
-
},
|
|
6108
|
-
async error(m) {
|
|
6109
|
-
if (hasBridge("log"))
|
|
6110
|
-
await window.craft.log.error(m);
|
|
6111
|
-
else
|
|
6112
|
-
console.error(m);
|
|
6113
|
-
}
|
|
6114
|
-
};
|
|
6115
|
-
// src/bonjour.ts
|
|
6116
|
-
var bonjour = {
|
|
6117
|
-
async browse(serviceType) {
|
|
6118
|
-
if (!hasBridge("bonjour"))
|
|
6119
|
-
return { started: false, reason: "bridge unavailable" };
|
|
6120
|
-
return await window.craft.bonjour.browse(serviceType);
|
|
6121
|
-
},
|
|
6122
|
-
async stop() {
|
|
6123
|
-
if (hasBridge("bonjour"))
|
|
6124
|
-
await window.craft.bonjour.stop();
|
|
6125
|
-
},
|
|
6126
|
-
onFound(cb) {
|
|
6127
|
-
return onCraftEvent("craft:bonjour:found", cb);
|
|
6128
|
-
},
|
|
6129
|
-
onLost(cb) {
|
|
6130
|
-
return onCraftEvent("craft:bonjour:lost", cb);
|
|
6131
|
-
}
|
|
6132
|
-
};
|
|
6133
|
-
// src/spotlight.ts
|
|
6134
|
-
var spotlight = {
|
|
6135
|
-
async index(items) {
|
|
6136
|
-
if (!hasBridge("spotlight"))
|
|
6137
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
6138
|
-
return await window.craft.spotlight.index(items);
|
|
6139
|
-
},
|
|
6140
|
-
async remove(ids) {
|
|
6141
|
-
if (!hasBridge("spotlight"))
|
|
6142
|
-
return { ok: false };
|
|
6143
|
-
return await window.craft.spotlight.remove(ids);
|
|
6144
|
-
},
|
|
6145
|
-
async removeAll() {
|
|
6146
|
-
if (!hasBridge("spotlight"))
|
|
6147
|
-
return { ok: false };
|
|
6148
|
-
return await window.craft.spotlight.removeAll();
|
|
6149
|
-
}
|
|
6150
|
-
};
|
|
6151
|
-
// src/speech-recognition.ts
|
|
6152
|
-
var speechRecognition = {
|
|
6153
|
-
async isAvailable() {
|
|
6154
|
-
if (!hasBridge("speechRecognition"))
|
|
6155
|
-
return false;
|
|
6156
|
-
return await window.craft.speechRecognition.isAvailable();
|
|
6157
|
-
},
|
|
6158
|
-
async start(opts) {
|
|
6159
|
-
if (!hasBridge("speechRecognition"))
|
|
6160
|
-
return { started: false, reason: "bridge unavailable" };
|
|
6161
|
-
return await window.craft.speechRecognition.start(opts);
|
|
6162
|
-
},
|
|
6163
|
-
async stop() {
|
|
6164
|
-
if (hasBridge("speechRecognition"))
|
|
6165
|
-
await window.craft.speechRecognition.stop();
|
|
6166
|
-
},
|
|
6167
|
-
onPartial(cb) {
|
|
6168
|
-
return onCraftEvent("craft:speechRecognition:partial", cb);
|
|
6169
|
-
},
|
|
6170
|
-
onFinal(cb) {
|
|
6171
|
-
return onCraftEvent("craft:speechRecognition:final", cb);
|
|
6172
|
-
}
|
|
6173
|
-
};
|
|
6174
|
-
// src/vision.ts
|
|
6175
|
-
var vision = {
|
|
6176
|
-
async recognizeText(path) {
|
|
6177
|
-
if (!path)
|
|
6178
|
-
throw new Error("vision.recognizeText: path is required");
|
|
6179
|
-
if (!hasBridge("vision"))
|
|
6180
|
-
return [];
|
|
6181
|
-
return await window.craft.vision.recognizeText(path);
|
|
6182
|
-
},
|
|
6183
|
-
async detectFaces(path) {
|
|
6184
|
-
if (!path)
|
|
6185
|
-
throw new Error("vision.detectFaces: path is required");
|
|
6186
|
-
if (!hasBridge("vision"))
|
|
6187
|
-
return [];
|
|
6188
|
-
return await window.craft.vision.detectFaces(path);
|
|
6189
|
-
},
|
|
6190
|
-
async detectBarcodes(path) {
|
|
6191
|
-
if (!path)
|
|
6192
|
-
throw new Error("vision.detectBarcodes: path is required");
|
|
6193
|
-
if (!hasBridge("vision"))
|
|
6194
|
-
return [];
|
|
6195
|
-
return await window.craft.vision.detectBarcodes(path);
|
|
6196
|
-
}
|
|
6197
|
-
};
|
|
6198
|
-
// src/midi.ts
|
|
6199
|
-
var midi = {
|
|
6200
|
-
async listSources() {
|
|
6201
|
-
if (!hasBridge("midi"))
|
|
6202
|
-
return [];
|
|
6203
|
-
return await window.craft.midi.listSources();
|
|
6204
|
-
},
|
|
6205
|
-
async listDestinations() {
|
|
6206
|
-
if (!hasBridge("midi"))
|
|
6207
|
-
return [];
|
|
6208
|
-
return await window.craft.midi.listDestinations();
|
|
6209
|
-
},
|
|
6210
|
-
async send(destinationIndex, data) {
|
|
6211
|
-
if (!hasBridge("midi"))
|
|
6212
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
6213
|
-
return await window.craft.midi.send(destinationIndex, data);
|
|
6214
|
-
},
|
|
6215
|
-
async subscribe(sourceIndex) {
|
|
6216
|
-
if (!hasBridge("midi"))
|
|
6217
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
6218
|
-
return await window.craft.midi.subscribe(sourceIndex);
|
|
6219
|
-
},
|
|
6220
|
-
async unsubscribe(sourceIndex) {
|
|
6221
|
-
if (!hasBridge("midi"))
|
|
6222
|
-
return { ok: false };
|
|
6223
|
-
return await window.craft.midi.unsubscribe(sourceIndex);
|
|
6224
|
-
},
|
|
6225
|
-
onMessage(cb) {
|
|
6226
|
-
return onCraftEvent("craft:midi:message", cb);
|
|
6227
|
-
}
|
|
6228
|
-
};
|
|
6229
|
-
// src/coreml.ts
|
|
6230
|
-
var coreml = {
|
|
6231
|
-
async loadModel(id, path) {
|
|
6232
|
-
if (!id || !path)
|
|
6233
|
-
throw new Error("coreml.loadModel: id and path are required");
|
|
6234
|
-
if (!hasBridge("coreml"))
|
|
6235
|
-
return false;
|
|
6236
|
-
return await window.craft.coreml.loadModel(id, path);
|
|
6237
|
-
},
|
|
6238
|
-
async unloadModel(id) {
|
|
6239
|
-
if (!hasBridge("coreml"))
|
|
6240
|
-
return;
|
|
6241
|
-
await window.craft.coreml.unloadModel(id);
|
|
6242
|
-
},
|
|
6243
|
-
async predict(id, input) {
|
|
6244
|
-
if (!id)
|
|
6245
|
-
throw new Error("coreml.predict: id is required");
|
|
6246
|
-
if (!hasBridge("coreml"))
|
|
6247
|
-
return null;
|
|
6248
|
-
return await window.craft.coreml.predict(id, input);
|
|
6249
|
-
}
|
|
6250
|
-
};
|
|
6251
|
-
// src/continuity-camera.ts
|
|
6252
|
-
var continuityCamera = {
|
|
6253
|
-
async listCameras() {
|
|
6254
|
-
if (!hasBridge("continuityCamera"))
|
|
6255
|
-
return [];
|
|
6256
|
-
return await window.craft.continuityCamera.listCameras();
|
|
6257
|
-
}
|
|
6258
|
-
};
|
|
6259
|
-
// src/service-menu.ts
|
|
6260
|
-
var serviceMenu = {
|
|
6261
|
-
async register(name) {
|
|
6262
|
-
if (!name)
|
|
6263
|
-
throw new Error("serviceMenu.register: name is required");
|
|
6264
|
-
if (!hasBridge("serviceMenu"))
|
|
6265
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
6266
|
-
return await window.craft.serviceMenu.register(name);
|
|
6267
|
-
},
|
|
6268
|
-
async unregister(name) {
|
|
6269
|
-
if (!name)
|
|
6270
|
-
throw new Error("serviceMenu.unregister: name is required");
|
|
6271
|
-
if (!hasBridge("serviceMenu"))
|
|
6272
|
-
return;
|
|
6273
|
-
await window.craft.serviceMenu.unregister(name);
|
|
6274
|
-
},
|
|
6275
|
-
onInvoked(cb) {
|
|
6276
|
-
return onCraftEvent("craft:serviceMenu:invoked", cb);
|
|
6277
|
-
}
|
|
6278
|
-
};
|
|
6279
|
-
// src/serial.ts
|
|
6280
|
-
var serial = {
|
|
6281
|
-
async list() {
|
|
6282
|
-
if (!hasBridge("serial"))
|
|
6283
|
-
return [];
|
|
6284
|
-
return await window.craft.serial.list();
|
|
6285
|
-
},
|
|
6286
|
-
async open(path, baud = 9600) {
|
|
6287
|
-
if (!path)
|
|
6288
|
-
throw new Error("serial.open: path is required");
|
|
6289
|
-
if (!hasBridge("serial"))
|
|
6290
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
6291
|
-
return await window.craft.serial.open(path, baud);
|
|
6292
|
-
},
|
|
6293
|
-
async write(id, data) {
|
|
6294
|
-
if (!id)
|
|
6295
|
-
throw new Error("serial.write: id is required");
|
|
6296
|
-
if (!hasBridge("serial"))
|
|
6297
|
-
return { ok: false, reason: "bridge unavailable" };
|
|
6298
|
-
return await window.craft.serial.write(id, data);
|
|
6299
|
-
},
|
|
6300
|
-
async close(id) {
|
|
6301
|
-
if (!hasBridge("serial"))
|
|
6302
|
-
return;
|
|
6303
|
-
await window.craft.serial.close(id);
|
|
6304
|
-
},
|
|
6305
|
-
onData(cb) {
|
|
6306
|
-
return onCraftEvent("craft:serial:data", cb);
|
|
6307
|
-
}
|
|
6308
|
-
};
|
|
6309
|
-
// src/capabilities.ts
|
|
6310
|
-
var BRIDGE_INDEX = [
|
|
6311
|
-
{ name: "fs", support: "native" },
|
|
6312
|
-
{ name: "shell", support: "native" },
|
|
6313
|
-
{ name: "system", support: "all" },
|
|
6314
|
-
{ name: "clipboard", support: "all" },
|
|
6315
|
-
{ name: "dialog", support: "all" },
|
|
6316
|
-
{ name: "window", support: "native" },
|
|
6317
|
-
{ name: "tray", support: "native" },
|
|
6318
|
-
{ name: "menu", support: "native" },
|
|
6319
|
-
{ name: "theme", support: "all" },
|
|
6320
|
-
{ name: "screen", support: "all" },
|
|
6321
|
-
{ name: "network", support: "all" },
|
|
6322
|
-
{ name: "power", support: "all" },
|
|
6323
|
-
{ name: "battery", support: "all" },
|
|
6324
|
-
{ name: "notifications", support: "all" },
|
|
6325
|
-
{ name: "globalShortcuts", support: "native" },
|
|
6326
|
-
{ name: "autolaunch", support: "native" },
|
|
6327
|
-
{ name: "appInfo", support: "all" },
|
|
6328
|
-
{ name: "localServer", support: "native" },
|
|
6329
|
-
{ name: "bluetooth", support: "native" },
|
|
6330
|
-
{ name: "crashReporter", support: "all" },
|
|
6331
|
-
{ name: "updater", support: "native" },
|
|
6332
|
-
{ name: "iap", support: "macos" },
|
|
6333
|
-
{ name: "keychain", support: "native" },
|
|
6334
|
-
{ name: "log", support: "all" },
|
|
6335
|
-
{ name: "biometric", support: "macos" },
|
|
6336
|
-
{ name: "location", support: "macos" },
|
|
6337
|
-
{ name: "audio", support: "macos" },
|
|
6338
|
-
{ name: "deepLink", support: "native" },
|
|
6339
|
-
{ name: "handoff", support: "macos" },
|
|
6340
|
-
{ name: "liveActivities", support: "macos" },
|
|
6341
|
-
{ name: "touchbar", support: "macos" },
|
|
6342
|
-
{ name: "dragOut", support: "macos" },
|
|
6343
|
-
{ name: "appleScript", support: "macos" },
|
|
6344
|
-
{ name: "fileAssociations", support: "native" },
|
|
6345
|
-
{ name: "tags", support: "macos" },
|
|
6346
|
-
{ name: "pdf", support: "macos" },
|
|
6347
|
-
{ name: "bonjour", support: "macos" },
|
|
6348
|
-
{ name: "spotlight", support: "macos" },
|
|
6349
|
-
{ name: "speechRecognition", support: "macos" },
|
|
6350
|
-
{ name: "vision", support: "macos" },
|
|
6351
|
-
{ name: "midi", support: "macos" },
|
|
6352
|
-
{ name: "coreml", support: "macos" },
|
|
6353
|
-
{ name: "continuityCamera", support: "macos" },
|
|
6354
|
-
{ name: "serviceMenu", support: "macos" },
|
|
6355
|
-
{ name: "serial", support: "native" }
|
|
6356
|
-
];
|
|
6357
|
-
function getCapabilities() {
|
|
6358
|
-
return BRIDGE_INDEX.map(({ name, support }) => ({
|
|
6359
|
-
name,
|
|
6360
|
-
support,
|
|
6361
|
-
available: hasBridge(name)
|
|
6362
|
-
}));
|
|
6363
|
-
}
|
|
6364
|
-
function getCapability(name) {
|
|
6365
|
-
const entry = BRIDGE_INDEX.find((b) => b.name === name);
|
|
6366
|
-
if (!entry)
|
|
6367
|
-
return;
|
|
6368
|
-
return { ...entry, available: hasBridge(name) };
|
|
6369
|
-
}
|
|
6370
|
-
function isAvailable(name) {
|
|
6371
|
-
const cap = getCapability(name);
|
|
6372
|
-
return !!cap && cap.available;
|
|
6373
|
-
}
|
|
6374
2583
|
export {
|
|
6375
2584
|
windowEvents,
|
|
6376
2585
|
watchScreenSharing,
|
|
@@ -6420,7 +2629,7 @@ export {
|
|
|
6420
2629
|
requestNotificationPermission,
|
|
6421
2630
|
registerHotkey,
|
|
6422
2631
|
redactPII,
|
|
6423
|
-
|
|
2632
|
+
prompt,
|
|
6424
2633
|
printing,
|
|
6425
2634
|
permissions,
|
|
6426
2635
|
pdf,
|
|
@@ -6529,7 +2738,7 @@ export {
|
|
|
6529
2738
|
craftBinaryNotFoundMessage2 as craftBinaryNotFoundMessage,
|
|
6530
2739
|
coreml,
|
|
6531
2740
|
continuityCamera,
|
|
6532
|
-
|
|
2741
|
+
confirm,
|
|
6533
2742
|
closeAllWindows,
|
|
6534
2743
|
closeAllModals,
|
|
6535
2744
|
clipboard,
|
|
@@ -6541,7 +2750,7 @@ export {
|
|
|
6541
2750
|
audio,
|
|
6542
2751
|
appleScript,
|
|
6543
2752
|
app as appInfo,
|
|
6544
|
-
|
|
2753
|
+
alert,
|
|
6545
2754
|
UPDATE_MANIFEST_ASSET,
|
|
6546
2755
|
TRAY_MENU_STYLES,
|
|
6547
2756
|
TOAST_STYLES,
|
|
@@ -6553,5 +2762,3 @@ export {
|
|
|
6553
2762
|
AutoUpdater,
|
|
6554
2763
|
AVAILABLE_COMPONENTS
|
|
6555
2764
|
};
|
|
6556
|
-
|
|
6557
|
-
//# debugId=4BACEAAC5AF2924164756E2164756E21
|