mirinjs 0.1.0-alpha.15 → 0.1.0-alpha.17
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/package.json +1 -1
- package/src/config/manifest.ts +2 -0
- package/src/index.ts +3 -1
- package/src/native.ts +6 -0
- package/src/notification.ts +19 -0
- package/src/sidecar.ts +12 -7
- package/src/updater/lib/manifest.ts +15 -0
- package/src/updater/types.ts +4 -0
- package/src/updater/updater.ts +1 -0
package/package.json
CHANGED
package/src/config/manifest.ts
CHANGED
|
@@ -311,6 +311,8 @@ export interface ReleaseConfig {
|
|
|
311
311
|
baseUrl: string;
|
|
312
312
|
/** Update channel; baked into artifact names + support dir. Default "stable". */
|
|
313
313
|
channel?: string;
|
|
314
|
+
/** Optional markdown release notes embedded in the update manifest. */
|
|
315
|
+
notes?: string;
|
|
314
316
|
}
|
|
315
317
|
|
|
316
318
|
export interface CefConfig {
|
package/src/index.ts
CHANGED
|
@@ -50,10 +50,12 @@ export type { LogLevel } from "./logger.ts";
|
|
|
50
50
|
export { getLogLevel, Logger, logger, setLogLevel } from "./logger.ts";
|
|
51
51
|
export type { MenuItemTemplate, MenuRole } from "./menu.ts";
|
|
52
52
|
export { menu } from "./menu.ts";
|
|
53
|
+
export type { NotificationOptions } from "./notification.ts";
|
|
54
|
+
export { notification } from "./notification.ts";
|
|
53
55
|
export { NotAttachedError, resolveWorker } from "./runtime.ts";
|
|
54
56
|
export { globalShortcut } from "./shortcut.ts";
|
|
55
57
|
export type { SidecarOptions, SidecarProcess } from "./sidecar.ts";
|
|
56
|
-
export { sidecar } from "./sidecar.ts";
|
|
58
|
+
export { resolveSidecar, sidecar } from "./sidecar.ts";
|
|
57
59
|
export type { TrayOptions } from "./tray.ts";
|
|
58
60
|
export { Tray } from "./tray.ts";
|
|
59
61
|
export type { UpdateInfo, UpdateProgress, UpdaterEvents, UpdaterStatus } from "./updater/index.ts";
|
package/src/native.ts
CHANGED
|
@@ -42,6 +42,7 @@ const symbols = {
|
|
|
42
42
|
mirin_clipboard_read_text: { args: [], returns: FFIType.ptr },
|
|
43
43
|
mirin_clipboard_write_text: { args: [FFIType.ptr], returns: FFIType.void },
|
|
44
44
|
mirin_dialog_show: { args: [FFIType.ptr], returns: FFIType.void },
|
|
45
|
+
mirin_notification_show: { args: [FFIType.ptr], returns: FFIType.i32 },
|
|
45
46
|
} as const;
|
|
46
47
|
|
|
47
48
|
export type EventListener = (event: string) => void;
|
|
@@ -174,4 +175,9 @@ export class Core {
|
|
|
174
175
|
const buf = nullTerminated(specJson);
|
|
175
176
|
this.#lib.symbols.mirin_dialog_show(ptr(buf));
|
|
176
177
|
}
|
|
178
|
+
|
|
179
|
+
notificationShow(specJson: string): boolean {
|
|
180
|
+
const buf = nullTerminated(specJson);
|
|
181
|
+
return this.#lib.symbols.mirin_notification_show(ptr(buf)) === 1;
|
|
182
|
+
}
|
|
177
183
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { runtime } from "./runtime.ts";
|
|
2
|
+
|
|
3
|
+
export interface NotificationOptions {
|
|
4
|
+
title: string;
|
|
5
|
+
body?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const notification = {
|
|
9
|
+
/** Ask the operating system to display a desktop notification. */
|
|
10
|
+
show(options: NotificationOptions): boolean {
|
|
11
|
+
const title = options.title.trim();
|
|
12
|
+
if (!title || title.length > 128) return false;
|
|
13
|
+
if (options.body && options.body.length > 512) return false;
|
|
14
|
+
|
|
15
|
+
return runtime().core.notificationShow(
|
|
16
|
+
JSON.stringify({ ...options, title, appName: runtime().id }),
|
|
17
|
+
);
|
|
18
|
+
},
|
|
19
|
+
};
|
package/src/sidecar.ts
CHANGED
|
@@ -36,6 +36,17 @@ export interface SidecarProcess {
|
|
|
36
36
|
kill(signal?: number | NodeJS.Signals): void;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/** Resolve a declared sidecar's staged/bundled path without starting it. */
|
|
40
|
+
export function resolveSidecar(name: string): string {
|
|
41
|
+
const dir = runtime().sidecarDir;
|
|
42
|
+
if (!dir) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`resolveSidecar("${name}"): no sidecar dir (is this running under the mirin host?)`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return join(dir, name);
|
|
48
|
+
}
|
|
49
|
+
|
|
39
50
|
const children = new Set<Bun.Subprocess>();
|
|
40
51
|
let hooked = false;
|
|
41
52
|
|
|
@@ -68,15 +79,9 @@ function ensureHooks(): void {
|
|
|
68
79
|
* isn't attached or no `sidecarDir` is known (e.g. run outside the host).
|
|
69
80
|
*/
|
|
70
81
|
export function sidecar(name: string, opts: SidecarOptions = {}): SidecarProcess {
|
|
71
|
-
const dir = runtime().sidecarDir;
|
|
72
|
-
if (!dir) {
|
|
73
|
-
throw new Error(
|
|
74
|
-
`app.sidecar("${name}"): no sidecar dir (is this running under the mirin host?)`,
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
82
|
ensureHooks();
|
|
78
83
|
|
|
79
|
-
const bin =
|
|
84
|
+
const bin = resolveSidecar(name);
|
|
80
85
|
const child = Bun.spawn([bin, ...(opts.args ?? [])], {
|
|
81
86
|
cwd: opts.cwd,
|
|
82
87
|
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
@@ -8,11 +8,13 @@ export function parseManifest(
|
|
|
8
8
|
expected: { channel: string; platform: string; arch: string },
|
|
9
9
|
): Manifest {
|
|
10
10
|
const manifest = record(value, "manifest");
|
|
11
|
+
const body = optionalStringField(manifest, "body", 64 * 1024);
|
|
11
12
|
const parsed: Manifest = {
|
|
12
13
|
version: versionField(manifest, "version"),
|
|
13
14
|
channel: stringField(manifest, "channel"),
|
|
14
15
|
platform: stringField(manifest, "platform"),
|
|
15
16
|
arch: stringField(manifest, "arch"),
|
|
17
|
+
...(body === undefined ? {} : { body }),
|
|
16
18
|
tarHash: sha256Field(manifest, "tarHash"),
|
|
17
19
|
bundle: artifactField(manifest.bundle, "bundle"),
|
|
18
20
|
patches: patchesField(manifest.patches),
|
|
@@ -44,6 +46,19 @@ function stringField(source: Record<string, unknown>, key: string): string {
|
|
|
44
46
|
return value;
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
function optionalStringField(
|
|
50
|
+
source: Record<string, unknown>,
|
|
51
|
+
key: string,
|
|
52
|
+
maxLength: number,
|
|
53
|
+
): string | undefined {
|
|
54
|
+
const value = source[key];
|
|
55
|
+
if (value === undefined) return undefined;
|
|
56
|
+
if (typeof value !== "string" || value.length > maxLength) {
|
|
57
|
+
throw new Error(`invalid update manifest field: ${key}`);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
|
|
47
62
|
function versionField(source: Record<string, unknown>, key: string): string {
|
|
48
63
|
const value = stringField(source, key);
|
|
49
64
|
if (
|
package/src/updater/types.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface Manifest {
|
|
|
32
32
|
channel: string;
|
|
33
33
|
platform: string;
|
|
34
34
|
arch: string;
|
|
35
|
+
/** Optional markdown release notes shown by app UIs. */
|
|
36
|
+
body?: string;
|
|
35
37
|
/** SHA-256 of the uncompressed bundle tar (update identity + integrity). */
|
|
36
38
|
tarHash: string;
|
|
37
39
|
bundle: UpdateArtifact;
|
|
@@ -43,6 +45,8 @@ export interface UpdateInfo {
|
|
|
43
45
|
version: string;
|
|
44
46
|
currentVersion: string;
|
|
45
47
|
channel: string;
|
|
48
|
+
/** Optional markdown release notes from the update manifest. */
|
|
49
|
+
body?: string;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
export interface UpdateProgress {
|