@stacksjs/desktop 0.2.21 → 0.2.25
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/_bridge.d.ts +105 -0
- package/dist/app-info.d.ts +22 -0
- package/dist/apple-script.d.ts +8 -0
- package/dist/audio.d.ts +17 -0
- package/dist/battery.d.ts +15 -0
- package/dist/biometric.d.ts +14 -0
- package/dist/bluetooth.d.ts +52 -0
- package/dist/bonjour.d.ts +13 -0
- package/dist/capabilities.d.ts +31 -0
- package/dist/clipboard.d.ts +11 -0
- package/dist/continuity-camera.d.ts +10 -0
- package/dist/coreml.d.ts +6 -0
- package/dist/crash-reporter.d.ts +46 -0
- package/dist/deep-link.d.ts +10 -0
- package/dist/drag-out.d.ts +18 -0
- package/dist/file-associations.d.ts +5 -0
- package/dist/fs.d.ts +62 -0
- package/dist/global-shortcuts.d.ts +19 -0
- package/dist/handoff.d.ts +24 -0
- package/dist/hotkeys.d.ts +10 -8
- package/dist/iap.d.ts +79 -0
- package/dist/index.d.ts +322 -0
- package/dist/index.js +2505 -20
- package/dist/index.js.map +55 -7
- package/dist/keychain.d.ts +7 -0
- package/dist/live-activities.d.ts +11 -0
- package/dist/local-server.d.ts +23 -0
- package/dist/location.d.ts +29 -0
- package/dist/log.d.ts +7 -0
- package/dist/menu.d.ts +29 -0
- package/dist/midi.d.ts +17 -0
- package/dist/native-autolaunch.d.ts +6 -0
- package/dist/network.d.ts +33 -0
- package/dist/notifications.d.ts +56 -0
- package/dist/pdf.d.ts +5 -0
- package/dist/permissions.d.ts +21 -0
- package/dist/printing.d.ts +9 -0
- package/dist/screen-capture.d.ts +11 -0
- package/dist/screen.d.ts +18 -0
- package/dist/serial.d.ts +15 -0
- package/dist/service-menu.d.ts +10 -0
- package/dist/shell.d.ts +28 -0
- package/dist/speech-recognition.d.ts +12 -0
- package/dist/speech.d.ts +21 -0
- package/dist/spotlight.d.ts +12 -0
- package/dist/system.d.ts +16 -0
- package/dist/tags.d.ts +6 -0
- package/dist/test-utils.d.ts +17 -0
- package/dist/test-utils.js +108 -0
- package/dist/test-utils.js.map +10 -0
- package/dist/theme.d.ts +10 -0
- package/dist/touchbar.d.ts +29 -0
- package/dist/updater.d.ts +37 -0
- package/dist/vision.d.ts +17 -0
- package/dist/window-events.d.ts +20 -0
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -2772,14 +2772,19 @@ async function createWindow(url, options = {}) {
|
|
|
2772
2772
|
}
|
|
2773
2773
|
async function openDevWindow(port, options = {}) {
|
|
2774
2774
|
const url = `http://localhost:${port}/`;
|
|
2775
|
+
const isTestEnv = process3.env.NODE_ENV === "test" || process3.env.BUN_TEST;
|
|
2776
|
+
if (isTestEnv) {
|
|
2777
|
+
console.warn("\u26A0 Skipping native window in test environment");
|
|
2778
|
+
console.log("(Skipping browser fallback in test environment)");
|
|
2779
|
+
return false;
|
|
2780
|
+
}
|
|
2775
2781
|
try {
|
|
2776
2782
|
const { createApp } = await import("ts-craft");
|
|
2777
|
-
console.log("\u26A1 Opening native window
|
|
2778
|
-
const craftPath = getCraftBinaryPath();
|
|
2783
|
+
console.log("\u26A1 Opening native window via ts-craft\u2026");
|
|
2779
2784
|
const useSystemTray = !options.nativeSidebar;
|
|
2780
2785
|
const app = createApp({
|
|
2781
2786
|
url,
|
|
2782
|
-
craftPath,
|
|
2787
|
+
craftPath: getCraftBinaryPath(),
|
|
2783
2788
|
window: {
|
|
2784
2789
|
title: options.title || "stx Development",
|
|
2785
2790
|
width: options.width || 1400,
|
|
@@ -2798,30 +2803,51 @@ async function openDevWindow(port, options = {}) {
|
|
|
2798
2803
|
activeWindows.set(id, { app, url, options });
|
|
2799
2804
|
await app.show();
|
|
2800
2805
|
console.log(`\u2713 Native window opened at ${url}`);
|
|
2801
|
-
console.log(`\uD83D\uDCCC Look for the "stx Development" icon in your menubar`);
|
|
2802
2806
|
return true;
|
|
2803
|
-
} catch (
|
|
2804
|
-
|
|
2807
|
+
} catch (tsCraftErr) {
|
|
2808
|
+
const craftPath = getCraftBinaryPath();
|
|
2809
|
+
if (craftPath) {
|
|
2810
|
+
try {
|
|
2811
|
+
console.log(`\u26A1 Opening native window via craft binary (${craftPath})\u2026`);
|
|
2812
|
+
const { spawn } = await import("child_process");
|
|
2813
|
+
const args = [
|
|
2814
|
+
"--url",
|
|
2815
|
+
url,
|
|
2816
|
+
"--title",
|
|
2817
|
+
options.title || "stx Development",
|
|
2818
|
+
"--width",
|
|
2819
|
+
String(options.width || 1400),
|
|
2820
|
+
"--height",
|
|
2821
|
+
String(options.height || 900)
|
|
2822
|
+
];
|
|
2823
|
+
if (options.darkMode)
|
|
2824
|
+
args.push("--dark");
|
|
2825
|
+
if (options.hotReload ?? true)
|
|
2826
|
+
args.push("--hot-reload");
|
|
2827
|
+
const child = spawn(craftPath, args, { stdio: "inherit" });
|
|
2828
|
+
child.on("exit", () => process3.exit(0));
|
|
2829
|
+
child.on("error", (err) => console.warn("craft child error:", err.message));
|
|
2830
|
+
const id = `dev-window-${port}`;
|
|
2831
|
+
activeWindows.set(id, { app: { close: () => child.kill() }, url, options });
|
|
2832
|
+
console.log(`\u2713 Native window opened at ${url}`);
|
|
2833
|
+
return true;
|
|
2834
|
+
} catch (binaryErr) {
|
|
2835
|
+
console.warn("\u26A0 Could not spawn craft binary:", binaryErr.message);
|
|
2836
|
+
}
|
|
2837
|
+
} else {
|
|
2838
|
+
console.warn("\u26A0 ts-craft not installed and no craft binary found");
|
|
2839
|
+
console.warn(` (ts-craft error: ${tsCraftErr.message})`);
|
|
2840
|
+
}
|
|
2805
2841
|
if (process3.env.NODE_ENV === "test" || process3.env.BUN_TEST) {
|
|
2806
2842
|
console.log("(Skipping browser fallback in test environment)");
|
|
2807
2843
|
return false;
|
|
2808
2844
|
}
|
|
2809
|
-
console.log("\uD83D\uDCF1 Opening in browser instead
|
|
2845
|
+
console.log("\uD83D\uDCF1 Opening in browser instead\u2026");
|
|
2810
2846
|
try {
|
|
2811
2847
|
const { spawn } = await import("child_process");
|
|
2812
2848
|
const platform = process3.platform;
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
if (platform === "darwin") {
|
|
2816
|
-
command = "open";
|
|
2817
|
-
args = [url];
|
|
2818
|
-
} else if (platform === "win32") {
|
|
2819
|
-
command = "cmd";
|
|
2820
|
-
args = ["/c", "start", url];
|
|
2821
|
-
} else {
|
|
2822
|
-
command = "xdg-open";
|
|
2823
|
-
args = [url];
|
|
2824
|
-
}
|
|
2849
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
2850
|
+
const args = platform === "win32" ? ["/c", "start", url] : [url];
|
|
2825
2851
|
spawn(command, args, { detached: true, stdio: "ignore" }).unref();
|
|
2826
2852
|
console.log(`\u2713 Browser opened at ${url}`);
|
|
2827
2853
|
return true;
|
|
@@ -3760,10 +3786,2428 @@ function formatCompact(ms) {
|
|
|
3760
3786
|
}
|
|
3761
3787
|
return `${seconds}s`;
|
|
3762
3788
|
}
|
|
3789
|
+
// src/_bridge.ts
|
|
3790
|
+
function hasBridge(ns) {
|
|
3791
|
+
if (typeof window === "undefined")
|
|
3792
|
+
return false;
|
|
3793
|
+
const c = window.craft;
|
|
3794
|
+
return !!(c && c[ns]);
|
|
3795
|
+
}
|
|
3796
|
+
function requireBridge(ns) {
|
|
3797
|
+
if (!hasBridge(ns)) {
|
|
3798
|
+
throw new Error(`craft.${ns} is not available \u2014 this API requires a Craft native window`);
|
|
3799
|
+
}
|
|
3800
|
+
return window.craft[ns];
|
|
3801
|
+
}
|
|
3802
|
+
function onCraftEvent(name, cb) {
|
|
3803
|
+
if (typeof window === "undefined")
|
|
3804
|
+
return () => {};
|
|
3805
|
+
const h = (e) => cb(e.detail ?? {});
|
|
3806
|
+
window.addEventListener(name, h);
|
|
3807
|
+
return () => window.removeEventListener(name, h);
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
// src/clipboard.ts
|
|
3811
|
+
var clipboard = {
|
|
3812
|
+
async writeText(text) {
|
|
3813
|
+
if (hasBridge("clipboard")) {
|
|
3814
|
+
await window.craft.clipboard.writeText(text);
|
|
3815
|
+
return;
|
|
3816
|
+
}
|
|
3817
|
+
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
3818
|
+
await navigator.clipboard.writeText(text);
|
|
3819
|
+
}
|
|
3820
|
+
},
|
|
3821
|
+
async readText() {
|
|
3822
|
+
if (hasBridge("clipboard")) {
|
|
3823
|
+
const v = await window.craft.clipboard.readText();
|
|
3824
|
+
return typeof v === "string" ? v : "";
|
|
3825
|
+
}
|
|
3826
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.readText) {
|
|
3827
|
+
try {
|
|
3828
|
+
return await navigator.clipboard.readText();
|
|
3829
|
+
} catch {
|
|
3830
|
+
return "";
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
return "";
|
|
3834
|
+
},
|
|
3835
|
+
async writeHTML(html) {
|
|
3836
|
+
if (hasBridge("clipboard")) {
|
|
3837
|
+
await window.craft.clipboard.writeHTML(html);
|
|
3838
|
+
return;
|
|
3839
|
+
}
|
|
3840
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.write) {
|
|
3841
|
+
try {
|
|
3842
|
+
const item = new window.ClipboardItem({
|
|
3843
|
+
"text/html": new Blob([html], { type: "text/html" }),
|
|
3844
|
+
"text/plain": new Blob([stripHtml(html)], { type: "text/plain" })
|
|
3845
|
+
});
|
|
3846
|
+
await navigator.clipboard.write([item]);
|
|
3847
|
+
} catch {}
|
|
3848
|
+
}
|
|
3849
|
+
},
|
|
3850
|
+
async readHTML() {
|
|
3851
|
+
if (hasBridge("clipboard")) {
|
|
3852
|
+
const v = await window.craft.clipboard.readHTML();
|
|
3853
|
+
return typeof v === "string" ? v : "";
|
|
3854
|
+
}
|
|
3855
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.read) {
|
|
3856
|
+
try {
|
|
3857
|
+
const items = await navigator.clipboard.read();
|
|
3858
|
+
for (const item of items) {
|
|
3859
|
+
if (item.types.includes("text/html")) {
|
|
3860
|
+
const blob = await item.getType("text/html");
|
|
3861
|
+
return await blob.text();
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
} catch {}
|
|
3865
|
+
}
|
|
3866
|
+
return "";
|
|
3867
|
+
},
|
|
3868
|
+
async clear() {
|
|
3869
|
+
if (hasBridge("clipboard")) {
|
|
3870
|
+
await window.craft.clipboard.clear();
|
|
3871
|
+
return;
|
|
3872
|
+
}
|
|
3873
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
3874
|
+
try {
|
|
3875
|
+
await navigator.clipboard.writeText("");
|
|
3876
|
+
} catch {}
|
|
3877
|
+
}
|
|
3878
|
+
},
|
|
3879
|
+
async hasText() {
|
|
3880
|
+
if (hasBridge("clipboard")) {
|
|
3881
|
+
return await window.craft.clipboard.hasText();
|
|
3882
|
+
}
|
|
3883
|
+
return (await this.readText()).length > 0;
|
|
3884
|
+
},
|
|
3885
|
+
async hasHTML() {
|
|
3886
|
+
if (hasBridge("clipboard")) {
|
|
3887
|
+
return await window.craft.clipboard.hasHTML();
|
|
3888
|
+
}
|
|
3889
|
+
return (await this.readHTML()).length > 0;
|
|
3890
|
+
},
|
|
3891
|
+
async hasImage() {
|
|
3892
|
+
if (hasBridge("clipboard")) {
|
|
3893
|
+
return await window.craft.clipboard.hasImage();
|
|
3894
|
+
}
|
|
3895
|
+
return false;
|
|
3896
|
+
}
|
|
3897
|
+
};
|
|
3898
|
+
function stripHtml(html) {
|
|
3899
|
+
return html.replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/gi, "").replace(/<\/?(br|p|div|li|h[1-6])\b[^>]*>/gi, `
|
|
3900
|
+
`).replace(/<[^>]+>/g, "").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\n{3,}/g, `
|
|
3901
|
+
|
|
3902
|
+
`).trim();
|
|
3903
|
+
}
|
|
3904
|
+
// src/notifications.ts
|
|
3905
|
+
var notifications = {
|
|
3906
|
+
async show(options) {
|
|
3907
|
+
if (!options.title)
|
|
3908
|
+
throw new Error("notification title is required");
|
|
3909
|
+
if (hasBridge("notifications")) {
|
|
3910
|
+
await window.craft.notifications.show(options);
|
|
3911
|
+
return;
|
|
3912
|
+
}
|
|
3913
|
+
if (typeof window !== "undefined" && "Notification" in window) {
|
|
3914
|
+
const N = window.Notification;
|
|
3915
|
+
if (N.permission === "granted") {
|
|
3916
|
+
new N(options.title, { body: options.body, icon: options.icon });
|
|
3917
|
+
} else if (N.permission === "default") {
|
|
3918
|
+
const granted = await N.requestPermission() === "granted";
|
|
3919
|
+
if (granted)
|
|
3920
|
+
new N(options.title, { body: options.body, icon: options.icon });
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
},
|
|
3924
|
+
async schedule(options) {
|
|
3925
|
+
if (hasBridge("notifications")) {
|
|
3926
|
+
const o = { ...options };
|
|
3927
|
+
if (o.triggerAt instanceof Date)
|
|
3928
|
+
o.triggerAt = o.triggerAt.toISOString();
|
|
3929
|
+
await window.craft.notifications.schedule(o);
|
|
3930
|
+
return;
|
|
3931
|
+
}
|
|
3932
|
+
const fireAt = toEpochMs(options.triggerAt);
|
|
3933
|
+
const delay2 = Math.max(0, fireAt - Date.now());
|
|
3934
|
+
setTimeout(() => {
|
|
3935
|
+
this.show(options).catch(() => {});
|
|
3936
|
+
}, delay2);
|
|
3937
|
+
},
|
|
3938
|
+
async cancel(id) {
|
|
3939
|
+
if (hasBridge("notifications")) {
|
|
3940
|
+
await window.craft.notifications.cancel(id);
|
|
3941
|
+
}
|
|
3942
|
+
},
|
|
3943
|
+
async cancelAll() {
|
|
3944
|
+
if (hasBridge("notifications")) {
|
|
3945
|
+
await window.craft.notifications.cancelAll();
|
|
3946
|
+
}
|
|
3947
|
+
},
|
|
3948
|
+
async setBadge(n) {
|
|
3949
|
+
const safe = Math.max(0, Math.round(Number.isFinite(n) ? n : 0));
|
|
3950
|
+
if (hasBridge("notifications")) {
|
|
3951
|
+
await window.craft.notifications.setBadge(safe);
|
|
3952
|
+
return;
|
|
3953
|
+
}
|
|
3954
|
+
if (typeof navigator !== "undefined" && navigator.setAppBadge) {
|
|
3955
|
+
try {
|
|
3956
|
+
await navigator.setAppBadge(safe);
|
|
3957
|
+
} catch {}
|
|
3958
|
+
}
|
|
3959
|
+
},
|
|
3960
|
+
async clearBadge() {
|
|
3961
|
+
if (hasBridge("notifications")) {
|
|
3962
|
+
await window.craft.notifications.clearBadge();
|
|
3963
|
+
return;
|
|
3964
|
+
}
|
|
3965
|
+
if (typeof navigator !== "undefined" && navigator.clearAppBadge) {
|
|
3966
|
+
try {
|
|
3967
|
+
await navigator.clearAppBadge();
|
|
3968
|
+
} catch {}
|
|
3969
|
+
}
|
|
3970
|
+
},
|
|
3971
|
+
async requestPermission() {
|
|
3972
|
+
if (hasBridge("notifications")) {
|
|
3973
|
+
return await window.craft.notifications.requestPermission();
|
|
3974
|
+
}
|
|
3975
|
+
if (typeof window !== "undefined" && "Notification" in window) {
|
|
3976
|
+
const N = window.Notification;
|
|
3977
|
+
if (N.permission === "granted")
|
|
3978
|
+
return true;
|
|
3979
|
+
if (N.permission === "denied")
|
|
3980
|
+
return false;
|
|
3981
|
+
const result = await N.requestPermission();
|
|
3982
|
+
return result === "granted";
|
|
3983
|
+
}
|
|
3984
|
+
return false;
|
|
3985
|
+
},
|
|
3986
|
+
async registerCategories(categories) {
|
|
3987
|
+
if (!Array.isArray(categories) || categories.length === 0)
|
|
3988
|
+
return;
|
|
3989
|
+
if (hasBridge("notifications")) {
|
|
3990
|
+
const fn = window.craft.notifications.registerCategories;
|
|
3991
|
+
if (typeof fn === "function")
|
|
3992
|
+
await fn(categories);
|
|
3993
|
+
}
|
|
3994
|
+
},
|
|
3995
|
+
onActionClicked(cb) {
|
|
3996
|
+
return onCraftEvent("craft:notification:actionClicked", cb);
|
|
3997
|
+
},
|
|
3998
|
+
onReply(cb) {
|
|
3999
|
+
return onCraftEvent("craft:notification:reply", cb);
|
|
4000
|
+
}
|
|
4001
|
+
};
|
|
4002
|
+
function toEpochMs(t) {
|
|
4003
|
+
if (t == null)
|
|
4004
|
+
return Date.now();
|
|
4005
|
+
if (t instanceof Date)
|
|
4006
|
+
return t.getTime();
|
|
4007
|
+
if (typeof t === "number")
|
|
4008
|
+
return t;
|
|
4009
|
+
const parsed = Date.parse(t);
|
|
4010
|
+
return Number.isNaN(parsed) ? Date.now() : parsed;
|
|
4011
|
+
}
|
|
4012
|
+
// src/fs.ts
|
|
4013
|
+
var fs = {
|
|
4014
|
+
async readFile(path) {
|
|
4015
|
+
const r = await requireBridge("fs").readFile(path);
|
|
4016
|
+
return r && r.data || "";
|
|
4017
|
+
},
|
|
4018
|
+
async readBuffer(path) {
|
|
4019
|
+
const r = await requireBridge("fs").readFile(path);
|
|
4020
|
+
const text = r && r.data || "";
|
|
4021
|
+
if (r && r.base64 === true) {
|
|
4022
|
+
return base64ToBytes(text);
|
|
4023
|
+
}
|
|
4024
|
+
return new TextEncoder().encode(text);
|
|
4025
|
+
},
|
|
4026
|
+
async writeFile(path, data) {
|
|
4027
|
+
await requireBridge("fs").writeFile(path, data);
|
|
4028
|
+
},
|
|
4029
|
+
async writeBuffer(path, data) {
|
|
4030
|
+
const b64 = bytesToBase64(data);
|
|
4031
|
+
const bridge = requireBridge("fs");
|
|
4032
|
+
if (typeof bridge.writeFileBytes === "function") {
|
|
4033
|
+
await bridge.writeFileBytes(path, b64);
|
|
4034
|
+
} else {
|
|
4035
|
+
await bridge.writeFile(path, b64);
|
|
4036
|
+
}
|
|
4037
|
+
},
|
|
4038
|
+
async copy(from, to) {
|
|
4039
|
+
if (from === to)
|
|
4040
|
+
throw new Error("fs.copy: source and destination must differ");
|
|
4041
|
+
await requireBridge("fs").copy(from, to);
|
|
4042
|
+
},
|
|
4043
|
+
async move(from, to) {
|
|
4044
|
+
if (from === to)
|
|
4045
|
+
throw new Error("fs.move: source and destination must differ");
|
|
4046
|
+
await requireBridge("fs").move(from, to);
|
|
4047
|
+
},
|
|
4048
|
+
async appendFile(path, data) {
|
|
4049
|
+
await requireBridge("fs").appendFile(path, data);
|
|
4050
|
+
},
|
|
4051
|
+
async deleteFile(path) {
|
|
4052
|
+
await requireBridge("fs").deleteFile(path);
|
|
4053
|
+
},
|
|
4054
|
+
async exists(path) {
|
|
4055
|
+
return await requireBridge("fs").exists(path);
|
|
4056
|
+
},
|
|
4057
|
+
async stat(path) {
|
|
4058
|
+
return normalizeStat(await requireBridge("fs").stat(path));
|
|
4059
|
+
},
|
|
4060
|
+
async readDir(path) {
|
|
4061
|
+
const r = await requireBridge("fs").readDir(path);
|
|
4062
|
+
const raw = r && r.entries || [];
|
|
4063
|
+
const base = path.endsWith("/") ? path.slice(0, -1) : path;
|
|
4064
|
+
return raw.map((e) => ({
|
|
4065
|
+
name: e.name,
|
|
4066
|
+
path: `${base}/${e.name}`,
|
|
4067
|
+
isDirectory: !!e.isDirectory
|
|
4068
|
+
}));
|
|
4069
|
+
},
|
|
4070
|
+
async mkdir(path, opts) {
|
|
4071
|
+
await requireBridge("fs").mkdir(path, opts);
|
|
4072
|
+
},
|
|
4073
|
+
async rmdir(path, opts) {
|
|
4074
|
+
await requireBridge("fs").rmdir(path, opts);
|
|
4075
|
+
},
|
|
4076
|
+
async watch(path, id) {
|
|
4077
|
+
await requireBridge("fs").watch(path, id);
|
|
4078
|
+
},
|
|
4079
|
+
async unwatch(id) {
|
|
4080
|
+
await requireBridge("fs").unwatch(id);
|
|
4081
|
+
},
|
|
4082
|
+
onChange(cb) {
|
|
4083
|
+
return onCraftEvent("craft:fs:change", cb);
|
|
4084
|
+
},
|
|
4085
|
+
async watchTree(path, options, cb) {
|
|
4086
|
+
const id = `watch-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4087
|
+
const bridge = requireBridge("fs");
|
|
4088
|
+
await bridge.watch(path, id, { recursive: !!options.recursive });
|
|
4089
|
+
const allowed = options.kinds && options.kinds.length > 0 ? new Set(options.kinds) : null;
|
|
4090
|
+
const coalesceMs = Math.max(0, Math.floor(options.coalesceMs ?? 0));
|
|
4091
|
+
let buffer = [];
|
|
4092
|
+
let flushTimer = null;
|
|
4093
|
+
let stopped = false;
|
|
4094
|
+
const flush = () => {
|
|
4095
|
+
flushTimer = null;
|
|
4096
|
+
if (buffer.length === 0)
|
|
4097
|
+
return;
|
|
4098
|
+
const batch = buffer;
|
|
4099
|
+
buffer = [];
|
|
4100
|
+
try {
|
|
4101
|
+
cb(batch);
|
|
4102
|
+
} catch {}
|
|
4103
|
+
};
|
|
4104
|
+
const off = onCraftEvent("craft:fs:change", (e) => {
|
|
4105
|
+
if (stopped)
|
|
4106
|
+
return;
|
|
4107
|
+
if (e.id !== id)
|
|
4108
|
+
return;
|
|
4109
|
+
if (allowed && e.kind && !allowed.has(e.kind))
|
|
4110
|
+
return;
|
|
4111
|
+
buffer.push(e);
|
|
4112
|
+
if (coalesceMs === 0) {
|
|
4113
|
+
flush();
|
|
4114
|
+
return;
|
|
4115
|
+
}
|
|
4116
|
+
if (flushTimer == null) {
|
|
4117
|
+
flushTimer = setTimeout(flush, coalesceMs);
|
|
4118
|
+
}
|
|
4119
|
+
});
|
|
4120
|
+
return {
|
|
4121
|
+
id,
|
|
4122
|
+
async stop() {
|
|
4123
|
+
if (stopped)
|
|
4124
|
+
return;
|
|
4125
|
+
stopped = true;
|
|
4126
|
+
off();
|
|
4127
|
+
if (flushTimer) {
|
|
4128
|
+
clearTimeout(flushTimer);
|
|
4129
|
+
flushTimer = null;
|
|
4130
|
+
}
|
|
4131
|
+
if (buffer.length > 0)
|
|
4132
|
+
flush();
|
|
4133
|
+
try {
|
|
4134
|
+
await bridge.unwatch(id);
|
|
4135
|
+
} catch {}
|
|
4136
|
+
}
|
|
4137
|
+
};
|
|
4138
|
+
},
|
|
4139
|
+
async homeDir() {
|
|
4140
|
+
return await requireBridge("fs").homeDir();
|
|
4141
|
+
},
|
|
4142
|
+
async tempDir() {
|
|
4143
|
+
return await requireBridge("fs").tempDir();
|
|
4144
|
+
},
|
|
4145
|
+
async appDataDir() {
|
|
4146
|
+
return await requireBridge("fs").appDataDir();
|
|
4147
|
+
}
|
|
4148
|
+
};
|
|
4149
|
+
function bytesToBase64(bytes) {
|
|
4150
|
+
let s = "";
|
|
4151
|
+
for (let i = 0;i < bytes.length; i++)
|
|
4152
|
+
s += String.fromCharCode(bytes[i]);
|
|
4153
|
+
return typeof btoa === "function" ? btoa(s) : Buffer.from(bytes).toString("base64");
|
|
4154
|
+
}
|
|
4155
|
+
function base64ToBytes(b64) {
|
|
4156
|
+
const bin = typeof atob === "function" ? atob(b64) : Buffer.from(b64, "base64").toString("binary");
|
|
4157
|
+
const out = new Uint8Array(bin.length);
|
|
4158
|
+
for (let i = 0;i < bin.length; i++)
|
|
4159
|
+
out[i] = bin.charCodeAt(i);
|
|
4160
|
+
return out;
|
|
4161
|
+
}
|
|
4162
|
+
function normalizeStat(raw) {
|
|
4163
|
+
return {
|
|
4164
|
+
isFile: !!raw.isFile,
|
|
4165
|
+
isDirectory: !!raw.isDirectory,
|
|
4166
|
+
isSymlink: !!raw.isSymlink,
|
|
4167
|
+
size: Number(raw.size) || 0,
|
|
4168
|
+
modifiedAt: raw.modifiedAt != null ? raw.modifiedAt < 1000000000000 ? raw.modifiedAt * 1000 : raw.modifiedAt : 0
|
|
4169
|
+
};
|
|
4170
|
+
}
|
|
4171
|
+
// src/shell.ts
|
|
4172
|
+
var activeSpawnIds = new Set;
|
|
4173
|
+
var exitListenerAttached = false;
|
|
4174
|
+
function ensureExitListener() {
|
|
4175
|
+
if (exitListenerAttached)
|
|
4176
|
+
return;
|
|
4177
|
+
if (typeof window === "undefined" || typeof window.addEventListener !== "function")
|
|
4178
|
+
return;
|
|
4179
|
+
window.addEventListener("craft:shell:exit", (e) => {
|
|
4180
|
+
const detail = e.detail;
|
|
4181
|
+
if (detail?.id)
|
|
4182
|
+
activeSpawnIds.delete(detail.id);
|
|
4183
|
+
});
|
|
4184
|
+
exitListenerAttached = true;
|
|
4185
|
+
}
|
|
4186
|
+
var BLOCKED_SCHEMES = new Set(["javascript:", "data:", "file:", "vbscript:"]);
|
|
4187
|
+
var shell = {
|
|
4188
|
+
async openExternal(url) {
|
|
4189
|
+
const lc = url.trim().toLowerCase();
|
|
4190
|
+
for (const s of BLOCKED_SCHEMES) {
|
|
4191
|
+
if (lc.startsWith(s)) {
|
|
4192
|
+
throw new Error(`shell.openExternal: ${s} URLs are blocked for safety`);
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
if (hasBridge("shell")) {
|
|
4196
|
+
await window.craft.shell.openExternal(url);
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
if (typeof window !== "undefined" && typeof window.open === "function") {
|
|
4200
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
4201
|
+
}
|
|
4202
|
+
},
|
|
4203
|
+
async openPath(path) {
|
|
4204
|
+
await requireBridge("shell").openPath(path);
|
|
4205
|
+
},
|
|
4206
|
+
async showInFinder(path) {
|
|
4207
|
+
await requireBridge("shell").showInFinder(path);
|
|
4208
|
+
},
|
|
4209
|
+
async spawn(id, command, args = [], opts = {}) {
|
|
4210
|
+
ensureExitListener();
|
|
4211
|
+
if (!id || typeof id !== "string")
|
|
4212
|
+
throw new Error("shell.spawn: id must be a non-empty string");
|
|
4213
|
+
if (!command || typeof command !== "string")
|
|
4214
|
+
throw new Error("shell.spawn: command must be a non-empty string");
|
|
4215
|
+
if (!Array.isArray(args))
|
|
4216
|
+
throw new Error("shell.spawn: args must be an array");
|
|
4217
|
+
for (const a of args) {
|
|
4218
|
+
if (typeof a !== "string")
|
|
4219
|
+
throw new Error("shell.spawn: args entries must be strings");
|
|
4220
|
+
}
|
|
4221
|
+
if (activeSpawnIds.has(id)) {
|
|
4222
|
+
throw new Error(`shell.spawn: id "${id}" is already in use \u2014 call kill(id) first or pick a different id`);
|
|
4223
|
+
}
|
|
4224
|
+
activeSpawnIds.add(id);
|
|
4225
|
+
try {
|
|
4226
|
+
await requireBridge("shell").spawn(id, command, args, opts);
|
|
4227
|
+
} catch (e) {
|
|
4228
|
+
activeSpawnIds.delete(id);
|
|
4229
|
+
throw e;
|
|
4230
|
+
}
|
|
4231
|
+
},
|
|
4232
|
+
async kill(id) {
|
|
4233
|
+
await requireBridge("shell").kill(id);
|
|
4234
|
+
activeSpawnIds.delete(id);
|
|
4235
|
+
},
|
|
4236
|
+
async getEnv(name) {
|
|
4237
|
+
if (hasBridge("shell")) {
|
|
4238
|
+
const v = await window.craft.shell.getEnv(name);
|
|
4239
|
+
return v == null ? undefined : String(v);
|
|
4240
|
+
}
|
|
4241
|
+
return;
|
|
4242
|
+
},
|
|
4243
|
+
async setEnv(name, value) {
|
|
4244
|
+
await requireBridge("shell").setEnv(name, value);
|
|
4245
|
+
},
|
|
4246
|
+
onStdout(cb) {
|
|
4247
|
+
return onCraftEvent("craft:shell:stdout", cb);
|
|
4248
|
+
},
|
|
4249
|
+
onStderr(cb) {
|
|
4250
|
+
return onCraftEvent("craft:shell:stderr", cb);
|
|
4251
|
+
},
|
|
4252
|
+
onExit(cb) {
|
|
4253
|
+
return onCraftEvent("craft:shell:exit", cb);
|
|
4254
|
+
}
|
|
4255
|
+
};
|
|
4256
|
+
// src/global-shortcuts.ts
|
|
4257
|
+
var globalShortcuts = {
|
|
4258
|
+
async register(id, accelerator, opts) {
|
|
4259
|
+
if (!hasBridge("shortcuts"))
|
|
4260
|
+
return;
|
|
4261
|
+
await window.craft.shortcuts.register(id, accelerator, opts);
|
|
4262
|
+
},
|
|
4263
|
+
async unregister(id) {
|
|
4264
|
+
if (!hasBridge("shortcuts"))
|
|
4265
|
+
return;
|
|
4266
|
+
await window.craft.shortcuts.unregister(id);
|
|
4267
|
+
},
|
|
4268
|
+
async unregisterAll() {
|
|
4269
|
+
if (!hasBridge("shortcuts"))
|
|
4270
|
+
return;
|
|
4271
|
+
await window.craft.shortcuts.unregisterAll();
|
|
4272
|
+
},
|
|
4273
|
+
async enable(id) {
|
|
4274
|
+
if (!hasBridge("shortcuts"))
|
|
4275
|
+
return;
|
|
4276
|
+
await window.craft.shortcuts.enable(id);
|
|
4277
|
+
},
|
|
4278
|
+
async disable(id) {
|
|
4279
|
+
if (!hasBridge("shortcuts"))
|
|
4280
|
+
return;
|
|
4281
|
+
await window.craft.shortcuts.disable(id);
|
|
4282
|
+
},
|
|
4283
|
+
async isRegistered(id) {
|
|
4284
|
+
if (!hasBridge("shortcuts"))
|
|
4285
|
+
return false;
|
|
4286
|
+
return await window.craft.shortcuts.isRegistered(id);
|
|
4287
|
+
},
|
|
4288
|
+
async list() {
|
|
4289
|
+
if (!hasBridge("shortcuts"))
|
|
4290
|
+
return [];
|
|
4291
|
+
return await window.craft.shortcuts.list();
|
|
4292
|
+
},
|
|
4293
|
+
on(cb) {
|
|
4294
|
+
return onCraftEvent("craft:shortcut", cb);
|
|
4295
|
+
}
|
|
4296
|
+
};
|
|
4297
|
+
// src/theme.ts
|
|
4298
|
+
var theme = {
|
|
4299
|
+
get() {
|
|
4300
|
+
if (hasBridge("theme")) {
|
|
4301
|
+
try {
|
|
4302
|
+
return window.craft.theme.get();
|
|
4303
|
+
} catch {}
|
|
4304
|
+
}
|
|
4305
|
+
return { appearance: detectWebAppearance() };
|
|
4306
|
+
},
|
|
4307
|
+
onChange(cb) {
|
|
4308
|
+
cb(this.get());
|
|
4309
|
+
if (hasBridge("theme")) {
|
|
4310
|
+
return onCraftEvent("craft:theme", cb);
|
|
4311
|
+
}
|
|
4312
|
+
if (typeof window !== "undefined" && window.matchMedia) {
|
|
4313
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
4314
|
+
const handler = () => cb({ appearance: mq.matches ? "dark" : "light" });
|
|
4315
|
+
mq.addEventListener("change", handler);
|
|
4316
|
+
return () => mq.removeEventListener("change", handler);
|
|
4317
|
+
}
|
|
4318
|
+
return () => {};
|
|
4319
|
+
},
|
|
4320
|
+
async current() {
|
|
4321
|
+
return this.get();
|
|
4322
|
+
}
|
|
4323
|
+
};
|
|
4324
|
+
function detectWebAppearance() {
|
|
4325
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
4326
|
+
return "light";
|
|
4327
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
4328
|
+
}
|
|
4329
|
+
// src/drag-out.ts
|
|
4330
|
+
async function dragOut(paths, options = {}) {
|
|
4331
|
+
if (!hasBridge("dragOut")) {
|
|
4332
|
+
throw new Error("dragOut requires a Craft native window");
|
|
4333
|
+
}
|
|
4334
|
+
const arr = Array.isArray(paths) ? paths : [paths];
|
|
4335
|
+
if (arr.length === 0)
|
|
4336
|
+
throw new Error("dragOut: at least one path required");
|
|
4337
|
+
await window.craft.dragOut.start(arr, options);
|
|
4338
|
+
}
|
|
4339
|
+
function isDragOutAvailable() {
|
|
4340
|
+
return hasBridge("dragOut");
|
|
4341
|
+
}
|
|
4342
|
+
// src/deep-link.ts
|
|
4343
|
+
var deepLinks = {
|
|
4344
|
+
onUrl(cb) {
|
|
4345
|
+
if (!hasBridge("deepLink"))
|
|
4346
|
+
return () => {};
|
|
4347
|
+
return onCraftEvent("craft:deepLink", cb);
|
|
4348
|
+
},
|
|
4349
|
+
getInitialUrl() {
|
|
4350
|
+
if (typeof window === "undefined")
|
|
4351
|
+
return null;
|
|
4352
|
+
if (hasBridge("deepLink")) {
|
|
4353
|
+
try {
|
|
4354
|
+
return window.craft.deepLink.getInitialUrl();
|
|
4355
|
+
} catch {
|
|
4356
|
+
return null;
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
return window.__craftPendingDeepLink || null;
|
|
4360
|
+
},
|
|
4361
|
+
consumeInitialUrl() {
|
|
4362
|
+
const url = this.getInitialUrl();
|
|
4363
|
+
if (typeof window !== "undefined")
|
|
4364
|
+
window.__craftPendingDeepLink = undefined;
|
|
4365
|
+
return url;
|
|
4366
|
+
},
|
|
4367
|
+
isAvailable() {
|
|
4368
|
+
return hasBridge("deepLink");
|
|
4369
|
+
}
|
|
4370
|
+
};
|
|
4371
|
+
// src/battery.ts
|
|
4372
|
+
var battery = {
|
|
4373
|
+
async isCharging() {
|
|
4374
|
+
if (hasBridge("power"))
|
|
4375
|
+
return await window.craft.power.isCharging();
|
|
4376
|
+
const b = await getWebBatteryManager();
|
|
4377
|
+
return b ? !!b.charging : false;
|
|
4378
|
+
},
|
|
4379
|
+
async isPluggedIn() {
|
|
4380
|
+
if (hasBridge("power"))
|
|
4381
|
+
return await window.craft.power.isPluggedIn();
|
|
4382
|
+
const b = await getWebBatteryManager();
|
|
4383
|
+
return b ? !!b.charging || b.level >= 0.999 : false;
|
|
4384
|
+
},
|
|
4385
|
+
async isLowPowerMode() {
|
|
4386
|
+
if (hasBridge("power"))
|
|
4387
|
+
return await window.craft.power.isLowPowerMode();
|
|
4388
|
+
return false;
|
|
4389
|
+
},
|
|
4390
|
+
async level() {
|
|
4391
|
+
if (hasBridge("power")) {
|
|
4392
|
+
const v = await window.craft.power.batteryLevel();
|
|
4393
|
+
return typeof v === "number" ? v : null;
|
|
4394
|
+
}
|
|
4395
|
+
const b = await getWebBatteryManager();
|
|
4396
|
+
return b ? b.level : null;
|
|
4397
|
+
},
|
|
4398
|
+
async timeRemaining() {
|
|
4399
|
+
if (hasBridge("power")) {
|
|
4400
|
+
const r = await window.craft.power.timeRemaining();
|
|
4401
|
+
return typeof r === "number" ? r : null;
|
|
4402
|
+
}
|
|
4403
|
+
const b = await getWebBatteryManager();
|
|
4404
|
+
if (!b)
|
|
4405
|
+
return null;
|
|
4406
|
+
const sec = b.charging ? b.chargingTime : b.dischargingTime;
|
|
4407
|
+
return Number.isFinite(sec) ? Math.round(sec / 60) : null;
|
|
4408
|
+
},
|
|
4409
|
+
async thermalState() {
|
|
4410
|
+
if (hasBridge("power")) {
|
|
4411
|
+
const s = await window.craft.power.thermalState();
|
|
4412
|
+
return s || "unknown";
|
|
4413
|
+
}
|
|
4414
|
+
return "unknown";
|
|
4415
|
+
},
|
|
4416
|
+
async uptimeSeconds() {
|
|
4417
|
+
if (hasBridge("power"))
|
|
4418
|
+
return await window.craft.power.uptimeSeconds();
|
|
4419
|
+
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
4420
|
+
return Math.round(performance.now() / 1000);
|
|
4421
|
+
}
|
|
4422
|
+
return 0;
|
|
4423
|
+
},
|
|
4424
|
+
async preventSleep(reason = "app is busy") {
|
|
4425
|
+
if (hasBridge("power")) {
|
|
4426
|
+
await window.craft.power.preventSleep(reason);
|
|
4427
|
+
return;
|
|
4428
|
+
}
|
|
4429
|
+
if (typeof navigator === "undefined" || !navigator.wakeLock)
|
|
4430
|
+
return;
|
|
4431
|
+
const w = window;
|
|
4432
|
+
if (w.__craftWebWakeLock?.release) {
|
|
4433
|
+
try {
|
|
4434
|
+
await w.__craftWebWakeLock.release();
|
|
4435
|
+
} catch {}
|
|
4436
|
+
w.__craftWebWakeLock = null;
|
|
4437
|
+
}
|
|
4438
|
+
try {
|
|
4439
|
+
const sentinel = await navigator.wakeLock.request("screen");
|
|
4440
|
+
w.__craftWebWakeLock = sentinel;
|
|
4441
|
+
} catch {}
|
|
4442
|
+
},
|
|
4443
|
+
async allowSleep() {
|
|
4444
|
+
if (hasBridge("power")) {
|
|
4445
|
+
await window.craft.power.allowSleep();
|
|
4446
|
+
return;
|
|
4447
|
+
}
|
|
4448
|
+
const s = window.__craftWebWakeLock;
|
|
4449
|
+
if (s && typeof s.release === "function") {
|
|
4450
|
+
try {
|
|
4451
|
+
await s.release();
|
|
4452
|
+
} catch {}
|
|
4453
|
+
window.__craftWebWakeLock = null;
|
|
4454
|
+
}
|
|
4455
|
+
},
|
|
4456
|
+
onSleep(cb) {
|
|
4457
|
+
return onCraftEvent("craft:powerSleep", cb);
|
|
4458
|
+
},
|
|
4459
|
+
onWake(cb) {
|
|
4460
|
+
return onCraftEvent("craft:powerWake", cb);
|
|
4461
|
+
}
|
|
4462
|
+
};
|
|
4463
|
+
async function getWebBatteryManager() {
|
|
4464
|
+
if (typeof navigator === "undefined")
|
|
4465
|
+
return null;
|
|
4466
|
+
const nav = navigator;
|
|
4467
|
+
if (typeof nav.getBattery !== "function")
|
|
4468
|
+
return null;
|
|
4469
|
+
try {
|
|
4470
|
+
return await nav.getBattery();
|
|
4471
|
+
} catch {
|
|
4472
|
+
return null;
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
// src/network.ts
|
|
4476
|
+
var network = {
|
|
4477
|
+
async connectionType() {
|
|
4478
|
+
if (hasBridge("network"))
|
|
4479
|
+
return await window.craft.network.connectionType();
|
|
4480
|
+
return webConnectionType();
|
|
4481
|
+
},
|
|
4482
|
+
async wifiSSID() {
|
|
4483
|
+
if (hasBridge("network")) {
|
|
4484
|
+
const v = await window.craft.network.wifiSSID();
|
|
4485
|
+
return v || undefined;
|
|
4486
|
+
}
|
|
4487
|
+
return;
|
|
4488
|
+
},
|
|
4489
|
+
async wifiSignalStrength() {
|
|
4490
|
+
if (hasBridge("network")) {
|
|
4491
|
+
const v = await window.craft.network.wifiSignalStrength();
|
|
4492
|
+
return typeof v === "number" ? v : undefined;
|
|
4493
|
+
}
|
|
4494
|
+
return;
|
|
4495
|
+
},
|
|
4496
|
+
async ipAddress() {
|
|
4497
|
+
if (hasBridge("network"))
|
|
4498
|
+
return await window.craft.network.ipAddress();
|
|
4499
|
+
return "";
|
|
4500
|
+
},
|
|
4501
|
+
async macAddress() {
|
|
4502
|
+
if (hasBridge("network"))
|
|
4503
|
+
return await window.craft.network.macAddress();
|
|
4504
|
+
return "";
|
|
4505
|
+
},
|
|
4506
|
+
async interfaces() {
|
|
4507
|
+
if (hasBridge("network"))
|
|
4508
|
+
return await window.craft.network.interfaces();
|
|
4509
|
+
return [];
|
|
4510
|
+
},
|
|
4511
|
+
async isVPNConnected() {
|
|
4512
|
+
if (hasBridge("network"))
|
|
4513
|
+
return await window.craft.network.isVPNConnected();
|
|
4514
|
+
return false;
|
|
4515
|
+
},
|
|
4516
|
+
async proxySettings() {
|
|
4517
|
+
if (hasBridge("network")) {
|
|
4518
|
+
const r = await window.craft.network.proxySettings();
|
|
4519
|
+
return r || {};
|
|
4520
|
+
}
|
|
4521
|
+
return {};
|
|
4522
|
+
},
|
|
4523
|
+
async openPreferences() {
|
|
4524
|
+
if (hasBridge("network"))
|
|
4525
|
+
await window.craft.network.openPreferences();
|
|
4526
|
+
},
|
|
4527
|
+
onChange(cb) {
|
|
4528
|
+
if (hasBridge("network")) {
|
|
4529
|
+
return onCraftEvent("craft:networkChange", cb);
|
|
4530
|
+
}
|
|
4531
|
+
if (typeof window === "undefined")
|
|
4532
|
+
return () => {};
|
|
4533
|
+
const onlineH = () => cb({ type: webConnectionType(), online: true });
|
|
4534
|
+
const offlineH = () => cb({ type: "none", online: false });
|
|
4535
|
+
window.addEventListener("online", onlineH);
|
|
4536
|
+
window.addEventListener("offline", offlineH);
|
|
4537
|
+
return () => {
|
|
4538
|
+
window.removeEventListener("online", onlineH);
|
|
4539
|
+
window.removeEventListener("offline", offlineH);
|
|
4540
|
+
};
|
|
4541
|
+
}
|
|
4542
|
+
};
|
|
4543
|
+
function webConnectionType() {
|
|
4544
|
+
if (typeof navigator === "undefined")
|
|
4545
|
+
return "unknown";
|
|
4546
|
+
if (navigator.onLine === false)
|
|
4547
|
+
return "none";
|
|
4548
|
+
const conn = navigator.connection;
|
|
4549
|
+
if (!conn)
|
|
4550
|
+
return "unknown";
|
|
4551
|
+
const t = String(conn.type || conn.effectiveType || "unknown").toLowerCase();
|
|
4552
|
+
if (t === "wifi" || t === "cellular" || t === "ethernet" || t === "bluetooth" || t === "none")
|
|
4553
|
+
return t;
|
|
4554
|
+
return "unknown";
|
|
4555
|
+
}
|
|
4556
|
+
// src/updater.ts
|
|
4557
|
+
var updater = {
|
|
4558
|
+
async checkForUpdates() {
|
|
4559
|
+
if (!hasBridge("updater"))
|
|
4560
|
+
return;
|
|
4561
|
+
await window.craft.updater.checkForUpdates();
|
|
4562
|
+
},
|
|
4563
|
+
async checkInBackground() {
|
|
4564
|
+
if (!hasBridge("updater"))
|
|
4565
|
+
return;
|
|
4566
|
+
await window.craft.updater.checkInBackground();
|
|
4567
|
+
},
|
|
4568
|
+
async setAutomaticChecks(on) {
|
|
4569
|
+
if (!hasBridge("updater"))
|
|
4570
|
+
return;
|
|
4571
|
+
await window.craft.updater.setAutomaticChecks(on);
|
|
4572
|
+
},
|
|
4573
|
+
async setCheckInterval(seconds) {
|
|
4574
|
+
if (!hasBridge("updater"))
|
|
4575
|
+
return;
|
|
4576
|
+
if (!Number.isFinite(seconds)) {
|
|
4577
|
+
throw new Error("setCheckInterval: must be a finite number");
|
|
4578
|
+
}
|
|
4579
|
+
const safe = seconds <= 0 ? 0 : Math.max(60, Math.round(seconds));
|
|
4580
|
+
await window.craft.updater.setCheckInterval(safe);
|
|
4581
|
+
},
|
|
4582
|
+
async setFeedURL(url) {
|
|
4583
|
+
if (!hasBridge("updater"))
|
|
4584
|
+
return;
|
|
4585
|
+
await window.craft.updater.setFeedURL(url);
|
|
4586
|
+
},
|
|
4587
|
+
async getLastUpdateCheckDate() {
|
|
4588
|
+
if (!hasBridge("updater"))
|
|
4589
|
+
return null;
|
|
4590
|
+
const v = await window.craft.updater.getLastUpdateCheckDate();
|
|
4591
|
+
return v || null;
|
|
4592
|
+
},
|
|
4593
|
+
async getUpdateInfo() {
|
|
4594
|
+
if (!hasBridge("updater"))
|
|
4595
|
+
return null;
|
|
4596
|
+
const v = await window.craft.updater.getUpdateInfo();
|
|
4597
|
+
if (!v || typeof v.version !== "string" || v.version.length === 0)
|
|
4598
|
+
return null;
|
|
4599
|
+
return v;
|
|
4600
|
+
},
|
|
4601
|
+
onAvailable(cb) {
|
|
4602
|
+
return onCraftEvent("craft:updateAvailable", cb);
|
|
4603
|
+
},
|
|
4604
|
+
onDownloaded(cb) {
|
|
4605
|
+
return onCraftEvent("craft:updateDownloaded", cb);
|
|
4606
|
+
},
|
|
4607
|
+
async verifySignature({ payload, signatureB64, publicKeyB64 }) {
|
|
4608
|
+
const data = toArrayBufferBytes(payload);
|
|
4609
|
+
let publicKey;
|
|
4610
|
+
try {
|
|
4611
|
+
publicKey = await crypto.subtle.importKey("raw", base64ToBytes2(publicKeyB64), { name: "Ed25519" }, false, ["verify"]);
|
|
4612
|
+
} catch {
|
|
4613
|
+
return false;
|
|
4614
|
+
}
|
|
4615
|
+
try {
|
|
4616
|
+
return await crypto.subtle.verify("Ed25519", publicKey, base64ToBytes2(signatureB64), data);
|
|
4617
|
+
} catch {
|
|
4618
|
+
return false;
|
|
4619
|
+
}
|
|
4620
|
+
},
|
|
4621
|
+
async verifyDownload({ url, signatureB64, publicKeyB64, fetchInit }) {
|
|
4622
|
+
let response;
|
|
4623
|
+
try {
|
|
4624
|
+
response = await fetch(url, fetchInit);
|
|
4625
|
+
} catch {
|
|
4626
|
+
return { ok: false, reason: "fetch-failed" };
|
|
4627
|
+
}
|
|
4628
|
+
if (!response.ok) {
|
|
4629
|
+
return { ok: false, reason: "http-error", status: response.status };
|
|
4630
|
+
}
|
|
4631
|
+
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
4632
|
+
let publicKey;
|
|
4633
|
+
try {
|
|
4634
|
+
publicKey = await crypto.subtle.importKey("raw", base64ToBytes2(publicKeyB64), { name: "Ed25519" }, false, ["verify"]);
|
|
4635
|
+
} catch {
|
|
4636
|
+
return { ok: false, reason: "bad-key" };
|
|
4637
|
+
}
|
|
4638
|
+
let valid = false;
|
|
4639
|
+
try {
|
|
4640
|
+
valid = await crypto.subtle.verify("Ed25519", publicKey, base64ToBytes2(signatureB64), toArrayBufferBytes(buffer));
|
|
4641
|
+
} catch {
|
|
4642
|
+
valid = false;
|
|
4643
|
+
}
|
|
4644
|
+
if (!valid)
|
|
4645
|
+
return { ok: false, reason: "bad-signature" };
|
|
4646
|
+
return { ok: true, payload: buffer };
|
|
4647
|
+
}
|
|
4648
|
+
};
|
|
4649
|
+
function toArrayBufferBytes(input) {
|
|
4650
|
+
if (input instanceof ArrayBuffer)
|
|
4651
|
+
return new Uint8Array(input);
|
|
4652
|
+
const out = new ArrayBuffer(input.byteLength);
|
|
4653
|
+
const view = new Uint8Array(out);
|
|
4654
|
+
view.set(input);
|
|
4655
|
+
return view;
|
|
4656
|
+
}
|
|
4657
|
+
function base64ToBytes2(b64) {
|
|
4658
|
+
if (typeof atob === "function") {
|
|
4659
|
+
const bin = atob(b64);
|
|
4660
|
+
const buffer = new ArrayBuffer(bin.length);
|
|
4661
|
+
const out = new Uint8Array(buffer);
|
|
4662
|
+
for (let i = 0;i < bin.length; i++)
|
|
4663
|
+
out[i] = bin.charCodeAt(i);
|
|
4664
|
+
return out;
|
|
4665
|
+
}
|
|
4666
|
+
const node = Buffer.from(b64, "base64");
|
|
4667
|
+
const buf = new ArrayBuffer(node.length);
|
|
4668
|
+
new Uint8Array(buf).set(node);
|
|
4669
|
+
return new Uint8Array(buf);
|
|
4670
|
+
}
|
|
4671
|
+
// src/window-events.ts
|
|
4672
|
+
var windowEvents = {
|
|
4673
|
+
onFocus(cb) {
|
|
4674
|
+
if (hasBridge("window"))
|
|
4675
|
+
return onCraftEvent("craft:window:focus", () => cb());
|
|
4676
|
+
return webEvent("focus", cb);
|
|
4677
|
+
},
|
|
4678
|
+
onBlur(cb) {
|
|
4679
|
+
if (hasBridge("window"))
|
|
4680
|
+
return onCraftEvent("craft:window:blur", () => cb());
|
|
4681
|
+
return webEvent("blur", cb);
|
|
4682
|
+
},
|
|
4683
|
+
onResize(cb) {
|
|
4684
|
+
if (hasBridge("window"))
|
|
4685
|
+
return onCraftEvent("craft:window:resize", cb);
|
|
4686
|
+
if (typeof window === "undefined")
|
|
4687
|
+
return () => {};
|
|
4688
|
+
const h = () => cb({ width: window.innerWidth, height: window.innerHeight });
|
|
4689
|
+
window.addEventListener("resize", h);
|
|
4690
|
+
return () => window.removeEventListener("resize", h);
|
|
4691
|
+
},
|
|
4692
|
+
onMove(cb) {
|
|
4693
|
+
if (hasBridge("window"))
|
|
4694
|
+
return onCraftEvent("craft:window:move", cb);
|
|
4695
|
+
return () => {};
|
|
4696
|
+
},
|
|
4697
|
+
onClose(cb) {
|
|
4698
|
+
if (hasBridge("window"))
|
|
4699
|
+
return onCraftEvent("craft:window:close", () => cb());
|
|
4700
|
+
return webEvent("beforeunload", cb);
|
|
4701
|
+
},
|
|
4702
|
+
onMinimize(cb) {
|
|
4703
|
+
if (hasBridge("window"))
|
|
4704
|
+
return onCraftEvent("craft:window:minimize", () => cb());
|
|
4705
|
+
if (typeof document === "undefined")
|
|
4706
|
+
return () => {};
|
|
4707
|
+
const h = () => {
|
|
4708
|
+
if (document.visibilityState === "hidden")
|
|
4709
|
+
cb();
|
|
4710
|
+
};
|
|
4711
|
+
document.addEventListener("visibilitychange", h);
|
|
4712
|
+
return () => document.removeEventListener("visibilitychange", h);
|
|
4713
|
+
},
|
|
4714
|
+
onRestore(cb) {
|
|
4715
|
+
if (hasBridge("window"))
|
|
4716
|
+
return onCraftEvent("craft:window:restore", () => cb());
|
|
4717
|
+
if (typeof document === "undefined")
|
|
4718
|
+
return () => {};
|
|
4719
|
+
const h = () => {
|
|
4720
|
+
if (document.visibilityState === "visible")
|
|
4721
|
+
cb();
|
|
4722
|
+
};
|
|
4723
|
+
document.addEventListener("visibilitychange", h);
|
|
4724
|
+
return () => document.removeEventListener("visibilitychange", h);
|
|
4725
|
+
}
|
|
4726
|
+
};
|
|
4727
|
+
function webEvent(name, cb) {
|
|
4728
|
+
if (typeof window === "undefined")
|
|
4729
|
+
return () => {};
|
|
4730
|
+
const h = () => cb();
|
|
4731
|
+
window.addEventListener(name, h);
|
|
4732
|
+
return () => window.removeEventListener(name, h);
|
|
4733
|
+
}
|
|
4734
|
+
// src/app-info.ts
|
|
4735
|
+
var DEFAULT_INFO = { name: "", version: "0.0.0" };
|
|
4736
|
+
var app = {
|
|
4737
|
+
async hideDockIcon() {
|
|
4738
|
+
if (hasBridge("app"))
|
|
4739
|
+
await window.craft.app.hideDockIcon();
|
|
4740
|
+
},
|
|
4741
|
+
async showDockIcon() {
|
|
4742
|
+
if (hasBridge("app"))
|
|
4743
|
+
await window.craft.app.showDockIcon();
|
|
4744
|
+
},
|
|
4745
|
+
async quit() {
|
|
4746
|
+
if (hasBridge("app"))
|
|
4747
|
+
await window.craft.app.quit();
|
|
4748
|
+
},
|
|
4749
|
+
async getInfo() {
|
|
4750
|
+
if (!hasBridge("app"))
|
|
4751
|
+
return DEFAULT_INFO;
|
|
4752
|
+
const r = await window.craft.app.getInfo();
|
|
4753
|
+
return { ...DEFAULT_INFO, ...r || {} };
|
|
4754
|
+
},
|
|
4755
|
+
async notify(options) {
|
|
4756
|
+
if (!options.title)
|
|
4757
|
+
throw new Error("notify: title is required");
|
|
4758
|
+
if (hasBridge("app"))
|
|
4759
|
+
await window.craft.app.notify(options);
|
|
4760
|
+
},
|
|
4761
|
+
async setBadge(count) {
|
|
4762
|
+
if (hasBridge("app"))
|
|
4763
|
+
await window.craft.app.setBadge(count);
|
|
4764
|
+
},
|
|
4765
|
+
async bounce(type = "informational") {
|
|
4766
|
+
if (hasBridge("app"))
|
|
4767
|
+
await window.craft.app.bounce(type);
|
|
4768
|
+
}
|
|
4769
|
+
};
|
|
4770
|
+
// src/menu.ts
|
|
4771
|
+
var menu = {
|
|
4772
|
+
async set(items) {
|
|
4773
|
+
if (hasBridge("menu"))
|
|
4774
|
+
await window.craft.menu.set(items);
|
|
4775
|
+
},
|
|
4776
|
+
async setDock(items) {
|
|
4777
|
+
if (hasBridge("menu"))
|
|
4778
|
+
await window.craft.menu.setDock(items);
|
|
4779
|
+
},
|
|
4780
|
+
async addItem(parent, item) {
|
|
4781
|
+
if (hasBridge("menu"))
|
|
4782
|
+
await window.craft.menu.addItem(parent, item);
|
|
4783
|
+
},
|
|
4784
|
+
async removeItem(id) {
|
|
4785
|
+
if (hasBridge("menu"))
|
|
4786
|
+
await window.craft.menu.removeItem(id);
|
|
4787
|
+
},
|
|
4788
|
+
async enableItem(id) {
|
|
4789
|
+
if (hasBridge("menu"))
|
|
4790
|
+
await window.craft.menu.enableItem(id);
|
|
4791
|
+
},
|
|
4792
|
+
async disableItem(id) {
|
|
4793
|
+
if (hasBridge("menu"))
|
|
4794
|
+
await window.craft.menu.disableItem(id);
|
|
4795
|
+
},
|
|
4796
|
+
async checkItem(id) {
|
|
4797
|
+
if (hasBridge("menu"))
|
|
4798
|
+
await window.craft.menu.checkItem(id);
|
|
4799
|
+
},
|
|
4800
|
+
async uncheckItem(id) {
|
|
4801
|
+
if (hasBridge("menu"))
|
|
4802
|
+
await window.craft.menu.uncheckItem(id);
|
|
4803
|
+
},
|
|
4804
|
+
async setItemLabel(id, lbl) {
|
|
4805
|
+
if (hasBridge("menu"))
|
|
4806
|
+
await window.craft.menu.setItemLabel(id, lbl);
|
|
4807
|
+
},
|
|
4808
|
+
async clearDock() {
|
|
4809
|
+
if (hasBridge("menu"))
|
|
4810
|
+
await window.craft.menu.clearDock();
|
|
4811
|
+
},
|
|
4812
|
+
onAction(cb) {
|
|
4813
|
+
return onCraftEvent("craft:menu:action", cb);
|
|
4814
|
+
}
|
|
4815
|
+
};
|
|
4816
|
+
// src/system.ts
|
|
4817
|
+
var system = {
|
|
4818
|
+
accentColor: () => bridgeOr("system", "accentColor", () => ""),
|
|
4819
|
+
highlightColor: () => bridgeOr("system", "highlightColor", () => ""),
|
|
4820
|
+
language: () => bridgeOr("system", "language", () => {
|
|
4821
|
+
if (typeof navigator === "undefined")
|
|
4822
|
+
return "";
|
|
4823
|
+
return navigator.language?.split("-")[0] || "";
|
|
4824
|
+
}),
|
|
4825
|
+
locale: () => bridgeOr("system", "locale", () => {
|
|
4826
|
+
if (typeof navigator === "undefined")
|
|
4827
|
+
return "";
|
|
4828
|
+
return navigator.language || "";
|
|
4829
|
+
}),
|
|
4830
|
+
timezone: () => bridgeOr("system", "timezone", () => {
|
|
4831
|
+
try {
|
|
4832
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "";
|
|
4833
|
+
} catch {
|
|
4834
|
+
return "";
|
|
4835
|
+
}
|
|
4836
|
+
}),
|
|
4837
|
+
is24HourTime: () => bridgeOr("system", "is24HourTime", () => {
|
|
4838
|
+
try {
|
|
4839
|
+
const opts = new Intl.DateTimeFormat([], { hour: "numeric" }).resolvedOptions();
|
|
4840
|
+
return opts.hourCycle === "h23" || opts.hourCycle === "h24";
|
|
4841
|
+
} catch {
|
|
4842
|
+
return false;
|
|
4843
|
+
}
|
|
4844
|
+
}),
|
|
4845
|
+
reduceMotion: () => bridgeOr("system", "reduceMotion", () => mediaMatches("(prefers-reduced-motion: reduce)")),
|
|
4846
|
+
reduceTransparency: () => bridgeOr("system", "reduceTransparency", () => mediaMatches("(prefers-reduced-transparency: reduce)")),
|
|
4847
|
+
increaseContrast: () => bridgeOr("system", "increaseContrast", () => mediaMatches("(prefers-contrast: more)")),
|
|
4848
|
+
systemVersion: () => bridgeOr("system", "systemVersion", () => ""),
|
|
4849
|
+
hostname: () => bridgeOr("system", "hostname", () => ""),
|
|
4850
|
+
username: () => bridgeOr("system", "username", () => ""),
|
|
4851
|
+
async openPreferences() {
|
|
4852
|
+
if (hasBridge("system"))
|
|
4853
|
+
await window.craft.system.openPreferences();
|
|
4854
|
+
}
|
|
4855
|
+
};
|
|
4856
|
+
async function bridgeOr(ns, method, fallback) {
|
|
4857
|
+
if (hasBridge(ns))
|
|
4858
|
+
return await window.craft[ns][method]();
|
|
4859
|
+
return await fallback();
|
|
4860
|
+
}
|
|
4861
|
+
function mediaMatches(query) {
|
|
4862
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
4863
|
+
return false;
|
|
4864
|
+
return window.matchMedia(query).matches;
|
|
4865
|
+
}
|
|
4866
|
+
// src/screen.ts
|
|
4867
|
+
var screen = {
|
|
4868
|
+
async getDisplays() {
|
|
4869
|
+
if (hasBridge("screen"))
|
|
4870
|
+
return await window.craft.screen.getDisplays();
|
|
4871
|
+
return webDisplays();
|
|
4872
|
+
},
|
|
4873
|
+
async getPrimary() {
|
|
4874
|
+
if (hasBridge("screen")) {
|
|
4875
|
+
const r = await window.craft.screen.getPrimary();
|
|
4876
|
+
return r && typeof r.width === "number" ? r : null;
|
|
4877
|
+
}
|
|
4878
|
+
return webDisplays()[0] ?? null;
|
|
4879
|
+
},
|
|
4880
|
+
onChange(cb) {
|
|
4881
|
+
if (hasBridge("screen"))
|
|
4882
|
+
return onCraftEvent("craft:screen:change", () => cb());
|
|
4883
|
+
if (typeof window === "undefined")
|
|
4884
|
+
return () => {};
|
|
4885
|
+
const h = () => cb();
|
|
4886
|
+
window.addEventListener("resize", h);
|
|
4887
|
+
return () => window.removeEventListener("resize", h);
|
|
4888
|
+
}
|
|
4889
|
+
};
|
|
4890
|
+
function webDisplays() {
|
|
4891
|
+
if (typeof window === "undefined" || !window.screen)
|
|
4892
|
+
return [];
|
|
4893
|
+
const s = window.screen;
|
|
4894
|
+
return [{
|
|
4895
|
+
id: 0,
|
|
4896
|
+
x: s.left ?? 0,
|
|
4897
|
+
y: s.top ?? 0,
|
|
4898
|
+
width: s.width || 0,
|
|
4899
|
+
height: s.height || 0,
|
|
4900
|
+
workX: s.availLeft ?? 0,
|
|
4901
|
+
workY: s.availTop ?? 0,
|
|
4902
|
+
workWidth: s.availWidth ?? s.width ?? 0,
|
|
4903
|
+
workHeight: s.availHeight ?? s.height ?? 0,
|
|
4904
|
+
scaleFactor: window.devicePixelRatio || 1
|
|
4905
|
+
}];
|
|
4906
|
+
}
|
|
4907
|
+
// src/keychain.ts
|
|
4908
|
+
var keychain = {
|
|
4909
|
+
async set(service, account, password) {
|
|
4910
|
+
if (!service)
|
|
4911
|
+
throw new Error("keychain.set: service is required");
|
|
4912
|
+
if (!account)
|
|
4913
|
+
throw new Error("keychain.set: account is required");
|
|
4914
|
+
await requireBridge("keychain").set(service, account, password);
|
|
4915
|
+
},
|
|
4916
|
+
async get(service, account) {
|
|
4917
|
+
if (!service)
|
|
4918
|
+
throw new Error("keychain.get: service is required");
|
|
4919
|
+
if (!account)
|
|
4920
|
+
throw new Error("keychain.get: account is required");
|
|
4921
|
+
const v = await requireBridge("keychain").get(service, account);
|
|
4922
|
+
return typeof v === "string" ? v : null;
|
|
4923
|
+
},
|
|
4924
|
+
async delete(service, account) {
|
|
4925
|
+
if (!service)
|
|
4926
|
+
throw new Error("keychain.delete: service is required");
|
|
4927
|
+
if (!account)
|
|
4928
|
+
throw new Error("keychain.delete: account is required");
|
|
4929
|
+
await requireBridge("keychain").delete(service, account);
|
|
4930
|
+
},
|
|
4931
|
+
async has(service, account) {
|
|
4932
|
+
if (!service)
|
|
4933
|
+
throw new Error("keychain.has: service is required");
|
|
4934
|
+
if (!account)
|
|
4935
|
+
throw new Error("keychain.has: account is required");
|
|
4936
|
+
return await requireBridge("keychain").has(service, account);
|
|
4937
|
+
}
|
|
4938
|
+
};
|
|
4939
|
+
// src/permissions.ts
|
|
4940
|
+
var permissions = {
|
|
4941
|
+
async check(name) {
|
|
4942
|
+
if (hasBridge("permissions"))
|
|
4943
|
+
return await window.craft.permissions.check(name);
|
|
4944
|
+
return await webCheck(name);
|
|
4945
|
+
},
|
|
4946
|
+
async request(name) {
|
|
4947
|
+
if (hasBridge("permissions"))
|
|
4948
|
+
return await window.craft.permissions.request(name);
|
|
4949
|
+
return await webRequest(name);
|
|
4950
|
+
},
|
|
4951
|
+
async openSettings(name) {
|
|
4952
|
+
if (hasBridge("permissions"))
|
|
4953
|
+
await window.craft.permissions.openSettings(name);
|
|
4954
|
+
}
|
|
4955
|
+
};
|
|
4956
|
+
async function webCheck(name) {
|
|
4957
|
+
if (typeof navigator === "undefined" || !navigator.permissions?.query)
|
|
4958
|
+
return "not-supported";
|
|
4959
|
+
try {
|
|
4960
|
+
const result = await navigator.permissions.query({ name });
|
|
4961
|
+
return mapWebState(result.state);
|
|
4962
|
+
} catch {
|
|
4963
|
+
return "not-supported";
|
|
4964
|
+
}
|
|
4965
|
+
}
|
|
4966
|
+
async function webRequest(name) {
|
|
4967
|
+
if (name === "notifications" && typeof window !== "undefined" && "Notification" in window) {
|
|
4968
|
+
const r = await window.Notification.requestPermission();
|
|
4969
|
+
return r === "granted" ? "granted" : r === "denied" ? "denied" : "undetermined";
|
|
4970
|
+
}
|
|
4971
|
+
return await webCheck(name);
|
|
4972
|
+
}
|
|
4973
|
+
function mapWebState(s) {
|
|
4974
|
+
if (s === "granted")
|
|
4975
|
+
return "granted";
|
|
4976
|
+
if (s === "denied")
|
|
4977
|
+
return "denied";
|
|
4978
|
+
if (s === "prompt")
|
|
4979
|
+
return "undetermined";
|
|
4980
|
+
return "undetermined";
|
|
4981
|
+
}
|
|
4982
|
+
// src/printing.ts
|
|
4983
|
+
var printing = {
|
|
4984
|
+
async print() {
|
|
4985
|
+
if (hasBridge("printing")) {
|
|
4986
|
+
await window.craft.printing.print();
|
|
4987
|
+
return;
|
|
4988
|
+
}
|
|
4989
|
+
if (typeof window !== "undefined" && typeof window.print === "function") {
|
|
4990
|
+
window.print();
|
|
4991
|
+
}
|
|
4992
|
+
},
|
|
4993
|
+
async printToPDF(path) {
|
|
4994
|
+
if (!path)
|
|
4995
|
+
throw new Error("printToPDF: path is required");
|
|
4996
|
+
const isPosixAbs = path.startsWith("/");
|
|
4997
|
+
const isWinAbs = /^[a-zA-Z]:[\\/]/.test(path) || path.startsWith("\\\\");
|
|
4998
|
+
if (!isPosixAbs && !isWinAbs) {
|
|
4999
|
+
throw new Error("printToPDF: path must be absolute");
|
|
5000
|
+
}
|
|
5001
|
+
const r = await requireBridge("printing").printToPDF(path);
|
|
5002
|
+
return { ok: !!(r && r.ok), path: r?.path };
|
|
5003
|
+
}
|
|
5004
|
+
};
|
|
5005
|
+
// src/native-autolaunch.ts
|
|
5006
|
+
var nativeAutoLaunch = {
|
|
5007
|
+
async enable() {
|
|
5008
|
+
if (!hasBridge("autoLaunch"))
|
|
5009
|
+
return false;
|
|
5010
|
+
return await window.craft.autoLaunch.enable();
|
|
5011
|
+
},
|
|
5012
|
+
async disable() {
|
|
5013
|
+
if (!hasBridge("autoLaunch"))
|
|
5014
|
+
return false;
|
|
5015
|
+
return await window.craft.autoLaunch.disable();
|
|
5016
|
+
},
|
|
5017
|
+
async isEnabled() {
|
|
5018
|
+
if (!hasBridge("autoLaunch"))
|
|
5019
|
+
return false;
|
|
5020
|
+
return await window.craft.autoLaunch.isEnabled();
|
|
5021
|
+
}
|
|
5022
|
+
};
|
|
5023
|
+
// src/touchbar.ts
|
|
5024
|
+
var touchbar = {
|
|
5025
|
+
async addItem(item) {
|
|
5026
|
+
if (hasBridge("touchbar"))
|
|
5027
|
+
await window.craft.touchbar.addItem(item);
|
|
5028
|
+
},
|
|
5029
|
+
async removeItem(id) {
|
|
5030
|
+
if (hasBridge("touchbar"))
|
|
5031
|
+
await window.craft.touchbar.removeItem(id);
|
|
5032
|
+
},
|
|
5033
|
+
async updateItem(id, props) {
|
|
5034
|
+
if (hasBridge("touchbar"))
|
|
5035
|
+
await window.craft.touchbar.updateItem(id, props);
|
|
5036
|
+
},
|
|
5037
|
+
async setLabel(id, label) {
|
|
5038
|
+
if (hasBridge("touchbar"))
|
|
5039
|
+
await window.craft.touchbar.setLabel(id, label);
|
|
5040
|
+
},
|
|
5041
|
+
async setIcon(id, icon) {
|
|
5042
|
+
if (hasBridge("touchbar"))
|
|
5043
|
+
await window.craft.touchbar.setIcon(id, icon);
|
|
5044
|
+
},
|
|
5045
|
+
async setEnabled(id, enabled) {
|
|
5046
|
+
if (hasBridge("touchbar"))
|
|
5047
|
+
await window.craft.touchbar.setEnabled(id, enabled);
|
|
5048
|
+
},
|
|
5049
|
+
async setSliderValue(id, value) {
|
|
5050
|
+
if (hasBridge("touchbar"))
|
|
5051
|
+
await window.craft.touchbar.setSliderValue(id, value);
|
|
5052
|
+
},
|
|
5053
|
+
async clear() {
|
|
5054
|
+
if (hasBridge("touchbar"))
|
|
5055
|
+
await window.craft.touchbar.clear();
|
|
5056
|
+
},
|
|
5057
|
+
async show() {
|
|
5058
|
+
if (hasBridge("touchbar"))
|
|
5059
|
+
await window.craft.touchbar.show();
|
|
5060
|
+
},
|
|
5061
|
+
async hide() {
|
|
5062
|
+
if (hasBridge("touchbar"))
|
|
5063
|
+
await window.craft.touchbar.hide();
|
|
5064
|
+
},
|
|
5065
|
+
onAction(cb) {
|
|
5066
|
+
return onCraftEvent("craft:touchbar:action", cb);
|
|
5067
|
+
}
|
|
5068
|
+
};
|
|
5069
|
+
// src/bluetooth.ts
|
|
5070
|
+
var HEX_RE = /^[\da-f]*$/i;
|
|
5071
|
+
function assertHex(label, hex) {
|
|
5072
|
+
if (typeof hex !== "string" || !HEX_RE.test(hex) || hex.length % 2 !== 0) {
|
|
5073
|
+
throw new Error(`${label}: must be a hex string with even length, got ${JSON.stringify(hex)}`);
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
var bluetooth = {
|
|
5077
|
+
async isEnabled() {
|
|
5078
|
+
return hasBridge("bluetooth") ? await window.craft.bluetooth.isEnabled() : false;
|
|
5079
|
+
},
|
|
5080
|
+
async powerState() {
|
|
5081
|
+
return hasBridge("bluetooth") ? await window.craft.bluetooth.powerState() : "unknown";
|
|
5082
|
+
},
|
|
5083
|
+
async connectedDevices() {
|
|
5084
|
+
return hasBridge("bluetooth") ? await window.craft.bluetooth.connectedDevices() : [];
|
|
5085
|
+
},
|
|
5086
|
+
async pairedDevices() {
|
|
5087
|
+
return hasBridge("bluetooth") ? await window.craft.bluetooth.pairedDevices() : [];
|
|
5088
|
+
},
|
|
5089
|
+
async startDiscovery() {
|
|
5090
|
+
if (hasBridge("bluetooth"))
|
|
5091
|
+
await window.craft.bluetooth.startDiscovery();
|
|
5092
|
+
},
|
|
5093
|
+
async stopDiscovery() {
|
|
5094
|
+
if (hasBridge("bluetooth"))
|
|
5095
|
+
await window.craft.bluetooth.stopDiscovery();
|
|
5096
|
+
},
|
|
5097
|
+
async isDiscovering() {
|
|
5098
|
+
return hasBridge("bluetooth") ? await window.craft.bluetooth.isDiscovering() : false;
|
|
5099
|
+
},
|
|
5100
|
+
async connect(id) {
|
|
5101
|
+
if (hasBridge("bluetooth"))
|
|
5102
|
+
await window.craft.bluetooth.connect(id);
|
|
5103
|
+
},
|
|
5104
|
+
async disconnect(id) {
|
|
5105
|
+
if (hasBridge("bluetooth"))
|
|
5106
|
+
await window.craft.bluetooth.disconnect(id);
|
|
5107
|
+
},
|
|
5108
|
+
async openPreferences() {
|
|
5109
|
+
if (hasBridge("bluetooth"))
|
|
5110
|
+
await window.craft.bluetooth.openPreferences();
|
|
5111
|
+
},
|
|
5112
|
+
async discoverServices(deviceId) {
|
|
5113
|
+
if (!deviceId)
|
|
5114
|
+
throw new Error("bluetooth.discoverServices: deviceId is required");
|
|
5115
|
+
if (!hasBridge("bluetooth"))
|
|
5116
|
+
return [];
|
|
5117
|
+
const r = await window.craft.bluetooth.discoverServices(deviceId);
|
|
5118
|
+
return Array.isArray(r) ? r : [];
|
|
5119
|
+
},
|
|
5120
|
+
async discoverCharacteristics(deviceId, serviceUuid) {
|
|
5121
|
+
if (!deviceId || !serviceUuid)
|
|
5122
|
+
throw new Error("bluetooth.discoverCharacteristics: deviceId and serviceUuid are required");
|
|
5123
|
+
if (!hasBridge("bluetooth"))
|
|
5124
|
+
return [];
|
|
5125
|
+
const r = await window.craft.bluetooth.discoverCharacteristics(deviceId, serviceUuid);
|
|
5126
|
+
return Array.isArray(r) ? r : [];
|
|
5127
|
+
},
|
|
5128
|
+
async readCharacteristic(deviceId, serviceUuid, characteristicUuid) {
|
|
5129
|
+
if (!deviceId || !serviceUuid || !characteristicUuid) {
|
|
5130
|
+
throw new Error("bluetooth.readCharacteristic: deviceId, serviceUuid, characteristicUuid are required");
|
|
5131
|
+
}
|
|
5132
|
+
if (!hasBridge("bluetooth"))
|
|
5133
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
5134
|
+
return await window.craft.bluetooth.readCharacteristic(deviceId, serviceUuid, characteristicUuid);
|
|
5135
|
+
},
|
|
5136
|
+
async writeCharacteristic(deviceId, serviceUuid, characteristicUuid, valueHex, mode = "with-response") {
|
|
5137
|
+
if (!deviceId || !serviceUuid || !characteristicUuid) {
|
|
5138
|
+
throw new Error("bluetooth.writeCharacteristic: deviceId, serviceUuid, characteristicUuid are required");
|
|
5139
|
+
}
|
|
5140
|
+
assertHex("bluetooth.writeCharacteristic.valueHex", valueHex);
|
|
5141
|
+
if (!hasBridge("bluetooth"))
|
|
5142
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
5143
|
+
return await window.craft.bluetooth.writeCharacteristic(deviceId, serviceUuid, characteristicUuid, valueHex, mode);
|
|
5144
|
+
},
|
|
5145
|
+
async setCharacteristicNotify(deviceId, serviceUuid, characteristicUuid, on) {
|
|
5146
|
+
if (!deviceId || !serviceUuid || !characteristicUuid) {
|
|
5147
|
+
throw new Error("bluetooth.setCharacteristicNotify: deviceId, serviceUuid, characteristicUuid are required");
|
|
5148
|
+
}
|
|
5149
|
+
if (!hasBridge("bluetooth"))
|
|
5150
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
5151
|
+
return await window.craft.bluetooth.setCharacteristicNotify(deviceId, serviceUuid, characteristicUuid, on);
|
|
5152
|
+
},
|
|
5153
|
+
onDeviceFound(cb) {
|
|
5154
|
+
return onCraftEvent("craft:bluetooth:deviceFound", cb);
|
|
5155
|
+
},
|
|
5156
|
+
onDeviceConnected(cb) {
|
|
5157
|
+
return onCraftEvent("craft:bluetooth:deviceConnected", cb);
|
|
5158
|
+
},
|
|
5159
|
+
onDeviceDisconnected(cb) {
|
|
5160
|
+
return onCraftEvent("craft:bluetooth:deviceDisconnected", cb);
|
|
5161
|
+
},
|
|
5162
|
+
onCharacteristicValue(cb) {
|
|
5163
|
+
return onCraftEvent("craft:bluetooth:characteristicValue", cb);
|
|
5164
|
+
}
|
|
5165
|
+
};
|
|
5166
|
+
// src/speech.ts
|
|
5167
|
+
var speech = {
|
|
5168
|
+
async speak(text, options) {
|
|
5169
|
+
if (!text)
|
|
5170
|
+
throw new Error("speech.speak: text is required");
|
|
5171
|
+
if (hasBridge("speech")) {
|
|
5172
|
+
await window.craft.speech.speak(text, options);
|
|
5173
|
+
return;
|
|
5174
|
+
}
|
|
5175
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5176
|
+
const u = new window.SpeechSynthesisUtterance(text);
|
|
5177
|
+
if (options) {
|
|
5178
|
+
if (options.rate != null)
|
|
5179
|
+
u.rate = options.rate;
|
|
5180
|
+
if (options.pitch != null)
|
|
5181
|
+
u.pitch = options.pitch;
|
|
5182
|
+
if (options.volume != null)
|
|
5183
|
+
u.volume = options.volume;
|
|
5184
|
+
if (options.voice) {
|
|
5185
|
+
const voices = window.speechSynthesis.getVoices();
|
|
5186
|
+
const match = voices.find((v) => v.voiceURI === options.voice || v.name === options.voice || v.lang === options.voice);
|
|
5187
|
+
if (match)
|
|
5188
|
+
u.voice = match;
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
window.speechSynthesis.speak(u);
|
|
5192
|
+
}
|
|
5193
|
+
},
|
|
5194
|
+
async stop() {
|
|
5195
|
+
if (hasBridge("speech")) {
|
|
5196
|
+
await window.craft.speech.stop();
|
|
5197
|
+
return;
|
|
5198
|
+
}
|
|
5199
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5200
|
+
window.speechSynthesis.cancel();
|
|
5201
|
+
}
|
|
5202
|
+
},
|
|
5203
|
+
async pause() {
|
|
5204
|
+
if (hasBridge("speech")) {
|
|
5205
|
+
await window.craft.speech.pause();
|
|
5206
|
+
return;
|
|
5207
|
+
}
|
|
5208
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5209
|
+
window.speechSynthesis.pause();
|
|
5210
|
+
}
|
|
5211
|
+
},
|
|
5212
|
+
async resume() {
|
|
5213
|
+
if (hasBridge("speech")) {
|
|
5214
|
+
await window.craft.speech.resume();
|
|
5215
|
+
return;
|
|
5216
|
+
}
|
|
5217
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5218
|
+
window.speechSynthesis.resume();
|
|
5219
|
+
}
|
|
5220
|
+
},
|
|
5221
|
+
async isSpeaking() {
|
|
5222
|
+
if (hasBridge("speech"))
|
|
5223
|
+
return await window.craft.speech.isSpeaking();
|
|
5224
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5225
|
+
return !!window.speechSynthesis.speaking;
|
|
5226
|
+
}
|
|
5227
|
+
return false;
|
|
5228
|
+
},
|
|
5229
|
+
async getVoices() {
|
|
5230
|
+
if (hasBridge("speech"))
|
|
5231
|
+
return await window.craft.speech.getVoices();
|
|
5232
|
+
if (typeof window !== "undefined" && window.speechSynthesis) {
|
|
5233
|
+
const raw = window.speechSynthesis.getVoices();
|
|
5234
|
+
return raw.map((v) => ({
|
|
5235
|
+
id: v.voiceURI || v.name,
|
|
5236
|
+
name: v.name,
|
|
5237
|
+
language: v.lang || "",
|
|
5238
|
+
quality: "default"
|
|
5239
|
+
}));
|
|
5240
|
+
}
|
|
5241
|
+
return [];
|
|
5242
|
+
}
|
|
5243
|
+
};
|
|
5244
|
+
// src/crash-reporter.ts
|
|
5245
|
+
var jsQueue = [];
|
|
5246
|
+
var jsEnabled = true;
|
|
5247
|
+
var jsUserId;
|
|
5248
|
+
var jsAppVersion;
|
|
5249
|
+
var crashReporter = {
|
|
5250
|
+
async report(entry) {
|
|
5251
|
+
if (hasBridge("crashReporter")) {
|
|
5252
|
+
await window.craft.crashReporter.report(entry);
|
|
5253
|
+
return;
|
|
5254
|
+
}
|
|
5255
|
+
if (!jsEnabled)
|
|
5256
|
+
return;
|
|
5257
|
+
const normalized = entry instanceof Error ? {
|
|
5258
|
+
timestamp: Date.now(),
|
|
5259
|
+
severity: "error",
|
|
5260
|
+
message: entry.message,
|
|
5261
|
+
source: "js",
|
|
5262
|
+
stack: entry.stack || "",
|
|
5263
|
+
userId: jsUserId,
|
|
5264
|
+
appVersion: jsAppVersion
|
|
5265
|
+
} : {
|
|
5266
|
+
timestamp: Date.now(),
|
|
5267
|
+
severity: entry.severity || "error",
|
|
5268
|
+
message: entry.message || "",
|
|
5269
|
+
source: entry.source || "js",
|
|
5270
|
+
stack: entry.stack || "",
|
|
5271
|
+
userId: jsUserId,
|
|
5272
|
+
appVersion: jsAppVersion
|
|
5273
|
+
};
|
|
5274
|
+
if (jsQueue.length >= 64)
|
|
5275
|
+
jsQueue.shift();
|
|
5276
|
+
jsQueue.push(normalized);
|
|
5277
|
+
},
|
|
5278
|
+
async flush() {
|
|
5279
|
+
if (hasBridge("crashReporter"))
|
|
5280
|
+
return await window.craft.crashReporter.flush();
|
|
5281
|
+
return [...jsQueue];
|
|
5282
|
+
},
|
|
5283
|
+
async clear() {
|
|
5284
|
+
if (hasBridge("crashReporter")) {
|
|
5285
|
+
await window.craft.crashReporter.clear();
|
|
5286
|
+
return;
|
|
5287
|
+
}
|
|
5288
|
+
jsQueue.length = 0;
|
|
5289
|
+
},
|
|
5290
|
+
async setEnabled(on) {
|
|
5291
|
+
if (hasBridge("crashReporter")) {
|
|
5292
|
+
await window.craft.crashReporter.setEnabled(on);
|
|
5293
|
+
return;
|
|
5294
|
+
}
|
|
5295
|
+
jsEnabled = on;
|
|
5296
|
+
},
|
|
5297
|
+
async isEnabled() {
|
|
5298
|
+
if (hasBridge("crashReporter"))
|
|
5299
|
+
return await window.craft.crashReporter.isEnabled();
|
|
5300
|
+
return jsEnabled;
|
|
5301
|
+
},
|
|
5302
|
+
async setUser(id) {
|
|
5303
|
+
if (hasBridge("crashReporter")) {
|
|
5304
|
+
await window.craft.crashReporter.setUser(id);
|
|
5305
|
+
return;
|
|
5306
|
+
}
|
|
5307
|
+
jsUserId = id || undefined;
|
|
5308
|
+
},
|
|
5309
|
+
async setAppVersion(version) {
|
|
5310
|
+
if (hasBridge("crashReporter")) {
|
|
5311
|
+
await window.craft.crashReporter.setAppVersion(version);
|
|
5312
|
+
return;
|
|
5313
|
+
}
|
|
5314
|
+
jsAppVersion = version || undefined;
|
|
5315
|
+
},
|
|
5316
|
+
attachGlobalHandlers() {
|
|
5317
|
+
if (hasBridge("crashReporter") && window.craft.crashReporter.attachGlobalHandlers) {
|
|
5318
|
+
return window.craft.crashReporter.attachGlobalHandlers();
|
|
5319
|
+
}
|
|
5320
|
+
if (typeof window === "undefined")
|
|
5321
|
+
return () => {};
|
|
5322
|
+
const errorH = (e) => {
|
|
5323
|
+
crashReporter.report({
|
|
5324
|
+
severity: "error",
|
|
5325
|
+
message: e.message,
|
|
5326
|
+
source: "js",
|
|
5327
|
+
stack: e.error?.stack || `${e.message}
|
|
5328
|
+
at ${e.filename}:${e.lineno}:${e.colno}`
|
|
5329
|
+
}).catch(() => {});
|
|
5330
|
+
};
|
|
5331
|
+
const rejectH = (e) => {
|
|
5332
|
+
const r = e.reason;
|
|
5333
|
+
crashReporter.report({
|
|
5334
|
+
severity: "error",
|
|
5335
|
+
message: r?.message || String(r),
|
|
5336
|
+
source: "js",
|
|
5337
|
+
stack: r?.stack || ""
|
|
5338
|
+
}).catch(() => {});
|
|
5339
|
+
};
|
|
5340
|
+
window.addEventListener("error", errorH);
|
|
5341
|
+
window.addEventListener("unhandledrejection", rejectH);
|
|
5342
|
+
return () => {
|
|
5343
|
+
window.removeEventListener("error", errorH);
|
|
5344
|
+
window.removeEventListener("unhandledrejection", rejectH);
|
|
5345
|
+
};
|
|
5346
|
+
},
|
|
5347
|
+
forwardTo(options) {
|
|
5348
|
+
return startForwarder(options);
|
|
5349
|
+
}
|
|
5350
|
+
};
|
|
5351
|
+
var DEFAULT_PERSIST_KEY = "craft:crashReporter:pending";
|
|
5352
|
+
var EMAIL_RE = /[\w.+-]+@[\w-]+\.[\w.-]+/g;
|
|
5353
|
+
var IPV4_RE = /\b(?:\d{1,3}\.){3}\d{1,3}\b/g;
|
|
5354
|
+
var HOME_PATH_RE = /\/(?:Users|home)\/[^\s/'"`]+/g;
|
|
5355
|
+
function redactPII(entry) {
|
|
5356
|
+
const scrub = (s) => s.replace(EMAIL_RE, "<email>").replace(IPV4_RE, "<ip>").replace(HOME_PATH_RE, "/<home>");
|
|
5357
|
+
return {
|
|
5358
|
+
...entry,
|
|
5359
|
+
message: scrub(entry.message),
|
|
5360
|
+
stack: scrub(entry.stack)
|
|
5361
|
+
};
|
|
5362
|
+
}
|
|
5363
|
+
async function signPayload(secret, body) {
|
|
5364
|
+
const enc = new TextEncoder;
|
|
5365
|
+
const key = await crypto.subtle.importKey("raw", enc.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
5366
|
+
const sig = await crypto.subtle.sign("HMAC", key, enc.encode(body));
|
|
5367
|
+
return [...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
5368
|
+
}
|
|
5369
|
+
function loadPersisted(key) {
|
|
5370
|
+
if (!key || typeof localStorage === "undefined")
|
|
5371
|
+
return [];
|
|
5372
|
+
try {
|
|
5373
|
+
const raw = localStorage.getItem(key);
|
|
5374
|
+
if (!raw)
|
|
5375
|
+
return [];
|
|
5376
|
+
const parsed = JSON.parse(raw);
|
|
5377
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
5378
|
+
} catch {
|
|
5379
|
+
return [];
|
|
5380
|
+
}
|
|
5381
|
+
}
|
|
5382
|
+
function savePersisted(key, entries) {
|
|
5383
|
+
if (!key || typeof localStorage === "undefined")
|
|
5384
|
+
return;
|
|
5385
|
+
try {
|
|
5386
|
+
if (entries.length === 0)
|
|
5387
|
+
localStorage.removeItem(key);
|
|
5388
|
+
else
|
|
5389
|
+
localStorage.setItem(key, JSON.stringify(entries));
|
|
5390
|
+
} catch {}
|
|
5391
|
+
}
|
|
5392
|
+
function startForwarder(options) {
|
|
5393
|
+
const {
|
|
5394
|
+
endpoint,
|
|
5395
|
+
intervalMs = 60000,
|
|
5396
|
+
signingSecret,
|
|
5397
|
+
redact = true,
|
|
5398
|
+
headers = {},
|
|
5399
|
+
maxRetries = 5,
|
|
5400
|
+
persistKey
|
|
5401
|
+
} = options;
|
|
5402
|
+
const storageKey = persistKey === null ? null : persistKey ?? DEFAULT_PERSIST_KEY;
|
|
5403
|
+
let pending = loadPersisted(storageKey);
|
|
5404
|
+
let stopped = false;
|
|
5405
|
+
let timer = null;
|
|
5406
|
+
let inFlight = null;
|
|
5407
|
+
const redactor = typeof redact === "function" ? redact : redact === false ? (e) => e : redactPII;
|
|
5408
|
+
async function postBatch(batch) {
|
|
5409
|
+
const body = JSON.stringify({ entries: batch });
|
|
5410
|
+
const requestHeaders = {
|
|
5411
|
+
"Content-Type": "application/json",
|
|
5412
|
+
...headers
|
|
5413
|
+
};
|
|
5414
|
+
if (signingSecret) {
|
|
5415
|
+
requestHeaders["X-Craft-Signature"] = await signPayload(signingSecret, body);
|
|
5416
|
+
}
|
|
5417
|
+
let attempt = 0;
|
|
5418
|
+
let delay2 = 1000;
|
|
5419
|
+
while (!stopped) {
|
|
5420
|
+
try {
|
|
5421
|
+
const res = await fetch(endpoint, { method: "POST", headers: requestHeaders, body });
|
|
5422
|
+
if (res.ok)
|
|
5423
|
+
return;
|
|
5424
|
+
if (res.status >= 400 && res.status < 500)
|
|
5425
|
+
return;
|
|
5426
|
+
throw new Error(`HTTP ${res.status}`);
|
|
5427
|
+
} catch (err) {
|
|
5428
|
+
attempt += 1;
|
|
5429
|
+
if (attempt > maxRetries) {
|
|
5430
|
+
pending = [...batch, ...pending];
|
|
5431
|
+
savePersisted(storageKey, pending);
|
|
5432
|
+
throw err;
|
|
5433
|
+
}
|
|
5434
|
+
await new Promise((r) => {
|
|
5435
|
+
setTimeout(r, delay2);
|
|
5436
|
+
});
|
|
5437
|
+
delay2 = Math.min(delay2 * 2, 60000);
|
|
5438
|
+
}
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
async function drain() {
|
|
5442
|
+
if (stopped || inFlight)
|
|
5443
|
+
return inFlight ?? undefined;
|
|
5444
|
+
const fresh = await crashReporter.flush();
|
|
5445
|
+
if (fresh.length > 0)
|
|
5446
|
+
await crashReporter.clear();
|
|
5447
|
+
pending = [...pending, ...fresh.map((e) => redactor(e))];
|
|
5448
|
+
if (pending.length === 0)
|
|
5449
|
+
return;
|
|
5450
|
+
const batch = pending;
|
|
5451
|
+
pending = [];
|
|
5452
|
+
savePersisted(storageKey, pending);
|
|
5453
|
+
inFlight = postBatch(batch).catch(() => {}).finally(() => {
|
|
5454
|
+
inFlight = null;
|
|
5455
|
+
});
|
|
5456
|
+
return inFlight;
|
|
5457
|
+
}
|
|
5458
|
+
if (intervalMs > 0) {
|
|
5459
|
+
timer = setInterval(() => {
|
|
5460
|
+
drain().catch(() => {});
|
|
5461
|
+
}, intervalMs);
|
|
5462
|
+
}
|
|
5463
|
+
return {
|
|
5464
|
+
async flushNow() {
|
|
5465
|
+
await drain();
|
|
5466
|
+
},
|
|
5467
|
+
stop() {
|
|
5468
|
+
stopped = true;
|
|
5469
|
+
if (timer)
|
|
5470
|
+
clearInterval(timer);
|
|
5471
|
+
timer = null;
|
|
5472
|
+
},
|
|
5473
|
+
pending() {
|
|
5474
|
+
return [...pending];
|
|
5475
|
+
}
|
|
5476
|
+
};
|
|
5477
|
+
}
|
|
5478
|
+
// src/iap.ts
|
|
5479
|
+
var iap = {
|
|
5480
|
+
async isAvailable() {
|
|
5481
|
+
if (!hasBridge("iap"))
|
|
5482
|
+
return false;
|
|
5483
|
+
return await window.craft.iap.isAvailable();
|
|
5484
|
+
},
|
|
5485
|
+
async getProducts(ids) {
|
|
5486
|
+
if (!hasBridge("iap"))
|
|
5487
|
+
return [];
|
|
5488
|
+
const arr = Array.isArray(ids) ? ids : [String(ids)];
|
|
5489
|
+
return await window.craft.iap.getProducts(arr);
|
|
5490
|
+
},
|
|
5491
|
+
async purchase(productId) {
|
|
5492
|
+
if (!hasBridge("iap"))
|
|
5493
|
+
return { queued: false, productId, reason: "IAP bridge not available" };
|
|
5494
|
+
const r = await window.craft.iap.purchase(productId);
|
|
5495
|
+
return { queued: !!(r && r.queued), productId: r?.productId, reason: r?.reason };
|
|
5496
|
+
},
|
|
5497
|
+
async restorePurchases() {
|
|
5498
|
+
if (!hasBridge("iap"))
|
|
5499
|
+
return { ok: false };
|
|
5500
|
+
const r = await window.craft.iap.restorePurchases();
|
|
5501
|
+
return { ok: !!(r && r.ok) };
|
|
5502
|
+
},
|
|
5503
|
+
async finishTransaction(transactionId) {
|
|
5504
|
+
if (!hasBridge("iap"))
|
|
5505
|
+
return;
|
|
5506
|
+
await window.craft.iap.finishTransaction(transactionId);
|
|
5507
|
+
},
|
|
5508
|
+
async getReceiptData() {
|
|
5509
|
+
if (!hasBridge("iap"))
|
|
5510
|
+
return null;
|
|
5511
|
+
const r = await window.craft.iap.getReceiptData();
|
|
5512
|
+
return r ? String(r) : null;
|
|
5513
|
+
},
|
|
5514
|
+
onPurchased(cb) {
|
|
5515
|
+
return onCraftEvent("craft:iap:purchased", cb);
|
|
5516
|
+
},
|
|
5517
|
+
onFailed(cb) {
|
|
5518
|
+
return onCraftEvent("craft:iap:failed", cb);
|
|
5519
|
+
},
|
|
5520
|
+
onRestored(cb) {
|
|
5521
|
+
return onCraftEvent("craft:iap:restored", cb);
|
|
5522
|
+
},
|
|
5523
|
+
onProductsLoaded(cb) {
|
|
5524
|
+
return onCraftEvent("craft:iap:productsLoaded", (e) => cb(e.products || []));
|
|
5525
|
+
},
|
|
5526
|
+
onRefunded(cb) {
|
|
5527
|
+
return onCraftEvent("craft:iap:refunded", cb);
|
|
5528
|
+
},
|
|
5529
|
+
onSubscriptionStatusChanged(cb) {
|
|
5530
|
+
return onCraftEvent("craft:iap:subscriptionStatusChanged", cb);
|
|
5531
|
+
},
|
|
5532
|
+
async getActiveSubscriptions() {
|
|
5533
|
+
if (!hasBridge("iap"))
|
|
5534
|
+
return [];
|
|
5535
|
+
const fn = window.craft.iap.getActiveSubscriptions;
|
|
5536
|
+
if (typeof fn !== "function")
|
|
5537
|
+
return [];
|
|
5538
|
+
const r = await fn();
|
|
5539
|
+
return Array.isArray(r) ? r : [];
|
|
5540
|
+
},
|
|
5541
|
+
async isEligibleForIntroOffer(productId) {
|
|
5542
|
+
if (!hasBridge("iap"))
|
|
5543
|
+
return false;
|
|
5544
|
+
const fn = window.craft.iap.isEligibleForIntroOffer;
|
|
5545
|
+
if (typeof fn !== "function")
|
|
5546
|
+
return false;
|
|
5547
|
+
return !!await fn(productId);
|
|
5548
|
+
}
|
|
5549
|
+
};
|
|
5550
|
+
// src/handoff.ts
|
|
5551
|
+
var handoff = {
|
|
5552
|
+
async startActivity(type, options) {
|
|
5553
|
+
if (!type)
|
|
5554
|
+
throw new Error("handoff.startActivity: type is required");
|
|
5555
|
+
if (!hasBridge("handoff"))
|
|
5556
|
+
return false;
|
|
5557
|
+
const r = await window.craft.handoff.startActivity(type, options);
|
|
5558
|
+
return typeof r === "boolean" ? r : !!(r && r.ok);
|
|
5559
|
+
},
|
|
5560
|
+
async updateActivity(options) {
|
|
5561
|
+
if (!hasBridge("handoff"))
|
|
5562
|
+
return false;
|
|
5563
|
+
const r = await window.craft.handoff.updateActivity(options);
|
|
5564
|
+
return typeof r === "boolean" ? r : !!(r && r.ok);
|
|
5565
|
+
},
|
|
5566
|
+
async stopActivity() {
|
|
5567
|
+
if (!hasBridge("handoff"))
|
|
5568
|
+
return;
|
|
5569
|
+
await window.craft.handoff.stopActivity();
|
|
5570
|
+
},
|
|
5571
|
+
async getCurrentActivity() {
|
|
5572
|
+
if (!hasBridge("handoff"))
|
|
5573
|
+
return null;
|
|
5574
|
+
const r = await window.craft.handoff.getCurrentActivity();
|
|
5575
|
+
return r && typeof r.type === "string" ? r : null;
|
|
5576
|
+
},
|
|
5577
|
+
onIncoming(cb) {
|
|
5578
|
+
return onCraftEvent("craft:handoff:incoming", cb);
|
|
5579
|
+
}
|
|
5580
|
+
};
|
|
5581
|
+
// src/live-activities.ts
|
|
5582
|
+
var liveActivities = {
|
|
5583
|
+
async start(type, state) {
|
|
5584
|
+
return handoff.startActivity(type, {
|
|
5585
|
+
title: state?.title,
|
|
5586
|
+
webpageURL: state?.webpageURL,
|
|
5587
|
+
userInfo: state?.state
|
|
5588
|
+
});
|
|
5589
|
+
},
|
|
5590
|
+
async update(state) {
|
|
5591
|
+
return handoff.updateActivity({
|
|
5592
|
+
title: state.title,
|
|
5593
|
+
webpageURL: state.webpageURL,
|
|
5594
|
+
userInfo: state.state
|
|
5595
|
+
});
|
|
5596
|
+
},
|
|
5597
|
+
async stop() {
|
|
5598
|
+
await handoff.stopActivity();
|
|
5599
|
+
}
|
|
5600
|
+
};
|
|
5601
|
+
// src/location.ts
|
|
5602
|
+
var location = {
|
|
5603
|
+
async requestPermission(mode = "whenInUse") {
|
|
5604
|
+
if (hasBridge("location"))
|
|
5605
|
+
return await window.craft.location.requestPermission(mode);
|
|
5606
|
+
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5607
|
+
return "undetermined";
|
|
5608
|
+
}
|
|
5609
|
+
return "not-supported";
|
|
5610
|
+
},
|
|
5611
|
+
async getAuthorization() {
|
|
5612
|
+
if (hasBridge("location"))
|
|
5613
|
+
return await window.craft.location.getAuthorization();
|
|
5614
|
+
return "unknown";
|
|
5615
|
+
},
|
|
5616
|
+
async getCurrentLocation() {
|
|
5617
|
+
if (hasBridge("location"))
|
|
5618
|
+
return await window.craft.location.getCurrentLocation();
|
|
5619
|
+
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5620
|
+
navigator.geolocation.getCurrentPosition((pos) => {
|
|
5621
|
+
window.dispatchEvent(new CustomEvent("craft:location:update", {
|
|
5622
|
+
detail: {
|
|
5623
|
+
latitude: pos.coords.latitude,
|
|
5624
|
+
longitude: pos.coords.longitude,
|
|
5625
|
+
altitude: pos.coords.altitude,
|
|
5626
|
+
horizontalAccuracy: pos.coords.accuracy,
|
|
5627
|
+
verticalAccuracy: pos.coords.altitudeAccuracy,
|
|
5628
|
+
speed: pos.coords.speed
|
|
5629
|
+
}
|
|
5630
|
+
}));
|
|
5631
|
+
}, (err) => {
|
|
5632
|
+
window.dispatchEvent(new CustomEvent("craft:location:error", {
|
|
5633
|
+
detail: { message: err.message || String(err) }
|
|
5634
|
+
}));
|
|
5635
|
+
});
|
|
5636
|
+
return { requested: true };
|
|
5637
|
+
}
|
|
5638
|
+
return { requested: false };
|
|
5639
|
+
},
|
|
5640
|
+
async startWatching(options) {
|
|
5641
|
+
if (hasBridge("location"))
|
|
5642
|
+
return await window.craft.location.startWatching(options);
|
|
5643
|
+
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5644
|
+
const watchId = navigator.geolocation.watchPosition((pos) => {
|
|
5645
|
+
window.dispatchEvent(new CustomEvent("craft:location:update", {
|
|
5646
|
+
detail: {
|
|
5647
|
+
latitude: pos.coords.latitude,
|
|
5648
|
+
longitude: pos.coords.longitude,
|
|
5649
|
+
altitude: pos.coords.altitude,
|
|
5650
|
+
horizontalAccuracy: pos.coords.accuracy,
|
|
5651
|
+
verticalAccuracy: pos.coords.altitudeAccuracy,
|
|
5652
|
+
speed: pos.coords.speed
|
|
5653
|
+
}
|
|
5654
|
+
}));
|
|
5655
|
+
});
|
|
5656
|
+
window.__craftWebLocationWatchId = watchId;
|
|
5657
|
+
return true;
|
|
5658
|
+
}
|
|
5659
|
+
return false;
|
|
5660
|
+
},
|
|
5661
|
+
async stopWatching() {
|
|
5662
|
+
if (hasBridge("location")) {
|
|
5663
|
+
await window.craft.location.stopWatching();
|
|
5664
|
+
return;
|
|
5665
|
+
}
|
|
5666
|
+
if (typeof navigator !== "undefined" && navigator.geolocation) {
|
|
5667
|
+
const id = window.__craftWebLocationWatchId;
|
|
5668
|
+
if (id != null) {
|
|
5669
|
+
navigator.geolocation.clearWatch(id);
|
|
5670
|
+
window.__craftWebLocationWatchId = null;
|
|
5671
|
+
}
|
|
5672
|
+
}
|
|
5673
|
+
},
|
|
5674
|
+
onUpdate(cb) {
|
|
5675
|
+
return onCraftEvent("craft:location:update", cb);
|
|
5676
|
+
},
|
|
5677
|
+
onError(cb) {
|
|
5678
|
+
return onCraftEvent("craft:location:error", cb);
|
|
5679
|
+
},
|
|
5680
|
+
onAuthChanged(cb) {
|
|
5681
|
+
return onCraftEvent("craft:location:authChanged", cb);
|
|
5682
|
+
}
|
|
5683
|
+
};
|
|
5684
|
+
// src/screen-capture.ts
|
|
5685
|
+
var screenCapture = {
|
|
5686
|
+
async captureScreen() {
|
|
5687
|
+
if (!hasBridge("screenCapture"))
|
|
5688
|
+
return null;
|
|
5689
|
+
const r = await window.craft.screenCapture.captureScreen();
|
|
5690
|
+
return r ? String(r) : null;
|
|
5691
|
+
},
|
|
5692
|
+
async captureWindow(id) {
|
|
5693
|
+
if (!hasBridge("screenCapture"))
|
|
5694
|
+
return null;
|
|
5695
|
+
if (!Number.isFinite(id) || id <= 0)
|
|
5696
|
+
throw new Error("captureWindow: id must be a positive number");
|
|
5697
|
+
const r = await window.craft.screenCapture.captureWindow(id);
|
|
5698
|
+
return r ? String(r) : null;
|
|
5699
|
+
},
|
|
5700
|
+
async listWindows() {
|
|
5701
|
+
if (!hasBridge("screenCapture"))
|
|
5702
|
+
return [];
|
|
5703
|
+
return await window.craft.screenCapture.listWindows();
|
|
5704
|
+
}
|
|
5705
|
+
};
|
|
5706
|
+
// src/local-server.ts
|
|
5707
|
+
var localServer = {
|
|
5708
|
+
async start(port = 0, host = "127.0.0.1") {
|
|
5709
|
+
if (!hasBridge("localServer"))
|
|
5710
|
+
return { port: 0, started: false, reason: "bridge unavailable" };
|
|
5711
|
+
return await window.craft.localServer.start(port, host);
|
|
5712
|
+
},
|
|
5713
|
+
async stop() {
|
|
5714
|
+
if (!hasBridge("localServer"))
|
|
5715
|
+
return;
|
|
5716
|
+
await window.craft.localServer.stop();
|
|
5717
|
+
},
|
|
5718
|
+
async respond(options) {
|
|
5719
|
+
if (!hasBridge("localServer"))
|
|
5720
|
+
return;
|
|
5721
|
+
await window.craft.localServer.respond(options || { status: 200, body: "OK" });
|
|
5722
|
+
},
|
|
5723
|
+
onRequest(cb) {
|
|
5724
|
+
return onCraftEvent("craft:localServer:request", cb);
|
|
5725
|
+
},
|
|
5726
|
+
async awaitOAuthCallback(options = {}) {
|
|
5727
|
+
requireBridge("localServer");
|
|
5728
|
+
const { port: requestedPort = 0, host = "127.0.0.1", timeoutMs = 5 * 60 * 1000, successHTML } = options;
|
|
5729
|
+
const start = await this.start(requestedPort, host);
|
|
5730
|
+
if (!start.started)
|
|
5731
|
+
throw new Error(`localServer: start failed${start.reason ? ` \u2014 ${start.reason}` : ""}`);
|
|
5732
|
+
return new Promise((resolve, reject) => {
|
|
5733
|
+
const timer = setTimeout(() => {
|
|
5734
|
+
off();
|
|
5735
|
+
this.stop().catch(() => {});
|
|
5736
|
+
reject(new Error("localServer: OAuth callback timed out"));
|
|
5737
|
+
}, timeoutMs);
|
|
5738
|
+
const off = this.onRequest(({ url }) => {
|
|
5739
|
+
clearTimeout(timer);
|
|
5740
|
+
off();
|
|
5741
|
+
const body = successHTML ?? `<!doctype html><meta charset="utf-8"><title>Done</title>
|
|
5742
|
+
<style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f5f5f7}</style>
|
|
5743
|
+
<div><h1>You can close this tab.</h1><p>Returning to the app\u2026</p></div>
|
|
5744
|
+
<script>setTimeout(()=>window.close(),1500)</script>`;
|
|
5745
|
+
this.respond({ status: 200, body, contentType: "text/html; charset=utf-8" }).catch(() => {}).finally(() => this.stop().catch(() => {}));
|
|
5746
|
+
resolve({ url, port: start.port });
|
|
5747
|
+
});
|
|
5748
|
+
});
|
|
5749
|
+
}
|
|
5750
|
+
};
|
|
5751
|
+
// src/biometric.ts
|
|
5752
|
+
var biometric = {
|
|
5753
|
+
async isAvailable() {
|
|
5754
|
+
if (!hasBridge("biometric"))
|
|
5755
|
+
return false;
|
|
5756
|
+
return await window.craft.biometric.isAvailable();
|
|
5757
|
+
},
|
|
5758
|
+
async getBiometryType() {
|
|
5759
|
+
if (!hasBridge("biometric"))
|
|
5760
|
+
return "none";
|
|
5761
|
+
return await window.craft.biometric.getBiometryType();
|
|
5762
|
+
},
|
|
5763
|
+
async evaluate(reason, options) {
|
|
5764
|
+
if (!reason)
|
|
5765
|
+
throw new Error("biometric.evaluate: reason is required");
|
|
5766
|
+
if (!hasBridge("biometric"))
|
|
5767
|
+
return { success: false, errorCode: -1 };
|
|
5768
|
+
return await window.craft.biometric.evaluate(reason, options);
|
|
5769
|
+
}
|
|
5770
|
+
};
|
|
5771
|
+
// src/audio.ts
|
|
5772
|
+
var webAudio = null;
|
|
5773
|
+
var audio = {
|
|
5774
|
+
async play(path, options) {
|
|
5775
|
+
if (hasBridge("audio")) {
|
|
5776
|
+
return await window.craft.audio.play(path, options);
|
|
5777
|
+
}
|
|
5778
|
+
if (typeof window === "undefined" || typeof Audio === "undefined")
|
|
5779
|
+
return false;
|
|
5780
|
+
if (webAudio) {
|
|
5781
|
+
webAudio.pause();
|
|
5782
|
+
webAudio = null;
|
|
5783
|
+
}
|
|
5784
|
+
webAudio = new Audio(path);
|
|
5785
|
+
if (options?.volume != null)
|
|
5786
|
+
webAudio.volume = options.volume;
|
|
5787
|
+
if (options?.loops)
|
|
5788
|
+
webAudio.loop = true;
|
|
5789
|
+
try {
|
|
5790
|
+
await webAudio.play();
|
|
5791
|
+
return true;
|
|
5792
|
+
} catch {
|
|
5793
|
+
return false;
|
|
5794
|
+
}
|
|
5795
|
+
},
|
|
5796
|
+
async playSystemSound(name) {
|
|
5797
|
+
if (hasBridge("audio"))
|
|
5798
|
+
return await window.craft.audio.playSystemSound(name);
|
|
5799
|
+
if (typeof window === "undefined" || typeof Audio === "undefined")
|
|
5800
|
+
return false;
|
|
5801
|
+
try {
|
|
5802
|
+
webAudio = new Audio(`/System/Library/Sounds/${name}.aiff`);
|
|
5803
|
+
await webAudio.play();
|
|
5804
|
+
return true;
|
|
5805
|
+
} catch {
|
|
5806
|
+
return false;
|
|
5807
|
+
}
|
|
5808
|
+
},
|
|
5809
|
+
async stop() {
|
|
5810
|
+
if (hasBridge("audio")) {
|
|
5811
|
+
await window.craft.audio.stop();
|
|
5812
|
+
return;
|
|
5813
|
+
}
|
|
5814
|
+
if (webAudio) {
|
|
5815
|
+
webAudio.pause();
|
|
5816
|
+
webAudio.currentTime = 0;
|
|
5817
|
+
webAudio = null;
|
|
5818
|
+
}
|
|
5819
|
+
},
|
|
5820
|
+
async isPlaying() {
|
|
5821
|
+
if (hasBridge("audio"))
|
|
5822
|
+
return await window.craft.audio.isPlaying();
|
|
5823
|
+
return !!(webAudio && !webAudio.paused);
|
|
5824
|
+
},
|
|
5825
|
+
async startRecording(path, options) {
|
|
5826
|
+
if (hasBridge("audio"))
|
|
5827
|
+
return await window.craft.audio.startRecording(path, options);
|
|
5828
|
+
return false;
|
|
5829
|
+
},
|
|
5830
|
+
async stopRecording() {
|
|
5831
|
+
if (hasBridge("audio"))
|
|
5832
|
+
await window.craft.audio.stopRecording();
|
|
5833
|
+
},
|
|
5834
|
+
async isRecording() {
|
|
5835
|
+
if (hasBridge("audio"))
|
|
5836
|
+
return await window.craft.audio.isRecording();
|
|
5837
|
+
return false;
|
|
5838
|
+
}
|
|
5839
|
+
};
|
|
5840
|
+
// src/apple-script.ts
|
|
5841
|
+
var appleScript = {
|
|
5842
|
+
async execute(source) {
|
|
5843
|
+
if (!source)
|
|
5844
|
+
throw new Error("appleScript.execute: source is required");
|
|
5845
|
+
if (!hasBridge("appleScript"))
|
|
5846
|
+
return { ok: false };
|
|
5847
|
+
return await window.craft.appleScript.execute(source);
|
|
5848
|
+
}
|
|
5849
|
+
};
|
|
5850
|
+
// src/file-associations.ts
|
|
5851
|
+
var fileAssociations = {
|
|
5852
|
+
async getDefault(uti) {
|
|
5853
|
+
if (!uti)
|
|
5854
|
+
throw new Error("fileAssociations.getDefault: uti is required");
|
|
5855
|
+
if (!hasBridge("fileAssociations"))
|
|
5856
|
+
return null;
|
|
5857
|
+
const v = await window.craft.fileAssociations.getDefault(uti);
|
|
5858
|
+
return v ? String(v) : null;
|
|
5859
|
+
},
|
|
5860
|
+
async setDefault(uti, bundleId) {
|
|
5861
|
+
if (!uti || !bundleId)
|
|
5862
|
+
throw new Error("fileAssociations.setDefault: uti and bundleId are required");
|
|
5863
|
+
if (!hasBridge("fileAssociations"))
|
|
5864
|
+
return false;
|
|
5865
|
+
return await window.craft.fileAssociations.setDefault(uti, bundleId);
|
|
5866
|
+
}
|
|
5867
|
+
};
|
|
5868
|
+
// src/tags.ts
|
|
5869
|
+
var tags = {
|
|
5870
|
+
async get(path) {
|
|
5871
|
+
if (!path)
|
|
5872
|
+
throw new Error("tags.get: path is required");
|
|
5873
|
+
if (!hasBridge("tags"))
|
|
5874
|
+
return [];
|
|
5875
|
+
return await window.craft.tags.get(path);
|
|
5876
|
+
},
|
|
5877
|
+
async set(path, t) {
|
|
5878
|
+
if (!path)
|
|
5879
|
+
throw new Error("tags.set: path is required");
|
|
5880
|
+
if (!hasBridge("tags"))
|
|
5881
|
+
return false;
|
|
5882
|
+
const arr = Array.isArray(t) ? t : [String(t)];
|
|
5883
|
+
return await window.craft.tags.set(path, arr);
|
|
5884
|
+
},
|
|
5885
|
+
async clear(path) {
|
|
5886
|
+
if (!path)
|
|
5887
|
+
throw new Error("tags.clear: path is required");
|
|
5888
|
+
if (!hasBridge("tags"))
|
|
5889
|
+
return false;
|
|
5890
|
+
return await window.craft.tags.clear(path);
|
|
5891
|
+
}
|
|
5892
|
+
};
|
|
5893
|
+
// src/pdf.ts
|
|
5894
|
+
var pdf = {
|
|
5895
|
+
async countPages(path) {
|
|
5896
|
+
if (!path)
|
|
5897
|
+
throw new Error("pdf.countPages: path is required");
|
|
5898
|
+
if (!hasBridge("pdf"))
|
|
5899
|
+
return 0;
|
|
5900
|
+
return await window.craft.pdf.countPages(path);
|
|
5901
|
+
},
|
|
5902
|
+
async extractText(path) {
|
|
5903
|
+
if (!path)
|
|
5904
|
+
throw new Error("pdf.extractText: path is required");
|
|
5905
|
+
if (!hasBridge("pdf"))
|
|
5906
|
+
return "";
|
|
5907
|
+
return await window.craft.pdf.extractText(path);
|
|
5908
|
+
}
|
|
5909
|
+
};
|
|
5910
|
+
// src/log.ts
|
|
5911
|
+
var log = {
|
|
5912
|
+
async debug(m) {
|
|
5913
|
+
if (hasBridge("log"))
|
|
5914
|
+
await window.craft.log.debug(m);
|
|
5915
|
+
else
|
|
5916
|
+
console.debug(m);
|
|
5917
|
+
},
|
|
5918
|
+
async info(m) {
|
|
5919
|
+
if (hasBridge("log"))
|
|
5920
|
+
await window.craft.log.info(m);
|
|
5921
|
+
else
|
|
5922
|
+
console.info(m);
|
|
5923
|
+
},
|
|
5924
|
+
async warn(m) {
|
|
5925
|
+
if (hasBridge("log"))
|
|
5926
|
+
await window.craft.log.warn(m);
|
|
5927
|
+
else
|
|
5928
|
+
console.warn(m);
|
|
5929
|
+
},
|
|
5930
|
+
async error(m) {
|
|
5931
|
+
if (hasBridge("log"))
|
|
5932
|
+
await window.craft.log.error(m);
|
|
5933
|
+
else
|
|
5934
|
+
console.error(m);
|
|
5935
|
+
}
|
|
5936
|
+
};
|
|
5937
|
+
// src/bonjour.ts
|
|
5938
|
+
var bonjour = {
|
|
5939
|
+
async browse(serviceType) {
|
|
5940
|
+
if (!hasBridge("bonjour"))
|
|
5941
|
+
return { started: false, reason: "bridge unavailable" };
|
|
5942
|
+
return await window.craft.bonjour.browse(serviceType);
|
|
5943
|
+
},
|
|
5944
|
+
async stop() {
|
|
5945
|
+
if (hasBridge("bonjour"))
|
|
5946
|
+
await window.craft.bonjour.stop();
|
|
5947
|
+
},
|
|
5948
|
+
onFound(cb) {
|
|
5949
|
+
return onCraftEvent("craft:bonjour:found", cb);
|
|
5950
|
+
},
|
|
5951
|
+
onLost(cb) {
|
|
5952
|
+
return onCraftEvent("craft:bonjour:lost", cb);
|
|
5953
|
+
}
|
|
5954
|
+
};
|
|
5955
|
+
// src/spotlight.ts
|
|
5956
|
+
var spotlight = {
|
|
5957
|
+
async index(items) {
|
|
5958
|
+
if (!hasBridge("spotlight"))
|
|
5959
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
5960
|
+
return await window.craft.spotlight.index(items);
|
|
5961
|
+
},
|
|
5962
|
+
async remove(ids) {
|
|
5963
|
+
if (!hasBridge("spotlight"))
|
|
5964
|
+
return { ok: false };
|
|
5965
|
+
return await window.craft.spotlight.remove(ids);
|
|
5966
|
+
},
|
|
5967
|
+
async removeAll() {
|
|
5968
|
+
if (!hasBridge("spotlight"))
|
|
5969
|
+
return { ok: false };
|
|
5970
|
+
return await window.craft.spotlight.removeAll();
|
|
5971
|
+
}
|
|
5972
|
+
};
|
|
5973
|
+
// src/speech-recognition.ts
|
|
5974
|
+
var speechRecognition = {
|
|
5975
|
+
async isAvailable() {
|
|
5976
|
+
if (!hasBridge("speechRecognition"))
|
|
5977
|
+
return false;
|
|
5978
|
+
return await window.craft.speechRecognition.isAvailable();
|
|
5979
|
+
},
|
|
5980
|
+
async start(opts) {
|
|
5981
|
+
if (!hasBridge("speechRecognition"))
|
|
5982
|
+
return { started: false, reason: "bridge unavailable" };
|
|
5983
|
+
return await window.craft.speechRecognition.start(opts);
|
|
5984
|
+
},
|
|
5985
|
+
async stop() {
|
|
5986
|
+
if (hasBridge("speechRecognition"))
|
|
5987
|
+
await window.craft.speechRecognition.stop();
|
|
5988
|
+
},
|
|
5989
|
+
onPartial(cb) {
|
|
5990
|
+
return onCraftEvent("craft:speechRecognition:partial", cb);
|
|
5991
|
+
},
|
|
5992
|
+
onFinal(cb) {
|
|
5993
|
+
return onCraftEvent("craft:speechRecognition:final", cb);
|
|
5994
|
+
}
|
|
5995
|
+
};
|
|
5996
|
+
// src/vision.ts
|
|
5997
|
+
var vision = {
|
|
5998
|
+
async recognizeText(path) {
|
|
5999
|
+
if (!path)
|
|
6000
|
+
throw new Error("vision.recognizeText: path is required");
|
|
6001
|
+
if (!hasBridge("vision"))
|
|
6002
|
+
return [];
|
|
6003
|
+
return await window.craft.vision.recognizeText(path);
|
|
6004
|
+
},
|
|
6005
|
+
async detectFaces(path) {
|
|
6006
|
+
if (!path)
|
|
6007
|
+
throw new Error("vision.detectFaces: path is required");
|
|
6008
|
+
if (!hasBridge("vision"))
|
|
6009
|
+
return [];
|
|
6010
|
+
return await window.craft.vision.detectFaces(path);
|
|
6011
|
+
},
|
|
6012
|
+
async detectBarcodes(path) {
|
|
6013
|
+
if (!path)
|
|
6014
|
+
throw new Error("vision.detectBarcodes: path is required");
|
|
6015
|
+
if (!hasBridge("vision"))
|
|
6016
|
+
return [];
|
|
6017
|
+
return await window.craft.vision.detectBarcodes(path);
|
|
6018
|
+
}
|
|
6019
|
+
};
|
|
6020
|
+
// src/midi.ts
|
|
6021
|
+
var midi = {
|
|
6022
|
+
async listSources() {
|
|
6023
|
+
if (!hasBridge("midi"))
|
|
6024
|
+
return [];
|
|
6025
|
+
return await window.craft.midi.listSources();
|
|
6026
|
+
},
|
|
6027
|
+
async listDestinations() {
|
|
6028
|
+
if (!hasBridge("midi"))
|
|
6029
|
+
return [];
|
|
6030
|
+
return await window.craft.midi.listDestinations();
|
|
6031
|
+
},
|
|
6032
|
+
async send(destinationIndex, data) {
|
|
6033
|
+
if (!hasBridge("midi"))
|
|
6034
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
6035
|
+
return await window.craft.midi.send(destinationIndex, data);
|
|
6036
|
+
},
|
|
6037
|
+
async subscribe(sourceIndex) {
|
|
6038
|
+
if (!hasBridge("midi"))
|
|
6039
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
6040
|
+
return await window.craft.midi.subscribe(sourceIndex);
|
|
6041
|
+
},
|
|
6042
|
+
async unsubscribe(sourceIndex) {
|
|
6043
|
+
if (!hasBridge("midi"))
|
|
6044
|
+
return { ok: false };
|
|
6045
|
+
return await window.craft.midi.unsubscribe(sourceIndex);
|
|
6046
|
+
},
|
|
6047
|
+
onMessage(cb) {
|
|
6048
|
+
return onCraftEvent("craft:midi:message", cb);
|
|
6049
|
+
}
|
|
6050
|
+
};
|
|
6051
|
+
// src/coreml.ts
|
|
6052
|
+
var coreml = {
|
|
6053
|
+
async loadModel(id, path) {
|
|
6054
|
+
if (!id || !path)
|
|
6055
|
+
throw new Error("coreml.loadModel: id and path are required");
|
|
6056
|
+
if (!hasBridge("coreml"))
|
|
6057
|
+
return false;
|
|
6058
|
+
return await window.craft.coreml.loadModel(id, path);
|
|
6059
|
+
},
|
|
6060
|
+
async unloadModel(id) {
|
|
6061
|
+
if (!hasBridge("coreml"))
|
|
6062
|
+
return;
|
|
6063
|
+
await window.craft.coreml.unloadModel(id);
|
|
6064
|
+
},
|
|
6065
|
+
async predict(id, input) {
|
|
6066
|
+
if (!id)
|
|
6067
|
+
throw new Error("coreml.predict: id is required");
|
|
6068
|
+
if (!hasBridge("coreml"))
|
|
6069
|
+
return null;
|
|
6070
|
+
return await window.craft.coreml.predict(id, input);
|
|
6071
|
+
}
|
|
6072
|
+
};
|
|
6073
|
+
// src/continuity-camera.ts
|
|
6074
|
+
var continuityCamera = {
|
|
6075
|
+
async listCameras() {
|
|
6076
|
+
if (!hasBridge("continuityCamera"))
|
|
6077
|
+
return [];
|
|
6078
|
+
return await window.craft.continuityCamera.listCameras();
|
|
6079
|
+
}
|
|
6080
|
+
};
|
|
6081
|
+
// src/service-menu.ts
|
|
6082
|
+
var serviceMenu = {
|
|
6083
|
+
async register(name) {
|
|
6084
|
+
if (!name)
|
|
6085
|
+
throw new Error("serviceMenu.register: name is required");
|
|
6086
|
+
if (!hasBridge("serviceMenu"))
|
|
6087
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
6088
|
+
return await window.craft.serviceMenu.register(name);
|
|
6089
|
+
},
|
|
6090
|
+
async unregister(name) {
|
|
6091
|
+
if (!name)
|
|
6092
|
+
throw new Error("serviceMenu.unregister: name is required");
|
|
6093
|
+
if (!hasBridge("serviceMenu"))
|
|
6094
|
+
return;
|
|
6095
|
+
await window.craft.serviceMenu.unregister(name);
|
|
6096
|
+
},
|
|
6097
|
+
onInvoked(cb) {
|
|
6098
|
+
return onCraftEvent("craft:serviceMenu:invoked", cb);
|
|
6099
|
+
}
|
|
6100
|
+
};
|
|
6101
|
+
// src/serial.ts
|
|
6102
|
+
var serial = {
|
|
6103
|
+
async list() {
|
|
6104
|
+
if (!hasBridge("serial"))
|
|
6105
|
+
return [];
|
|
6106
|
+
return await window.craft.serial.list();
|
|
6107
|
+
},
|
|
6108
|
+
async open(path, baud = 9600) {
|
|
6109
|
+
if (!path)
|
|
6110
|
+
throw new Error("serial.open: path is required");
|
|
6111
|
+
if (!hasBridge("serial"))
|
|
6112
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
6113
|
+
return await window.craft.serial.open(path, baud);
|
|
6114
|
+
},
|
|
6115
|
+
async write(id, data) {
|
|
6116
|
+
if (!id)
|
|
6117
|
+
throw new Error("serial.write: id is required");
|
|
6118
|
+
if (!hasBridge("serial"))
|
|
6119
|
+
return { ok: false, reason: "bridge unavailable" };
|
|
6120
|
+
return await window.craft.serial.write(id, data);
|
|
6121
|
+
},
|
|
6122
|
+
async close(id) {
|
|
6123
|
+
if (!hasBridge("serial"))
|
|
6124
|
+
return;
|
|
6125
|
+
await window.craft.serial.close(id);
|
|
6126
|
+
},
|
|
6127
|
+
onData(cb) {
|
|
6128
|
+
return onCraftEvent("craft:serial:data", cb);
|
|
6129
|
+
}
|
|
6130
|
+
};
|
|
6131
|
+
// src/capabilities.ts
|
|
6132
|
+
var BRIDGE_INDEX = [
|
|
6133
|
+
{ name: "fs", support: "native" },
|
|
6134
|
+
{ name: "shell", support: "native" },
|
|
6135
|
+
{ name: "system", support: "all" },
|
|
6136
|
+
{ name: "clipboard", support: "all" },
|
|
6137
|
+
{ name: "dialog", support: "all" },
|
|
6138
|
+
{ name: "window", support: "native" },
|
|
6139
|
+
{ name: "tray", support: "native" },
|
|
6140
|
+
{ name: "menu", support: "native" },
|
|
6141
|
+
{ name: "theme", support: "all" },
|
|
6142
|
+
{ name: "screen", support: "all" },
|
|
6143
|
+
{ name: "network", support: "all" },
|
|
6144
|
+
{ name: "power", support: "all" },
|
|
6145
|
+
{ name: "battery", support: "all" },
|
|
6146
|
+
{ name: "notifications", support: "all" },
|
|
6147
|
+
{ name: "globalShortcuts", support: "native" },
|
|
6148
|
+
{ name: "autolaunch", support: "native" },
|
|
6149
|
+
{ name: "appInfo", support: "all" },
|
|
6150
|
+
{ name: "localServer", support: "native" },
|
|
6151
|
+
{ name: "bluetooth", support: "native" },
|
|
6152
|
+
{ name: "crashReporter", support: "all" },
|
|
6153
|
+
{ name: "updater", support: "native" },
|
|
6154
|
+
{ name: "iap", support: "macos" },
|
|
6155
|
+
{ name: "keychain", support: "native" },
|
|
6156
|
+
{ name: "log", support: "all" },
|
|
6157
|
+
{ name: "biometric", support: "macos" },
|
|
6158
|
+
{ name: "location", support: "macos" },
|
|
6159
|
+
{ name: "audio", support: "macos" },
|
|
6160
|
+
{ name: "deepLink", support: "native" },
|
|
6161
|
+
{ name: "handoff", support: "macos" },
|
|
6162
|
+
{ name: "liveActivities", support: "macos" },
|
|
6163
|
+
{ name: "touchbar", support: "macos" },
|
|
6164
|
+
{ name: "dragOut", support: "macos" },
|
|
6165
|
+
{ name: "appleScript", support: "macos" },
|
|
6166
|
+
{ name: "fileAssociations", support: "native" },
|
|
6167
|
+
{ name: "tags", support: "macos" },
|
|
6168
|
+
{ name: "pdf", support: "macos" },
|
|
6169
|
+
{ name: "bonjour", support: "macos" },
|
|
6170
|
+
{ name: "spotlight", support: "macos" },
|
|
6171
|
+
{ name: "speechRecognition", support: "macos" },
|
|
6172
|
+
{ name: "vision", support: "macos" },
|
|
6173
|
+
{ name: "midi", support: "macos" },
|
|
6174
|
+
{ name: "coreml", support: "macos" },
|
|
6175
|
+
{ name: "continuityCamera", support: "macos" },
|
|
6176
|
+
{ name: "serviceMenu", support: "macos" },
|
|
6177
|
+
{ name: "serial", support: "native" }
|
|
6178
|
+
];
|
|
6179
|
+
function getCapabilities() {
|
|
6180
|
+
return BRIDGE_INDEX.map(({ name, support }) => ({
|
|
6181
|
+
name,
|
|
6182
|
+
support,
|
|
6183
|
+
available: hasBridge(name)
|
|
6184
|
+
}));
|
|
6185
|
+
}
|
|
6186
|
+
function getCapability(name) {
|
|
6187
|
+
const entry = BRIDGE_INDEX.find((b) => b.name === name);
|
|
6188
|
+
if (!entry)
|
|
6189
|
+
return;
|
|
6190
|
+
return { ...entry, available: hasBridge(name) };
|
|
6191
|
+
}
|
|
6192
|
+
function isAvailable(name) {
|
|
6193
|
+
const cap = getCapability(name);
|
|
6194
|
+
return !!cap && cap.available;
|
|
6195
|
+
}
|
|
3763
6196
|
export {
|
|
6197
|
+
windowEvents,
|
|
6198
|
+
vision,
|
|
6199
|
+
updater,
|
|
3764
6200
|
unregisterHotkey,
|
|
3765
6201
|
unregisterAllHotkeys,
|
|
3766
6202
|
triggerTrayAction,
|
|
6203
|
+
touchbar,
|
|
6204
|
+
theme,
|
|
6205
|
+
tags,
|
|
6206
|
+
system,
|
|
6207
|
+
spotlight,
|
|
6208
|
+
speechRecognition,
|
|
6209
|
+
speech,
|
|
6210
|
+
signPayload,
|
|
3767
6211
|
showWarningToast,
|
|
3768
6212
|
showWarningModal,
|
|
3769
6213
|
showWarningDialog,
|
|
@@ -3784,18 +6228,42 @@ export {
|
|
|
3784
6228
|
showColorPicker,
|
|
3785
6229
|
showAlertDialog,
|
|
3786
6230
|
showAlert,
|
|
6231
|
+
shell,
|
|
3787
6232
|
setDesktopConfig,
|
|
3788
6233
|
setAutoLaunch,
|
|
6234
|
+
serviceMenu,
|
|
6235
|
+
serial,
|
|
6236
|
+
screenCapture,
|
|
6237
|
+
screen,
|
|
3789
6238
|
resetDesktopConfig,
|
|
3790
6239
|
requestNotificationPermission,
|
|
3791
6240
|
registerHotkey,
|
|
6241
|
+
redactPII,
|
|
3792
6242
|
prompt2 as prompt,
|
|
6243
|
+
printing,
|
|
6244
|
+
permissions,
|
|
6245
|
+
pdf,
|
|
3793
6246
|
parseShortcut,
|
|
3794
6247
|
openDevWindow,
|
|
3795
6248
|
notify,
|
|
6249
|
+
notifications,
|
|
6250
|
+
network,
|
|
6251
|
+
nativeAutoLaunch,
|
|
6252
|
+
midi,
|
|
6253
|
+
menu,
|
|
6254
|
+
log,
|
|
6255
|
+
location,
|
|
6256
|
+
localServer,
|
|
6257
|
+
liveActivities,
|
|
6258
|
+
keychain,
|
|
3796
6259
|
isWebviewAvailable,
|
|
6260
|
+
isDragOutAvailable,
|
|
3797
6261
|
isCaffeinated,
|
|
6262
|
+
isAvailable,
|
|
3798
6263
|
isAutoLaunchEnabled,
|
|
6264
|
+
iap,
|
|
6265
|
+
handoff,
|
|
6266
|
+
globalShortcuts,
|
|
3799
6267
|
getWindowBridgeScript,
|
|
3800
6268
|
getWindow,
|
|
3801
6269
|
getTrayInstance,
|
|
@@ -3804,19 +6272,25 @@ export {
|
|
|
3804
6272
|
getRegisteredHotkeys,
|
|
3805
6273
|
getDialogBridgeScript,
|
|
3806
6274
|
getDesktopConfig,
|
|
6275
|
+
getCapability,
|
|
6276
|
+
getCapabilities,
|
|
3807
6277
|
getCaffeinateStatus,
|
|
3808
6278
|
getActiveWindowIds,
|
|
3809
6279
|
getActiveTrayInstances,
|
|
3810
6280
|
getActiveModalCount,
|
|
3811
6281
|
getActiveAlertCount,
|
|
6282
|
+
fs,
|
|
3812
6283
|
formatTime,
|
|
3813
6284
|
formatShortcut,
|
|
3814
6285
|
formatRemainingTime,
|
|
3815
6286
|
formatDuration,
|
|
3816
6287
|
formatCompact,
|
|
6288
|
+
fileAssociations,
|
|
6289
|
+
dragOut,
|
|
3817
6290
|
dismissAllAlerts,
|
|
3818
6291
|
dismissAlertById,
|
|
3819
6292
|
delay,
|
|
6293
|
+
deepLinks,
|
|
3820
6294
|
decaffeinate,
|
|
3821
6295
|
createWindowWithHTML,
|
|
3822
6296
|
createWindow,
|
|
@@ -3859,10 +6333,21 @@ export {
|
|
|
3859
6333
|
createAvatar,
|
|
3860
6334
|
createAutocomplete,
|
|
3861
6335
|
createAccordion,
|
|
6336
|
+
crashReporter,
|
|
6337
|
+
coreml,
|
|
6338
|
+
continuityCamera,
|
|
3862
6339
|
confirm2 as confirm,
|
|
3863
6340
|
closeAllWindows,
|
|
3864
6341
|
closeAllModals,
|
|
6342
|
+
clipboard,
|
|
3865
6343
|
caffeinate,
|
|
6344
|
+
bonjour,
|
|
6345
|
+
bluetooth,
|
|
6346
|
+
biometric,
|
|
6347
|
+
battery,
|
|
6348
|
+
audio,
|
|
6349
|
+
appleScript,
|
|
6350
|
+
app as appInfo,
|
|
3866
6351
|
alert2 as alert,
|
|
3867
6352
|
TRAY_MENU_STYLES,
|
|
3868
6353
|
TOAST_STYLES,
|
|
@@ -3871,4 +6356,4 @@ export {
|
|
|
3871
6356
|
AVAILABLE_COMPONENTS
|
|
3872
6357
|
};
|
|
3873
6358
|
|
|
3874
|
-
//# debugId=
|
|
6359
|
+
//# debugId=EABDD0C2E7CA346F64756E2164756E21
|