@simplepush/cli 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.mjs +50 -19
- package/dist/main.mjs.map +1 -1
- package/package.json +2 -2
package/dist/main.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import { mkdir, stat, writeFile } from "node:fs/promises";
|
|
|
14
14
|
import { connect, createConnection } from "node:net";
|
|
15
15
|
import path, { basename, extname, join } from "node:path";
|
|
16
16
|
//#region package.json
|
|
17
|
-
var version = "0.
|
|
17
|
+
var version = "0.7.0";
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/errors.ts
|
|
20
20
|
/** No CLI session saved — `sp auth login` hasn't been run (or was logged out). */
|
|
@@ -573,6 +573,46 @@ const quietOption = Options.boolean("quiet").pipe(Options.withAlias("q"), Option
|
|
|
573
573
|
/** Shared helper for repeatable validated text options. */
|
|
574
574
|
const mappedText = (name, parse) => Options.text(name).pipe(Options.mapTryCatch(parse, toHelp));
|
|
575
575
|
//#endregion
|
|
576
|
+
//#region src/services/browser.ts
|
|
577
|
+
/** The command line that opens `url` on `platform`. Pure, so it can be tested
|
|
578
|
+
* for every platform from one machine. */
|
|
579
|
+
function browserLaunch(platform, url) {
|
|
580
|
+
switch (platform) {
|
|
581
|
+
case "darwin": return {
|
|
582
|
+
command: "open",
|
|
583
|
+
args: [url],
|
|
584
|
+
windowsVerbatimArguments: false
|
|
585
|
+
};
|
|
586
|
+
case "win32": return {
|
|
587
|
+
command: "cmd",
|
|
588
|
+
args: [
|
|
589
|
+
"/c",
|
|
590
|
+
"start",
|
|
591
|
+
"\"\"",
|
|
592
|
+
url.replace(/&/g, "^&")
|
|
593
|
+
],
|
|
594
|
+
windowsVerbatimArguments: true
|
|
595
|
+
};
|
|
596
|
+
default: return {
|
|
597
|
+
command: "xdg-open",
|
|
598
|
+
args: [url],
|
|
599
|
+
windowsVerbatimArguments: false
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
/** Fire-and-forget. A failure to spawn is swallowed: the caller has already
|
|
604
|
+
* printed the URL, so the user can open it by hand. */
|
|
605
|
+
const openInBrowser = (url) => Effect.sync(() => {
|
|
606
|
+
const launch = browserLaunch(process.platform, url);
|
|
607
|
+
try {
|
|
608
|
+
spawn(launch.command, launch.args, {
|
|
609
|
+
detached: true,
|
|
610
|
+
stdio: "ignore",
|
|
611
|
+
windowsVerbatimArguments: launch.windowsVerbatimArguments
|
|
612
|
+
}).unref();
|
|
613
|
+
} catch {}
|
|
614
|
+
});
|
|
615
|
+
//#endregion
|
|
576
616
|
//#region src/format.ts
|
|
577
617
|
function formatInstant(iso) {
|
|
578
618
|
const d = new Date(iso);
|
|
@@ -661,21 +701,6 @@ const startCallbackServer = Effect.gen(function* () {
|
|
|
661
701
|
awaitCallback: Deferred.await(callback)
|
|
662
702
|
};
|
|
663
703
|
});
|
|
664
|
-
const openInBrowser = (url) => Effect.sync(() => {
|
|
665
|
-
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
666
|
-
const args = process.platform === "win32" ? [
|
|
667
|
-
"/c",
|
|
668
|
-
"start",
|
|
669
|
-
"",
|
|
670
|
-
url
|
|
671
|
-
] : [url];
|
|
672
|
-
try {
|
|
673
|
-
spawn(cmd, args, {
|
|
674
|
-
detached: true,
|
|
675
|
-
stdio: "ignore"
|
|
676
|
-
}).unref();
|
|
677
|
-
} catch {}
|
|
678
|
-
});
|
|
679
704
|
function preferDeviceFlow() {
|
|
680
705
|
if (process.env.SP_AUTH_DEVICE === "1") return true;
|
|
681
706
|
if (process.env.SSH_CONNECTION || process.env.SSH_TTY) return true;
|
|
@@ -2476,7 +2501,7 @@ function formatHit(h) {
|
|
|
2476
2501
|
return [
|
|
2477
2502
|
`${h.ref} [${h.kind}] ${h.createdAt}`,
|
|
2478
2503
|
h.title !== void 0 ? ` ${h.title}` : void 0,
|
|
2479
|
-
h.actor !== void 0 ? ` by: ${h.actor}` : void 0,
|
|
2504
|
+
h.actor !== void 0 ? ` by: ${h.actor.name !== void 0 ? `${h.actor.name} (${h.actor.publicId})` : h.actor.publicId}` : void 0,
|
|
2480
2505
|
h.snippet !== void 0 ? ` ${h.snippet}` : void 0,
|
|
2481
2506
|
h.location !== void 0 ? ` at: ${h.location.latitude},${h.location.longitude}${h.location.distanceMeters !== void 0 ? ` (${Math.round(h.location.distanceMeters)}m away)` : ""}` : void 0
|
|
2482
2507
|
].filter((l) => l !== void 0).join("\n");
|
|
@@ -2883,6 +2908,7 @@ const broadcastOption$1 = Options.boolean("broadcast").pipe(Options.withAlias("b
|
|
|
2883
2908
|
const orgTopicOption$1 = Options.text("org-topic").pipe(Options.withAlias("o"), Options.withDescription("Send to an org topic by value (from `sp org topics list`). Org send; mutually exclusive with --member, --broadcast, and -k/--topic (the personal topic)."), Options.optional);
|
|
2884
2909
|
const tagOption$1 = Options.text("tag").pipe(Options.withDescription("Optional notification tag — recipients can use it to coalesce / replace prior notifications with the same tag."), Options.optional);
|
|
2885
2910
|
const imageOption = Options.text("image").pipe(Options.withDescription("Image URL to show in the push (PNG/JPEG/GIF). Renders on iOS + Android. Mutually exclusive with --audio. URLs only — file uploads are SDK-only."), Options.optional);
|
|
2911
|
+
const linkOption$2 = Options.text("link").pipe(Options.withAlias("l"), Options.withDescription("A URL shown as an \"Open link\" button on the push. Any scheme: https opens the browser, an app's deep link (unifi-protect://...) opens that app. Mutually exclusive with the input flags."), Options.optional);
|
|
2886
2912
|
const audioOption = Options.text("audio").pipe(Options.withDescription("Audio URL to play inline in the push (AIFF/WAV/MP3/M4A; iOS only). Mutually exclusive with --image. URLs only."), Options.optional);
|
|
2887
2913
|
const noEncryptOption$2 = Options.boolean("no-encrypt").pipe(Options.withDescription("Send the body in plaintext even when an unlocked vault is available."));
|
|
2888
2914
|
const actionInputOption = Options.text("action-input").pipe(Options.withAlias("a"), Options.withDescription("Add an actions input: tap-buttons the recipient answers with (e.g. Accept/Deny). Format: `[description;]key=Label[:style],...`, actions comma-separated; style is default|destructive. Use `\\,` for a literal comma in a label. A notification carries at most one input."), Options.optional);
|
|
@@ -2932,6 +2958,7 @@ const notifyCommand = Command.make("notify", {
|
|
|
2932
2958
|
tag: tagOption$1,
|
|
2933
2959
|
image: imageOption,
|
|
2934
2960
|
audio: audioOption,
|
|
2961
|
+
link: linkOption$2,
|
|
2935
2962
|
"text-input": textInputOption,
|
|
2936
2963
|
"choice-input": choiceInputOption,
|
|
2937
2964
|
"action-input": actionInputOption,
|
|
@@ -2961,6 +2988,7 @@ const notifyCommand = Command.make("notify", {
|
|
|
2961
2988
|
const message = args.content;
|
|
2962
2989
|
const imageUrl = Option.getOrUndefined(args.image);
|
|
2963
2990
|
const audioUrl = Option.getOrUndefined(args.audio);
|
|
2991
|
+
const linkUrl = Option.getOrUndefined(args.link);
|
|
2964
2992
|
if (imageUrl !== void 0 && audioUrl !== void 0) return yield* Effect.fail(new UserError({ message: "only one of --image or --audio may be set" }));
|
|
2965
2993
|
const mediaUrl = imageUrl ?? audioUrl;
|
|
2966
2994
|
const mediaKind = imageUrl !== void 0 ? "image" : "audio";
|
|
@@ -2969,6 +2997,7 @@ const notifyCommand = Command.make("notify", {
|
|
|
2969
2997
|
if (notifyMediaContentType(mediaUrl, mediaKind) === null) return yield* Effect.fail(new UserError({ message: `--${mediaKind} URL must point to a supported ${mediaKind} type (by extension); got "${mediaUrl}"` }));
|
|
2970
2998
|
}
|
|
2971
2999
|
const input = yield* parseNotificationInput(args["text-input"], Option.getOrUndefined(args["choice-input"]), Option.getOrUndefined(args["action-input"]));
|
|
3000
|
+
if (input !== void 0 && linkUrl !== void 0) return yield* Effect.fail(new UserError({ message: "a notification carries either an input or --link, not both: the input's buttons take the action slots, so the link would never be shown" }));
|
|
2972
3001
|
if (isOrgTarget) {
|
|
2973
3002
|
const api = yield* Api;
|
|
2974
3003
|
const vault = yield* (yield* VaultAccess).forSendOrPlaintext(args.noEncrypt);
|
|
@@ -2985,7 +3014,8 @@ const notifyCommand = Command.make("notify", {
|
|
|
2985
3014
|
...tagOpt !== void 0 ? { tag: tagOpt } : {},
|
|
2986
3015
|
...input !== void 0 ? { input } : {},
|
|
2987
3016
|
...imageUrl !== void 0 ? { image: imageUrl } : {},
|
|
2988
|
-
...audioUrl !== void 0 ? { audio: audioUrl } : {}
|
|
3017
|
+
...audioUrl !== void 0 ? { audio: audioUrl } : {},
|
|
3018
|
+
...linkUrl !== void 0 ? { link: linkUrl } : {}
|
|
2989
3019
|
};
|
|
2990
3020
|
yield* Effect.scoped(Effect.gen(function* () {
|
|
2991
3021
|
const client = yield* acquireOrgClient({
|
|
@@ -3045,7 +3075,8 @@ const notifyCommand = Command.make("notify", {
|
|
|
3045
3075
|
...tagOpt !== void 0 ? { tag: tagOpt } : {},
|
|
3046
3076
|
...input !== void 0 ? { input } : {},
|
|
3047
3077
|
...imageUrl !== void 0 ? { image: imageUrl } : {},
|
|
3048
|
-
...audioUrl !== void 0 ? { audio: audioUrl } : {}
|
|
3078
|
+
...audioUrl !== void 0 ? { audio: audioUrl } : {},
|
|
3079
|
+
...linkUrl !== void 0 ? { link: linkUrl } : {}
|
|
3049
3080
|
};
|
|
3050
3081
|
yield* Effect.scoped(Effect.gen(function* () {
|
|
3051
3082
|
const client = yield* acquireClient({
|